提交 8fd0a7f9 编写于 作者: qiuyiuestc's avatar qiuyiuestc

Update USB Device Stack to support more device controllers;

Pass USB CV test verification;
Code cleanup;
上级 db02f562
......@@ -20,6 +20,7 @@
* Change Logs:
* Date Author Notes
* 2012-10-01 Yi Qiu first version
* 2013-04-26 aozima add DEVICEQUALIFIER support.
*/
#ifndef __USB_COMMON_H__
......@@ -148,13 +149,22 @@ extern "C" {
#define USB_EPNO_MASK 0x7f
#define USB_DIR_OUT 0x00
#define USB_DIR_IN 0x80
#define USB_DIR_INOUT 0x40
#define USB_DIR_MASK 0x80
#define ID_UNASSIGNED 0
#define ID_ASSIGNED 1
#define RH_GET_PORT_STATUS 0
#define RH_SET_PORT_STATUS 1
#define RH_CLEAR_PORT_FEATURE 2
#define RH_SET_PORT_FEATURE 3
#define USB_BUS_POWERED 0
#define USB_SELF_POWERED 1
#define USB_REMOTE_WAKEUP 1
#define USB_EP_HALT 0
/*
* Port feature numbers
*/
......@@ -205,6 +215,7 @@ extern "C" {
#define USB_EP_ATTR(attr) (attr & USB_EP_ATTR_TYPE_MASK)
#define USB_EP_DESC_NUM(addr) (addr & USB_EP_DESC_NUM_MASK)
#define USB_EP_DIR(addr) ((addr & USB_DIR_MASK)>>7)
#define uswap_32(x) \
((((x) & 0xff000000) >> 24) | \
......@@ -239,7 +250,7 @@ struct usb_descriptor
};
typedef struct usb_descriptor* udesc_t;
struct udevice_descriptor
struct udevice_descriptor
{
rt_uint8_t bLength;
rt_uint8_t type;
......@@ -258,7 +269,7 @@ struct udevice_descriptor
};
typedef struct udevice_descriptor* udev_desc_t;
struct uconfig_descriptor
struct uconfig_descriptor
{
rt_uint8_t bLength;
rt_uint8_t type;
......@@ -272,7 +283,7 @@ struct uconfig_descriptor
};
typedef struct uconfig_descriptor* ucfg_desc_t;
struct uinterface_descriptor
struct uinterface_descriptor
{
rt_uint8_t bLength;
rt_uint8_t type;
......@@ -287,7 +298,7 @@ struct uinterface_descriptor
typedef struct uinterface_descriptor* uintf_desc_t;
/* Interface Association Descriptor (IAD) */
struct uiad_descriptor
struct uiad_descriptor
{
rt_uint8_t bLength;
rt_uint8_t bDescriptorType;
......@@ -300,7 +311,7 @@ struct uiad_descriptor
};
typedef struct uiad_descriptor* uiad_desc_t;
struct uendpoint_descriptor
struct uendpoint_descriptor
{
rt_uint8_t bLength;
rt_uint8_t type;
......@@ -311,7 +322,7 @@ struct uendpoint_descriptor
};
typedef struct uendpoint_descriptor* uep_desc_t;
struct ustring_descriptor
struct ustring_descriptor
{
rt_uint8_t bLength;
rt_uint8_t type;
......@@ -319,19 +330,34 @@ struct ustring_descriptor
};
typedef struct ustring_descriptor* ustr_desc_t;
struct uhub_descriptor
struct uhub_descriptor
{
rt_uint8_t length;
rt_uint8_t type;
rt_uint8_t num_ports;
rt_uint16_t characteristics;
rt_uint16_t characteristics;
rt_uint8_t pwron_to_good; /* power on to power good */
rt_uint8_t current;
rt_uint8_t current;
rt_uint8_t removable[8];
rt_uint8_t pwr_ctl[8];
};
typedef struct uhub_descriptor* uhub_desc_t;
/* USB_DESC_TYPE_DEVICEQUALIFIER: Device Qualifier descriptor */
struct usb_qualifier_descriptor
{
rt_uint8_t bLength;
rt_uint8_t bDescriptorType;
rt_uint16_t bcdUSB; // TODO: big-endian.
rt_uint8_t bDeviceClass;
rt_uint8_t bDeviceSubClass;
rt_uint8_t bDeviceProtocol;
rt_uint8_t bMaxPacketSize0;
rt_uint8_t bNumConfigurations;
rt_uint8_t bRESERVED;
} __attribute__ ((packed));
struct uhid_descriptor
{
rt_uint8_t bLength;
......@@ -352,15 +378,17 @@ struct ureqest
rt_uint8_t request_type;
rt_uint8_t request;
rt_uint16_t value;
rt_uint16_t index;
rt_uint16_t index;
rt_uint16_t length;
};
typedef struct ureqest* ureq_t;
#ifndef MIN
#define MIN(a, b) (a < b ? a : b)
#define MAX(a, b) (a > b ? a : b)
#endif
/*
/*
* the define related to mass storage
*/
#define USBREQ_GET_MAX_LUN 0xfe
......@@ -368,6 +396,11 @@ typedef struct ureqest* ureq_t;
#define SIZEOF_CSW 0x0d
#define SIZEOF_CBW 0x1f
#define SIZEOF_INQUIRY_CMD 0x24
#define SIZEOF_MODE_SENSE_6 0x4
#define SIZEOF_READ_CAPACITIES 0xc
#define SIZEOF_READ_CAPACITY 0x8
#define SIZEOF_REQUEST_SENSE 0x12
#define CBWFLAGS_DIR_M 0x80
#define CBWFLAGS_DIR_IN 0x80
......@@ -376,7 +409,7 @@ typedef struct ureqest* ureq_t;
#define SCSI_TEST_UNIT_READY 0x00
#define SCSI_REQUEST_SENSE 0x03
#define SCSI_INQUIRY_CMD 0x12
#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1e
#define SCSI_ALLOW_REMOVAL 0x1e
#define SCSI_MODE_SENSE_6 0x1a
#define SCSI_START_STOP 0x1b
#define SCSI_READ_CAPACITIES 0x23
......@@ -389,7 +422,7 @@ typedef struct ureqest* ureq_t;
#define CSW_SIGNATURE 0x53425355
#define CBW_TAG_VALUE 0x12345678
struct ustorage_cbw
struct ustorage_cbw
{
rt_uint32_t signature;
rt_uint32_t tag;
......@@ -401,11 +434,11 @@ struct ustorage_cbw
};
typedef struct ustorage_cbw* ustorage_cbw_t;
struct ustorage_csw
struct ustorage_csw
{
rt_uint32_t signature;
rt_uint32_t tag;
rt_uint32_t data_reside;
rt_int32_t data_reside;
rt_uint8_t status;
};
typedef struct ustorage_csw* ustorage_csw_t;
......
......@@ -20,7 +20,8 @@
* Change Logs:
* Date Author Notes
* 2012-10-01 Yi Qiu first version
* 2012-12-12 heyuanjie87 change endpoint and class handler
* 2012-12-12 heyuanjie87 change endpoint and function handler
* 2013-04-26 aozima add DEVICEQUALIFIER support.
*/
#ifndef __USB_DEVICE_H__
......@@ -31,59 +32,115 @@
/* Vendor ID */
#ifdef USB_VENDOR_ID
#define _VENDOR_ID USB_VENDOR_ID
#define _VENDOR_ID USB_VENDOR_ID
#else
#define _VENDOR_ID 0x0EFF
#define _VENDOR_ID 0x0EFF
#endif
/* Product ID */
#ifdef USB_PRODUCT_ID
#define _PRODUCT_ID USB_PRODUCT_ID
#define _PRODUCT_ID USB_PRODUCT_ID
#else
#define _PRODUCT_ID 0x0001
#define _PRODUCT_ID 0x0001
#endif
#define USB_BCD_DEVICE 0x0200 /* USB Specification Release Number in Binary-Coded Decimal */
#define USB_BCD_VERSION 0x0200 /* USB 2.0 */
struct uclass;
#define USB_BCD_DEVICE 0x0200 /* USB Specification Release Number in Binary-Coded Decimal */
#define USB_BCD_VERSION 0x0200 /* USB 2.0 */
#define EP0_IN_ADDR 0x80
#define EP0_OUT_ADDR 0x00
#define EP_HANDLER(ep, func, size) RT_ASSERT(ep != RT_NULL); ep->handler(func, size)
#define EP_ADDRESS(ep) ep->ep_desc->bEndpointAddress
#define EP_MAXPACKET(ep) ep->ep_desc->wMaxPacketSize
#define FUNC_ENABLE(func) do{ \
if(func->ops->enable != RT_NULL && \
func->enabled == RT_FALSE) \
{ \
if(func->ops->enable(func) == RT_EOK) \
func->enabled = RT_TRUE; \
} \
}while(0)
#define FUNC_DISABLE(func) do{ \
if(func->ops->disable != RT_NULL && \
func->enabled == RT_TRUE) \
{ \
func->enabled = RT_FALSE; \
func->ops->disable(func); \
} \
}while(0)
struct ufunction;
struct udevice;
struct uendpoint;
typedef enum
{
/* request to read full count */
UIO_REQUEST_READ_FULL,
/* request to read any count */
UIO_REQUEST_READ_BEST,
/* request to write full count */
UIO_REQUEST_WRITE,
}UIO_REQUEST_TYPE;
struct udcd_ops
{
rt_err_t (*set_address)(rt_uint8_t value);
rt_err_t (*clear_feature)(rt_uint16_t value, rt_uint16_t index);
rt_err_t (*set_feature)(rt_uint16_t value, rt_uint16_t index);
rt_err_t (*ep_alloc)(struct uendpoint* ep);
rt_err_t (*ep_free)(struct uendpoint* ep);
rt_err_t (*ep_stall)(struct uendpoint* ep);
rt_err_t (*ep_run)(struct uendpoint* ep);
rt_err_t (*ep_stop)(struct uendpoint* ep);
rt_err_t (*ep_read)(struct uendpoint* ep, void *buffer, rt_size_t size);
rt_size_t (*ep_write)(struct uendpoint* ep, void *buffer, rt_size_t size);
rt_err_t (*send_status)(void);
rt_err_t (*set_address)(rt_uint8_t address);
rt_err_t (*set_config)(rt_uint8_t address);
rt_err_t (*ep_set_stall)(rt_uint8_t address);
rt_err_t (*ep_clear_stall)(rt_uint8_t address);
rt_err_t (*ep_enable)(struct uendpoint* ep);
rt_err_t (*ep_disable)(struct uendpoint* ep);
rt_size_t (*ep_read_prepare)(rt_uint8_t address, void *buffer, rt_size_t size);
rt_size_t (*ep_read)(rt_uint8_t address, void *buffer);
rt_size_t (*ep_write)(rt_uint8_t address, void *buffer, rt_size_t size);
rt_err_t (*ep0_send_status)(void);
rt_err_t (*suspend)(void);
rt_err_t (*wakeup)(void);
};
struct udcd
struct ep_id
{
struct rt_device parent;
struct udcd_ops* ops;
struct rt_completion completion;
rt_uint8_t addr;
rt_uint8_t type;
rt_uint8_t dir;
rt_uint8_t maxpacket;
rt_uint8_t status;
};
typedef struct udcd* udcd_t;
typedef rt_err_t (*udep_handler_t)(struct udevice* device, struct uclass* cls, rt_size_t size);
typedef rt_err_t (*udep_handler_t)(struct ufunction* func, rt_size_t size);
struct uendpoint
struct uio_request
{
rt_list_t list;
UIO_REQUEST_TYPE req_type;
rt_uint8_t* buffer;
rt_size_t size;
rt_size_t remain_size;
};
typedef struct uio_request* uio_request_t;
struct uendpoint
{
rt_list_t list;
uep_desc_t ep_desc;
rt_list_t request_list;
struct uio_request request;
rt_uint8_t* buffer;
rt_bool_t stalled;
struct ep_id* id;
udep_handler_t handler;
rt_bool_t is_stall;
rt_err_t (*rx_indicate)(struct udevice* dev, rt_size_t size);
};
typedef struct uendpoint* uep_t;
struct udcd
{
struct rt_device parent;
const struct udcd_ops* ops;
struct uendpoint ep0;
struct ep_id* ep_pool;
};
typedef struct udcd* udcd_t;
struct ualtsetting
{
rt_list_t list;
......@@ -94,7 +151,7 @@ struct ualtsetting
};
typedef struct ualtsetting* ualtsetting_t;
typedef rt_err_t (*uintf_handler_t)(struct udevice* device, struct uclass* cls, ureq_t setup);
typedef rt_err_t (*uintf_handler_t)(struct ufunction* func, ureq_t setup);
struct uinterface
{
......@@ -106,32 +163,32 @@ struct uinterface
};
typedef struct uinterface* uintf_t;
struct uclass_ops
struct ufunction_ops
{
rt_err_t (*run)(struct udevice* device, struct uclass* cls);
rt_err_t (*stop)(struct udevice* device, struct uclass* cls);
rt_err_t (*sof_handler)(struct udevice* device, struct uclass* cls);
rt_err_t (*enable)(struct ufunction* func);
rt_err_t (*disable)(struct ufunction* func);
rt_err_t (*sof_handler)(struct ufunction* func);
};
typedef struct uclass_ops* uclass_ops_t;
typedef struct ufunction_ops* ufunction_ops_t;
struct uclass
struct ufunction
{
rt_list_t list;
uclass_ops_t ops;
void* eps;
ufunction_ops_t ops;
struct udevice* device;
udev_desc_t dev_desc;
void* user_data;
rt_bool_t enabled;
rt_list_t intf_list;
};
typedef struct uclass* uclass_t;
typedef struct ufunction* ufunction_t;
struct uconfig
{
rt_list_t list;
struct uconfig_descriptor cfg_desc;
rt_list_t cls_list;
rt_list_t func_list;
};
typedef struct uconfig* uconfig_t;
......@@ -139,6 +196,8 @@ struct udevice
{
rt_list_t list;
struct udevice_descriptor dev_desc;
struct usb_qualifier_descriptor * dev_qualifier;
const char** str;
udevice_state_t state;
......@@ -154,8 +213,11 @@ enum udev_msg_type
{
USB_MSG_SETUP_NOTIFY,
USB_MSG_DATA_NOTIFY,
USB_MSG_EP0_OUT,
USB_MSG_EP_CLEAR_FEATURE,
USB_MSG_SOF,
USB_MSG_RESET,
USB_MSG_PLUG_IN,
/* we don't need to add a "PLUG_IN" event because after the cable is
* plugged in(before any SETUP) the classed have nothing to do. If the host
* is ready, it will send RESET and we will have USB_MSG_RESET. So, a RESET
......@@ -164,153 +226,184 @@ enum udev_msg_type
};
typedef enum udev_msg_type udev_msg_type;
struct ep_msg
{
rt_size_t size;
rt_uint8_t ep_addr;
};
struct udev_msg
{
udev_msg_type type;
udcd_t dcd;
union
{
struct
{
rt_size_t size;
rt_uint8_t ep_addr;
} ep_msg;
struct
{
rt_uint32_t* packet;
} setup_msg;
struct ep_msg ep_msg;
struct ureqest setup;
} content;
};
typedef struct udev_msg* udev_msg_t;
udevice_t rt_usbd_device_create(void);
uconfig_t rt_usbd_config_create(void);
uclass_t rt_usbd_class_create(udevice_t device,
udev_desc_t dev_desc,
uclass_ops_t ops);
uintf_t rt_usbd_interface_create(udevice_t device, uintf_handler_t handler);
uep_t rt_usbd_endpoint_create(uep_desc_t ep_desc, udep_handler_t handler);
ualtsetting_t rt_usbd_altsetting_create(rt_size_t desc_size);
udevice_t rt_usbd_device_new(void);
uconfig_t rt_usbd_config_new(void);
ufunction_t rt_usbd_function_new(udevice_t device, udev_desc_t dev_desc,
ufunction_ops_t ops);
uintf_t rt_usbd_interface_new(udevice_t device, uintf_handler_t handler);
uep_t rt_usbd_endpoint_new(uep_desc_t ep_desc, udep_handler_t handler);
ualtsetting_t rt_usbd_altsetting_new(rt_size_t desc_size);
rt_err_t rt_usbd_core_init(void);
rt_err_t rt_usb_device_init(const char *udc_name);
rt_err_t rt_usbd_post_event(struct udev_msg *msg, rt_size_t size);
rt_err_t rt_usbd_free_device(udevice_t device);
rt_err_t rt_usb_device_init(void);
rt_err_t rt_usbd_event_signal(struct udev_msg* msg);
rt_err_t rt_usbd_device_set_controller(udevice_t device, udcd_t dcd);
rt_err_t rt_usbd_device_set_descriptor(udevice_t device, udev_desc_t dev_desc);
rt_err_t rt_usbd_device_set_string(udevice_t device, const char** ustring);
rt_err_t rt_usbd_device_set_qualifier(udevice_t device, struct usb_qualifier_descriptor* qualifier);
rt_err_t rt_usbd_device_add_config(udevice_t device, uconfig_t cfg);
rt_err_t rt_usbd_config_add_class(uconfig_t cfg, uclass_t cls);
rt_err_t rt_usbd_class_add_interface(uclass_t cls, uintf_t intf);
rt_err_t rt_usbd_config_add_function(uconfig_t cfg, ufunction_t func);
rt_err_t rt_usbd_function_add_interface(ufunction_t func, uintf_t intf);
rt_err_t rt_usbd_interface_add_altsetting(uintf_t intf, ualtsetting_t setting);
rt_err_t rt_usbd_altsetting_add_endpoint(ualtsetting_t setting, uep_t ep);
rt_err_t rt_usbd_altsetting_config_descriptor(ualtsetting_t setting,
const void *desc,
rt_off_t intf_pos);
rt_err_t rt_usbd_altsetting_config_descriptor(ualtsetting_t setting, const void* desc, rt_off_t intf_pos);
rt_err_t rt_usbd_set_config(udevice_t device, rt_uint8_t value);
rt_err_t rt_usbd_set_altsetting(uintf_t intf, rt_uint8_t value);
udevice_t rt_usbd_find_device(udcd_t dcd);
uconfig_t rt_usbd_find_config(udevice_t device, rt_uint8_t value);
uintf_t rt_usbd_find_interface(udevice_t device,
rt_uint8_t value,
uclass_t *pcls);
uep_t rt_usbd_find_endpoint(udevice_t device,
uclass_t *pcls,
rt_uint8_t ep_addr);
uclass_t rt_usbd_class_mstorage_create(udevice_t device);
uclass_t rt_usbd_class_cdc_create(udevice_t device);
uclass_t rt_usbd_class_rndis_create(udevice_t device);
uclass_t rt_usbd_class_dap_create(udevice_t device);
uintf_t rt_usbd_find_interface(udevice_t device, rt_uint8_t value, ufunction_t *pfunc);
uep_t rt_usbd_find_endpoint(udevice_t device, ufunction_t* pfunc, rt_uint8_t ep_addr);
rt_size_t rt_usbd_io_request(udevice_t device, uep_t ep, uio_request_t req);
rt_size_t rt_usbd_ep0_write(udevice_t device, void *buffer, rt_size_t size);
rt_size_t rt_usbd_ep0_read(udevice_t device, void *buffer, rt_size_t size,
rt_err_t (*rx_ind)(udevice_t device, rt_size_t size));
ufunction_t rt_usbd_function_mstorage_create(udevice_t device);
ufunction_t rt_usbd_function_cdc_create(udevice_t device);
ufunction_t rt_usbd_function_rndis_create(udevice_t device);
ufunction_t rt_usbd_function_dap_create(udevice_t device);
#ifdef RT_USB_DEVICE_COMPOSITE
rt_err_t rt_usbd_class_set_iad(uclass_t cls, uiad_desc_t iad_desc);
rt_err_t rt_usbd_function_set_iad(ufunction_t func, uiad_desc_t iad_desc);
#endif
rt_inline rt_err_t dcd_set_address(udcd_t dcd, rt_uint8_t value)
{
RT_ASSERT(dcd != RT_NULL);
return dcd->ops->set_address(value);
}
rt_inline rt_err_t dcd_clear_feature(udcd_t dcd,
rt_uint16_t value,
rt_uint16_t index)
rt_err_t rt_usbd_set_feature(udevice_t device, rt_uint16_t value, rt_uint16_t index);
rt_err_t rt_usbd_clear_feature(udevice_t device, rt_uint16_t value, rt_uint16_t index);
rt_err_t rt_usbd_ep_set_stall(udevice_t device, uep_t ep);
rt_err_t rt_usbd_ep_clear_stall(udevice_t device, uep_t ep);
rt_err_t rt_usbd_ep0_set_stall(udevice_t device);
rt_err_t rt_usbd_ep0_clear_stall(udevice_t device);
rt_err_t rt_usbd_ep0_setup_handler(udcd_t dcd, struct ureqest* setup);
rt_err_t rt_usbd_ep0_in_handler(udcd_t dcd);
rt_err_t rt_usbd_ep0_out_handler(udcd_t dcd, rt_size_t size);
rt_err_t rt_usbd_ep_in_handler(udcd_t dcd, rt_uint8_t address);
rt_err_t rt_usbd_ep_out_handler(udcd_t dcd, rt_uint8_t address, rt_size_t size);
rt_err_t rt_usbd_reset_handler(udcd_t dcd);
rt_err_t rt_usbd_connect_handler(udcd_t dcd);
rt_err_t rt_usbd_disconnect_handler(udcd_t dcd);
rt_err_t rt_usbd_sof_handler(udcd_t dcd);
rt_inline rt_err_t dcd_set_address(udcd_t dcd, rt_uint8_t address)
{
RT_ASSERT(dcd != RT_NULL);
RT_ASSERT(dcd->ops != RT_NULL);
RT_ASSERT(dcd->ops->set_address != RT_NULL);
return dcd->ops->clear_feature(value, index);
return dcd->ops->set_address(address);
}
rt_inline rt_err_t dcd_set_feature(udcd_t dcd,
rt_uint8_t value,
rt_uint16_t index)
rt_inline rt_err_t dcd_set_config(udcd_t dcd, rt_uint8_t address)
{
RT_ASSERT(dcd != RT_NULL);
RT_ASSERT(dcd->ops != RT_NULL);
RT_ASSERT(dcd->ops->set_config != RT_NULL);
return dcd->ops->set_feature(value, index);
return dcd->ops->set_config(address);
}
rt_inline rt_err_t dcd_ep_stall(udcd_t dcd, uep_t ep)
rt_inline rt_err_t dcd_ep_enable(udcd_t dcd, uep_t ep)
{
RT_ASSERT(dcd != RT_NULL);
RT_ASSERT(dcd->ops != RT_NULL);
RT_ASSERT(dcd->ops->ep_enable != RT_NULL);
return dcd->ops->ep_stall(ep);
return dcd->ops->ep_enable(ep);
}
rt_inline rt_uint8_t dcd_ep_alloc(udcd_t dcd, uep_t ep)
rt_inline rt_err_t dcd_ep_disable(udcd_t dcd, uep_t ep)
{
RT_ASSERT(dcd != RT_NULL);
RT_ASSERT(dcd->ops != RT_NULL);
RT_ASSERT(dcd->ops->ep_disable != RT_NULL);
return dcd->ops->ep_alloc(ep);
return dcd->ops->ep_disable(ep);
}
rt_inline rt_err_t dcd_ep_free(udcd_t dcd, uep_t ep)
rt_inline rt_size_t dcd_ep_read_prepare(udcd_t dcd, rt_uint8_t address, void *buffer,
rt_size_t size)
{
RT_ASSERT(dcd != RT_NULL);
RT_ASSERT(dcd->ops != RT_NULL);
return dcd->ops->ep_free(ep);
if(dcd->ops->ep_read_prepare != RT_NULL)
{
return dcd->ops->ep_read_prepare(address, buffer, size);
}
else
{
return 0;
}
}
rt_inline rt_err_t dcd_ep_run(udcd_t dcd, uep_t ep)
rt_inline rt_size_t dcd_ep_read(udcd_t dcd, rt_uint8_t address, void *buffer)
{
RT_ASSERT(dcd != RT_NULL);
RT_ASSERT(dcd->ops != RT_NULL);
return dcd->ops->ep_run(ep);
if(dcd->ops->ep_read != RT_NULL)
{
return dcd->ops->ep_read(address, buffer);
}
else
{
return 0;
}
}
rt_inline rt_err_t dcd_ep_stop(udcd_t dcd, uep_t ep)
rt_inline rt_size_t dcd_ep_write(udcd_t dcd, rt_uint8_t address, void *buffer,
rt_size_t size)
{
RT_ASSERT(dcd != RT_NULL);
RT_ASSERT(dcd->ops != RT_NULL);
RT_ASSERT(dcd->ops->ep_write != RT_NULL);
return dcd->ops->ep_stop(ep);
return dcd->ops->ep_write(address, buffer, size);
}
rt_inline rt_err_t dcd_ep_read(udcd_t dcd, uep_t ep, void *buffer,
rt_size_t size)
rt_inline rt_err_t dcd_ep0_send_status(udcd_t dcd)
{
RT_ASSERT(dcd != RT_NULL);
RT_ASSERT(dcd->ops != RT_NULL);
RT_ASSERT(dcd->ops->ep0_send_status != RT_NULL);
return dcd->ops->ep_read(ep, buffer, size);
return dcd->ops->ep0_send_status();
}
rt_inline rt_size_t dcd_ep_write(udcd_t dcd,
uep_t ep,
void *buffer,
rt_size_t size)
{
rt_inline rt_err_t dcd_ep_set_stall(udcd_t dcd, rt_uint8_t address)
{
RT_ASSERT(dcd != RT_NULL);
RT_ASSERT(dcd->ops != RT_NULL);
RT_ASSERT(dcd->ops->ep_set_stall != RT_NULL);
return dcd->ops->ep_write(ep, buffer, size);
return dcd->ops->ep_set_stall(address);
}
rt_inline rt_err_t dcd_send_status(udcd_t dcd)
rt_inline rt_err_t dcd_ep_clear_stall(udcd_t dcd, rt_uint8_t address)
{
RT_ASSERT(dcd != RT_NULL);
RT_ASSERT(dcd->ops != RT_NULL);
RT_ASSERT(dcd->ops->ep_clear_stall != RT_NULL);
return dcd->ops->send_status();
return dcd->ops->ep_clear_stall(address);
}
#endif
......@@ -13,9 +13,6 @@ if GetDepend('RT_USB_DEVICE_CDC'):
if GetDepend('RT_USB_DEVICE_MSTORAGE'):
src += Glob('class/mstorage.c')
if GetDepend('RT_USB_DEVICE_RNDIS'):
src += Glob('class/rndis.c')
CPPPATH = [cwd]
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_USB_DEVICE'], CPPPATH = CPPPATH)
......
......@@ -20,34 +20,56 @@
* Change Logs:
* Date Author Notes
* 2012-10-02 Yi Qiu first version
* 2012-12-12 heyuanjie87 change endpoints and class handler
* 2012-12-12 heyuanjie87 change endpoints and function handler
* 2013-06-25 heyuanjie87 remove SOF mechinism
* 2013-07-20 Yi Qiu do more test
*/
#include <rtthread.h>
#include <rtservice.h>
#include <rtdevice.h>
#include <rthw.h>
#include "cdc.h"
#ifdef RT_USB_DEVICE_CDC
#define TX_TIMEOUT 100
#define CDC_RX_BUFSIZE 2048
#define CDC_TX_BUFSIZE 2048
static rt_uint8_t rx_rbp[CDC_RX_BUFSIZE];
static rt_uint8_t tx_rbp[CDC_TX_BUFSIZE];
static struct rt_ringbuffer rx_ringbuffer;
static struct rt_ringbuffer tx_ringbuffer;
static struct serial_ringbuffer vcom_int_rx;
#define CDC_MAX_PACKET_SIZE 64
#define VCOM_DEVICE "vcom"
static struct rt_serial_device vcom_serial;
#define CDC_MaxPacketSize 64
ALIGN(RT_ALIGN_SIZE)
static rt_uint8_t rx_buf[CDC_RX_BUFSIZE];
ALIGN(RT_ALIGN_SIZE)
static rt_uint8_t tx_buf[CDC_TX_BUFSIZE];
static rt_uint8_t vcom_thread_stack[512];
static struct rt_thread vcom_thread;
#define VCOM_MQ_MSG_SZ 16
#define VCOM_MQ_MAX_MSG 4
/* internal of the message queue: every message is associated with a pointer,
* so in order to recveive VCOM_MQ_MAX_MSG messages, we have to allocate more
* than VCOM_MQ_MSG_SZ*VCOM_MQ_MAX_MSG memery. */
static rt_uint8_t vcom_tx_thread_mq_pool[(VCOM_MQ_MSG_SZ+sizeof(void*))*VCOM_MQ_MAX_MSG];
static struct rt_messagequeue vcom_tx_thread_mq;
static struct ucdc_line_coding line_coding;
struct vcom
{
struct rt_serial_device serial;
uep_t ep_out;
uep_t ep_in;
uep_t ep_cmd;
rt_bool_t connected;
rt_bool_t in_sending;
struct rt_completion wait;
rt_uint8_t rx_rbp[CDC_RX_BUFSIZE];
struct rt_ringbuffer rx_ringbuffer;
struct serial_ringbuffer vcom_int_rx;
};
volatile static rt_bool_t vcom_connected = RT_FALSE;
volatile static rt_bool_t vcom_in_sending = RT_FALSE;
struct vcom_tx_msg
{
struct rt_serial_device * serial;
const char *buf;
rt_size_t size;
};
static struct udevice_descriptor dev_desc =
{
......@@ -57,7 +79,7 @@ static struct udevice_descriptor dev_desc =
USB_CLASS_CDC, //bDeviceClass;
0x00, //bDeviceSubClass;
0x00, //bDeviceProtocol;
CDC_MaxPacketSize, //bMaxPacketSize0;
CDC_MAX_PACKET_SIZE, //bMaxPacketSize0;
_VENDOR_ID, //idVendor;
_PRODUCT_ID, //idProduct;
USB_BCD_DEVICE, //bcdDevice;
......@@ -67,6 +89,18 @@ static struct udevice_descriptor dev_desc =
USB_DYNAMIC, //bNumConfigurations;
};
static struct usb_qualifier_descriptor dev_qualifier =
{
sizeof(dev_qualifier),
USB_DESC_TYPE_DEVICEQUALIFIER,
0x0200,
USB_CLASS_CDC,
0x00,
64,
0x01,
0,
};
/* communcation interface descriptor */
const static struct ucdc_comm_descriptor _comm_desc =
{
......@@ -85,19 +119,19 @@ const static struct ucdc_comm_descriptor _comm_desc =
USB_DESC_LENGTH_INTERFACE,
USB_DESC_TYPE_INTERFACE,
USB_DYNAMIC,
0x00,
0x00,
0x01,
USB_CDC_CLASS_COMM,
USB_CDC_SUBCLASS_ACM,
USB_CDC_PROTOCOL_V25TER,
0x00,
/* Header Functional Descriptor */
0x05,
/* Header Functional Descriptor */
0x05,
USB_CDC_CS_INTERFACE,
USB_CDC_SCS_HEADER,
0x0110,
/* Call Management Functional Descriptor */
0x05,
/* Call Management Functional Descriptor */
0x05,
USB_CDC_CS_INTERFACE,
USB_CDC_SCS_CALL_MGMT,
0x00,
......@@ -107,13 +141,13 @@ const static struct ucdc_comm_descriptor _comm_desc =
USB_CDC_CS_INTERFACE,
USB_CDC_SCS_ACM,
0x02,
/* Union Functional Descriptor */
/* Union Functional Descriptor */
0x05,
USB_CDC_CS_INTERFACE,
USB_CDC_SCS_UNION,
USB_DYNAMIC,
USB_DYNAMIC,
/* Endpoint Descriptor */
/* Endpoint Descriptor */
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
USB_DYNAMIC | USB_DIR_IN,
......@@ -130,23 +164,23 @@ const static struct ucdc_data_descriptor _data_desc =
USB_DESC_TYPE_INTERFACE,
USB_DYNAMIC,
0x00,
0x02,
0x02,
USB_CDC_CLASS_DATA,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
/* endpoint, bulk out */
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
USB_DYNAMIC | USB_DIR_OUT,
USB_EP_ATTR_BULK,
USB_EP_ATTR_BULK,
USB_CDC_BUFSIZE,
0x00,
0x00,
/* endpoint, bulk in */
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
USB_DYNAMIC | USB_DIR_IN,
USB_EP_ATTR_BULK,
USB_EP_ATTR_BULK,
USB_CDC_BUFSIZE,
0x00,
};
......@@ -156,18 +190,24 @@ const static char* _ustring[] =
"Language",
"RT-Thread Team.",
"RTT Virtual Serial",
"1.1.0",
"32021919830108",
"Configuration",
"Interface",
};
static void rt_usb_vcom_init(struct ufunction *func);
static void _vcom_reset_state(void)
static void _vcom_reset_state(ufunction_t func)
{
int lvl = rt_hw_interrupt_disable();
tx_ringbuffer.read_mirror = tx_ringbuffer.read_index = 0;
tx_ringbuffer.write_mirror = tx_ringbuffer.write_index = 0;
vcom_connected = RT_FALSE;
vcom_in_sending = RT_FALSE;
struct vcom* data;
int lvl;
RT_ASSERT(func != RT_NULL)
data = (struct vcom*)func->user_data;
lvl = rt_hw_interrupt_disable();
data->connected = RT_FALSE;
data->in_sending = RT_FALSE;
/*rt_kprintf("reset USB serial\n", cnt);*/
rt_hw_interrupt_enable(lvl);
}
......@@ -175,95 +215,73 @@ static void _vcom_reset_state(void)
/**
* This function will handle cdc bulk in endpoint request.
*
* @param device the usb device object.
* @param func the usb function object.
* @param size request size.
*
* @return RT_EOK.
*/
static rt_err_t _ep_in_handler(udevice_t device, uclass_t cls, rt_size_t size)
static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size)
{
rt_uint32_t level;
rt_uint32_t remain;
cdc_eps_t eps;
struct vcom *data;
eps = (cdc_eps_t)cls->eps;
level = rt_hw_interrupt_disable();
remain = rt_ringbuffer_data_len(&tx_ringbuffer);
if (remain != 0)
{
/* although vcom_in_sending is set in SOF handler in the very
* beginning, we have to guarantee the state is right when start
* sending. There is at least one extreme case where we have finished the
* last IN transaction but the vcom_in_sending is RT_FALSE.
*
* Ok, what the extreme case is: pour data into vcom in loop. Open
* terminal on the PC, you will see the data. Then close it. So the
* data will be sent to the PC in the back. When the buffer of the PC
* driver is full. It will not send IN packet to the board and you will
* have no chance to clear vcom_in_sending in this function. The data
* will fill into the ringbuffer until it is full, and we will reset
* the state machine and clear vcom_in_sending. When you open the
* terminal on the PC again. The IN packet will appear on the line and
* we will, eventually, reach here with vcom_in_sending is clear.
*/
vcom_in_sending = RT_TRUE;
rt_ringbuffer_get(&tx_ringbuffer, eps->ep_in->buffer, remain);
rt_hw_interrupt_enable(level);
/* send data to host */
dcd_ep_write(device->dcd, eps->ep_in, eps->ep_in->buffer, remain);
RT_ASSERT(func != RT_NULL);
return RT_EOK;
}
RT_DEBUG_LOG(RT_DEBUG_USB, ("_ep_in_handler %d\n", size));
if (size != 0 &&
(size % CDC_MaxPacketSize) == 0)
data = (struct vcom*)func->user_data;
if ((size != 0) && (size % CDC_MAX_PACKET_SIZE == 0))
{
/* don't have data right now. Send a zero-length-packet to
* terminate the transaction.
*
* FIXME: actually, this might not be the right place to send zlp.
* Only the rt_device_write could know how much data is sending. */
vcom_in_sending = RT_TRUE;
rt_hw_interrupt_enable(level);
dcd_ep_write(device->dcd, eps->ep_in, RT_NULL, 0);
return RT_EOK;
}
else
{
vcom_in_sending = RT_FALSE;
rt_hw_interrupt_enable(level);
data->in_sending = RT_TRUE;
data->ep_in->request.buffer = RT_NULL;
data->ep_in->request.size = 0;
data->ep_in->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
return RT_EOK;
}
rt_completion_done(&data->wait);
return RT_EOK;
}
/**
* This function will handle cdc bulk out endpoint request.
*
* @param device the usb device object.
* @param func the usb function object.
* @param size request size.
*
* @return RT_EOK.
*/
static rt_err_t _ep_out_handler(udevice_t device, uclass_t cls, rt_size_t size)
static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size)
{
rt_uint32_t level;
cdc_eps_t eps;
struct vcom *data;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(func != RT_NULL);
eps = (cdc_eps_t)cls->eps;
RT_DEBUG_LOG(RT_DEBUG_USB, ("_ep_out_handler %d\n", size));
data = (struct vcom*)func->user_data;
/* receive data from USB VCOM */
level = rt_hw_interrupt_disable();
rt_ringbuffer_put(&rx_ringbuffer, eps->ep_out->buffer, size);
rt_ringbuffer_put(&data->rx_ringbuffer, data->ep_out->buffer, size);
rt_hw_interrupt_enable(level);
/* notify receive data */
rt_hw_serial_isr(&vcom_serial);
rt_hw_serial_isr(&data->serial);
dcd_ep_read(device->dcd, eps->ep_out, eps->ep_out->buffer,
eps->ep_out->ep_desc->wMaxPacketSize);
data->ep_out->request.buffer = data->ep_out->buffer;
data->ep_out->request.size = EP_MAXPACKET(data->ep_out);
data->ep_out->request.req_type = UIO_REQUEST_READ_BEST;
rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request);
return RT_EOK;
}
......@@ -276,9 +294,9 @@ static rt_err_t _ep_out_handler(udevice_t device, uclass_t cls, rt_size_t size)
*
* @return RT_EOK.
*/
static rt_err_t _ep_cmd_handler(udevice_t device, uclass_t cls, rt_size_t size)
static rt_err_t _ep_cmd_handler(ufunction_t func, rt_size_t size)
{
RT_ASSERT(device != RT_NULL);
RT_ASSERT(func != RT_NULL);
RT_DEBUG_LOG(RT_DEBUG_USB, ("_ep_cmd_handler\n"));
......@@ -301,14 +319,25 @@ static rt_err_t _cdc_get_line_coding(udevice_t device, ureq_t setup)
RT_ASSERT(device != RT_NULL);
RT_ASSERT(setup != RT_NULL);
RT_DEBUG_LOG(RT_DEBUG_USB, ("_cdc_get_line_coding\n"));
data.dwDTERate = 115200;
data.bCharFormat = 0;
data.bDataBits = 8;
data.bParityType = 0;
size = setup->length > 7 ? 7 : setup->length;
dcd_ep_write(device->dcd, 0, (void*)&data, size);
rt_usbd_ep0_write(device, (void*)&data, size);
return RT_EOK;
}
static rt_err_t _cdc_set_line_coding_callback(udevice_t device, rt_size_t size)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("_cdc_set_line_coding_callback\n"));
dcd_ep0_send_status(device->dcd);
return RT_EOK;
}
......@@ -322,21 +351,13 @@ static rt_err_t _cdc_get_line_coding(udevice_t device, ureq_t setup)
*/
static rt_err_t _cdc_set_line_coding(udevice_t device, ureq_t setup)
{
struct ucdc_line_coding data;
rt_err_t ret;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(setup != RT_NULL);
rt_completion_init(&device->dcd->completion);
RT_DEBUG_LOG(RT_DEBUG_USB, ("_cdc_set_line_coding\n"));
dcd_ep_read(device->dcd, 0, (void*)&data, setup->length);
ret = rt_completion_wait(&device->dcd->completion, 100);
if(ret != RT_EOK)
{
rt_kprintf("_cdc_set_line_coding timeout\n");
}
rt_usbd_ep0_read(device, (void*)&line_coding, sizeof(struct ucdc_line_coding),
_cdc_set_line_coding_callback);
return RT_EOK;
}
......@@ -349,11 +370,16 @@ static rt_err_t _cdc_set_line_coding(udevice_t device, ureq_t setup)
*
* @return RT_EOK on successful.
*/
static rt_err_t _interface_handler(udevice_t device, uclass_t cls, ureq_t setup)
static rt_err_t _interface_handler(ufunction_t func, ureq_t setup)
{
RT_ASSERT(device != RT_NULL);
struct vcom *data;
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
RT_ASSERT(setup != RT_NULL);
data = (struct vcom*)func->user_data;
switch(setup->request)
{
case CDC_SEND_ENCAPSULATED_COMMAND:
......@@ -367,14 +393,14 @@ static rt_err_t _interface_handler(udevice_t device, uclass_t cls, ureq_t setup)
case CDC_CLEAR_COMM_FEATURE:
break;
case CDC_SET_LINE_CODING:
_cdc_set_line_coding(device, setup);
vcom_connected = RT_TRUE;
_cdc_set_line_coding(func->device, setup);
data->connected = RT_TRUE;
break;
case CDC_GET_LINE_CODING:
_cdc_get_line_coding(device, setup);
_cdc_get_line_coding(func->device, setup);
break;
case CDC_SET_CONTROL_LINE_STATE:
dcd_send_status(device->dcd);
dcd_ep0_send_status(func->device->dcd);
break;
case CDC_SEND_BREAK:
break;
......@@ -387,92 +413,66 @@ static rt_err_t _interface_handler(udevice_t device, uclass_t cls, ureq_t setup)
}
/**
* This function will run cdc class, it will be called on handle set configuration request.
* This function will run cdc function, it will be called on handle set configuration request.
*
* @param device the usb device object.
* @param func the usb function object.
*
* @return RT_EOK on successful.
*/
static rt_err_t _class_run(udevice_t device, uclass_t cls)
static rt_err_t _function_enable(ufunction_t func)
{
cdc_eps_t eps;
RT_ASSERT(device != RT_NULL);
RT_DEBUG_LOG(RT_DEBUG_USB, ("cdc class run\n"));
eps = (cdc_eps_t)cls->eps;
struct vcom *data;
eps->ep_in->buffer = tx_buf;
eps->ep_out->buffer = rx_buf;
RT_ASSERT(func != RT_NULL);
_vcom_reset_state();
RT_DEBUG_LOG(RT_DEBUG_USB, ("cdc function enable\n"));
dcd_ep_read(device->dcd, eps->ep_out, eps->ep_out->buffer,
eps->ep_out->ep_desc->wMaxPacketSize);
_vcom_reset_state(func);
data = (struct vcom*)func->user_data;
data->ep_out->buffer = rt_malloc(CDC_RX_BUFSIZE);
data->ep_out->request.buffer = data->ep_out->buffer;
data->ep_out->request.size = EP_MAXPACKET(data->ep_out);
data->ep_out->request.req_type = UIO_REQUEST_READ_BEST;
rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request);
return RT_EOK;
}
/**
* This function will stop cdc class, it will be called on handle set configuration request.
* This function will stop cdc function, it will be called on handle set configuration request.
*
* @param device the usb device object.
* @param func the usb function object.
*
* @return RT_EOK on successful.
*/
static rt_err_t _class_stop(udevice_t device, uclass_t cls)
static rt_err_t _function_disable(ufunction_t func)
{
RT_ASSERT(device != RT_NULL);
struct vcom *data;
RT_DEBUG_LOG(RT_DEBUG_USB, ("cdc class stop\n"));
_vcom_reset_state();
return RT_EOK;
}
RT_ASSERT(func != RT_NULL);
/**
* This function will handle system sof event.
*
* @param device the usb device object.
*
* @return RT_EOK on successful.
*/
static rt_err_t _class_sof_handler(udevice_t device, uclass_t cls)
{
rt_uint32_t level;
rt_size_t size;
cdc_eps_t eps;
RT_DEBUG_LOG(RT_DEBUG_USB, ("cdc function disable\n"));
if (vcom_connected != RT_TRUE)
return -RT_ERROR;
_vcom_reset_state(func);
if (vcom_in_sending)
data = (struct vcom*)func->user_data;
if(data->ep_out->buffer != RT_NULL)
{
return RT_EOK;
rt_free(data->ep_out->buffer);
data->ep_out->buffer = RT_NULL;
}
eps = (cdc_eps_t)cls->eps;
size = rt_ringbuffer_data_len(&tx_ringbuffer);
if (size == 0)
return -RT_EFULL;
level = rt_hw_interrupt_disable();
rt_ringbuffer_get(&tx_ringbuffer, eps->ep_in->buffer, size);
rt_hw_interrupt_enable(level);
/* send data to host */
vcom_in_sending = RT_TRUE;
dcd_ep_write(device->dcd, eps->ep_in, eps->ep_in->buffer, size);
return RT_EOK;
}
static struct uclass_ops ops =
static struct ufunction_ops ops =
{
_class_run,
_class_stop,
_class_sof_handler,
_function_enable,
_function_disable,
RT_NULL,
};
/**
......@@ -483,7 +483,8 @@ static struct uclass_ops ops =
*
* @return RT_EOK on successful.
*/
static rt_err_t _cdc_descriptor_config(ucdc_comm_desc_t comm, rt_uint8_t cintf_nr, ucdc_data_desc_t data, rt_uint8_t dintf_nr)
static rt_err_t _cdc_descriptor_config(ucdc_comm_desc_t comm,
rt_uint8_t cintf_nr, ucdc_data_desc_t data, rt_uint8_t dintf_nr)
{
comm->call_mgmt_desc.data_interface = dintf_nr;
comm->union_desc.master_interface = cintf_nr;
......@@ -496,16 +497,16 @@ static rt_err_t _cdc_descriptor_config(ucdc_comm_desc_t comm, rt_uint8_t cintf_n
}
/**
* This function will create a cdc class instance.
* This function will create a cdc function instance.
*
* @param device the usb device object.
*
* @return RT_EOK on successful.
*/
uclass_t rt_usbd_class_cdc_create(udevice_t device)
ufunction_t rt_usbd_function_cdc_create(udevice_t device)
{
uclass_t cdc;
cdc_eps_t eps;
ufunction_t func;
struct vcom* data;
uintf_t intf_comm, intf_data;
ualtsetting_t comm_setting, data_setting;
ucdc_data_desc_t data_desc;
......@@ -516,19 +517,26 @@ uclass_t rt_usbd_class_cdc_create(udevice_t device)
/* set usb device string description */
rt_usbd_device_set_string(device, _ustring);
/* create a cdc class */
cdc = rt_usbd_class_create(device, &dev_desc, &ops);
/* create a cdc class endpoints collection */
eps = rt_malloc(sizeof(struct cdc_eps));
cdc->eps = (void*)eps;
/* create a cdc function */
func = rt_usbd_function_new(device, &dev_desc, &ops);
rt_usbd_device_set_qualifier(device, &dev_qualifier);
/* allocate memory for cdc vcom data */
data = (struct vcom*)rt_malloc(sizeof(struct vcom));
rt_memset(data, 0, sizeof(struct vcom));
func->user_data = (void*)data;
/* initilize vcom */
rt_usb_vcom_init(func);
/* create a cdc communication interface and a cdc data interface */
intf_comm = rt_usbd_interface_create(device, _interface_handler);
intf_data = rt_usbd_interface_create(device, _interface_handler);
intf_comm = rt_usbd_interface_new(device, _interface_handler);
intf_data = rt_usbd_interface_new(device, _interface_handler);
/* create a communication alternate setting and a data alternate setting */
comm_setting = rt_usbd_altsetting_create(sizeof(struct ucdc_comm_descriptor));
data_setting = rt_usbd_altsetting_create(sizeof(struct ucdc_data_descriptor));
comm_setting = rt_usbd_altsetting_new(sizeof(struct ucdc_comm_descriptor));
data_setting = rt_usbd_altsetting_new(sizeof(struct ucdc_data_descriptor));
/* config desc in alternate setting */
rt_usbd_altsetting_config_descriptor(comm_setting, &_comm_desc,
......@@ -537,39 +545,39 @@ uclass_t rt_usbd_class_cdc_create(udevice_t device)
/* configure the cdc interface descriptor */
_cdc_descriptor_config(comm_setting->desc, intf_comm->intf_num, data_setting->desc, intf_data->intf_num);
/* create a bulk in and a bulk endpoint */
data_desc = (ucdc_data_desc_t)data_setting->desc;
eps->ep_out = rt_usbd_endpoint_create(&data_desc->ep_out_desc, _ep_out_handler);
eps->ep_in = rt_usbd_endpoint_create(&data_desc->ep_in_desc, _ep_in_handler);
/* add the bulk out and bulk in endpoints to the data alternate setting */
rt_usbd_altsetting_add_endpoint(data_setting, eps->ep_in);
rt_usbd_altsetting_add_endpoint(data_setting, eps->ep_out);
/* add the data alternate setting to the data interface
then set default setting of the interface */
rt_usbd_interface_add_altsetting(intf_data, data_setting);
rt_usbd_set_altsetting(intf_data, 0);
/* add the cdc data interface to cdc class */
rt_usbd_class_add_interface(cdc, intf_data);
/* create a command endpoint */
comm_desc = (ucdc_comm_desc_t)comm_setting->desc;
eps->ep_cmd = rt_usbd_endpoint_create(&comm_desc->ep_desc, _ep_cmd_handler);
data->ep_cmd = rt_usbd_endpoint_new(&comm_desc->ep_desc, _ep_cmd_handler);
/* add the command endpoint to the cdc communication interface */
rt_usbd_altsetting_add_endpoint(comm_setting, eps->ep_cmd);
rt_usbd_altsetting_add_endpoint(comm_setting, data->ep_cmd);
/* add the communication alternate setting to the communication interface,
then set default setting of the interface */
rt_usbd_interface_add_altsetting(intf_comm, comm_setting);
rt_usbd_set_altsetting(intf_comm, 0);
/* add the communication interface to the cdc class */
rt_usbd_class_add_interface(cdc, intf_comm);
/* add the communication interface to the cdc function */
rt_usbd_function_add_interface(func, intf_comm);
return cdc;
/* create a bulk in and a bulk endpoint */
data_desc = (ucdc_data_desc_t)data_setting->desc;
data->ep_out = rt_usbd_endpoint_new(&data_desc->ep_out_desc, _ep_out_handler);
data->ep_in = rt_usbd_endpoint_new(&data_desc->ep_in_desc, _ep_in_handler);
/* add the bulk out and bulk in endpoints to the data alternate setting */
rt_usbd_altsetting_add_endpoint(data_setting, data->ep_in);
rt_usbd_altsetting_add_endpoint(data_setting, data->ep_out);
/* add the data alternate setting to the data interface
then set default setting of the interface */
rt_usbd_interface_add_altsetting(intf_data, data_setting);
rt_usbd_set_altsetting(intf_data, 0);
/* add the cdc data interface to cdc function */
rt_usbd_function_add_interface(func, intf_data);
return func;
}
/**
......@@ -597,80 +605,106 @@ static rt_err_t _vcom_control(struct rt_serial_device *serial,
return RT_EOK;
}
static int _vcom_putc(struct rt_serial_device *serial, char c)
static int _vcom_getc(struct rt_serial_device *serial)
{
int result;
rt_uint8_t ch;
rt_uint32_t level;
int cnt;
struct ufunction *func;
struct vcom *data;
func = (struct ufunction*)serial->parent.user_data;
data = (struct vcom*)func->user_data;
if (vcom_connected != RT_TRUE)
{
return 0;
}
/* if the buffer is full, there is a chance that the host would pull some
* data out soon. But we cannot rely on that and if we wait to long, just
* return. */
for (cnt = 500;
rt_ringbuffer_space_len(&tx_ringbuffer) == 0 && cnt;
cnt--)
{
/*rt_kprintf("wait for %d\n", cnt);*/
if (vcom_connected != RT_TRUE)
return 0;
}
if (cnt == 0)
{
/* OK, we believe that the connection is lost. So don't send any more
* data and act as the USB cable is not plugged in. Reset the VCOM
* state machine */
_vcom_reset_state();
return 0;
}
result = -1;
level = rt_hw_interrupt_disable();
if (rt_ringbuffer_space_len(&tx_ringbuffer))
if(rt_ringbuffer_getchar(&data->rx_ringbuffer, &ch) != 0)
{
rt_ringbuffer_putchar(&tx_ringbuffer, c);
result = ch;
}
rt_hw_interrupt_enable(level);
return 1;
return result;
}
static int _vcom_getc(struct rt_serial_device *serial)
static rt_size_t _vcom_tx(struct rt_serial_device *serial,
const char *buf, rt_size_t size)
{
int result;
rt_uint8_t ch;
rt_uint32_t level;
struct vcom_tx_msg msg;
result = -1;
RT_ASSERT(serial != RT_NULL);
RT_ASSERT(buf != RT_NULL);
level = rt_hw_interrupt_disable();
if (rt_ringbuffer_data_len(&rx_ringbuffer))
msg.buf = buf;
msg.serial = serial;
msg.size = size;
if (rt_mq_send(&vcom_tx_thread_mq, (void*)&msg,
sizeof(struct vcom_tx_msg)) != RT_EOK)
{
rt_ringbuffer_getchar(&rx_ringbuffer, &ch);
result = ch;
rt_kprintf("vcom send msg fail\n");
return 0;
}
rt_hw_interrupt_enable(level);
return result;
return size;
}
static const struct rt_uart_ops usb_vcom_ops =
{
_vcom_configure,
_vcom_control,
_vcom_putc,
RT_NULL,
_vcom_getc,
RT_NULL,
//_vcom_tx,
};
void rt_usb_vcom_init(void)
/* Vcom Tx Thread */
static void vcom_tx_thread_entry(void* parameter)
{
struct serial_configure config;
struct vcom_tx_msg msg;
while (1)
{
if (rt_mq_recv(&vcom_tx_thread_mq, (void*)&msg,
sizeof(struct vcom_tx_msg), RT_WAITING_FOREVER) == RT_EOK)
{
struct ufunction *func;
struct vcom *data;
func = (struct ufunction*)msg.serial->parent.user_data;
data = (struct vcom*)func->user_data;
if (!data->connected)
{
continue;
}
rt_completion_init(&data->wait);
data->ep_in->request.buffer = (void*)msg.buf;
data->ep_in->request.size = msg.size;
data->ep_in->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
if (rt_completion_wait(&data->wait, TX_TIMEOUT) != RT_EOK)
{
rt_kprintf("vcom tx timeout\n");
}
}
}
}
static void rt_usb_vcom_init(struct ufunction *func)
{
rt_err_t result = RT_EOK;
struct serial_configure config;
struct vcom *data = (struct vcom*)func->user_data;
/* initialize ring buffer */
rt_ringbuffer_init(&rx_ringbuffer, rx_rbp, CDC_RX_BUFSIZE);
rt_ringbuffer_init(&tx_ringbuffer, tx_rbp, CDC_TX_BUFSIZE);
rt_ringbuffer_init(&data->rx_ringbuffer, data->rx_rbp, CDC_RX_BUFSIZE);
config.baud_rate = BAUD_RATE_115200;
config.bit_order = BIT_ORDER_LSB;
......@@ -679,14 +713,25 @@ void rt_usb_vcom_init(void)
config.stop_bits = STOP_BITS_1;
config.invert = NRZ_NORMAL;
vcom_serial.ops = &usb_vcom_ops;
vcom_serial.int_rx = &vcom_int_rx;
vcom_serial.config = config;
data->serial.ops = &usb_vcom_ops;
data->serial.int_rx = &data->vcom_int_rx;
data->serial.config = config;
/* register vcom device */
rt_hw_serial_register(&vcom_serial, "vcom",
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
RT_NULL);
rt_hw_serial_register(&data->serial, VCOM_DEVICE,
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX,
func);
/* create an vcom message queue */
rt_mq_init(&vcom_tx_thread_mq, "vcomq", vcom_tx_thread_mq_pool, VCOM_MQ_MSG_SZ,
sizeof(vcom_tx_thread_mq_pool), RT_IPC_FLAG_FIFO);
/* init usb device thread */
rt_thread_init(&vcom_thread, "vcom", vcom_tx_thread_entry, RT_NULL,
vcom_thread_stack, 512, 8, 20);
result = rt_thread_startup(&vcom_thread);
RT_ASSERT(result == RT_EOK);
}
#endif
......@@ -21,7 +21,8 @@
* Date Author Notes
* 2012-10-01 Yi Qiu first version
* 2012-11-25 Heyuanjie87 reduce the memory consumption
* 2012-12-09 Heyuanjie87 change class and endpoint handler
* 2012-12-09 Heyuanjie87 change function and endpoint handler
* 2013-07-25 Yi Qiu update for USB CV test
*/
#include <rtthread.h>
......@@ -31,19 +32,55 @@
#ifdef RT_USB_DEVICE_MSTORAGE
#define STATUS_CBW 0x00
#define STATUS_CSW 0x01
#define STATUS_RECEIVE 0x02
#define STATUS_SEND 0x03
enum STAT
{
STAT_CBW,
STAT_CMD,
STAT_CSW,
STAT_RECEIVE,
STAT_SEND,
};
typedef enum
{
FIXED,
COUNT,
BLOCK_COUNT,
}CB_SIZE_TYPE;
static int status = STATUS_CBW;
ALIGN(RT_ALIGN_SIZE)
static struct ustorage_csw csw;
static rt_device_t disk;
static rt_uint32_t _block;
static rt_uint32_t _count, _size;
static struct rt_device_blk_geometry geometry;
static rt_uint32_t _removed = 0;
typedef enum
{
DIR_IN,
DIR_OUT,
DIR_NONE,
}CB_DIR;
typedef rt_size_t (*cbw_handler)(ufunction_t func, ustorage_cbw_t cbw);
struct scsi_cmd
{
rt_uint16_t cmd;
cbw_handler handler;
rt_size_t cmd_len;
CB_SIZE_TYPE type;
rt_size_t data_size;
CB_DIR dir;
};
struct mstorage
{
struct ustorage_csw csw_response;
uep_t ep_in;
uep_t ep_out;
int status;
rt_uint32_t cb_data_size;
rt_device_t disk;
rt_uint32_t block;
rt_int32_t count;
rt_int32_t size;
struct scsi_cmd* processing;
struct rt_device_blk_geometry geometry;
};
static struct udevice_descriptor dev_desc =
{
......@@ -63,6 +100,18 @@ static struct udevice_descriptor dev_desc =
USB_DYNAMIC, //bNumConfigurations;
};
static struct usb_qualifier_descriptor dev_qualifier =
{
sizeof(dev_qualifier),
USB_DESC_TYPE_DEVICEQUALIFIER,
0x0200,
USB_CLASS_MASS_STORAGE,
0x00,
64,
0x01,
0,
};
const static struct umass_descriptor _mass_desc =
{
USB_DESC_LENGTH_INTERFACE, //bLength;
......@@ -95,270 +144,489 @@ const static char* _ustring[] =
"Language",
"RT-Thread Team.",
"RTT Mass Storage",
"1.1.0",
"320219198301",
"Configuration",
"Interface",
};
static rt_size_t _test_unit_ready(ufunction_t func, ustorage_cbw_t cbw);
static rt_size_t _request_sense(ufunction_t func, ustorage_cbw_t cbw);
static rt_size_t _inquiry_cmd(ufunction_t func, ustorage_cbw_t cbw);
static rt_size_t _allow_removal(ufunction_t func, ustorage_cbw_t cbw);
static rt_size_t _start_stop(ufunction_t func, ustorage_cbw_t cbw);
static rt_size_t _mode_sense_6(ufunction_t func, ustorage_cbw_t cbw);
static rt_size_t _read_capacities(ufunction_t func, ustorage_cbw_t cbw);
static rt_size_t _read_capacity(ufunction_t func, ustorage_cbw_t cbw);
static rt_size_t _read_10(ufunction_t func, ustorage_cbw_t cbw);
static rt_size_t _write_10(ufunction_t func, ustorage_cbw_t cbw);
static rt_size_t _verify_10(ufunction_t func, ustorage_cbw_t cbw);
static struct scsi_cmd cmd_data[] =
{
{SCSI_TEST_UNIT_READY, _test_unit_ready, 6, FIXED, 0, DIR_NONE},
{SCSI_REQUEST_SENSE, _request_sense, 6, COUNT, 0, DIR_IN},
{SCSI_INQUIRY_CMD, _inquiry_cmd, 6, COUNT, 0, DIR_IN},
{SCSI_ALLOW_REMOVAL, _allow_removal, 6, FIXED, 0, DIR_NONE},
{SCSI_MODE_SENSE_6, _mode_sense_6, 6, COUNT, 0, DIR_IN},
{SCSI_START_STOP, _start_stop, 6, FIXED, 0, DIR_NONE},
{SCSI_READ_CAPACITIES, _read_capacities, 10, COUNT, 0, DIR_NONE},
{SCSI_READ_CAPACITY, _read_capacity, 10, FIXED, 8, DIR_IN},
{SCSI_READ_10, _read_10, 10, BLOCK_COUNT, 0, DIR_IN},
{SCSI_WRITE_10, _write_10, 10, BLOCK_COUNT, 0, DIR_OUT},
{SCSI_VERIFY_10, _verify_10, 10, FIXED, 0, DIR_NONE},
};
static void _send_status(ufunction_t func)
{
struct mstorage *data;
RT_ASSERT(func != RT_NULL);
RT_DEBUG_LOG(RT_DEBUG_USB, ("_send_status\n"));
data = (struct mstorage*)func->user_data;
data->ep_in->request.buffer = (rt_uint8_t*)&data->csw_response;
data->ep_in->request.size = SIZEOF_CSW;
data->ep_in->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
data->status = STAT_CSW;
}
static rt_size_t _test_unit_ready(ufunction_t func, ustorage_cbw_t cbw)
{
struct mstorage *data;
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
RT_DEBUG_LOG(RT_DEBUG_USB, ("_test_unit_ready\n"));
data = (struct mstorage*)func->user_data;
data->csw_response.status = 0;
return 0;
}
static rt_size_t _allow_removal(ufunction_t func, ustorage_cbw_t cbw)
{
struct mstorage *data;
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
RT_DEBUG_LOG(RT_DEBUG_USB, ("_allow_removal\n"));
data = (struct mstorage*)func->user_data;
data->csw_response.status = 0;
return 0;
}
/**
* This function will allocate an usb device instance from system.
* This function will handle inquiry command request.
*
* @param parent the hub instance to which the new allocated device attached.
* @param port the hub port.
* @param func the usb function object.
* @param cbw the command block wrapper.
*
* @return the allocate instance on successful, or RT_NULL on failure.
* @return RT_EOK on successful.
*/
static rt_err_t _inquiry_cmd(udevice_t device, uep_t ep_in)
static rt_size_t _inquiry_cmd(ufunction_t func, ustorage_cbw_t cbw)
{
rt_uint8_t data[36];
struct mstorage *data;
rt_uint8_t *buf;
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
RT_ASSERT(cbw != RT_NULL);
*(rt_uint32_t*)&data[0] = 0x0 | (0x80 << 8);
*(rt_uint32_t*)&data[4] = 31;
RT_DEBUG_LOG(RT_DEBUG_USB, ("_inquiry_cmd\n"));
rt_memset(&data[8], 0x20, 28);
rt_memcpy(&data[8], "RTT", 3);
rt_memcpy(&data[16], "USB Disk", 8);
data = (struct mstorage*)func->user_data;
buf = data->ep_in->buffer;
dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, 36);
*(rt_uint32_t*)&buf[0] = 0x0 | (0x80 << 8);
*(rt_uint32_t*)&buf[4] = 31;
return RT_EOK;
rt_memset(&buf[8], 0x20, 28);
rt_memcpy(&buf[8], "RTT", 3);
rt_memcpy(&buf[16], "USB Disk", 8);
data->cb_data_size = MIN(data->cb_data_size, SIZEOF_INQUIRY_CMD);
data->ep_in->request.buffer = buf;
data->ep_in->request.size = data->cb_data_size;
data->ep_in->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
data->status = STAT_CMD;
return data->cb_data_size;
}
/**
* This function will handle sense request.
*
* @param device the usb device object.
* @param func the usb function object.
* @param cbw the command block wrapper.
*
* @return RT_EOK on successful.
*/
static rt_err_t _request_sense(udevice_t device, uep_t ep_in)
static rt_size_t _request_sense(ufunction_t func, ustorage_cbw_t cbw)
{
struct request_sense_data data;
data.ErrorCode = 0x70;
data.Valid = 0;
data.SenseKey = 2; //TODO
data.Information[0] = 0;
data.Information[1] = 0;
data.Information[2] = 0;
data.Information[3] = 0;
data.AdditionalSenseLength = 0x0a;
data.AdditionalSenseCode = 0x3a; //TODO
data.AdditionalSenseCodeQualifier =0;
struct mstorage *data;
struct request_sense_data *buf;
dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, sizeof(struct request_sense_data));
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
RT_ASSERT(cbw != RT_NULL);
return RT_EOK;
RT_DEBUG_LOG(RT_DEBUG_USB, ("_request_sense\n"));
data = (struct mstorage*)func->user_data;
buf = (struct request_sense_data *)data->ep_in->buffer;
buf->ErrorCode = 0x70;
buf->Valid = 0;
buf->SenseKey = 2;
buf->Information[0] = 0;
buf->Information[1] = 0;
buf->Information[2] = 0;
buf->Information[3] = 0;
buf->AdditionalSenseLength = 0x0a;
buf->AdditionalSenseCode = 0x3a;
buf->AdditionalSenseCodeQualifier = 0;
data->cb_data_size = MIN(data->cb_data_size, SIZEOF_REQUEST_SENSE);
data->ep_in->request.buffer = (rt_uint8_t*)data->ep_in->buffer;
data->ep_in->request.size = data->cb_data_size;
data->ep_in->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
data->status = STAT_CMD;
return data->cb_data_size;
}
/**
* This function will handle mode_sense_6 request.
*
* @param device the usb device object.
* @param func the usb function object.
* @param cbw the command block wrapper.
*
* @return RT_EOK on successful.
*/
static rt_err_t _mode_sense_6(udevice_t device, uep_t ep_in)
static rt_size_t _mode_sense_6(ufunction_t func, ustorage_cbw_t cbw)
{
rt_uint8_t data[4];
struct mstorage *data;
rt_uint8_t *buf;
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
RT_ASSERT(cbw != RT_NULL);
data[0]=3;
data[1]=0;
data[2]=0;
data[3]=0;
RT_DEBUG_LOG(RT_DEBUG_USB, ("_mode_sense_6\n"));
dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, 4);
data = (struct mstorage*)func->user_data;
buf = data->ep_in->buffer;
buf[0] = 3;
buf[1] = 0;
buf[2] = 0;
buf[3] = 0;
return RT_EOK;
data->cb_data_size = MIN(data->cb_data_size, SIZEOF_MODE_SENSE_6);
data->ep_in->request.buffer = buf;
data->ep_in->request.size = data->cb_data_size;
data->ep_in->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
data->status = STAT_CMD;
return data->cb_data_size;
}
/**
* This function will handle read_capacities request.
*
* @param device the usb device object.
* @param func the usb function object.
* @param cbw the command block wrapper.
*
* @return RT_EOK on successful.
*/
static rt_err_t _read_capacities(udevice_t device, uep_t ep_in)
static rt_size_t _read_capacities(ufunction_t func, ustorage_cbw_t cbw)
{
rt_uint8_t data[12];
struct mstorage *data;
rt_uint8_t *buf;
rt_uint32_t sector_count, sector_size;
RT_ASSERT(device != RT_NULL);
sector_count = geometry.sector_count;
sector_size = geometry.bytes_per_sector;
*(rt_uint32_t*)&data[0] = 0x08000000;
data[4] = sector_count >> 24;
data[5] = 0xff & (sector_count >> 16);
data[6] = 0xff & (sector_count >> 8);
data[7] = 0xff & (sector_count);
data[8] = 0x02;
data[9] = 0xff & (sector_size >> 16);
data[10] = 0xff & (sector_size >> 8);
data[11] = 0xff & sector_size;
dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, 12);
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
RT_ASSERT(cbw != RT_NULL);
return RT_EOK;
RT_DEBUG_LOG(RT_DEBUG_USB, ("_read_capacities\n"));
data = (struct mstorage*)func->user_data;
buf = data->ep_in->buffer;
sector_count = data->geometry.sector_count;
sector_size = data->geometry.bytes_per_sector;
*(rt_uint32_t*)&buf[0] = 0x08000000;
buf[4] = sector_count >> 24;
buf[5] = 0xff & (sector_count >> 16);
buf[6] = 0xff & (sector_count >> 8);
buf[7] = 0xff & (sector_count);
buf[8] = 0x02;
buf[9] = 0xff & (sector_size >> 16);
buf[10] = 0xff & (sector_size >> 8);
buf[11] = 0xff & sector_size;
data->cb_data_size = MIN(data->cb_data_size, SIZEOF_READ_CAPACITIES);
data->ep_in->request.buffer = buf;
data->ep_in->request.size = data->cb_data_size;
data->ep_in->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
data->status = STAT_CMD;
return data->cb_data_size;
}
/**
* This function will handle read_capacity request.
*
* @param device the usb device object.
* @param func the usb function object.
* @param cbw the command block wapper.
*
* @return RT_EOK on successful.
*/
static rt_err_t _read_capacity(udevice_t device, uep_t ep_in)
static rt_size_t _read_capacity(ufunction_t func, ustorage_cbw_t cbw)
{
rt_uint8_t data[8];
rt_uint32_t sector_count, sector_size;
struct mstorage *data;
RT_ASSERT(device != RT_NULL);
sector_count = geometry.sector_count;
sector_size = geometry.bytes_per_sector;
data[0] = sector_count >> 24;
data[1] = 0xff & (sector_count >> 16);
data[2] = 0xff & (sector_count >> 8);
data[3] = 0xff & (sector_count);
data[4] = 0x0;
data[5] = 0xff & (sector_size >> 16);
data[6] = 0xff & (sector_size >> 8);
data[7] = 0xff & sector_size;
rt_uint8_t *buf;
rt_uint32_t sector_count, sector_size;
dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, 8);
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
RT_ASSERT(cbw != RT_NULL);
return RT_EOK;
RT_DEBUG_LOG(RT_DEBUG_USB, ("_read_capacity\n"));
data = (struct mstorage*)func->user_data;
buf = data->ep_in->buffer;
sector_count = data->geometry.sector_count;
sector_size = data->geometry.bytes_per_sector;
buf[0] = sector_count >> 24;
buf[1] = 0xff & (sector_count >> 16);
buf[2] = 0xff & (sector_count >> 8);
buf[3] = 0xff & (sector_count);
buf[4] = 0x0;
buf[5] = 0xff & (sector_size >> 16);
buf[6] = 0xff & (sector_size >> 8);
buf[7] = 0xff & sector_size;
data->cb_data_size = MIN(data->cb_data_size, SIZEOF_READ_CAPACITY);
data->ep_in->request.buffer = buf;
data->ep_in->request.size = data->cb_data_size;
data->ep_in->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
data->status = STAT_CMD;
return data->cb_data_size;
}
/**
* This function will handle read_10 request.
*
* @param device the usb device object.
* @param func the usb function object.
* @param cbw the command block wrapper.
*
* @return RT_EOK on successful.
*/
static rt_err_t _read_10(udevice_t device, ustorage_cbw_t cbw, uep_t ep_in)
static rt_size_t _read_10(ufunction_t func, ustorage_cbw_t cbw)
{
RT_ASSERT(device != RT_NULL);
struct mstorage *data;
rt_size_t size;
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
RT_ASSERT(cbw != RT_NULL);
_block = cbw->cb[2]<<24 | cbw->cb[3]<<16 | cbw->cb[4]<<8 |
cbw->cb[5]<<0 ;
data = (struct mstorage*)func->user_data;
data->block = cbw->cb[2]<<24 | cbw->cb[3]<<16 | cbw->cb[4]<<8 |
cbw->cb[5]<<0;
data->count = cbw->cb[7]<<8 | cbw->cb[8]<<0;
_count = cbw->cb[7]<<8 | cbw->cb[8]<<0 ;
RT_ASSERT(data->count < data->geometry.sector_count);
RT_ASSERT(_count < geometry.sector_count);
rt_device_read(disk, _block, ep_in->buffer, 1);
dcd_ep_write(device->dcd, ep_in, ep_in->buffer, geometry.bytes_per_sector);
_count --;
if (_count)
{
_block ++;
status = STATUS_SEND;
}
else
data->csw_response.data_reside = data->cb_data_size;
size = rt_device_read(data->disk, data->block, data->ep_in->buffer, 1);
if(size == 0)
{
status = STATUS_CSW;
rt_kprintf("read data error\n");
}
return RT_EOK;
data->ep_in->request.buffer = data->ep_in->buffer;
data->ep_in->request.size = data->geometry.bytes_per_sector;
data->ep_in->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
data->status = STAT_SEND;
return data->geometry.bytes_per_sector;
}
/**
* This function will handle write_10 request.
*
* @param device the usb device object.
* @param func the usb function object.
* @param cbw the command block wrapper.
*
* @return RT_EOK on successful.
*/
static rt_err_t _write_10(udevice_t device, ustorage_cbw_t cbw, uep_t ep_out)
static rt_size_t _write_10(ufunction_t func, ustorage_cbw_t cbw)
{
RT_ASSERT(device != RT_NULL);
RT_ASSERT(cbw != RT_NULL);
_block = cbw->cb[2]<<24 | cbw->cb[3]<<16 | cbw->cb[4]<<8 |
cbw->cb[5]<<0 ;
_count = cbw->cb[7]<<8 | cbw->cb[8]<<0;
csw.data_reside = cbw->xfer_len;
_size = _count * geometry.bytes_per_sector;
struct mstorage *data;
RT_DEBUG_LOG(RT_DEBUG_USB, ("_write_10 count 0x%x 0x%x\n",
_count, geometry.sector_count));
dcd_ep_read(device->dcd, ep_out, ep_out->buffer, geometry.bytes_per_sector);
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
RT_ASSERT(cbw != RT_NULL);
return RT_EOK;
data = (struct mstorage*)func->user_data;
data->block = cbw->cb[2]<<24 | cbw->cb[3]<<16 | cbw->cb[4]<<8 |
cbw->cb[5]<<0;
data->count = cbw->cb[7]<<8 | cbw->cb[8];
data->csw_response.data_reside = cbw->xfer_len;
data->size = data->count * data->geometry.bytes_per_sector;
RT_DEBUG_LOG(RT_DEBUG_USB, ("_write_10 count 0x%x block 0x%x 0x%x\n",
data->count, data->block, data->geometry.sector_count));
data->csw_response.data_reside = data->cb_data_size;
data->ep_out->request.buffer = data->ep_out->buffer;
data->ep_out->request.size = data->geometry.bytes_per_sector;
data->ep_out->request.req_type = UIO_REQUEST_READ_FULL;
rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request);
data->status = STAT_RECEIVE;
return data->geometry.bytes_per_sector;
}
/**
* This function will handle verify_10 request.
*
* @param device the usb device object.
* @param func the usb function object.
*
* @return RT_EOK on successful.
*/
static rt_err_t _verify_10(udevice_t device)
static rt_size_t _verify_10(ufunction_t func, ustorage_cbw_t cbw)
{
return RT_EOK;
}
struct mstorage *data;
static void _send_status(udevice_t device, mass_eps_t eps, ustorage_csw_t csw)
{
dcd_ep_write(device->dcd, eps->ep_in, (rt_uint8_t*)csw, SIZEOF_CSW);
dcd_ep_read(device->dcd, eps->ep_out, eps->ep_out->buffer, SIZEOF_CBW);
status = STATUS_CBW;
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
RT_DEBUG_LOG(RT_DEBUG_USB, ("_verify_10\n"));
data = (struct mstorage*)func->user_data;
data->csw_response.status = 0;
return 0;
}
static void _start_stop(ustorage_cbw_t cbw)
static rt_size_t _start_stop(ufunction_t func,
ustorage_cbw_t cbw)
{
//TODO
_removed = 1;
struct mstorage *data;
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
RT_DEBUG_LOG(RT_DEBUG_USB, ("_start_stop\n"));
data = (struct mstorage*)func->user_data;
data->csw_response.status = 0;
return 0;
}
/**
* This function will handle mass storage bulk in endpoint request.
*
* @param device the usb device object.
* @param size request size.
*
* @return RT_EOK.
*/
static rt_err_t _ep_in_handler(udevice_t device, uclass_t cls, rt_size_t size)
static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size)
{
mass_eps_t eps;
RT_ASSERT(device != RT_NULL);
struct mstorage *data;
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
eps = cls->eps;
if (status == STATUS_CSW)
{
_send_status(device, eps, &csw);
}
else if (status == STATUS_SEND)
RT_DEBUG_LOG(RT_DEBUG_USB, ("_ep_in_handler\n"));
data = (struct mstorage*)func->user_data;
switch(data->status)
{
rt_device_read(disk, _block, eps->ep_in->buffer, 1);
dcd_ep_write(device->dcd, eps->ep_in, eps->ep_in->buffer,
geometry.bytes_per_sector);
_count --;
if (_count)
case STAT_CSW:
if(data->ep_in->request.size != SIZEOF_CSW)
{
_block ++;
status = STATUS_SEND;
rt_kprintf("Size of csw command error\n");
rt_usbd_ep_set_stall(func->device, data->ep_in);
}
else
{
status = STATUS_CSW;
RT_DEBUG_LOG(RT_DEBUG_USB, ("return to cbw status\n"));
data->ep_out->request.buffer = data->ep_out->buffer;
data->ep_out->request.size = SIZEOF_CBW;
data->ep_out->request.req_type = UIO_REQUEST_READ_FULL;
rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request);
data->status = STAT_CBW;
}
}
break;
case STAT_CMD:
if(data->csw_response.data_reside == 0xFF)
{
data->csw_response.data_reside = 0;
}
else
{
data->csw_response.data_reside -= data->ep_in->request.size;
if(data->csw_response.data_reside != 0)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("data_reside %d, request %d\n",
data->csw_response.data_reside, data->ep_in->request.size));
if(data->processing->dir == DIR_OUT)
{
rt_usbd_ep_set_stall(func->device, data->ep_out);
}
else
{
rt_usbd_ep_set_stall(func->device, data->ep_in);
}
data->csw_response.data_reside = 0;
}
}
_send_status(func);
break;
case STAT_SEND:
data->csw_response.data_reside -= data->ep_in->request.size;
data->count--;
data->block++;
if(data->count > 0 && data->csw_response.data_reside > 0)
{
if(rt_device_read(data->disk, data->block, data->ep_in->buffer, 1) == 0)
{
rt_kprintf("disk read error\n");
rt_usbd_ep_set_stall(func->device, data->ep_in);
return -RT_ERROR;
}
data->ep_in->request.buffer = data->ep_in->buffer;
data->ep_in->request.size = data->geometry.bytes_per_sector;
data->ep_in->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request);
}
else
{
_send_status(func);
}
break;
}
return RT_EOK;
return RT_EOK;
}
#ifdef MASS_CBW_DUMP
......@@ -376,134 +644,283 @@ static void cbw_dump(struct ustorage_cbw* cbw)
}
#endif
/**
* This function will handle mass storage bulk out endpoint request.
*
* @param device the usb device object.
* @param size request size.
*
* @return RT_EOK.
*/
static rt_err_t _ep_out_handler(udevice_t device, uclass_t cls, rt_size_t size)
static struct scsi_cmd* _find_cbw_command(rt_uint16_t cmd)
{
mass_eps_t eps;
RT_ASSERT(device != RT_NULL);
int i;
eps = (mass_eps_t)cls->eps;
if(status == STATUS_CBW)
for(i=0; i<sizeof(cmd_data)/sizeof(struct scsi_cmd); i++)
{
struct ustorage_cbw* cbw;
if(cmd_data[i].cmd == cmd)
return &cmd_data[i];
}
/* dump cbw information */
cbw = (struct ustorage_cbw*)eps->ep_out->buffer;
return RT_NULL;
}
if(cbw->signature == CBW_SIGNATURE)
{
csw.signature = CSW_SIGNATURE;
csw.tag = cbw->tag;
csw.data_reside = 0;
csw.status = 0;
}
else
return -RT_ERROR;
static void _cb_len_calc(ufunction_t func, struct scsi_cmd* cmd,
ustorage_cbw_t cbw)
{
struct mstorage *data;
RT_ASSERT(func != RT_NULL);
RT_ASSERT(cmd != RT_NULL);
RT_ASSERT(cbw != RT_NULL);
switch(cbw->cb[0])
data = (struct mstorage*)func->user_data;
if(cmd->cmd_len == 6)
{
switch(cmd->type)
{
case SCSI_TEST_UNIT_READY:
csw.status = _removed;
_send_status(device, eps, &csw);
break;
case SCSI_REQUEST_SENSE:
_request_sense(device, eps->ep_in);
status = STATUS_CSW;
break;
case SCSI_INQUIRY_CMD:
_inquiry_cmd(device, eps->ep_in);
status = STATUS_CSW;
break;
case SCSI_MODE_SENSE_6:
_mode_sense_6(device, eps->ep_in);
status = STATUS_CSW;
case COUNT:
data->cb_data_size = cbw->cb[4];
break;
case SCSI_ALLOW_MEDIUM_REMOVAL:
_send_status(device, eps, &csw);
case BLOCK_COUNT:
data->cb_data_size = cbw->cb[4] * data->geometry.bytes_per_sector;
break;
case SCSI_READ_CAPACITIES:
_read_capacities(device, eps->ep_in);
status = STATUS_CSW;
case FIXED:
data->cb_data_size = cmd->data_size;
break;
case SCSI_READ_CAPACITY:
_read_capacity(device, eps->ep_in);
status = STATUS_CSW;
default:
break;
case SCSI_READ_10:
_read_10(device, cbw, eps->ep_in);
}
}
else if(cmd->cmd_len == 10)
{
switch(cmd->type)
{
case COUNT:
data->cb_data_size = cbw->cb[7]<<8 | cbw->cb[8];
break;
case SCSI_WRITE_10:
_write_10(device, cbw, eps->ep_out);
status = STATUS_RECEIVE;
case BLOCK_COUNT:
data->cb_data_size = (cbw->cb[7]<<8 | cbw->cb[8]) *
data->geometry.bytes_per_sector;
break;
case SCSI_VERIFY_10:
_verify_10(device);
case FIXED:
data->cb_data_size = cmd->data_size;
break;
case SCSI_START_STOP:
_start_stop(cbw);
_send_status(device, eps, &csw);
default:
break;
}
}
else if(status == STATUS_RECEIVE)
else
{
rt_kprintf("cmd_len error %d\n", cmd->cmd_len);
}
}
static rt_bool_t _cbw_verify(ufunction_t func, struct scsi_cmd* cmd,
ustorage_cbw_t cbw)
{
struct mstorage *data;
RT_ASSERT(cmd != RT_NULL);
RT_ASSERT(cbw != RT_NULL);
RT_ASSERT(func != RT_NULL);
data = (struct mstorage*)func->user_data;
if(cmd->cmd_len != cbw->cb_len)
{
rt_kprintf("cb_len error\n");
cmd->cmd_len = cbw->cb_len;
}
if(cbw->xfer_len > 0 && data->cb_data_size == 0)
{
rt_kprintf("xfer_len > 0 && data_size == 0\n");
return RT_FALSE;
}
if(cbw->xfer_len == 0 && data->cb_data_size > 0)
{
rt_kprintf("xfer_len == 0 && data_size > 0");
return RT_FALSE;
}
if((cbw->dflags & USB_DIR_IN) && cmd->dir == DIR_OUT ||
!(cbw->dflags & USB_DIR_IN) && cmd->dir == DIR_IN)
{
rt_kprintf("dir error\n");
return RT_FALSE;
}
if(cbw->xfer_len > data->cb_data_size)
{
rt_kprintf("xfer_len > data_size\n");
return RT_FALSE;
}
if(cbw->xfer_len < data->cb_data_size)
{
rt_kprintf("xfer_len < data_size\n");
data->cb_data_size = cbw->xfer_len;
data->csw_response.status = 1;
}
return RT_TRUE;
}
static rt_size_t _cbw_handler(ufunction_t func, struct scsi_cmd* cmd,
ustorage_cbw_t cbw)
{
struct mstorage *data;
RT_ASSERT(func != RT_NULL);
RT_ASSERT(cbw != RT_NULL);
RT_ASSERT(cmd->handler != RT_NULL);
data = (struct mstorage*)func->user_data;
data->processing = cmd;
return cmd->handler(func, cbw);
}
/**
* This function will handle mass storage bulk out endpoint request.
*
* @param func the usb function object.
* @param size request size.
*
* @return RT_EOK.
*/
static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size)
{
struct mstorage *data;
struct scsi_cmd* cmd;
rt_size_t len;
struct ustorage_cbw* cbw;
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
RT_DEBUG_LOG(RT_DEBUG_USB, ("_ep_out_handler %d\n", size));
data = (struct mstorage*)func->user_data;
cbw = (struct ustorage_cbw*)data->ep_out->buffer;
if(data->status == STAT_CBW)
{
/* dump cbw information */
if(cbw->signature != CBW_SIGNATURE || size != SIZEOF_CBW)
{
goto exit;
}
data->csw_response.signature = CSW_SIGNATURE;
data->csw_response.tag = cbw->tag;
data->csw_response.data_reside = cbw->xfer_len;
data->csw_response.status = 0;
RT_DEBUG_LOG(RT_DEBUG_USB, ("ep_out reside %d\n", data->csw_response.data_reside));
cmd = _find_cbw_command(cbw->cb[0]);
if(cmd == RT_NULL)
{
rt_kprintf("can't find cbw command\n");
goto exit;
}
_cb_len_calc(func, cmd, cbw);
if(!_cbw_verify(func, cmd, cbw))
{
goto exit;
}
len = _cbw_handler(func, cmd, cbw);
if(len == 0)
{
_send_status(func);
}
return RT_EOK;
}
else if(data->status == STAT_RECEIVE)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("write size 0x%x block 0x%x oount 0x%x\n",
size, _block, _size));
RT_DEBUG_LOG(RT_DEBUG_USB, ("\nwrite size %d block 0x%x oount 0x%x\n",
size, data->block, data->size));
data->size -= size;
data->csw_response.data_reside -= size;
_size -= size;
csw.data_reside -= size;
rt_device_write(data->disk, data->block, data->ep_out->buffer, 1);
rt_device_write(disk, _block, eps->ep_in->buffer, 1);
_block ++;
if(_size == 0)
if(data->csw_response.data_reside != 0)
{
_send_status(device, eps, &csw);
data->ep_out->request.buffer = data->ep_out->buffer;
data->ep_out->request.size = data->geometry.bytes_per_sector;
data->ep_out->request.req_type = UIO_REQUEST_READ_FULL;
rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request);
data->block ++;
}
else
{
dcd_ep_read(device->dcd, eps->ep_out, eps->ep_out->buffer,
geometry.bytes_per_sector);
_send_status(func);
}
return RT_EOK;
}
else
exit:
if(data->csw_response.data_reside)
{
rt_kprintf("none cbw status\n");
if(cbw->dflags & USB_DIR_IN)
{
rt_usbd_ep_set_stall(func->device, data->ep_in);
}
else
{
rt_usbd_ep_set_stall(func->device, data->ep_in);
rt_usbd_ep_set_stall(func->device, data->ep_out);
}
}
return RT_EOK;
data->csw_response.status = 1;
_send_status(func);
return -RT_ERROR;
}
/**
* This function will handle mass storage interface request.
*
* @param device the usb device object.
* @param func the usb function object.
* @param setup the setup request.
*
* @return RT_EOK on successful.
*/
static rt_err_t _interface_handler(udevice_t device, uclass_t cls, ureq_t setup)
static rt_err_t _interface_handler(ufunction_t func, ureq_t setup)
{
rt_uint8_t lun = 0;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
RT_ASSERT(setup != RT_NULL);
RT_DEBUG_LOG(RT_DEBUG_USB, ("_interface_handler\n"));
RT_DEBUG_LOG(RT_DEBUG_USB, ("mstorage_interface_handler\n"));
switch(setup->request)
{
case USBREQ_GET_MAX_LUN:
dcd_ep_write(device->dcd, 0, &lun, 1);
case USBREQ_GET_MAX_LUN:
RT_DEBUG_LOG(RT_DEBUG_USB, ("USBREQ_GET_MAX_LUN\n"));
if(setup->value || setup->length != 1)
{
rt_usbd_ep0_set_stall(func->device);
}
else
{
rt_usbd_ep0_write(func->device, &lun, 1);
}
break;
case USBREQ_MASS_STORAGE_RESET:
RT_DEBUG_LOG(RT_DEBUG_USB, ("USBREQ_MASS_STORAGE_RESET\n"));
if(setup->value || setup->length != 0)
{
rt_usbd_ep0_set_stall(func->device);
}
else
{
rt_usbd_ep0_write(func->device, RT_NULL, 0);
}
break;
default:
rt_kprintf("unknown interface request\n");
......@@ -514,81 +931,114 @@ static rt_err_t _interface_handler(udevice_t device, uclass_t cls, ureq_t setup)
}
/**
* This function will run mass storage class, it will be called on handle set configuration request.
* This function will run mass storage function, it will be called on handle set configuration request.
*
* @param device the usb device object.
* @param func the usb function object.
*
* @return RT_EOK on successful.
*/
static rt_err_t _class_run(udevice_t device, uclass_t cls)
static rt_err_t _function_enable(ufunction_t func)
{
mass_eps_t eps;
rt_uint8_t *buffer;
RT_ASSERT(device != RT_NULL);
struct mstorage *data;
RT_ASSERT(func != RT_NULL);
RT_DEBUG_LOG(RT_DEBUG_USB, ("mass storage run\n"));
eps = (mass_eps_t)cls->eps;
RT_DEBUG_LOG(RT_DEBUG_USB, ("Mass storage function enabled\n"));
data = (struct mstorage*)func->user_data;
disk = rt_device_find(RT_USB_MSTORAGE_DISK_NAME);
if(disk == RT_NULL)
data->disk = rt_device_find(RT_USB_MSTORAGE_DISK_NAME);
if(data->disk == RT_NULL)
{
rt_kprintf("no disk named %s\n", RT_USB_MSTORAGE_DISK_NAME);
rt_kprintf("no data->disk named %s\n", RT_USB_MSTORAGE_DISK_NAME);
return -RT_ERROR;
}
if(rt_device_control(disk, RT_DEVICE_CTRL_BLK_GETGEOME, (void*)&geometry) != RT_EOK)
return -RT_ERROR;
buffer = (rt_uint8_t*)rt_malloc(geometry.bytes_per_sector);
if(buffer == RT_NULL)
if(rt_device_open(data->disk, RT_DEVICE_OFLAG_RDWR) != RT_EOK)
{
rt_kprintf("disk open error\n");
return -RT_ERROR;
}
if(rt_device_control(data->disk, RT_DEVICE_CTRL_BLK_GETGEOME,
(void*)&data->geometry) != RT_EOK)
{
rt_kprintf("get disk info error\n");
return -RT_ERROR;
}
data->ep_in->buffer = (rt_uint8_t*)rt_malloc(data->geometry.bytes_per_sector);
if(data->ep_in->buffer == RT_NULL)
{
rt_kprintf("no memory\n");
return -RT_ENOMEM;
eps->ep_out->buffer = buffer;
eps->ep_in->buffer = buffer;
dcd_ep_read(device->dcd, eps->ep_out, eps->ep_out->buffer, SIZEOF_CBW);
}
data->ep_out->buffer = (rt_uint8_t*)rt_malloc(data->geometry.bytes_per_sector);
if(data->ep_out->buffer == RT_NULL)
{
rt_free(data->ep_in->buffer);
rt_kprintf("no memory\n");
return -RT_ENOMEM;
}
/* prepare to read CBW request */
data->ep_out->request.buffer = data->ep_out->buffer;
data->ep_out->request.size = SIZEOF_CBW;
data->ep_out->request.req_type = UIO_REQUEST_READ_FULL;
rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request);
return RT_EOK;
}
/**
* This function will stop mass storage class, it will be called on handle set configuration request.
* This function will stop mass storage function, it will be called on handle set configuration request.
*
* @param device the usb device object.
*
* @return RT_EOK on successful.
*/
static rt_err_t _class_stop(udevice_t device, uclass_t cls)
static rt_err_t _function_disable(ufunction_t func)
{
mass_eps_t eps;
RT_ASSERT(device != RT_NULL);
struct mstorage *data;
RT_ASSERT(func != RT_NULL);
RT_DEBUG_LOG(RT_DEBUG_USB, ("Mass storage function disabled\n"));
RT_DEBUG_LOG(RT_DEBUG_USB, ("mass storage stop\n"));
eps = (mass_eps_t)cls->eps;
rt_free(eps->ep_in->buffer);
eps->ep_out->buffer = RT_NULL;
eps->ep_in->buffer = RT_NULL;
data = (struct mstorage*)func->user_data;
if(data->ep_in->buffer != RT_NULL)
{
rt_free(data->ep_in->buffer);
data->ep_in->buffer = RT_NULL;
}
if(data->ep_out->buffer != RT_NULL)
{
rt_free(data->ep_out->buffer);
data->ep_out->buffer = RT_NULL;
}
data->status = STAT_CBW;
return RT_EOK;
}
static struct uclass_ops ops =
static struct ufunction_ops ops =
{
_class_run,
_class_stop,
_function_enable,
_function_disable,
RT_NULL,
};
/**
* This function will create a mass storage class instance.
* This function will create a mass storage function instance.
*
* @param device the usb device object.
*
* @return RT_EOK on successful.
*/
uclass_t rt_usbd_class_mstorage_create(udevice_t device)
ufunction_t rt_usbd_function_mstorage_create(udevice_t device)
{
uintf_t intf;
mass_eps_t eps;
uclass_t mstorage;
struct mstorage *data;
ufunction_t func;
ualtsetting_t setting;
umass_desc_t mass_desc;
......@@ -597,37 +1047,42 @@ uclass_t rt_usbd_class_mstorage_create(udevice_t device)
/* set usb device string description */
rt_usbd_device_set_string(device, _ustring);
/* create a mass storage class */
mstorage = rt_usbd_class_create(device, &dev_desc, &ops);
/* create a mass storage endpoints collection */
eps = (mass_eps_t)rt_malloc(sizeof(struct mass_eps));
mstorage->eps = (void*)eps;
/* create an interface */
intf = rt_usbd_interface_create(device, _interface_handler);
/* create an alternate setting */
setting = rt_usbd_altsetting_create(sizeof(struct umass_descriptor));
/* create a mass storage function */
func = rt_usbd_function_new(device, &dev_desc, &ops);
device->dev_qualifier = &dev_qualifier;
/* allocate memory for mass storage function data */
data = (struct mstorage*)rt_malloc(sizeof(struct mstorage));
rt_memset(data, 0, sizeof(struct mstorage));
func->user_data = (void*)data;
/* create an interface object */
intf = rt_usbd_interface_new(device, _interface_handler);
/* create an alternate setting object */
setting = rt_usbd_altsetting_new(sizeof(struct umass_descriptor));
/* config desc in alternate setting */
rt_usbd_altsetting_config_descriptor(setting, &_mass_desc, 0);
/* create a bulk out and a bulk in endpoint */
mass_desc = (umass_desc_t)setting->desc;
eps->ep_in = rt_usbd_endpoint_create(&mass_desc->ep_in_desc, _ep_in_handler);
eps->ep_out = rt_usbd_endpoint_create(&mass_desc->ep_out_desc, _ep_out_handler);
data->ep_in = rt_usbd_endpoint_new(&mass_desc->ep_in_desc, _ep_in_handler);
data->ep_out = rt_usbd_endpoint_new(&mass_desc->ep_out_desc, _ep_out_handler);
/* add the bulk out and bulk in endpoint to the alternate setting */
rt_usbd_altsetting_add_endpoint(setting, eps->ep_out);
rt_usbd_altsetting_add_endpoint(setting, eps->ep_in);
rt_usbd_altsetting_add_endpoint(setting, data->ep_out);
rt_usbd_altsetting_add_endpoint(setting, data->ep_in);
/* add the alternate setting to the interface, then set default setting */
rt_usbd_interface_add_altsetting(intf, setting);
rt_usbd_set_altsetting(intf, 0);
/* add the interface to the mass storage class */
rt_usbd_class_add_interface(mstorage, intf);
/* add the interface to the mass storage function */
rt_usbd_function_add_interface(func, intf);
return mstorage;
return func;
}
#endif
......
......@@ -59,13 +59,6 @@ struct request_sense_data
rt_uint8_t Reserved4[4];
}request_sense_data_t;
struct mass_eps
{
uep_t ep_in;
uep_t ep_out;
};
typedef struct mass_eps* mass_eps_t;
#pragma pack()
#endif
......@@ -20,8 +20,10 @@
* Change Logs:
* Date Author Notes
* 2012-10-01 Yi Qiu first version
* 2012-12-12 heyuanjie87 change endpoint and class handler
* 2012-12-12 heyuanjie87 change endpoint and function handler
* 2012-12-30 heyuanjie87 change inferface handler
* 2013-04-26 aozima add DEVICEQUALIFIER support.
* 2013-07-25 Yi Qiu update for USB CV test
*/
#include <rtthread.h>
......@@ -29,6 +31,11 @@
static rt_list_t device_list;
static rt_size_t rt_usbd_ep_write(udevice_t device, uep_t ep, void *buffer, rt_size_t size);
static rt_size_t rt_usbd_ep_read_prepare(udevice_t device, uep_t ep, void *buffer, rt_size_t size);
static rt_err_t rt_usbd_ep_assign(udevice_t device, uep_t ep);
static rt_err_t rt_usbd_ep_unassign(udevice_t device, uep_t ep);
/**
* This function will handle get_device_descriptor request.
*
......@@ -37,7 +44,7 @@ static rt_list_t device_list;
*
* @return RT_EOK on successful.
*/
static rt_err_t _get_device_descriptor(struct udevice *device, ureq_t setup)
static rt_err_t _get_device_descriptor(struct udevice* device, ureq_t setup)
{
rt_size_t size;
......@@ -52,7 +59,8 @@ static rt_err_t _get_device_descriptor(struct udevice *device, ureq_t setup)
USB_DESC_LENGTH_DEVICE : setup->length;
/* send device descriptor to endpoint 0 */
dcd_ep_write(device->dcd, 0, (rt_uint8_t *)&device->dev_desc, size);
rt_usbd_ep0_write(device, (rt_uint8_t*)&device->dev_desc,
size);
return RT_EOK;
}
......@@ -65,7 +73,7 @@ static rt_err_t _get_device_descriptor(struct udevice *device, ureq_t setup)
*
* @return RT_EOK on successful.
*/
static rt_err_t _get_config_descriptor(struct udevice *device, ureq_t setup)
static rt_err_t _get_config_descriptor(struct udevice* device, ureq_t setup)
{
rt_size_t size;
ucfg_desc_t cfg_desc;
......@@ -81,7 +89,7 @@ static rt_err_t _get_config_descriptor(struct udevice *device, ureq_t setup)
cfg_desc->wTotalLength : setup->length;
/* send configuration descriptor to endpoint 0 */
dcd_ep_write(device->dcd, 0, (rt_uint8_t *)cfg_desc, size);
rt_usbd_ep0_write(device, (rt_uint8_t*)cfg_desc, size);
return RT_EOK;
}
......@@ -94,7 +102,7 @@ static rt_err_t _get_config_descriptor(struct udevice *device, ureq_t setup)
*
* @return RT_EOK on successful, -RT_ERROR on invalid request.
*/
static rt_err_t _get_string_descriptor(struct udevice *device, ureq_t setup)
static rt_err_t _get_string_descriptor(struct udevice* device, ureq_t setup)
{
struct ustring_descriptor str_desc;
rt_uint8_t index, i;
......@@ -109,14 +117,13 @@ static rt_err_t _get_string_descriptor(struct udevice *device, ureq_t setup)
str_desc.type = USB_DESC_TYPE_STRING;
index = setup->value & 0xFF;
if (index > USB_STRING_INTERFACE_INDEX)
if(index > USB_STRING_INTERFACE_INDEX)
{
rt_kprintf("unknown string index\n");
dcd_ep_stall(device->dcd, 0);
rt_usbd_ep0_set_stall(device);
return -RT_ERROR;
}
if (index == 0)
if(index == 0)
{
str_desc.bLength = 4;
str_desc.String[0] = 0x09;
......@@ -127,7 +134,7 @@ static rt_err_t _get_string_descriptor(struct udevice *device, ureq_t setup)
len = rt_strlen(device->str[index]);
str_desc.bLength = len*2 + 2;
for (i=0; i<len; i++)
for(i=0; i<len; i++)
{
str_desc.String[i*2] = device->str[index][i];
str_desc.String[i*2 + 1] = 0;
......@@ -140,7 +147,29 @@ static rt_err_t _get_string_descriptor(struct udevice *device, ureq_t setup)
len = setup->length;
/* send string descriptor to endpoint 0 */
dcd_ep_write(device->dcd, 0, (rt_uint8_t *)&str_desc, len);
rt_usbd_ep0_write(device, (rt_uint8_t*)&str_desc, len);
return RT_EOK;
}
static rt_err_t _get_qualifier_descriptor(struct udevice* device, ureq_t setup)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("_get_qualifier_descriptor\n"));
/* parameter check */
RT_ASSERT(device != RT_NULL);
RT_ASSERT(setup != RT_NULL);
if(device->dev_qualifier)
{
/* send device qualifier descriptor to endpoint 0 */
rt_usbd_ep0_write(device, (rt_uint8_t*)device->dev_qualifier,
sizeof(struct usb_qualifier_descriptor));
}
else
{
rt_usbd_ep0_set_stall(device);
}
return RT_EOK;
}
......@@ -153,15 +182,15 @@ static rt_err_t _get_string_descriptor(struct udevice *device, ureq_t setup)
*
* @return RT_EOK on successful.
*/
static rt_err_t _get_descriptor(struct udevice *device, ureq_t setup)
static rt_err_t _get_descriptor(struct udevice* device, ureq_t setup)
{
/* parameter check */
RT_ASSERT(device != RT_NULL);
RT_ASSERT(setup != RT_NULL);
if (setup->request_type == USB_REQ_TYPE_DIR_IN)
if(setup->request_type == USB_REQ_TYPE_DIR_IN)
{
switch (setup->value >> 8)
switch(setup->value >> 8)
{
case USB_DESC_TYPE_DEVICE:
_get_device_descriptor(device, setup);
......@@ -173,18 +202,18 @@ static rt_err_t _get_descriptor(struct udevice *device, ureq_t setup)
_get_string_descriptor(device, setup);
break;
case USB_DESC_TYPE_DEVICEQUALIFIER:
dcd_ep_stall(device->dcd, 0);
_get_qualifier_descriptor(device, setup);
break;
default:
rt_kprintf("unsupported descriptor request\n");
dcd_ep_stall(device->dcd, 0);
rt_usbd_ep0_set_stall(device);
break;
}
}
else
{
rt_kprintf("request direction error\n");
dcd_ep_stall(device->dcd, 0);
rt_usbd_ep0_set_stall(device);
}
return RT_EOK;
......@@ -198,7 +227,7 @@ static rt_err_t _get_descriptor(struct udevice *device, ureq_t setup)
*
* @return RT_EOK on successful.
*/
static rt_err_t _get_interface(struct udevice *device, ureq_t setup)
static rt_err_t _get_interface(struct udevice* device, ureq_t setup)
{
rt_uint8_t value;
uintf_t intf;
......@@ -211,8 +240,7 @@ static rt_err_t _get_interface(struct udevice *device, ureq_t setup)
if (device->state != USB_STATE_CONFIGURED)
{
dcd_ep_stall(device->dcd, 0);
rt_usbd_ep0_set_stall(device);
return -RT_ERROR;
}
......@@ -221,7 +249,7 @@ static rt_err_t _get_interface(struct udevice *device, ureq_t setup)
value = intf->curr_setting->intf_desc->bAlternateSetting;
/* send the interface alternate setting to endpoint 0*/
dcd_ep_write(device->dcd, 0, &value, 1);
rt_usbd_ep0_write(device, &value, 1);
return RT_EOK;
}
......@@ -234,11 +262,11 @@ static rt_err_t _get_interface(struct udevice *device, ureq_t setup)
*
* @return RT_EOK on successful.
*/
static rt_err_t _set_interface(struct udevice *device, ureq_t setup)
static rt_err_t _set_interface(struct udevice* device, ureq_t setup)
{
uintf_t intf;
uep_t ep;
struct rt_list_node *i;
struct rt_list_node* i;
ualtsetting_t setting;
/* parameter check */
......@@ -249,11 +277,10 @@ static rt_err_t _set_interface(struct udevice *device, ureq_t setup)
if (device->state != USB_STATE_CONFIGURED)
{
dcd_ep_stall(device->dcd, 0);
rt_usbd_ep0_set_stall(device);
return -RT_ERROR;
}
/* find the specified interface */
intf = rt_usbd_find_interface(device, setup->index & 0xFF, RT_NULL);
......@@ -262,13 +289,13 @@ static rt_err_t _set_interface(struct udevice *device, ureq_t setup)
setting = intf->curr_setting;
/* start all endpoints of the interface alternate setting */
for (i=setting->ep_list.next; i != &setting->ep_list; i=i->next)
for(i=setting->ep_list.next; i != &setting->ep_list; i=i->next)
{
ep = (uep_t)rt_list_entry(i, struct uendpoint, list);
dcd_ep_stop(device->dcd, ep);
dcd_ep_run(device->dcd, ep);
dcd_ep_disable(device->dcd, ep);
dcd_ep_enable(device->dcd, ep);
}
dcd_send_status(device->dcd);
dcd_ep0_send_status(device->dcd);
return RT_EOK;
}
......@@ -281,7 +308,7 @@ static rt_err_t _set_interface(struct udevice *device, ureq_t setup)
*
* @return RT_EOK on successful.
*/
static rt_err_t _get_config(struct udevice *device, ureq_t setup)
static rt_err_t _get_config(struct udevice* device, ureq_t setup)
{
rt_uint8_t value;
......@@ -291,7 +318,7 @@ static rt_err_t _get_config(struct udevice *device, ureq_t setup)
RT_ASSERT(device->curr_cfg != RT_NULL);
RT_DEBUG_LOG(RT_DEBUG_USB, ("_get_config\n"));
if (device->state == USB_STATE_CONFIGURED)
{
/* get current configuration */
......@@ -302,7 +329,7 @@ static rt_err_t _get_config(struct udevice *device, ureq_t setup)
value = 0;
}
/* write the current configuration to endpoint 0 */
dcd_ep_write(device->dcd, 0, &value, 1);
rt_usbd_ep0_write(device, &value, 1);
return RT_EOK;
}
......@@ -315,7 +342,7 @@ static rt_err_t _get_config(struct udevice *device, ureq_t setup)
*
* @return RT_EOK on successful.
*/
static rt_err_t _set_config(struct udevice *device, ureq_t setup)
static rt_err_t _set_config(struct udevice* device, ureq_t setup)
{
struct rt_list_node *i, *j, *k;
uconfig_t cfg;
......@@ -331,8 +358,7 @@ static rt_err_t _set_config(struct udevice *device, ureq_t setup)
if (setup->value > device->dev_desc.bNumConfigurations)
{
dcd_ep_stall(device->dcd, 0);
rt_usbd_ep0_set_stall(device);
return -RT_ERROR;
}
......@@ -348,33 +374,32 @@ static rt_err_t _set_config(struct udevice *device, ureq_t setup)
rt_usbd_set_config(device, setup->value);
cfg = device->curr_cfg;
for (i=cfg->cls_list.next; i!=&cfg->cls_list; i=i->next)
for (i=cfg->func_list.next; i!=&cfg->func_list; i=i->next)
{
/* run all classes and their endpoints in the configuration */
uclass_t cls = (uclass_t)rt_list_entry(i, struct uclass, list);
for (j=cls->intf_list.next; j!=&cls->intf_list; j=j->next)
/* run all functiones and their endpoints in the configuration */
ufunction_t func = (ufunction_t)rt_list_entry(i, struct ufunction, list);
for(j=func->intf_list.next; j!=&func->intf_list; j=j->next)
{
intf = (uintf_t)rt_list_entry(j, struct uinterface, list);
setting = intf->curr_setting;
for (k=setting->ep_list.next; k != &setting->ep_list; k=k->next)
for(k=setting->ep_list.next; k != &setting->ep_list; k=k->next)
{
ep = (uep_t)rt_list_entry(k, struct uendpoint, list);
/* first stop then start endpoint */
dcd_ep_stop(device->dcd, ep);
dcd_ep_run(device->dcd, ep);
/* first disable then enable an endpoint */
dcd_ep_disable(device->dcd, ep);
dcd_ep_enable(device->dcd, ep);
}
}
/* after running all endpoints, then run class */
if (cls->ops->run != RT_NULL)
cls->ops->run(device, cls);
/* after enabled endpoints, then enable function */
FUNC_ENABLE(func);
}
device->state = USB_STATE_CONFIGURED;
_exit:
/* issue status stage */
dcd_send_status(device->dcd);
dcd_ep0_send_status(device->dcd);
return RT_EOK;
}
......@@ -387,38 +412,38 @@ _exit:
*
* @return RT_EOK on successful.
*/
static rt_err_t _set_address(struct udevice *device, ureq_t setup)
static rt_err_t _set_address(struct udevice* device, ureq_t setup)
{
/* parameter check */
RT_ASSERT(device != RT_NULL);
RT_ASSERT(setup != RT_NULL);
RT_DEBUG_LOG(RT_DEBUG_USB, ("_set_address\n"));
/* issue status stage */
dcd_ep0_send_status(device->dcd);
/* set address in device control driver */
dcd_set_address(device->dcd, setup->value);
RT_DEBUG_LOG(RT_DEBUG_USB, ("_set_address\n"));
device->state = USB_STATE_ADDRESS;
/* issue status stage */
dcd_send_status(device->dcd);
return RT_EOK;
}
/**
* This function will handle standard request to
* interface that defined in class-specifics
* This function will handle standard request to
* interface that defined in function-specifics
*
* @param device the usb device object.
* @param setup the setup request.
*
* @return RT_EOK on successful.
* @return RT_EOK on successful.
*/
static rt_err_t _request_interface(struct udevice *device, ureq_t setup)
static rt_err_t _request_interface(struct udevice* device, ureq_t setup)
{
uintf_t intf;
uclass_t cls;
ufunction_t func;
rt_err_t ret;
/* parameter check */
......@@ -427,16 +452,16 @@ static rt_err_t _request_interface(struct udevice *device, ureq_t setup)
RT_DEBUG_LOG(RT_DEBUG_USB, ("_request_interface\n"));
intf = rt_usbd_find_interface(device, setup->index & 0xFF, &cls);
intf = rt_usbd_find_interface(device, setup->index & 0xFF, &func);
if (intf != RT_NULL)
{
ret = intf->handler(device, cls, setup);
ret = intf->handler(func, setup);
}
else
{
ret = -RT_ERROR;
}
return ret;
}
......@@ -448,7 +473,7 @@ static rt_err_t _request_interface(struct udevice *device, ureq_t setup)
*
* @return RT_EOK on successful.
*/
static rt_err_t _standard_request(struct udevice *device, ureq_t setup)
static rt_err_t _standard_request(struct udevice* device, ureq_t setup)
{
udcd_t dcd;
rt_uint16_t value = 0;
......@@ -459,20 +484,20 @@ static rt_err_t _standard_request(struct udevice *device, ureq_t setup)
dcd = device->dcd;
switch (setup->request_type & USB_REQ_TYPE_RECIPIENT_MASK)
switch(setup->request_type & USB_REQ_TYPE_RECIPIENT_MASK)
{
case USB_REQ_TYPE_DEVICE:
switch (setup->request)
switch(setup->request)
{
case USB_REQ_GET_STATUS:
dcd_ep_write(device->dcd, 0, &value, 2);
rt_usbd_ep0_write(device, &value, 2);
break;
case USB_REQ_CLEAR_FEATURE:
dcd_clear_feature(dcd, setup->value, setup->index);
dcd_send_status(dcd);
rt_usbd_clear_feature(device, setup->value, setup->index);
dcd_ep0_send_status(dcd);
break;
case USB_REQ_SET_FEATURE:
dcd_set_feature(dcd, setup->value, setup->index);
rt_usbd_set_feature(device, setup->value, setup->index);
break;
case USB_REQ_SET_ADDRESS:
_set_address(device, setup);
......@@ -481,7 +506,7 @@ static rt_err_t _standard_request(struct udevice *device, ureq_t setup)
_get_descriptor(device, setup);
break;
case USB_REQ_SET_DESCRIPTOR:
dcd_ep_stall(dcd, 0);
rt_usbd_ep0_set_stall(device);
break;
case USB_REQ_GET_CONFIGURATION:
_get_config(device, setup);
......@@ -491,12 +516,12 @@ static rt_err_t _standard_request(struct udevice *device, ureq_t setup)
break;
default:
rt_kprintf("unknown device request\n");
dcd_ep_stall(device->dcd, 0);
rt_usbd_ep0_set_stall(device);
break;
}
break;
case USB_REQ_TYPE_INTERFACE:
switch (setup->request)
switch(setup->request)
{
case USB_REQ_GET_INTERFACE:
_get_interface(device, setup);
......@@ -508,8 +533,7 @@ static rt_err_t _standard_request(struct udevice *device, ureq_t setup)
if (_request_interface(device, setup) != RT_EOK)
{
rt_kprintf("unknown interface request\n");
dcd_ep_stall(device->dcd, 0);
rt_usbd_ep0_set_stall(device);
return - RT_ERROR;
}
else
......@@ -517,53 +541,69 @@ static rt_err_t _standard_request(struct udevice *device, ureq_t setup)
}
break;
case USB_REQ_TYPE_ENDPOINT:
switch (setup->request)
switch(setup->request)
{
case USB_REQ_GET_STATUS:
{
/* TODO */
uep_t ep;
ep = rt_usbd_find_endpoint(device, RT_NULL, setup->index);
value = ep->is_stall;
dcd_ep_write(dcd, 0, &value, 2);
value = ep->stalled;
rt_usbd_ep0_write(device, &value, 2);
}
break;
case USB_REQ_CLEAR_FEATURE:
{
uep_t ep;
uio_request_t req;
struct rt_list_node *node;
ep = rt_usbd_find_endpoint(device, RT_NULL, setup->index);
ep->is_stall = 0;
dcd_clear_feature(dcd, setup->value, setup->index);
dcd_send_status(dcd);
if(USB_EP_HALT == setup->value && ep->stalled == RT_TRUE)
{
rt_usbd_clear_feature(device, setup->value, setup->index);
dcd_ep0_send_status(dcd);
ep->stalled = RT_FALSE;
for (node = ep->request_list.next; node != &ep->request_list; node = node->next)
{
req = (uio_request_t)rt_list_entry(node, struct uio_request, list);
rt_usbd_io_request(device, ep, req);
RT_DEBUG_LOG(RT_DEBUG_USB, ("fired a request\n"));
}
rt_list_init(&ep->request_list);
}
}
break;
case USB_REQ_SET_FEATURE:
{
uep_t ep;
ep = rt_usbd_find_endpoint(device, RT_NULL, setup->index);
ep->is_stall = 1;
dcd_set_feature(dcd, setup->value, setup->index);
dcd_send_status(dcd);
if(USB_EP_HALT == setup->value)
{
ep = rt_usbd_find_endpoint(device, RT_NULL, setup->index);
ep->stalled = RT_TRUE;
rt_usbd_set_feature(device, setup->value, setup->index);
dcd_ep0_send_status(dcd);
}
}
break;
case USB_REQ_SYNCH_FRAME:
break;
default:
rt_kprintf("unknown endpoint request\n");
dcd_ep_stall(device->dcd, 0);
rt_usbd_ep0_set_stall(device);
break;
}
break;
case USB_REQ_TYPE_OTHER:
rt_kprintf("unknown other type request\n");
dcd_ep_stall(device->dcd, 0);
rt_usbd_ep0_set_stall(device);
break;
default:
rt_kprintf("unknown type request\n");
dcd_ep_stall(device->dcd, 0);
rt_usbd_ep0_set_stall(device);
break;
}
......@@ -571,47 +611,68 @@ static rt_err_t _standard_request(struct udevice *device, ureq_t setup)
}
/**
* This function will handle class request.
* This function will handle function request.
*
* @param device the usb device object.
* @param setup the setup request.
*
* @return RT_EOK on successful, -RT_ERROR on invalid request.
*/
static rt_err_t _class_request(udevice_t device, ureq_t setup)
static rt_err_t _function_request(udevice_t device, ureq_t setup)
{
uintf_t intf;
uclass_t cls;
ufunction_t func;
/* parameter check */
RT_ASSERT(device != RT_NULL);
RT_ASSERT(setup != RT_NULL);
/* verify request value */
if (setup->index > device->curr_cfg->cfg_desc.bNumInterfaces)
if(setup->index > device->curr_cfg->cfg_desc.bNumInterfaces)
{
dcd_ep_stall(device->dcd, 0);
rt_usbd_ep0_set_stall(device);
return -RT_ERROR;
}
switch (setup->request_type & USB_REQ_TYPE_RECIPIENT_MASK)
switch(setup->request_type & USB_REQ_TYPE_RECIPIENT_MASK)
{
case USB_REQ_TYPE_INTERFACE:
intf = rt_usbd_find_interface(device, setup->index & 0xFF, &cls);
intf->handler(device, cls, setup);
intf = rt_usbd_find_interface(device, setup->index & 0xFF, &func);
if(intf == RT_NULL)
{
rt_kprintf("unkwown interface request\n");
rt_usbd_ep0_set_stall(device);
}
else
{
intf->handler(func, setup);
}
break;
case USB_REQ_TYPE_ENDPOINT:
break;
default:
rt_kprintf("unknown class request type\n");
dcd_ep_stall(device->dcd, 0);
rt_kprintf("unknown function request type\n");
rt_usbd_ep0_set_stall(device);
break;
}
return RT_EOK;
}
static rt_err_t _dump_setup_packet(ureq_t setup)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("[\n"));
RT_DEBUG_LOG(RT_DEBUG_USB, ("setup_request 0x%x\n",
setup->request_type));
RT_DEBUG_LOG(RT_DEBUG_USB, ("value 0x%x\n", setup->value));
RT_DEBUG_LOG(RT_DEBUG_USB, ("length 0x%x\n", setup->length));
RT_DEBUG_LOG(RT_DEBUG_USB, ("index 0x%x\n", setup->index));
RT_DEBUG_LOG(RT_DEBUG_USB, ("request 0x%x\n", setup->request));
RT_DEBUG_LOG(RT_DEBUG_USB, ("]\n"));
return RT_EOK;
}
/**
* This function will handle setup request.
*
......@@ -626,29 +687,22 @@ static rt_err_t _setup_request(udevice_t device, ureq_t setup)
RT_ASSERT(device != RT_NULL);
RT_ASSERT(setup != RT_NULL);
RT_DEBUG_LOG(RT_DEBUG_USB, ("[\n"));
RT_DEBUG_LOG(RT_DEBUG_USB, ("setup_request_handler 0x%x\n",
setup->request_type));
RT_DEBUG_LOG(RT_DEBUG_USB, ("value 0x%x\n", setup->value));
RT_DEBUG_LOG(RT_DEBUG_USB, ("length 0x%x\n", setup->length));
RT_DEBUG_LOG(RT_DEBUG_USB, ("index 0x%x\n", setup->index));
RT_DEBUG_LOG(RT_DEBUG_USB, ("request 0x%x\n", setup->request));
RT_DEBUG_LOG(RT_DEBUG_USB, ("]\n"));
_dump_setup_packet(setup);
switch ((setup->request_type & USB_REQ_TYPE_MASK))
switch((setup->request_type & USB_REQ_TYPE_MASK))
{
case USB_REQ_TYPE_STANDARD:
_standard_request(device, setup);
break;
case USB_REQ_TYPE_CLASS:
_class_request(device, setup);
_function_request(device, setup);
break;
case USB_REQ_TYPE_VENDOR:
rt_kprintf("vendor type request\n");
break;
default:
rt_kprintf("unknown setup request type\n");
dcd_ep_stall(device->dcd, 0);
rt_usbd_ep0_set_stall(device);
return -RT_ERROR;
}
......@@ -656,104 +710,207 @@ static rt_err_t _setup_request(udevice_t device, ureq_t setup)
}
/**
* This function will notity sof event to all of class.
* This function will hanle data notify event.
*
* @param device the usb device object.
* @param device the usb device object.
* @param ep_msg the endpoint message.
*
* @return RT_EOK.
*/
rt_err_t _sof_notify(udevice_t device)
static rt_err_t _data_notify(udevice_t device, struct ep_msg* ep_msg)
{
struct rt_list_node *i;
uclass_t cls;
uep_t ep;
ufunction_t func;
rt_size_t size = 0;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(ep_msg != RT_NULL);
if (device->state != USB_STATE_CONFIGURED)
{
return -RT_ERROR;
}
ep = rt_usbd_find_endpoint(device, &func, ep_msg->ep_addr);
if(ep == RT_NULL)
{
rt_kprintf("invalid endpoint\n");
return -RT_ERROR;
}
if(EP_ADDRESS(ep) & USB_DIR_IN)
{
if(ep->request.remain_size >= EP_MAXPACKET(ep))
{
dcd_ep_write(device->dcd, EP_ADDRESS(ep),
ep->request.buffer, EP_MAXPACKET(ep));
ep->request.remain_size -= EP_MAXPACKET(ep);
ep->request.buffer += EP_MAXPACKET(ep);
}
else if(ep->request.remain_size > 0)
{
dcd_ep_write(device->dcd, EP_ADDRESS(ep),
ep->request.buffer, ep->request.remain_size);
ep->request.remain_size = 0;
}
else
{
EP_HANDLER(ep, func, size);
}
}
else
{
size = ep_msg->size;
if(ep->request.remain_size == 0)
{
return RT_EOK;
}
if(size == 0)
{
size = dcd_ep_read(device->dcd, EP_ADDRESS(ep),
ep->request.buffer);
}
ep->request.remain_size -= size;
ep->request.buffer += size;
if(ep->request.req_type == UIO_REQUEST_READ_BEST)
{
EP_HANDLER(ep, func, size);
}
else if(ep->request.remain_size == 0)
{
EP_HANDLER(ep, func, ep->request.size);
}
}
return RT_EOK;
}
static rt_err_t _ep0_out_notify(udevice_t device, struct ep_msg* ep_msg)
{
uep_t ep0;
rt_size_t size;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(ep_msg != RT_NULL);
RT_ASSERT(device->dcd != RT_NULL);
/* to notity every class that sof event comes */
for (i = device->curr_cfg->cls_list.next;
i != &device->curr_cfg->cls_list;
i = i->next)
ep0 = &device->dcd->ep0;
size = ep_msg->size;
if(ep0->request.remain_size == 0)
{
return RT_EOK;
}
if(size == 0)
{
size = dcd_ep_read(device->dcd, EP0_OUT_ADDR, ep0->request.buffer);
if(size == 0)
{
return RT_EOK;
}
}
ep0->request.remain_size -= size;
ep0->request.buffer += size;
if(ep0->request.remain_size == 0)
{
cls = (uclass_t)rt_list_entry(i, struct uclass, list);
if (cls->ops->sof_handler != RT_NULL)
cls->ops->sof_handler(device, cls);
/* invoke callback */
if(ep0->rx_indicate != RT_NULL)
{
ep0->rx_indicate(device, size);
}
}
return RT_EOK;
}
/**
* This function will stop all class.
* This function will notity sof event to all of function.
*
* @param device the usb device object.
*
* @return RT_EOK.
*/
rt_err_t _stop_notify(udevice_t device)
static rt_err_t _sof_notify(udevice_t device)
{
struct rt_list_node *i;
uclass_t cls;
ufunction_t func;
RT_ASSERT(device != RT_NULL);
/* to notity every class that sof event comes */
for (i = device->curr_cfg->cls_list.next;
i != &device->curr_cfg->cls_list;
i = i->next)
/* to notity every function that sof event comes */
for (i=device->curr_cfg->func_list.next;
i!=&device->curr_cfg->func_list; i=i->next)
{
cls = (uclass_t)rt_list_entry(i, struct uclass, list);
if (cls->ops->stop != RT_NULL)
cls->ops->stop(device, cls);
func = (ufunction_t)rt_list_entry(i, struct ufunction, list);
if(func->ops->sof_handler != RT_NULL)
func->ops->sof_handler(func);
}
return RT_EOK;
}
/**
* This function will run all class.
* This function will disable all USB functions.
*
* @param device the usb device object.
*
* @return RT_EOK.
*/
rt_err_t _run_notify(udevice_t device)
static rt_err_t _stop_notify(udevice_t device)
{
struct rt_list_node *i;
uclass_t cls;
ufunction_t func;
RT_ASSERT(device != RT_NULL);
/* to notity every class that sof event comes */
for (i = device->curr_cfg->cls_list.next;
i != &device->curr_cfg->cls_list;
/* to notity every function */
for (i = device->curr_cfg->func_list.next;
i != &device->curr_cfg->func_list;
i = i->next)
{
cls = (uclass_t)rt_list_entry(i, struct uclass, list);
if (cls->ops->run != RT_NULL)
cls->ops->run(device, cls);
func = (ufunction_t)rt_list_entry(i, struct ufunction, list);
FUNC_DISABLE(func);
}
return RT_EOK;
}
/**
* This function will reset all class.
*
* @param device the usb device object.
*
* @return RT_EOK.
*/
rt_err_t _reset_notify(udevice_t device)
static rt_size_t rt_usbd_ep_write(udevice_t device, uep_t ep, void *buffer, rt_size_t size)
{
struct rt_list_node *i;
uclass_t cls;
rt_uint16_t maxpacket;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->dcd != RT_NULL);
RT_ASSERT(ep != RT_NULL);
RT_ASSERT(device != RT_NULL);
maxpacket = EP_MAXPACKET(ep);
if(ep->request.remain_size >= maxpacket)
{
dcd_ep_write(device->dcd, EP_ADDRESS(ep), ep->request.buffer, maxpacket);
ep->request.remain_size -= maxpacket;
ep->request.buffer += maxpacket;
}
else
{
dcd_ep_write(device->dcd, EP_ADDRESS(ep), ep->request.buffer,
ep->request.remain_size);
ep->request.remain_size = 0;
}
_stop_notify(device);
_run_notify(device);
return size;
}
return RT_EOK;
static rt_size_t rt_usbd_ep_read_prepare(udevice_t device, uep_t ep, void *buffer, rt_size_t size)
{
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->dcd != RT_NULL);
RT_ASSERT(ep != RT_NULL);
RT_ASSERT(buffer != RT_NULL);
RT_ASSERT(ep->ep_desc != RT_NULL);
return dcd_ep_read_prepare(device->dcd, EP_ADDRESS(ep), buffer, size);
}
/**
......@@ -763,18 +920,17 @@ rt_err_t _reset_notify(udevice_t device)
*
* @return an usb device object on success, RT_NULL on fail.
*/
udevice_t rt_usbd_device_create(void)
udevice_t rt_usbd_device_new(void)
{
udevice_t udevice;
RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_device_create\n"));
RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_device_new\n"));
/* allocate memory for the object */
udevice = rt_malloc(sizeof(struct udevice));
if (udevice == RT_NULL)
if(udevice == RT_NULL)
{
rt_kprintf("alloc memery failed\n");
return RT_NULL;
}
rt_memset(udevice, 0, sizeof(struct udevice));
......@@ -783,7 +939,7 @@ udevice_t rt_usbd_device_create(void)
rt_list_init(&udevice->cfg_list);
/* insert the device object to device list */
rt_list_insert_after(&device_list, &udevice->list);
rt_list_insert_before(&device_list, &udevice->list);
return udevice;
}
......@@ -791,7 +947,7 @@ udevice_t rt_usbd_device_create(void)
/**
* This function will set usb device string description.
*
* @param device the usb device object.
* @param device the usb device object.
* @param ustring pointer to string pointer array.
*
* @return RT_EOK.
......@@ -808,6 +964,17 @@ rt_err_t rt_usbd_device_set_string(udevice_t device, const char** ustring)
return RT_EOK;
}
rt_err_t rt_usbd_device_set_qualifier(udevice_t device, struct usb_qualifier_descriptor* qualifier)
{
/* parameter check */
RT_ASSERT(device != RT_NULL);
RT_ASSERT(qualifier != RT_NULL);
device->dev_qualifier = qualifier;
return RT_EOK;
}
/**
* This function will set an usb controller driver to a device.
*
......@@ -855,31 +1022,30 @@ rt_err_t rt_usbd_device_set_descriptor(udevice_t device, udev_desc_t dev_desc)
*
* @return an usb configuration object.
*/
uconfig_t rt_usbd_config_create(void)
uconfig_t rt_usbd_config_new(void)
{
uconfig_t cfg;
RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_config_create\n"));
RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_config_new\n"));
/* allocate memory for the object */
cfg = rt_malloc(sizeof(struct uconfig));
if (cfg == RT_NULL)
if(cfg == RT_NULL)
{
rt_kprintf("alloc memery failed\n");
return RT_NULL;
}
rt_memset(cfg, 0, sizeof(struct uconfig));
/* set default value */
cfg->cfg_desc.bLength = USB_DESC_LENGTH_CONFIG;
cfg->cfg_desc.type = USB_DESC_TYPE_CONFIGURATION;
cfg->cfg_desc.bLength = USB_DESC_LENGTH_CONFIG;
cfg->cfg_desc.type = USB_DESC_TYPE_CONFIGURATION;
cfg->cfg_desc.wTotalLength = USB_DESC_LENGTH_CONFIG;
cfg->cfg_desc.bmAttributes = 0xC0;
cfg->cfg_desc.MaxPower = 0x32;
cfg->cfg_desc.MaxPower = 0x32;
/* to initialize class object list */
rt_list_init(&cfg->cls_list);
/* to initialize function object list */
rt_list_init(&cfg->func_list);
return cfg;
}
......@@ -892,21 +1058,20 @@ uconfig_t rt_usbd_config_create(void)
*
* @return an usb interface object on success, RT_NULL on fail.
*/
uintf_t rt_usbd_interface_create(udevice_t device, uintf_handler_t handler)
uintf_t rt_usbd_interface_new(udevice_t device, uintf_handler_t handler)
{
uintf_t intf;
RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_interface_create\n"));
RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_interface_new\n"));
/* parameter check */
RT_ASSERT(device != RT_NULL);
/* allocate memory for the object */
intf = (uintf_t)rt_malloc(sizeof(struct uinterface));
if (intf == RT_NULL)
if(intf == RT_NULL)
{
rt_kprintf("alloc memery failed\n");
return RT_NULL;
}
intf->intf_num = device->nr_intf;
......@@ -928,21 +1093,20 @@ uintf_t rt_usbd_interface_create(udevice_t device, uintf_handler_t handler)
*
* @return an usb alternate setting object on success, RT_NULL on fail.
*/
ualtsetting_t rt_usbd_altsetting_create(rt_size_t desc_size)
ualtsetting_t rt_usbd_altsetting_new(rt_size_t desc_size)
{
ualtsetting_t setting;
RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_altsetting_create\n"));
RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_altsetting_new\n"));
/* parameter check */
RT_ASSERT(desc_size > 0);
/* allocate memory for the object */
setting = (ualtsetting_t)rt_malloc(sizeof(struct ualtsetting));
if (setting == RT_NULL)
if(setting == RT_NULL)
{
rt_kprintf("alloc memery failed\n");
return RT_NULL;
}
/* allocate memory for the desc */
......@@ -951,7 +1115,6 @@ ualtsetting_t rt_usbd_altsetting_create(rt_size_t desc_size)
{
rt_kprintf("alloc desc memery failed\n");
rt_free(setting);
return RT_NULL;
}
......@@ -973,56 +1136,53 @@ ualtsetting_t rt_usbd_altsetting_create(rt_size_t desc_size)
*
* @return RT_EOK.
*/
rt_err_t rt_usbd_altsetting_config_descriptor(ualtsetting_t setting,
const void *desc,
rt_off_t intf_pos)
rt_err_t rt_usbd_altsetting_config_descriptor(ualtsetting_t setting, const void* desc, rt_off_t intf_pos)
{
RT_ASSERT(setting != RT_NULL);
RT_ASSERT(setting->desc !=RT_NULL);
rt_memcpy(setting->desc, desc, setting->desc_size);
setting->intf_desc = (uintf_desc_t)((char *)setting->desc + intf_pos);
setting->intf_desc = (uintf_desc_t)((char*)setting->desc + intf_pos);
return RT_EOK;
}
/**
* This function will create an usb class object.
* This function will create an usb function object.
*
* @param device the usb device object.
* @param dev_desc the device descriptor.
* @param ops the operation set.
*
* @return an usb class object on success, RT_NULL on fail.
* @return an usb function object on success, RT_NULL on fail.
*/
uclass_t rt_usbd_class_create(udevice_t device,
udev_desc_t dev_desc,
uclass_ops_t ops)
ufunction_t rt_usbd_function_new(udevice_t device, udev_desc_t dev_desc,
ufunction_ops_t ops)
{
uclass_t cls;
ufunction_t func;
RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_class_create\n"));
RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_function_new\n"));
/* parameter check */
RT_ASSERT(device != RT_NULL);
RT_ASSERT(dev_desc != RT_NULL);
/* allocate memory for the object */
cls = (uclass_t)rt_malloc(sizeof(struct uclass));
if (cls == RT_NULL)
func = (ufunction_t)rt_malloc(sizeof(struct ufunction));
if(func == RT_NULL)
{
rt_kprintf("alloc memery failed\n");
return RT_NULL;
}
cls->dev_desc = dev_desc;
cls->ops = ops;
cls->device = device;
func->dev_desc = dev_desc;
func->ops = ops;
func->device = device;
func->enabled = RT_FALSE;
/* to initialize interface list */
rt_list_init(&cls->intf_list);
rt_list_init(&func->intf_list);
return cls;
return func;
}
/**
......@@ -1033,26 +1193,27 @@ uclass_t rt_usbd_class_create(udevice_t device,
*
* @return an usb endpoint object on success, RT_NULL on fail.
*/
uep_t rt_usbd_endpoint_create(uep_desc_t ep_desc, udep_handler_t handler)
uep_t rt_usbd_endpoint_new(uep_desc_t ep_desc, udep_handler_t handler)
{
uep_t ep;
RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_endpoint_create\n"));
RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_endpoint_new\n"));
/* parameter check */
RT_ASSERT(ep_desc != RT_NULL);
/* allocate memory for the object */
ep = (uep_t)rt_malloc(sizeof(struct uendpoint));
if (ep == RT_NULL)
if(ep == RT_NULL)
{
rt_kprintf("alloc memery failed\n");
return RT_NULL;
}
ep->ep_desc = ep_desc;
ep->handler = handler;
ep->buffer = RT_NULL;
ep->stalled = RT_FALSE;
rt_list_init(&ep->request_list);
return ep;
}
......@@ -1066,7 +1227,7 @@ uep_t rt_usbd_endpoint_create(uep_desc_t ep_desc, udep_handler_t handler)
*/
udevice_t rt_usbd_find_device(udcd_t dcd)
{
struct rt_list_node *node;
struct rt_list_node* node;
udevice_t device;
/* parameter check */
......@@ -1076,12 +1237,10 @@ udevice_t rt_usbd_find_device(udcd_t dcd)
for (node = device_list.next; node != &device_list; node = node->next)
{
device = (udevice_t)rt_list_entry(node, struct udevice, list);
if (device->dcd == dcd)
return device;
if(device->dcd == dcd) return device;
}
rt_kprintf("can't find device\n");
return RT_NULL;
}
......@@ -1095,7 +1254,7 @@ udevice_t rt_usbd_find_device(udcd_t dcd)
*/
uconfig_t rt_usbd_find_config(udevice_t device, rt_uint8_t value)
{
struct rt_list_node *node;
struct rt_list_node* node;
uconfig_t cfg = RT_NULL;
RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_find_config\n"));
......@@ -1105,17 +1264,16 @@ uconfig_t rt_usbd_find_config(udevice_t device, rt_uint8_t value)
RT_ASSERT(value <= device->dev_desc.bNumConfigurations);
/* search a configration in the the device */
for (node = device->cfg_list.next;
node != &device->cfg_list;
node = node->next)
for (node = device->cfg_list.next; node != &device->cfg_list; node = node->next)
{
cfg = (uconfig_t)rt_list_entry(node, struct udevice, list);
if (cfg->cfg_desc.bConfigurationValue == value)
if(cfg->cfg_desc.bConfigurationValue == value)
{
return cfg;
}
}
rt_kprintf("can't find configuration %d\n", value);
return RT_NULL;
}
......@@ -1127,12 +1285,10 @@ uconfig_t rt_usbd_find_config(udevice_t device, rt_uint8_t value)
*
* @return an usb configuration object on found or RT_NULL on not found.
*/
uintf_t rt_usbd_find_interface(udevice_t device,
rt_uint8_t value,
uclass_t *pcls)
uintf_t rt_usbd_find_interface(udevice_t device, rt_uint8_t value, ufunction_t *pfunc)
{
struct rt_list_node *i, *j;
uclass_t cls;
ufunction_t func;
uintf_t intf;
RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_find_interface\n"));
......@@ -1142,26 +1298,23 @@ uintf_t rt_usbd_find_interface(udevice_t device,
RT_ASSERT(value < device->nr_intf);
/* search an interface in the current configuration */
for (i = device->curr_cfg->cls_list.next;
i != &device->curr_cfg->cls_list;
i = i->next)
for (i=device->curr_cfg->func_list.next;
i!=&device->curr_cfg->func_list; i=i->next)
{
cls = (uclass_t)rt_list_entry(i, struct uclass, list);
for (j=cls->intf_list.next; j!=&cls->intf_list; j=j->next)
func = (ufunction_t)rt_list_entry(i, struct ufunction, list);
for(j=func->intf_list.next; j!=&func->intf_list; j=j->next)
{
intf = (uintf_t)rt_list_entry(j, struct uinterface, list);
if (intf->intf_num == value)
if(intf->intf_num == value)
{
if (pcls != RT_NULL)
*pcls = cls;
if (pfunc != RT_NULL)
*pfunc = func;
return intf;
}
}
}
rt_kprintf("can't find interface %d\n", value);
return RT_NULL;
}
......@@ -1183,23 +1336,22 @@ ualtsetting_t rt_usbd_find_altsetting(uintf_t intf, rt_uint8_t value)
/* parameter check */
RT_ASSERT(intf != RT_NULL);
if (intf->curr_setting != RT_NULL)
if(intf->curr_setting != RT_NULL)
{
/* if the value equal to the current alternate setting, then do not search */
if (intf->curr_setting->intf_desc->bAlternateSetting == value)
if(intf->curr_setting->intf_desc->bAlternateSetting == value)
return intf->curr_setting;
}
/* search a setting in the alternate setting list */
for (i=intf->setting_list.next; i!=&intf->setting_list; i=i->next)
for(i=intf->setting_list.next; i!=&intf->setting_list; i=i->next)
{
setting =(ualtsetting_t)rt_list_entry(i, struct ualtsetting, list);
if (setting->intf_desc->bAlternateSetting == value)
if(setting->intf_desc->bAlternateSetting == value)
return setting;
}
rt_kprintf("can't find alternate setting %d\n", value);
return RT_NULL;
}
......@@ -1211,37 +1363,32 @@ ualtsetting_t rt_usbd_find_altsetting(uintf_t intf, rt_uint8_t value)
*
* @return an usb endpoint object on found or RT_NULL on not found.
*/
uep_t rt_usbd_find_endpoint(udevice_t device,
uclass_t *pcls,
rt_uint8_t ep_addr)
uep_t rt_usbd_find_endpoint(udevice_t device, ufunction_t* pfunc, rt_uint8_t ep_addr)
{
uep_t ep;
struct rt_list_node *i, *j, *k;
uclass_t cls;
ufunction_t func;
uintf_t intf;
/* parameter check */
RT_ASSERT(device != RT_NULL);
/* search a endpoint in the current configuration */
for (i = device->curr_cfg->cls_list.next;
i != &device->curr_cfg->cls_list;
i = i->next)
for (i=device->curr_cfg->func_list.next;
i!=&device->curr_cfg->func_list; i=i->next)
{
cls = (uclass_t)rt_list_entry(i, struct uclass, list);
for (j=cls->intf_list.next; j!=&cls->intf_list; j=j->next)
func = (ufunction_t)rt_list_entry(i, struct ufunction, list);
for(j=func->intf_list.next; j!=&func->intf_list; j=j->next)
{
intf = (uintf_t)rt_list_entry(j, struct uinterface, list);
for (k = intf->curr_setting->ep_list.next;
k != &intf->curr_setting->ep_list;
k = k->next)
for(k=intf->curr_setting->ep_list.next;
k!=&intf->curr_setting->ep_list; k=k->next)
{
ep = (uep_t)rt_list_entry(k, struct uendpoint, list);
if (ep->ep_desc->bEndpointAddress == ep_addr)
if(EP_ADDRESS(ep) == ep_addr)
{
if (pcls != RT_NULL)
*pcls = cls;
if (pfunc != RT_NULL)
*pfunc = func;
return ep;
}
}
......@@ -1249,7 +1396,6 @@ uep_t rt_usbd_find_endpoint(udevice_t device,
}
rt_kprintf("can't find endpoint 0x%x\n", ep_addr);
return RT_NULL;
}
......@@ -1264,7 +1410,7 @@ uep_t rt_usbd_find_endpoint(udevice_t device,
rt_err_t rt_usbd_device_add_config(udevice_t device, uconfig_t cfg)
{
struct rt_list_node *i, *j, *k;
uclass_t cls;
ufunction_t func;
uintf_t intf;
uep_t ep;
......@@ -1278,79 +1424,81 @@ rt_err_t rt_usbd_device_add_config(udevice_t device, uconfig_t cfg)
cfg->cfg_desc.bConfigurationValue = device->dev_desc.bNumConfigurations + 1;
device->dev_desc.bNumConfigurations++;
for (i=cfg->cls_list.next; i!=&cfg->cls_list; i=i->next)
for (i=cfg->func_list.next; i!=&cfg->func_list; i=i->next)
{
cls = (uclass_t)rt_list_entry(i, struct uclass, list);
func = (ufunction_t)rt_list_entry(i, struct ufunction, list);
for (j=cls->intf_list.next; j!=&cls->intf_list; j=j->next)
for(j=func->intf_list.next; j!=&func->intf_list; j=j->next)
{
intf = (uintf_t)rt_list_entry(j, struct uinterface, list);
cfg->cfg_desc.bNumInterfaces++;
/* allocate address for every endpoint in the interface alternate setting */
for (k = intf->curr_setting->ep_list.next;
k != &intf->curr_setting->ep_list;
k = k->next)
for(k=intf->curr_setting->ep_list.next;
k!=&intf->curr_setting->ep_list; k=k->next)
{
ep = (uep_t)rt_list_entry(k, struct uendpoint, list);
dcd_ep_alloc(device->dcd, ep);
if(rt_usbd_ep_assign(device, ep) != RT_EOK)
{
rt_kprintf("endpoint assign error\n");
}
}
/* construct complete configuration descriptor */
rt_memcpy((void *)&cfg->cfg_desc.data[cfg->cfg_desc.wTotalLength - USB_DESC_LENGTH_CONFIG],
(void *)intf->curr_setting->desc,
intf->curr_setting->desc_size);
rt_memcpy((void*)&cfg->cfg_desc.data[cfg->cfg_desc.wTotalLength - USB_DESC_LENGTH_CONFIG],
(void*)intf->curr_setting->desc,
intf->curr_setting->desc_size);
cfg->cfg_desc.wTotalLength += intf->curr_setting->desc_size;
}
}
/* insert the configuration to the list */
rt_list_insert_after(&device->cfg_list, &cfg->list);
rt_list_insert_before(&device->cfg_list, &cfg->list);
return RT_EOK;
}
/**
* This function will add a class to a configuration.
* This function will add a function to a configuration.
*
* @param cfg the configuration object.
* @param cls the class object.
* @param func the function object.
*
* @return RT_EOK.
*/
rt_err_t rt_usbd_config_add_class(uconfig_t cfg, uclass_t cls)
rt_err_t rt_usbd_config_add_function(uconfig_t cfg, ufunction_t func)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_config_add_class\n"));
RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_config_add_function\n"));
/* parameter check */
RT_ASSERT(cfg != RT_NULL);
RT_ASSERT(cls != RT_NULL);
RT_ASSERT(func != RT_NULL);
/* insert the class to the list */
rt_list_insert_after(&cfg->cls_list, &cls->list);
/* insert the function to the list */
rt_list_insert_before(&cfg->func_list, &func->list);
return RT_EOK;
}
/**
* This function will add an interface to a class.
* This function will add an interface to a function.
*
* @param cls the class object.
* @param func the function object.
* @param intf the interface object.
*
* @return RT_EOK.
*/
rt_err_t rt_usbd_class_add_interface(uclass_t cls, uintf_t intf)
rt_err_t rt_usbd_function_add_interface(ufunction_t func, uintf_t intf)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_class_add_interface\n"));
RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_function_add_interface\n"));
/* parameter check */
RT_ASSERT(cls != RT_NULL);
RT_ASSERT(func != RT_NULL);
RT_ASSERT(intf != RT_NULL);
/* insert the interface to the list */
rt_list_insert_after(&cls->intf_list, &intf->list);
rt_list_insert_before(&func->intf_list, &intf->list);
return RT_EOK;
}
......@@ -1374,7 +1522,7 @@ rt_err_t rt_usbd_interface_add_altsetting(uintf_t intf, ualtsetting_t setting)
setting->intf_desc->bInterfaceNumber = intf->intf_num;
/* insert the alternate setting to the list */
rt_list_insert_after(&intf->setting_list, &setting->list);
rt_list_insert_before(&intf->setting_list, &setting->list);
return RT_EOK;
}
......@@ -1396,7 +1544,7 @@ rt_err_t rt_usbd_altsetting_add_endpoint(ualtsetting_t setting, uep_t ep)
RT_ASSERT(ep != RT_NULL);
/* insert the endpoint to the list */
rt_list_insert_after(&setting->ep_list, &ep->list);
rt_list_insert_before(&setting->ep_list, &ep->list);
return RT_EOK;
}
......@@ -1451,9 +1599,387 @@ rt_err_t rt_usbd_set_config(udevice_t device, rt_uint8_t value)
/* set as current configuration */
device->curr_cfg = cfg;
dcd_set_config(device->dcd, value);
return RT_TRUE;
}
/**
* This function will request an IO transaction.
*
* @param device the usb device object.
* @param ep the endpoint object.
* @param req IO request.
*
* @return RT_EOK.
*/
rt_size_t rt_usbd_io_request(udevice_t device, uep_t ep, uio_request_t req)
{
rt_size_t size = 0;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(req != RT_NULL);
if(ep->stalled == RT_FALSE)
{
switch(req->req_type)
{
case UIO_REQUEST_READ_BEST:
case UIO_REQUEST_READ_FULL:
ep->request.remain_size = ep->request.size;
size = rt_usbd_ep_read_prepare(device, ep, req->buffer, req->size);
break;
case UIO_REQUEST_WRITE:
ep->request.remain_size = ep->request.size;
size = rt_usbd_ep_write(device, ep, req->buffer, req->size);
break;
default:
rt_kprintf("unknown request type\n");
break;
}
}
else
{
rt_list_insert_before(&ep->request_list, &req->list);
RT_DEBUG_LOG(RT_DEBUG_USB, ("suspend a request\n"));
}
return size;
}
/**
* This function will set feature for an usb device.
*
* @param device the usb device object.
* @param value the configuration number.
*
* @return RT_EOK.
*/
rt_err_t rt_usbd_set_feature(udevice_t device, rt_uint16_t value, rt_uint16_t index)
{
RT_ASSERT(device != RT_NULL);
if (value == USB_FEATURE_DEV_REMOTE_WAKEUP)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("set feature remote wakeup\n"));
}
else if (value == USB_FEATURE_ENDPOINT_HALT)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("set feature stall\n"));
dcd_ep_set_stall(device->dcd, (rt_uint32_t)(index & 0xFF));
}
return RT_EOK;
}
/**
* This function will clear feature for an usb device.
*
* @param device the usb device object.
* @param value the configuration number.
*
* @return RT_EOK.
*/
rt_err_t rt_usbd_clear_feature(udevice_t device, rt_uint16_t value, rt_uint16_t index)
{
RT_ASSERT(device != RT_NULL);
if (value == USB_FEATURE_DEV_REMOTE_WAKEUP)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("clear feature remote wakeup\n"));
}
else if (value == USB_FEATURE_ENDPOINT_HALT)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("clear feature stall\n"));
dcd_ep_clear_stall(device->dcd, (rt_uint32_t)(index & 0xFF));
}
return RT_EOK;
}
rt_err_t rt_usbd_ep0_set_stall(udevice_t device)
{
RT_ASSERT(device != RT_NULL);
return dcd_ep_set_stall(device->dcd, 0);
}
rt_err_t rt_usbd_ep0_clear_stall(udevice_t device)
{
RT_ASSERT(device != RT_NULL);
return dcd_ep_clear_stall(device->dcd, 0);
}
rt_err_t rt_usbd_ep_set_stall(udevice_t device, uep_t ep)
{
rt_err_t ret;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(ep != RT_NULL);
RT_ASSERT(ep->ep_desc != RT_NULL);
ret = dcd_ep_set_stall(device->dcd, EP_ADDRESS(ep));
if(ret == RT_EOK)
{
ep->stalled = RT_TRUE;
}
return ret;
}
rt_err_t rt_usbd_ep_clear_stall(udevice_t device, uep_t ep)
{
rt_err_t ret;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(ep != RT_NULL);
RT_ASSERT(ep->ep_desc != RT_NULL);
ret = dcd_ep_clear_stall(device->dcd, EP_ADDRESS(ep));
if(ret == RT_EOK)
{
ep->stalled = RT_FALSE;
}
return ret;
}
static rt_err_t rt_usbd_ep_assign(udevice_t device, uep_t ep)
{
int i = 0;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->dcd != RT_NULL);
RT_ASSERT(device->dcd->ep_pool != RT_NULL);
RT_ASSERT(ep != RT_NULL);
RT_ASSERT(ep->ep_desc != RT_NULL);
while(device->dcd->ep_pool[i].addr != 0xFF)
{
if(device->dcd->ep_pool[i].status == ID_UNASSIGNED &&
ep->ep_desc->bmAttributes == device->dcd->ep_pool[i].type)
{
EP_ADDRESS(ep) |= device->dcd->ep_pool[i].addr;
ep->id = &device->dcd->ep_pool[i];
device->dcd->ep_pool[i].status = ID_ASSIGNED;
RT_DEBUG_LOG(RT_DEBUG_USB, ("assigned %d\n", device->dcd->ep_pool[i].addr));
return RT_EOK;
}
i++;
}
return -RT_ERROR;
}
static rt_err_t rt_usbd_ep_unassign(udevice_t device, uep_t ep)
{
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->dcd != RT_NULL);
RT_ASSERT(device->dcd->ep_pool != RT_NULL);
RT_ASSERT(ep != RT_NULL);
RT_ASSERT(ep->ep_desc != RT_NULL);
ep->id->status = ID_UNASSIGNED;
return RT_EOK;
}
rt_err_t rt_usbd_ep0_setup_handler(udcd_t dcd, struct ureqest* setup)
{
struct udev_msg msg;
rt_size_t size;
RT_ASSERT(dcd != RT_NULL);
if(setup == RT_NULL)
{
size = dcd_ep_read(dcd, EP0_OUT_ADDR, (void*)&msg.content.setup);
if(size != sizeof(struct ureqest))
{
rt_kprintf("read setup packet error\n");
return -RT_ERROR;
}
}
else
{
rt_memcpy((void*)&msg.content.setup, (void*)setup, sizeof(struct ureqest));
}
msg.type = USB_MSG_SETUP_NOTIFY;
msg.dcd = dcd;
rt_usbd_event_signal(&msg);
return RT_EOK;
}
rt_err_t rt_usbd_ep0_in_handler(udcd_t dcd)
{
RT_ASSERT(dcd != RT_NULL);
if(dcd->ep0.request.remain_size >= dcd->ep0.id->maxpacket)
{
dcd_ep_write(dcd, EP0_IN_ADDR, dcd->ep0.request.buffer, dcd->ep0.id->maxpacket);
dcd->ep0.request.remain_size -= dcd->ep0.id->maxpacket;
}
else if(dcd->ep0.request.remain_size > 0)
{
dcd_ep_write(dcd, EP0_IN_ADDR, dcd->ep0.request.buffer, dcd->ep0.request.remain_size);
dcd->ep0.request.remain_size = 0;
}
else
{
dcd_ep_write(dcd, EP0_IN_ADDR, RT_NULL, 0);
}
return RT_EOK;
}
rt_err_t rt_usbd_ep0_out_handler(udcd_t dcd, rt_size_t size)
{
struct udev_msg msg;
RT_ASSERT(dcd != RT_NULL);
msg.type = USB_MSG_EP0_OUT;
msg.dcd = dcd;
msg.content.ep_msg.size = size;
rt_usbd_event_signal(&msg);
return RT_EOK;
}
rt_err_t rt_usbd_ep_in_handler(udcd_t dcd, rt_uint8_t address)
{
struct udev_msg msg;
RT_ASSERT(dcd != RT_NULL);
msg.type = USB_MSG_DATA_NOTIFY;
msg.dcd = dcd;
msg.content.ep_msg.ep_addr = address;
msg.content.ep_msg.size = 0;
rt_usbd_event_signal(&msg);
return RT_EOK;
}
rt_err_t rt_usbd_ep_out_handler(udcd_t dcd, rt_uint8_t address, rt_size_t size)
{
struct udev_msg msg;
RT_ASSERT(dcd != RT_NULL);
msg.type = USB_MSG_DATA_NOTIFY;
msg.dcd = dcd;
msg.content.ep_msg.ep_addr = address;
msg.content.ep_msg.size = size;
rt_usbd_event_signal(&msg);
return RT_EOK;
}
rt_err_t rt_usbd_reset_handler(udcd_t dcd)
{
struct udev_msg msg;
RT_ASSERT(dcd != RT_NULL);
msg.type = USB_MSG_RESET;
msg.dcd = dcd;
rt_usbd_event_signal(&msg);
return RT_EOK;
}
rt_err_t rt_usbd_connect_handler(udcd_t dcd)
{
struct udev_msg msg;
RT_ASSERT(dcd != RT_NULL);
msg.type = USB_MSG_PLUG_IN;
msg.dcd = dcd;
rt_usbd_event_signal(&msg);
return RT_EOK;
}
rt_err_t rt_usbd_disconnect_handler(udcd_t dcd)
{
struct udev_msg msg;
RT_ASSERT(dcd != RT_NULL);
msg.type = USB_MSG_PLUG_OUT;
msg.dcd = dcd;
rt_usbd_event_signal(&msg);
return RT_EOK;
}
rt_err_t rt_usbd_sof_handler(udcd_t dcd)
{
struct udev_msg msg;
RT_ASSERT(dcd != RT_NULL);
msg.type = USB_MSG_SOF;
msg.dcd = dcd;
rt_usbd_event_signal(&msg);
return RT_EOK;
}
rt_size_t rt_usbd_ep0_write(udevice_t device, void *buffer, rt_size_t size)
{
uep_t ep0;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->dcd != RT_NULL);
RT_ASSERT(buffer != RT_NULL);
RT_ASSERT(size > 0);
ep0 = &device->dcd->ep0;
ep0->request.size = size;
ep0->request.buffer = buffer;
ep0->request.remain_size = size;
if(ep0->request.remain_size >= ep0->id->maxpacket)
{
dcd_ep_write(device->dcd, EP0_IN_ADDR, ep0->request.buffer, ep0->id->maxpacket);
ep0->request.remain_size -= ep0->id->maxpacket;
ep0->request.buffer += ep0->id->maxpacket;
}
else
{
dcd_ep_write(device->dcd, EP0_IN_ADDR, ep0->request.buffer, ep0->request.remain_size);
ep0->request.remain_size = 0;
}
return size;
}
rt_size_t rt_usbd_ep0_read(udevice_t device, void *buffer, rt_size_t size,
rt_err_t (*rx_ind)(udevice_t device, rt_size_t size))
{
uep_t ep0;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->dcd != RT_NULL);
RT_ASSERT(buffer != RT_NULL);
ep0 = &device->dcd->ep0;
ep0->request.size = size;
ep0->request.buffer = buffer;
ep0->request.remain_size = size;
ep0->rx_indicate = rx_ind;
dcd_ep_read_prepare(device->dcd, EP0_OUT_ADDR, buffer, size);
return size;
}
static struct rt_messagequeue usb_mq;
/**
......@@ -1464,26 +1990,27 @@ static struct rt_messagequeue usb_mq;
*
* @return none.
*/
static void rt_usbd_thread_entry(void *parameter)
static void rt_usbd_thread_entry(void* parameter)
{
while (1)
while(1)
{
struct udev_msg msg;
udevice_t device;
uclass_t cls;
uep_t ep;
/* receive message */
if (rt_mq_recv(&usb_mq, &msg, sizeof(struct udev_msg), RT_WAITING_FOREVER) != RT_EOK)
if(rt_mq_recv(&usb_mq, &msg, sizeof(struct udev_msg),
RT_WAITING_FOREVER) != RT_EOK )
continue;
device = rt_usbd_find_device(msg.dcd);
if (device == RT_NULL)
if(device == RT_NULL)
{
rt_kprintf("invalid usb device\n");
continue;
}
RT_DEBUG_LOG(RT_DEBUG_USB, ("message type %d\n", msg.type));
switch (msg.type)
{
case USB_MSG_SOF:
......@@ -1492,26 +2019,28 @@ static void rt_usbd_thread_entry(void *parameter)
case USB_MSG_DATA_NOTIFY:
/* some buggy drivers will have USB_MSG_DATA_NOTIFY before the core
* got configured. */
if (device->state != USB_STATE_CONFIGURED)
break;
ep = rt_usbd_find_endpoint(device, &cls, msg.content.ep_msg.ep_addr);
if (ep != RT_NULL)
ep->handler(device, cls, msg.content.ep_msg.size);
else
rt_kprintf("invalid endpoint\n");
_data_notify(device, &msg.content.ep_msg);
break;
case USB_MSG_SETUP_NOTIFY:
_setup_request(device, (ureq_t)msg.content.setup_msg.packet);
_setup_request(device, &msg.content.setup);
break;
case USB_MSG_EP0_OUT:
_ep0_out_notify(device, &msg.content.ep_msg);
break;
case USB_MSG_RESET:
case USB_MSG_RESET:
RT_DEBUG_LOG(RT_DEBUG_USB, ("reset %d\n", device->state));
if (device->state == USB_STATE_ADDRESS)
_reset_notify(device);
_stop_notify(device);
break;
case USB_MSG_PLUG_IN:
device->state = USB_STATE_ATTACHED;
break;
case USB_MSG_PLUG_OUT:
device->state = USB_STATE_NOTATTACHED;
_stop_notify(device);
break;
default:
rt_kprintf("unknown msg type\n");
rt_kprintf("unknown msg type %d\n", msg.type);
break;
}
}
......@@ -1525,12 +2054,12 @@ static void rt_usbd_thread_entry(void *parameter)
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbd_post_event(struct udev_msg *msg, rt_size_t size)
rt_err_t rt_usbd_event_signal(struct udev_msg* msg)
{
RT_ASSERT(msg != RT_NULL);
/* send message to usb message queue */
return rt_mq_send(&usb_mq, (void *)msg, size);
return rt_mq_send(&usb_mq, (void*)msg, sizeof(struct udev_msg));
}
......@@ -1548,30 +2077,21 @@ static rt_uint8_t usb_mq_pool[(USBD_MQ_MSG_SZ+sizeof(void*))*USBD_MQ_MAX_MSG];
* This function will initialize usb device thread.
*
* @return none.
*
*/
rt_err_t rt_usbd_core_init(void)
{
rt_list_init(&device_list);
/* create an usb message queue */
rt_mq_init(&usb_mq,
"usbd",
usb_mq_pool,
USBD_MQ_MSG_SZ,
sizeof(usb_mq_pool),
RT_IPC_FLAG_FIFO);
rt_mq_init(&usb_mq, "usbd", usb_mq_pool, USBD_MQ_MSG_SZ,
sizeof(usb_mq_pool), RT_IPC_FLAG_FIFO);
/* init usb device thread */
rt_thread_init(&usb_thread,
"usbd",
rt_usbd_thread_entry,
RT_NULL,
usb_thread_stack,
RT_USBD_THREAD_STACK_SZ,
RT_USBD_THREAD_PRIO,
20);
rt_thread_init(&usb_thread, "usbd", rt_usbd_thread_entry, RT_NULL,
usb_thread_stack, RT_USBD_THREAD_STACK_SZ, RT_USBD_THREAD_PRIO, 20);
/* rt_thread_init should always be OK, so start the thread without further
* checking. */
return rt_thread_startup(&usb_thread);
}
......@@ -16,7 +16,7 @@
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*
* Change Logs:
* Date Author Notes
* 2012-10-02 Yi Qiu first version
......@@ -28,13 +28,15 @@
#ifdef RT_USING_USB_DEVICE
#define USB_DEVICE_CONTROLLER_NAME "usbd"
#ifdef RT_USB_DEVICE_COMPOSITE
const static char* ustring[] =
{
"Language",
"RT-Thread Team.",
"RTT Composite Device",
"1.1.0",
"320219198301",
"Configuration",
"Interface",
};
......@@ -60,54 +62,54 @@ static struct udevice_descriptor compsit_desc =
};
#endif
rt_err_t rt_usb_device_init(const char* udc_name)
rt_err_t rt_usb_device_init(void)
{
rt_device_t udc;
udevice_t udevice;
uconfig_t cfg;
uclass_t cls;
ufunction_t func;
/* create and startup usb device thread */
rt_usbd_core_init();
RT_ASSERT(udc_name != RT_NULL);
/* create a device object */
udevice = rt_usbd_device_new();
udc = rt_device_find(udc_name);
udc = rt_device_find(USB_DEVICE_CONTROLLER_NAME);
if(udc == RT_NULL)
{
rt_kprintf("can't find usb device controller %s\n", udc_name);
rt_kprintf("can't find usb device controller %s\n", USB_DEVICE_CONTROLLER_NAME);
return -RT_ERROR;
}
/* create and startup usb device thread */
rt_usbd_core_init();
/* create a device object */
udevice = rt_usbd_device_create();
/* set usb controller driver to the device */
rt_usbd_device_set_controller(udevice, (udcd_t)udc);
/* create a configuration object */
cfg = rt_usbd_config_create();
cfg = rt_usbd_config_new();
#ifdef RT_USB_DEVICE_MSTORAGE
/* create a mass storage class object */
cls = rt_usbd_class_mstorage_create(udevice);
/* create a mass storage function object */
func = rt_usbd_function_mstorage_create(udevice);
/* add the class to the configuration */
rt_usbd_config_add_class(cfg, cls);
/* add the function to the configuration */
rt_usbd_config_add_function(cfg, func);
#endif
#ifdef RT_USB_DEVICE_CDC
/* create a cdc class object */
cls = rt_usbd_class_cdc_create(udevice);
/* create a cdc function object */
func = rt_usbd_function_cdc_create(udevice);
/* add the class to the configuration */
rt_usbd_config_add_class(cfg, cls);
/* add the function to the configuration */
rt_usbd_config_add_function(cfg, func);
#endif
#ifdef RT_USB_DEVICE_RNDIS
/* create a rndis class object */
cls = rt_usbd_class_rndis_create(udevice);
/* create a rndis function object */
func = rt_usbd_function_rndis_create(udevice);
/* add the class to the configuration */
rt_usbd_config_add_class(cfg, cls);
/* add the function to the configuration */
rt_usbd_config_add_function(cfg, func);
#endif
/* set device descriptor to the device */
......@@ -115,18 +117,18 @@ rt_err_t rt_usb_device_init(const char* udc_name)
rt_usbd_device_set_descriptor(udevice, &compsit_desc);
rt_usbd_device_set_string(udevice, ustring);
#else
rt_usbd_device_set_descriptor(udevice, cls->dev_desc);
rt_usbd_device_set_descriptor(udevice, func->dev_desc);
#endif
/* add the configuration to the device */
rt_usbd_device_add_config(udevice, cfg);
/* set default configuration to 1 */
rt_usbd_set_config(udevice, 1);
/* initialize usb device controller */
rt_device_init(udc);
/* set default configuration to 1 */
rt_usbd_set_config(udevice, 1);
return RT_EOK;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册