From 8fd0a7f9c61dde28d90ec4c3661e9e0e8327f7fc Mon Sep 17 00:00:00 2001 From: shaolin Date: Sun, 16 Feb 2014 17:42:35 +0800 Subject: [PATCH] Update USB Device Stack to support more device controllers; Pass USB CV test verification; Code cleanup; --- .../drivers/include/drivers/usb_common.h | 63 +- .../drivers/include/drivers/usb_device.h | 337 +++-- components/drivers/usb/usbdevice/SConscript | 3 - .../drivers/usb/usbdevice/class/cdc_vcom.c | 559 ++++---- .../drivers/usb/usbdevice/class/mstorage.c | 1057 ++++++++++----- .../drivers/usb/usbdevice/class/mstorage.h | 7 - components/drivers/usb/usbdevice/core/core.c | 1146 ++++++++++++----- .../drivers/usb/usbdevice/core/usbdevice.c | 66 +- 8 files changed, 2188 insertions(+), 1050 deletions(-) diff --git a/components/drivers/include/drivers/usb_common.h b/components/drivers/include/drivers/usb_common.h index 979deb4732..cd6f0432f3 100644 --- a/components/drivers/include/drivers/usb_common.h +++ b/components/drivers/include/drivers/usb_common.h @@ -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; diff --git a/components/drivers/include/drivers/usb_device.h b/components/drivers/include/drivers/usb_device.h index db03ee36ef..722251c82a 100644 --- a/components/drivers/include/drivers/usb_device.h +++ b/components/drivers/include/drivers/usb_device.h @@ -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 */ +#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 uclass; +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 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; - rt_uint8_t* buffer; 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); +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)); -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); +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_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->set_address(value); + return dcd->ops->set_address(address); } -rt_inline rt_err_t dcd_clear_feature(udcd_t dcd, - rt_uint16_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->clear_feature(value, index); + return dcd->ops->set_config(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_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->set_feature(value, index); + return dcd->ops->ep_enable(ep); } -rt_inline rt_err_t dcd_ep_stall(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_stall(ep); + return dcd->ops->ep_disable(ep); } -rt_inline rt_uint8_t dcd_ep_alloc(udcd_t dcd, uep_t ep) -{ - RT_ASSERT(dcd != RT_NULL); - - return dcd->ops->ep_alloc(ep); -} - -rt_inline rt_err_t dcd_ep_free(udcd_t dcd, uep_t ep) -{ - RT_ASSERT(dcd != RT_NULL); - - return dcd->ops->ep_free(ep); -} - -rt_inline rt_err_t dcd_ep_run(udcd_t dcd, uep_t ep) -{ - RT_ASSERT(dcd != RT_NULL); - - return dcd->ops->ep_run(ep); -} - -rt_inline rt_err_t dcd_ep_stop(udcd_t dcd, uep_t ep) -{ - RT_ASSERT(dcd != RT_NULL); - - return dcd->ops->ep_stop(ep); -} - -rt_inline rt_err_t dcd_ep_read(udcd_t dcd, uep_t ep, void *buffer, +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_read(ep, buffer, size); + if(dcd->ops->ep_read_prepare != RT_NULL) + { + return dcd->ops->ep_read_prepare(address, buffer, size); + } + else + { + return 0; + } } -rt_inline rt_size_t dcd_ep_write(udcd_t dcd, - uep_t ep, - void *buffer, +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); + + if(dcd->ops->ep_read != RT_NULL) + { + return dcd->ops->ep_read(address, buffer); + } + else + { + return 0; + } +} + +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_write(ep, buffer, size); + return dcd->ops->ep_write(address, buffer, size); } -rt_inline rt_err_t dcd_send_status(udcd_t dcd) +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->send_status(); + return dcd->ops->ep0_send_status(); +} + +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_set_stall(address); +} + +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->ep_clear_stall(address); } #endif diff --git a/components/drivers/usb/usbdevice/SConscript b/components/drivers/usb/usbdevice/SConscript index d46ec3db59..1ee9467410 100644 --- a/components/drivers/usb/usbdevice/SConscript +++ b/components/drivers/usb/usbdevice/SConscript @@ -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) diff --git a/components/drivers/usb/usbdevice/class/cdc_vcom.c b/components/drivers/usb/usbdevice/class/cdc_vcom.c index 5f284b0294..33f9f7abef 100644 --- a/components/drivers/usb/usbdevice/class/cdc_vcom.c +++ b/components/drivers/usb/usbdevice/class/cdc_vcom.c @@ -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 +#include #include #include #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; -volatile static rt_bool_t vcom_connected = RT_FALSE; -volatile static rt_bool_t vcom_in_sending = RT_FALSE; +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; +}; + +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); + RT_ASSERT(func != RT_NULL); - /* send data to host */ - dcd_ep_write(device->dcd, eps->ep_in, eps->ep_in->buffer, remain); + RT_DEBUG_LOG(RT_DEBUG_USB, ("_ep_in_handler %d\n", size)); - return RT_EOK; - } - - 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,17 +319,28 @@ 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; +} + /** * This function will handle cdc_set_line_coding request. * @@ -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); + struct vcom *data; - RT_DEBUG_LOG(RT_DEBUG_USB, ("cdc class run\n")); - eps = (cdc_eps_t)cls->eps; + RT_ASSERT(func != RT_NULL); - eps->ep_in->buffer = tx_buf; - eps->ep_out->buffer = rx_buf; + RT_DEBUG_LOG(RT_DEBUG_USB, ("cdc function enable\n")); - _vcom_reset_state(); - - 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")); + RT_ASSERT(func != RT_NULL); - _vcom_reset_state(); + RT_DEBUG_LOG(RT_DEBUG_USB, ("cdc function disable\n")); - return RT_EOK; -} + _vcom_reset_state(func); -/** - * 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; - - if (vcom_connected != RT_TRUE) - return -RT_ERROR; - - 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) -{ - rt_uint32_t level; - int cnt; - - 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; - } - - level = rt_hw_interrupt_disable(); - if (rt_ringbuffer_space_len(&tx_ringbuffer)) - { - rt_ringbuffer_putchar(&tx_ringbuffer, c); - } - rt_hw_interrupt_enable(level); - - return 1; -} - static int _vcom_getc(struct rt_serial_device *serial) { int result; rt_uint8_t ch; rt_uint32_t level; + struct ufunction *func; + struct vcom *data; + + func = (struct ufunction*)serial->parent.user_data; + data = (struct vcom*)func->user_data; result = -1; level = rt_hw_interrupt_disable(); - if (rt_ringbuffer_data_len(&rx_ringbuffer)) + + if(rt_ringbuffer_getchar(&data->rx_ringbuffer, &ch) != 0) { - rt_ringbuffer_getchar(&rx_ringbuffer, &ch); result = ch; } + rt_hw_interrupt_enable(level); return result; } +static rt_size_t _vcom_tx(struct rt_serial_device *serial, + const char *buf, rt_size_t size) +{ + struct vcom_tx_msg msg; + + RT_ASSERT(serial != RT_NULL); + RT_ASSERT(buf != RT_NULL); + + 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_kprintf("vcom send msg fail\n"); + return 0; + } + + 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 + diff --git a/components/drivers/usb/usbdevice/class/mstorage.c b/components/drivers/usb/usbdevice/class/mstorage.c index b0351f63e5..4ee45189f8 100644 --- a/components/drivers/usb/usbdevice/class/mstorage.c +++ b/components/drivers/usb/usbdevice/class/mstorage.c @@ -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 @@ -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, +}; -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 +{ + FIXED, + COUNT, + BLOCK_COUNT, +}CB_SIZE_TYPE; + +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", }; -/** - * This function will allocate an usb device instance from system. - * - * @param parent the hub instance to which the new allocated device attached. - * @param port the hub port. - * - * @return the allocate instance on successful, or RT_NULL on failure. - */ -static rt_err_t _inquiry_cmd(udevice_t device, uep_t ep_in) +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[] = { - rt_uint8_t data[36]; + {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}, +}; - *(rt_uint32_t*)&data[0] = 0x0 | (0x80 << 8); - *(rt_uint32_t*)&data[4] = 31; +static void _send_status(ufunction_t func) +{ + struct mstorage *data; - rt_memset(&data[8], 0x20, 28); - rt_memcpy(&data[8], "RTT", 3); - rt_memcpy(&data[16], "USB Disk", 8); + RT_ASSERT(func != RT_NULL); - dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, 36); + RT_DEBUG_LOG(RT_DEBUG_USB, ("_send_status\n")); - return RT_EOK; + 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 handle inquiry command request. + * + * @param func the usb function object. + * @param cbw the command block wrapper. + * + * @return RT_EOK on successful. + */ + +static rt_size_t _inquiry_cmd(ufunction_t func, ustorage_cbw_t cbw) +{ + struct mstorage *data; + rt_uint8_t *buf; + + RT_ASSERT(func != RT_NULL); + RT_ASSERT(func->device != RT_NULL); + RT_ASSERT(cbw != RT_NULL); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("_inquiry_cmd\n")); + + data = (struct mstorage*)func->user_data; + buf = data->ep_in->buffer; + + *(rt_uint32_t*)&buf[0] = 0x0 | (0x80 << 8); + *(rt_uint32_t*)&buf[4] = 31; + + 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; + struct mstorage *data; + struct request_sense_data *buf; - 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; + RT_ASSERT(func != RT_NULL); + RT_ASSERT(func->device != RT_NULL); + RT_ASSERT(cbw != RT_NULL); - dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, sizeof(struct request_sense_data)); + RT_DEBUG_LOG(RT_DEBUG_USB, ("_request_sense\n")); + + data = (struct mstorage*)func->user_data; + buf = (struct request_sense_data *)data->ep_in->buffer; - return RT_EOK; + 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; - data[0]=3; - data[1]=0; - data[2]=0; - data[3]=0; + RT_ASSERT(func != RT_NULL); + RT_ASSERT(func->device != RT_NULL); + RT_ASSERT(cbw != RT_NULL); - dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, 4); + RT_DEBUG_LOG(RT_DEBUG_USB, ("_mode_sense_6\n")); - return RT_EOK; + data = (struct mstorage*)func->user_data; + buf = data->ep_in->buffer; + buf[0] = 3; + buf[1] = 0; + buf[2] = 0; + buf[3] = 0; + + 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); + RT_ASSERT(func != RT_NULL); + RT_ASSERT(func->device != RT_NULL); + RT_ASSERT(cbw != RT_NULL); - sector_count = geometry.sector_count; - sector_size = geometry.bytes_per_sector; + RT_DEBUG_LOG(RT_DEBUG_USB, ("_read_capacities\n")); - *(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; + data = (struct mstorage*)func->user_data; + buf = data->ep_in->buffer; + sector_count = data->geometry.sector_count; + sector_size = data->geometry.bytes_per_sector; - dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, 12); + *(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; - return RT_EOK; + 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]; + struct mstorage *data; + + rt_uint8_t *buf; rt_uint32_t sector_count, sector_size; - RT_ASSERT(device != RT_NULL); + RT_ASSERT(func != RT_NULL); + RT_ASSERT(func->device != RT_NULL); + RT_ASSERT(cbw != RT_NULL); - sector_count = geometry.sector_count; - sector_size = geometry.bytes_per_sector; + RT_DEBUG_LOG(RT_DEBUG_USB, ("_read_capacity\n")); - 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; + data = (struct mstorage*)func->user_data; + buf = data->ep_in->buffer; + sector_count = data->geometry.sector_count; + sector_size = data->geometry.bytes_per_sector; - dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, 8); + 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; - return RT_EOK; + 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) + 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) { - _block ++; - status = STATUS_SEND; - } - else - { - 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); + struct mstorage *data; + + 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 ; - _count = cbw->cb[7]<<8 | cbw->cb[8]<<0; - csw.data_reside = cbw->xfer_len; - _size = _count * geometry.bytes_per_sector; + data = (struct mstorage*)func->user_data; - RT_DEBUG_LOG(RT_DEBUG_USB, ("_write_10 count 0x%x 0x%x\n", - _count, geometry.sector_count)); + 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; - dcd_ep_read(device->dcd, ep_out, ep_out->buffer, 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)); - return RT_EOK; + 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; + + 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 _send_status(udevice_t device, mass_eps_t eps, ustorage_csw_t csw) +static rt_size_t _start_stop(ufunction_t func, + ustorage_cbw_t cbw) { - 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; + 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; } -static void _start_stop(ustorage_cbw_t cbw) +static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size) { - //TODO - _removed = 1; -} + struct mstorage *data; + + RT_ASSERT(func != RT_NULL); + RT_ASSERT(func->device != RT_NULL); -/** - * 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) -{ - mass_eps_t eps; - RT_ASSERT(device != RT_NULL); + RT_DEBUG_LOG(RT_DEBUG_USB, ("_ep_in_handler\n")); + + data = (struct mstorage*)func->user_data; - eps = cls->eps; - if (status == STATUS_CSW) + switch(data->status) { - _send_status(device, eps, &csw); - } - else if (status == STATUS_SEND) - { - 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; + } - 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); + } + else + { + _send_status(func); + } + break; + } + + 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; iep_out->buffer; + return RT_NULL; +} - if(cbw->signature == CBW_SIGNATURE) +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); + + data = (struct mstorage*)func->user_data; + if(cmd->cmd_len == 6) + { + switch(cmd->type) { - csw.signature = CSW_SIGNATURE; - csw.tag = cbw->tag; - csw.data_reside = 0; - csw.status = 0; - } - else - return -RT_ERROR; - - switch(cbw->cb[0]) - { - case SCSI_TEST_UNIT_READY: - csw.status = _removed; - _send_status(device, eps, &csw); + case COUNT: + data->cb_data_size = cbw->cb[4]; break; - case SCSI_REQUEST_SENSE: - _request_sense(device, eps->ep_in); - status = STATUS_CSW; + case BLOCK_COUNT: + data->cb_data_size = cbw->cb[4] * data->geometry.bytes_per_sector; break; - case SCSI_INQUIRY_CMD: - _inquiry_cmd(device, eps->ep_in); - status = STATUS_CSW; + case FIXED: + data->cb_data_size = cmd->data_size; break; - case SCSI_MODE_SENSE_6: - _mode_sense_6(device, eps->ep_in); - status = STATUS_CSW; + default: break; - case SCSI_ALLOW_MEDIUM_REMOVAL: - _send_status(device, eps, &csw); - break; - case SCSI_READ_CAPACITIES: - _read_capacities(device, eps->ep_in); - status = STATUS_CSW; - break; - case SCSI_READ_CAPACITY: - _read_capacity(device, eps->ep_in); - status = STATUS_CSW; - break; - case SCSI_READ_10: - _read_10(device, cbw, eps->ep_in); - break; - case SCSI_WRITE_10: - _write_10(device, cbw, eps->ep_out); - status = STATUS_RECEIVE; - break; - case SCSI_VERIFY_10: - _verify_10(device); - break; - case SCSI_START_STOP: - _start_stop(cbw); - _send_status(device, eps, &csw); - break; - } + } } - else if(status == STATUS_RECEIVE) + else if(cmd->cmd_len == 10) { - RT_DEBUG_LOG(RT_DEBUG_USB, ("write size 0x%x block 0x%x oount 0x%x\n", - size, _block, _size)); - - _size -= size; - csw.data_reside -= size; - - rt_device_write(disk, _block, eps->ep_in->buffer, 1); - _block ++; - if(_size == 0) + switch(cmd->type) { - _send_status(device, eps, &csw); - } - else - { - dcd_ep_read(device->dcd, eps->ep_out, eps->ep_out->buffer, - geometry.bytes_per_sector); + case COUNT: + data->cb_data_size = cbw->cb[7]<<8 | cbw->cb[8]; + break; + case BLOCK_COUNT: + data->cb_data_size = (cbw->cb[7]<<8 | cbw->cb[8]) * + data->geometry.bytes_per_sector; + break; + case FIXED: + data->cb_data_size = cmd->data_size; + break; + default: + break; } } else { - rt_kprintf("none cbw status\n"); + rt_kprintf("cmd_len error %d\n", cmd->cmd_len); } - - return RT_EOK; } +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, ("\nwrite size %d block 0x%x oount 0x%x\n", + size, data->block, data->size)); + + data->size -= size; + data->csw_response.data_reside -= size; + + rt_device_write(data->disk, data->block, data->ep_out->buffer, 1); + + if(data->csw_response.data_reside != 0) + { + 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 + { + _send_status(func); + } + + return RT_EOK; + } + +exit: + if(data->csw_response.data_reside) + { + 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); + } + } + 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) + + if(rt_device_open(data->disk, RT_DEVICE_OFLAG_RDWR) != RT_EOK) + { + rt_kprintf("disk open error\n"); return -RT_ERROR; - - buffer = (rt_uint8_t*)rt_malloc(geometry.bytes_per_sector); - if(buffer == RT_NULL) + } + + 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 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; + RT_DEBUG_LOG(RT_DEBUG_USB, ("Mass storage function disabled\n")); + 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 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 */ - intf = rt_usbd_interface_create(device, _interface_handler); + /* create an interface object */ + intf = rt_usbd_interface_new(device, _interface_handler); - /* create an alternate setting */ - setting = rt_usbd_altsetting_create(sizeof(struct umass_descriptor)); + /* 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 diff --git a/components/drivers/usb/usbdevice/class/mstorage.h b/components/drivers/usb/usbdevice/class/mstorage.h index 4d53222a00..0f448a07d5 100644 --- a/components/drivers/usb/usbdevice/class/mstorage.h +++ b/components/drivers/usb/usbdevice/class/mstorage.h @@ -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 diff --git a/components/drivers/usb/usbdevice/core/core.c b/components/drivers/usb/usbdevice/core/core.c index f29ee26c2e..14deb316aa 100644 --- a/components/drivers/usb/usbdevice/core/core.c +++ b/components/drivers/usb/usbdevice/core/core.c @@ -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 @@ -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; istr[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); - - /* 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) + RT_ASSERT(ep_msg != RT_NULL); + + if (device->state != USB_STATE_CONFIGURED) { - cls = (uclass_t)rt_list_entry(i, struct uclass, list); - if (cls->ops->sof_handler != RT_NULL) - cls->ops->sof_handler(device, cls); + 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); + + 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) + { + /* 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_RESET: + case USB_MSG_EP0_OUT: + _ep0_out_notify(device, &msg.content.ep_msg); + break; + 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); } + diff --git a/components/drivers/usb/usbdevice/core/usbdevice.c b/components/drivers/usb/usbdevice/core/usbdevice.c index f5b2b9beac..adef1db2a0 100644 --- a/components/drivers/usb/usbdevice/core/usbdevice.c +++ b/components/drivers/usb/usbdevice/core/usbdevice.c @@ -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; - - RT_ASSERT(udc_name != RT_NULL); - - udc = rt_device_find(udc_name); - if(udc == RT_NULL) - { - rt_kprintf("can't find usb device controller %s\n", udc_name); - return -RT_ERROR; - } + ufunction_t func; /* create and startup usb device thread */ rt_usbd_core_init(); /* create a device object */ - udevice = rt_usbd_device_create(); + udevice = rt_usbd_device_new(); + + udc = rt_device_find(USB_DEVICE_CONTROLLER_NAME); + if(udc == RT_NULL) + { + rt_kprintf("can't find usb device controller %s\n", USB_DEVICE_CONTROLLER_NAME); + return -RT_ERROR; + } /* 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); - /* add the class to the configuration */ - rt_usbd_config_add_class(cfg, cls); +#ifdef RT_USB_DEVICE_RNDIS + /* create a rndis function object */ + func = rt_usbd_function_rndis_create(udevice); + + /* 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; }