瀏覽代碼

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
qiuyiuestc@gmail.com 12 年之前
父節點
當前提交
60c27fc4b5

+ 8 - 3
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

+ 9 - 2
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);

+ 6 - 1
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)

+ 27 - 3
components/drivers/usb/usbdevice/class/cdc_vcom.c

@@ -15,9 +15,10 @@
 #include <rtthread.h>
 #include <rtdevice.h>
 #include <rthw.h>
- 
 #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
+

+ 544 - 0
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 <rtthread.h>
+#include <rtservice.h>
+#include <rtdevice.h>
+#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

+ 53 - 0
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 <rtthread.h>
+
+#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()
+

+ 38 - 6
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.
  *

+ 38 - 14
components/drivers/usb/usbdevice/core/usbdevice.c

@@ -16,18 +16,36 @@
 #include <rtdevice.h>
 #include <rtservice.h>
 
-#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);