From 60c27fc4b5f96728bc39d7432b8862ce81c2e63b Mon Sep 17 00:00:00 2001 From: "qiuyiuestc@gmail.com" Date: Sun, 25 Nov 2012 00:02:10 +0000 Subject: [PATCH] add USB composite and mass storage class features in USB device stack git-svn-id: https://rt-thread.googlecode.com/svn/trunk@2447 bbd45198-f89e-11dd-88c7-29a3b14d5316 --- .../drivers/include/drivers/usb_common.h | 11 +- .../drivers/include/drivers/usb_device.h | 11 +- components/drivers/usb/usbdevice/SConscript | 7 +- .../drivers/usb/usbdevice/class/cdc_vcom.c | 30 +- .../drivers/usb/usbdevice/class/mstorage.c | 544 ++++++++++++++++++ .../drivers/usb/usbdevice/class/mstorage.h | 53 ++ components/drivers/usb/usbdevice/core/core.c | 44 +- .../drivers/usb/usbdevice/core/usbdevice.c | 52 +- 8 files changed, 723 insertions(+), 29 deletions(-) create mode 100644 components/drivers/usb/usbdevice/class/mstorage.c create mode 100644 components/drivers/usb/usbdevice/class/mstorage.h diff --git a/components/drivers/include/drivers/usb_common.h b/components/drivers/include/drivers/usb_common.h index 1a9ccf40ad..19c75b5f17 100644 --- a/components/drivers/include/drivers/usb_common.h +++ b/components/drivers/include/drivers/usb_common.h @@ -51,6 +51,7 @@ extern "C" { #define USB_DESC_TYPE_ENDPOINT 0x05 #define USB_DESC_TYPE_DEVICEQUALIFIER 0x06 #define USB_DESC_TYPE_OTHERSPEED 0x07 +#define USB_DESC_TYPE_IAD 0x0b #define USB_DESC_TYPE_HID 0x21 #define USB_DESC_TYPE_REPORT 0x22 #define USB_DESC_TYPE_PHYSICAL 0x23 @@ -58,6 +59,7 @@ extern "C" { #define USB_DESC_LENGTH_DEVICE 0x12 #define USB_DESC_LENGTH_CONFIG 0x9 +#define USB_DESC_LENGTH_IAD 0x8 #define USB_DESC_LENGTH_STRING 0x4 #define USB_DESC_LENGTH_INTERFACE 0x9 #define USB_DESC_LENGTH_ENDPOINT 0x7 @@ -244,7 +246,7 @@ struct uconfig_descriptor rt_uint8_t iConfiguration; rt_uint8_t bmAttributes; rt_uint8_t MaxPower; - rt_uint8_t data[128]; + rt_uint8_t data[256]; }; typedef struct uconfig_descriptor* ucfg_desc_t; @@ -263,7 +265,7 @@ struct uinterface_descriptor typedef struct uinterface_descriptor* uintf_desc_t; /* Interface Association Descriptor (IAD) */ -struct uassco_descriptor +struct uiad_descriptor { rt_uint8_t bLength; rt_uint8_t bDescriptorType; @@ -274,7 +276,7 @@ struct uassco_descriptor rt_uint8_t bFunctionProtocol; rt_uint8_t iFunction; }; -typedef struct uassco_descriptor* uassco_desc_t; +typedef struct uiad_descriptor* uiad_desc_t; struct uendpoint_descriptor { @@ -364,6 +366,9 @@ typedef struct ustorage_csw* ustorage_csw_t; #define USBREQ_GET_MAX_LUN 0xfe #define USBREQ_MASS_STORAGE_RESET 0xff +#define MIN(a, b) (a < b ? a : b) +#define MAX(a, b) (a > b ? a : b) + #pragma pack() #ifdef __cplusplus diff --git a/components/drivers/include/drivers/usb_device.h b/components/drivers/include/drivers/usb_device.h index 8d2257ccf4..a6c4afac86 100644 --- a/components/drivers/include/drivers/usb_device.h +++ b/components/drivers/include/drivers/usb_device.h @@ -92,7 +92,9 @@ struct uclass struct udevice* device; udev_desc_t dev_desc; - struct uassco_descriptor* assco; +#ifdef RT_USB_DEVICE_COMPOSITE + uiad_desc_t iad_desc; +#endif rt_list_t intf_list; }; typedef struct uclass* uclass_t; @@ -157,6 +159,7 @@ uep_t rt_usbd_endpoint_create(uep_desc_t ep_desc, ualtsetting_t rt_usbd_altsetting_create(uintf_desc_t intf_desc, rt_size_t desc_size); rt_err_t rt_usbd_core_init(void); +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_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); @@ -173,9 +176,13 @@ 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); uep_t rt_usbd_find_endpoint(udevice_t device, rt_uint8_t ep_addr); -uclass_t rt_usbd_class_mass_create(udevice_t device); +uclass_t rt_usbd_class_mstorage_create(udevice_t device); uclass_t rt_usbd_class_cdc_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); +#endif + rt_inline rt_err_t dcd_set_address(udcd_t dcd, rt_uint8_t value) { RT_ASSERT(dcd != RT_NULL); diff --git a/components/drivers/usb/usbdevice/SConscript b/components/drivers/usb/usbdevice/SConscript index 75d651f902..6cb9d0f5d9 100644 --- a/components/drivers/usb/usbdevice/SConscript +++ b/components/drivers/usb/usbdevice/SConscript @@ -5,9 +5,14 @@ cwd = GetCurrentDir() src = Split(""" core/core.c core/usbdevice.c -class/cdc_vcom.c """) +if GetDepend('RT_USB_DEVICE_CDC'): + src += Glob('class/cdc_vcom.c') + +if GetDepend('RT_USB_DEVICE_MSTORAGE'): + src += Glob('class/mstorage.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 6228370e16..4276b57c4c 100644 --- a/components/drivers/usb/usbdevice/class/cdc_vcom.c +++ b/components/drivers/usb/usbdevice/class/cdc_vcom.c @@ -15,9 +15,10 @@ #include #include #include - #include "cdc.h" +#ifdef RT_USB_DEVICE_CDC + static uclass_t cdc; static uep_t ep_in, ep_out, ep_cmd; @@ -49,6 +50,20 @@ static struct udevice_descriptor dev_desc = USB_DYNAMIC, //bNumConfigurations; }; +#ifdef RT_USB_DEVICE_COMPOSITE +static struct uiad_descriptor iad_desc = +{ + USB_DESC_LENGTH_IAD, + USB_DESC_TYPE_IAD, + USB_DYNAMIC, + 0x02, + USB_CDC_CLASS_COMM, + USB_CDC_SUBCLASS_ACM, + USB_CDC_PROTOCOL_V25TER, + 0x00, +}; +#endif + /* communcation interface descriptor */ static struct ucdc_comm_descriptor comm_desc = { @@ -389,7 +404,10 @@ static rt_err_t _cdc_descriptor_config(rt_uint8_t comm, rt_uint8_t data) comm_desc.call_mgmt_desc.data_interface = data; comm_desc.union_desc.master_interface = comm; comm_desc.union_desc.slave_interface0 = data; - +#ifdef RT_USB_DEVICE_COMPOSITE + iad_desc.bFirstInterface = comm; +#endif + return RT_EOK; } @@ -453,7 +471,11 @@ uclass_t rt_usbd_class_cdc_create(udevice_t device) /* add the communication interface to the cdc class */ rt_usbd_class_add_interface(cdc, intf_comm); - + +#ifdef RT_USB_DEVICE_COMPOSITE + rt_usbd_class_set_iad(cdc, &iad_desc); +#endif + return cdc; } @@ -550,3 +572,5 @@ void rt_usb_vcom_init(void) RT_NULL); } +#endif + diff --git a/components/drivers/usb/usbdevice/class/mstorage.c b/components/drivers/usb/usbdevice/class/mstorage.c new file mode 100644 index 0000000000..a8844ddf85 --- /dev/null +++ b/components/drivers/usb/usbdevice/class/mstorage.c @@ -0,0 +1,544 @@ +/* + * File : mstorage.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2012, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2012-10-01 Yi Qiu first version + */ + +#include +#include +#include +#include "mstorage.h" + +#ifdef RT_USB_DEVICE_MSTORAGE + +#define STATUS_CBW 0x00 +#define STATUS_CSW 0x01 +#define STATUS_RECEIVE 0x02 + +static uclass_t mstorage; +static uep_t ep_in, ep_out; +static rt_uint8_t *buffer; +static rt_uint8_t *write_ptr; +static int status = STATUS_CBW; +static struct ustorage_csw csw; +static rt_device_t disk; +static struct rt_device_blk_geometry geometry; + +static struct udevice_descriptor dev_desc = +{ + USB_DESC_LENGTH_DEVICE, //bLength; + USB_DESC_TYPE_DEVICE, //type; + USB_BCD_VERSION, //bcdUSB; + USB_CLASS_MASS_STORAGE, //bDeviceClass; + 0x00, //bDeviceSubClass; + 0x00, //bDeviceProtocol; + 0x40, //bMaxPacketSize0; + USB_VENDOR_ID, //idVendor; + USB_MASS_STORAGE_PRODUCT_ID,//idProduct; + USB_BCD_DEVICE, //bcdDevice; + USB_STRING_MANU_INDEX, //iManufacturer; + USB_STRING_PRODUCT_INDEX, //iProduct; + USB_STRING_SERIAL_INDEX, //iSerialNumber; + USB_DYNAMIC, //bNumConfigurations; +}; + +static struct umass_descriptor mass_desc = +{ + USB_DESC_LENGTH_INTERFACE, //bLength; + USB_DESC_TYPE_INTERFACE, //type; + USB_DYNAMIC, //bInterfaceNumber; + 0x00, //bAlternateSetting; + 0x02, //bNumEndpoints + USB_CLASS_MASS_STORAGE, //bInterfaceClass; + 0x06, //bInterfaceSubClass; + 0x50, //bInterfaceProtocol; + 0x00, //iInterface; + + USB_DESC_LENGTH_ENDPOINT, //bLength; + USB_DESC_TYPE_ENDPOINT, //type; + USB_DYNAMIC | USB_DIR_OUT, //bEndpointAddress; + USB_EP_ATTR_BULK, //bmAttributes; + 0x40, //wMaxPacketSize; + 0x00, //bInterval; + + USB_DESC_LENGTH_ENDPOINT, //bLength; + USB_DESC_TYPE_ENDPOINT, //type; + USB_DYNAMIC | USB_DIR_IN, //bEndpointAddress; + USB_EP_ATTR_BULK, //bmAttributes; + 0x40, //wMaxPacketSize; + 0x00, //bInterval; +}; + +/** + * 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) +{ + rt_uint8_t data[36]; + + *(rt_uint32_t*)&data[0] = 0x0 | (0x80 << 8); + *(rt_uint32_t*)&data[4] = 31; + + rt_memset(&data[8], 0x20, 28); + rt_memcpy(&data[8], "RTT", 3); + rt_memcpy(&data[16], "USB Disk", 8); + + dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, 36); + + return RT_EOK; +} + +/** + * This function will handle sense request. + * + * @param device the usb device object. + * + * @return RT_EOK on successful. + */ +static rt_err_t _request_sense(udevice_t device) +{ + struct request_sense_data data; + + data.ErrorCode = 0x70; + data.Valid = 0; + data.SenseKey = 5; + data.Information[0] = 0; + data.Information[1] = 0; + data.Information[2] = 0; + data.Information[3] = 0; + data.AdditionalSenseLength = 0x0b; + data.AdditionalSenseCode = 0x20; + data.AdditionalSenseCodeQualifier =0; + + dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, sizeof(struct request_sense_data)); + + return RT_EOK; +} + +/** + * This function will handle mode_sense_6 request. + * + * @param device the usb device object. + * + * @return RT_EOK on successful. + */ +static rt_err_t _mode_sense_6(udevice_t device) +{ + rt_uint8_t data[4]; + + data[0]=3; + data[1]=0; + data[2]=0; + data[3]=0; + + dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, 4); + + return RT_EOK; +} + +/** + * This function will handle read_capacities request. + * + * @param device the usb device object. + * + * @return RT_EOK on successful. + */ +static rt_err_t _read_capacities(udevice_t device) +{ + rt_uint8_t data[12]; + rt_uint32_t sector_count, sector_size; + + RT_ASSERT(device != RT_NULL); + + sector_count = geometry.sector_count; + sector_size = geometry.bytes_per_sector; + + *(rt_uint32_t*)&data[0] = 0x08000000; + data[4] = sector_count >> 24; + data[5] = 0xff & (sector_count >> 16); + data[6] = 0xff & (sector_count >> 8); + data[7] = 0xff & (sector_count); + data[8] = 0x02; + data[9] = 0xff & (sector_size >> 16); + data[10] = 0xff & (sector_size >> 8); + data[11] = 0xff & sector_size; + + dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, 12); + + return RT_EOK; +} + +/** + * This function will handle read_capacity request. + * + * @param device the usb device object. + * + * @return RT_EOK on successful. + */ +static rt_err_t _read_capacity(udevice_t device) +{ + rt_uint8_t data[8]; + rt_uint32_t sector_count, sector_size; + + RT_ASSERT(device != RT_NULL); + + sector_count = geometry.sector_count; + sector_size = geometry.bytes_per_sector; + + data[0] = sector_count >> 24; + data[1] = 0xff & (sector_count >> 16); + data[2] = 0xff & (sector_count >> 8); + data[3] = 0xff & (sector_count); + data[4] = 0x0; + data[5] = 0xff & (sector_size >> 16); + data[6] = 0xff & (sector_size >> 8); + data[7] = 0xff & sector_size; + + dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, 8); + + return RT_EOK; +} + +/** + * This function will handle read_10 request. + * + * @param device the usb device 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) +{ + rt_uint32_t block; + rt_uint32_t count; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(cbw != RT_NULL); + + block = cbw->cb[2]<<24 | cbw->cb[3]<<16 | cbw->cb[4]<<8 | + cbw->cb[5]<<0 ; + + count = cbw->cb[7]<<8 | cbw->cb[8]<<0 ; + + RT_ASSERT(count < geometry.sector_count); + + rt_device_read(disk, block, buffer, count); + dcd_ep_write(device->dcd, ep_in, buffer, count * geometry.bytes_per_sector); + + return RT_EOK; +} + +static rt_uint32_t _block; +static rt_uint32_t _count, _size; + +/** + * This function will handle write_10 request. + * + * @param device the usb device 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) +{ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(cbw != RT_NULL); + + _block = cbw->cb[2]<<24 | cbw->cb[3]<<16 | cbw->cb[4]<<8 | + cbw->cb[5]<<0 ; + _count = cbw->cb[7]<<8 | cbw->cb[8]<<0; + csw.data_reside = cbw->xfer_len; + _size = _count * geometry.bytes_per_sector; + write_ptr = buffer; + + RT_DEBUG_LOG(RT_DEBUG_USB, ("_write_10 count 0x%x 0x%x\n", + _count, geometry.sector_count)); + + dcd_ep_read(device->dcd, ep_out, buffer, MIN(_size, 4096)); + + return RT_EOK; +} + +/** + * This function will handle verify_10 request. + * + * @param device the usb device object. + * + * @return RT_EOK on successful. + */ +static rt_err_t _verify_10(udevice_t device) +{ + return RT_EOK; +} + +/** + * 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, rt_size_t size) +{ + RT_ASSERT(device != RT_NULL); + + if(status == STATUS_CSW) + { + dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&csw, SIZEOF_CSW); + status = STATUS_CBW; + dcd_ep_read(device->dcd, ep_out, ep_out->buffer, SIZEOF_CBW); + } + + return RT_EOK; +} + +static void cbw_dump(struct ustorage_cbw* cbw) +{ + RT_ASSERT(cbw != RT_NULL); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("signature 0x%x\n", cbw->signature)); + RT_DEBUG_LOG(RT_DEBUG_USB, ("tag 0x%x\n", cbw->tag)); + RT_DEBUG_LOG(RT_DEBUG_USB, ("xfer_len 0x%x\n", cbw->xfer_len)); + RT_DEBUG_LOG(RT_DEBUG_USB, ("dflags 0x%x\n", cbw->dflags)); + RT_DEBUG_LOG(RT_DEBUG_USB, ("lun 0x%x\n", cbw->lun)); + RT_DEBUG_LOG(RT_DEBUG_USB, ("cb_len 0x%x\n", cbw->cb_len)); + RT_DEBUG_LOG(RT_DEBUG_USB, ("cb[0] 0x%x\n", cbw->cb[0])); +} + +/** + * 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, rt_size_t size) +{ + RT_ASSERT(device != RT_NULL); + + if(status == STATUS_CBW) + { + struct ustorage_cbw* cbw; + + /* dump cbw information */ + cbw = (struct ustorage_cbw*)ep_out->buffer; + + if(cbw->signature == CBW_SIGNATURE) + { + csw.signature = CSW_SIGNATURE; + csw.tag = cbw->tag; + csw.data_reside = 0; + csw.status = 0; + } + + switch(cbw->cb[0]) + { + case SCSI_TEST_UNIT_READY: + dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&csw, SIZEOF_CSW); + dcd_ep_read(device->dcd, ep_out, ep_out->buffer, SIZEOF_CBW); + break; + case SCSI_REQUEST_SENSE: + _request_sense(device); + status = STATUS_CSW; + break; + case SCSI_INQUIRY_CMD: + _inquiry_cmd(device); + status = STATUS_CSW; + break; + case SCSI_MODE_SENSE_6: + _mode_sense_6(device); + status = STATUS_CSW; + break; + case SCSI_ALLOW_MEDIUM_REMOVAL: + dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&csw, SIZEOF_CSW); + dcd_ep_read(device->dcd, ep_out, ep_out->buffer, SIZEOF_CBW); + break; + case SCSI_READ_CAPACITIES: + _read_capacities(device); + status = STATUS_CSW; + break; + case SCSI_READ_CAPACITY: + _read_capacity(device); + status = STATUS_CSW; + break; + case SCSI_READ_10: + _read_10(device, cbw); + status = STATUS_CSW; + break; + case SCSI_WRITE_10: + _write_10(device, cbw); + status = STATUS_RECEIVE; + break; + case SCSI_VERIFY_10: + _verify_10(device); + break; + } + } + else if(status == STATUS_RECEIVE) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("write size 0x%x block 0x%x oount 0x%x\n", + size, _block, _size)); + + _size -= size; + write_ptr += size; + csw.data_reside -= size; + if(_size == 0) + { + rt_device_write(disk, _block, buffer, _count); + dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&csw, SIZEOF_CSW); + dcd_ep_read(device->dcd, ep_out, ep_out->buffer, SIZEOF_CBW); + status = STATUS_CBW; + } + else + { + dcd_ep_read(device->dcd, ep_out, write_ptr, MIN(_size, 4096)); + } + } + else + { + rt_kprintf("none cbw status\n"); + } + + return RT_EOK; +} + + +/** + * This function will handle mass storage interface request. + * + * @param device the usb device object. + * @param setup the setup request. + * + * @return RT_EOK on successful. + */ +static rt_err_t _interface_handler(udevice_t device, ureq_t setup) +{ + rt_uint8_t lun = 0; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(setup != RT_NULL); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("_interface_handler\n")); + + switch(setup->request) + { + case USBREQ_GET_MAX_LUN: + dcd_ep_write(device->dcd, 0, &lun, 1); + break; + case USBREQ_MASS_STORAGE_RESET: + break; + default: + rt_kprintf("unknown interface request\n"); + break; + } + + return RT_EOK; +} + +/** + * This function will run mass storage class, 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_run(udevice_t device) +{ + RT_ASSERT(device != RT_NULL); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("mass storage run\n")); + + disk = rt_device_find(RT_USB_MSTORAGE_DISK_NAME); + RT_ASSERT(disk != RT_NULL); + + buffer = (rt_uint8_t*)rt_malloc(RT_USB_MSTORAGE_BUFFER_SIZE); + + rt_device_control(disk, RT_DEVICE_CTRL_BLK_GETGEOME, (void*)&geometry); + dcd_ep_read(device->dcd, ep_out, ep_out->buffer, SIZEOF_CBW); + + return RT_EOK; +} + +/** + * This function will stop mass storage class, 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) +{ + RT_ASSERT(device != RT_NULL); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("mass storage stop\n")); + + rt_free(buffer); + return RT_EOK; +} + +static struct uclass_ops ops = +{ + _class_run, + _class_stop, + RT_NULL, +}; + +/** + * This function will create a mass storage class instance. + * + * @param device the usb device object. + * + * @return RT_EOK on successful. + */ +uclass_t rt_usbd_class_mstorage_create(udevice_t device) +{ + uintf_t intf; + ualtsetting_t setting; + + /* parameter check */ + RT_ASSERT(device != RT_NULL); + + /* create a mass storage class */ + mstorage = rt_usbd_class_create(device, &dev_desc, &ops); + + /* create an interface */ + intf = rt_usbd_interface_create(device, _interface_handler); + + /* create a bulk out and a bulk in endpoint */ + ep_in = rt_usbd_endpoint_create(&mass_desc.ep_in_desc, _ep_in_handler); + ep_out = rt_usbd_endpoint_create(&mass_desc.ep_out_desc, _ep_out_handler); + + /* create an alternate setting */ + setting = rt_usbd_altsetting_create(&mass_desc.intf_desc, + sizeof(struct umass_descriptor)); + + /* add the bulk out and bulk in endpoint to the alternate setting */ + rt_usbd_altsetting_add_endpoint(setting, ep_out); + rt_usbd_altsetting_add_endpoint(setting, 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); + + return mstorage; +} + +#endif diff --git a/components/drivers/usb/usbdevice/class/mstorage.h b/components/drivers/usb/usbdevice/class/mstorage.h new file mode 100644 index 0000000000..2ff74e6494 --- /dev/null +++ b/components/drivers/usb/usbdevice/class/mstorage.h @@ -0,0 +1,53 @@ +/* + * File : mstorage.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2012, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2012-10-01 Yi Qiu first version + */ +#include + +#define USBREQ_GET_MAX_LUN 0xfe +#define USBREQ_MASS_STORAGE_RESET 0xff + +#define USB_MASS_STORAGE_PRODUCT_ID 0x1000 /* Product ID */ + +#pragma pack(1) + +struct umass_descriptor +{ + struct uinterface_descriptor intf_desc; + struct uendpoint_descriptor ep_out_desc; + struct uendpoint_descriptor ep_in_desc; +}; +typedef struct umass_descriptor* umass_desc_t; + +struct capacity_data +{ + rt_uint8_t LastLogicalBlockAddress[4]; + rt_uint8_t BlockLengthInBytes[4]; +}; + +struct request_sense_data +{ + rt_uint8_t ErrorCode:7; + rt_uint8_t Valid:1; + rt_uint8_t Reserved1; + rt_uint8_t SenseKey:4; + rt_uint8_t Reserved2:4; + rt_uint8_t Information[4]; + rt_uint8_t AdditionalSenseLength; + rt_uint8_t Reserved3[4]; + rt_uint8_t AdditionalSenseCode; + rt_uint8_t AdditionalSenseCodeQualifier; + rt_uint8_t Reserved4[4]; +}request_sense_data_t; + +#pragma pack() + diff --git a/components/drivers/usb/usbdevice/core/core.c b/components/drivers/usb/usbdevice/core/core.c index cfd11cd485..13da280c17 100644 --- a/components/drivers/usb/usbdevice/core/core.c +++ b/components/drivers/usb/usbdevice/core/core.c @@ -122,9 +122,13 @@ static rt_err_t _get_string_descriptor(struct udevice* device, ureq_t setup) } } + if(setup->length == 0xFF) + len = str_desc.bLength; + else + len = setup->length; + /* send string descriptor to endpoint 0 */ - dcd_ep_write(device->dcd, 0, (rt_uint8_t*)&str_desc, - str_desc.bLength); + dcd_ep_write(device->dcd, 0, (rt_uint8_t*)&str_desc, len); return RT_EOK; } @@ -156,8 +160,11 @@ static rt_err_t _get_descriptor(struct udevice* device, ureq_t setup) case USB_DESC_TYPE_STRING: _get_string_descriptor(device, setup); break; + case USB_DESC_TYPE_DEVICEQUALIFIER: + dcd_ep_stall(device->dcd, 0); + break; default: - rt_kprintf("unknown descriptor\n"); + rt_kprintf("unsupported descriptor request\n"); dcd_ep_stall(device->dcd, 0); break; } @@ -768,6 +775,9 @@ uclass_t rt_usbd_class_create(udevice_t device, udev_desc_t dev_desc, cls->dev_desc = dev_desc; cls->ops = ops; cls->device = device; +#ifdef RT_USB_DEVICE_COMPOSITE + cls->iad_desc = RT_NULL; +#endif /* to initialize interface list */ rt_list_init(&cls->intf_list); @@ -874,8 +884,7 @@ 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) -{ - uep_t ep; +{ struct rt_list_node *i, *j; uclass_t cls; uintf_t intf; @@ -1008,6 +1017,16 @@ rt_err_t rt_usbd_device_add_config(udevice_t device, uconfig_t cfg) for (i=cfg->cls_list.next; i!=&cfg->cls_list; i=i->next) { cls = (uclass_t)rt_list_entry(i, struct uclass, list); + +#ifdef RT_USB_DEVICE_COMPOSITE + if(cls->iad_desc != RT_NULL) + { + rt_memcpy((void*)&cfg->cfg_desc.data[cfg->cfg_desc.wTotalLength - + USB_DESC_LENGTH_CONFIG], (void*)cls->iad_desc, USB_DESC_LENGTH_IAD); + cfg->cfg_desc.wTotalLength += USB_DESC_LENGTH_IAD; + } +#endif + for(j=cls->intf_list.next; j!=&cls->intf_list; j=j->next) { intf = (uintf_t)rt_list_entry(j, struct uinterface, list); @@ -1020,7 +1039,7 @@ rt_err_t rt_usbd_device_add_config(udevice_t device, uconfig_t cfg) ep = (uep_t)rt_list_entry(k, struct uendpoint, list); dcd_ep_alloc(device->dcd, ep); } - + /* construct complete configuration descriptor */ rt_memcpy((void*)&cfg->cfg_desc.data[cfg->cfg_desc.wTotalLength - USB_DESC_LENGTH_CONFIG], (void*)intf->curr_setting->intf_desc, @@ -1080,6 +1099,19 @@ rt_err_t rt_usbd_class_add_interface(uclass_t cls, uintf_t intf) return RT_EOK; } + +#ifdef RT_USB_DEVICE_COMPOSITE +rt_err_t rt_usbd_class_set_iad(uclass_t cls, uiad_desc_t iad_desc) +{ + RT_ASSERT(cls != RT_NULL); + RT_ASSERT(iad_desc != RT_NULL); + + cls->iad_desc = iad_desc; + + return RT_TRUE; +} +#endif + /** * This function will add an alternate setting to an interface. * diff --git a/components/drivers/usb/usbdevice/core/usbdevice.c b/components/drivers/usb/usbdevice/core/usbdevice.c index e2af11a3da..fb7813eeed 100644 --- a/components/drivers/usb/usbdevice/core/usbdevice.c +++ b/components/drivers/usb/usbdevice/core/usbdevice.c @@ -16,18 +16,36 @@ #include #include -#define RT_USB_DEVICE_CDC - const static char* ustring[] = { "Language", "RT-Thread Team.", - "UDISK", - "12345678", - "Config", + "RT-Thread Device", + "1.1.0", + "Configuration", "Interface", }; +#ifdef RT_USB_DEVICE_COMPOSITE +static struct udevice_descriptor compsit_desc = +{ + USB_DESC_LENGTH_DEVICE, //bLength; + USB_DESC_TYPE_DEVICE, //type; + USB_BCD_VERSION, //bcdUSB; + USB_CLASS_MISC, //bDeviceClass; + 0x02, //bDeviceSubClass; + 0x01, //bDeviceProtocol; + 0x40, //bMaxPacketSize0; + USB_VENDOR_ID, //idVendor; + 0xbacf, //idProduct; + USB_BCD_DEVICE, //bcdDevice; + USB_STRING_MANU_INDEX, //iManufacturer; + USB_STRING_PRODUCT_INDEX, //iProduct; + USB_STRING_SERIAL_INDEX, //iSerialNumber; + USB_DYNAMIC, //bNumConfigurations; +}; +#endif + rt_err_t rt_usb_device_init(const char* udc_name) { rt_device_t udc; @@ -56,22 +74,28 @@ rt_err_t rt_usb_device_init(const char* udc_name) /* create a configuration object */ cfg = rt_usbd_config_create(); -#if defined RT_USB_DEVICE_MASS_STORAGE +#ifdef RT_USB_DEVICE_MSTORAGE /* create a mass storage class object */ - cls = rt_usbd_class_mass_storage_create(udevice); -#elif defined RT_USB_DEVICE_CDC + cls = rt_usbd_class_mstorage_create(udevice); + + /* add the class to the configuration */ + rt_usbd_config_add_class(cfg, cls); +#endif +#ifdef RT_USB_DEVICE_CDC /* create a cdc class object */ - cls = rt_usbd_class_cdc_create(udevice); -#else - #error + cls = rt_usbd_class_cdc_create(udevice); + + /* add the class to the configuration */ + rt_usbd_config_add_class(cfg, cls); #endif /* set device descriptor to the device */ +#ifdef RT_USB_DEVICE_COMPOSITE + rt_usbd_device_set_descriptor(udevice, &compsit_desc); +#else rt_usbd_device_set_descriptor(udevice, cls->dev_desc); +#endif - /* add the class to the configuration */ - rt_usbd_config_add_class(cfg, cls); - /* add the configuration to the device */ rt_usbd_device_add_config(udevice, cfg); -- GitLab