USB MSD HID composite device hello world

Dependencies:   USBDevice mbed

Files at this revision

API Documentation at this revision

Comitter:
samux
Date:
Mon Jan 21 12:03:05 2013 +0000
Commit message:
USB MSD HID composite device hello world

Changed in this revision

USBDevice.lib Show annotated file Show diff for this revision Revisions of this file
USBMSD_HID.cpp Show annotated file Show diff for this revision Revisions of this file
USBMSD_HID.h Show annotated file Show diff for this revision Revisions of this file
USBMSD_SD/USBMSD_SD.cpp Show annotated file Show diff for this revision Revisions of this file
USBMSD_SD/USBMSD_SD.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice.lib	Mon Jan 21 12:03:05 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/USBDevice/#f8f057664123
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBMSD_HID.cpp	Mon Jan 21 12:03:05 2013 +0000
@@ -0,0 +1,858 @@
+/* Copyright (c) 2010-2011 mbed.org, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "stdint.h"
+#include "USBMSD_HID.h"
+
+#define DISK_OK         0x00
+#define NO_INIT         0x01
+#define NO_DISK         0x02
+#define WRITE_PROTECT   0x04
+
+#define CBW_Signature   0x43425355
+#define CSW_Signature   0x53425355
+
+// SCSI Commands
+#define TEST_UNIT_READY            0x00
+#define REQUEST_SENSE              0x03
+#define FORMAT_UNIT                0x04
+#define INQUIRY                    0x12
+#define MODE_SELECT6               0x15
+#define MODE_SENSE6                0x1A
+#define START_STOP_UNIT            0x1B
+#define MEDIA_REMOVAL              0x1E
+#define READ_FORMAT_CAPACITIES     0x23
+#define READ_CAPACITY              0x25
+#define READ10                     0x28
+#define WRITE10                    0x2A
+#define VERIFY10                   0x2F
+#define READ12                     0xA8
+#define WRITE12                    0xAA
+#define MODE_SELECT10              0x55
+#define MODE_SENSE10               0x5A
+
+// MSC class specific requests
+#define MSC_REQUEST_RESET          0xFF
+#define MSC_REQUEST_GET_MAX_LUN    0xFE
+
+#define DEFAULT_CONFIGURATION (1)
+
+// max packet size
+#define MAX_PACKET  MAX_PACKET_SIZE_EPBULK
+
+// CSW Status
+enum Status {
+    CSW_PASSED,
+    CSW_FAILED,
+    CSW_ERROR,
+};
+
+
+USBMSD_HID::USBMSD_HID(uint8_t output_report_length, uint8_t input_report_length, uint16_t vendor_id, uint16_t product_id, uint16_t product_release): USBDevice(vendor_id, product_id, product_release)
+{
+    stage = READ_CBW;
+    memset((void *)&cbw, 0, sizeof(CBW));
+    memset((void *)&csw, 0, sizeof(CSW));
+
+    output_length = output_report_length;
+    input_length = input_report_length;
+}
+
+
+bool USBMSD_HID::send(HID_REPORT *report)
+{
+    return USBDevice::write(EPINT_IN, report->data, report->length, MAX_HID_REPORT_SIZE);
+}
+
+bool USBMSD_HID::sendNB(HID_REPORT *report)
+{
+    return USBDevice::writeNB(EPINT_IN, report->data, report->length, MAX_HID_REPORT_SIZE);
+}
+
+
+bool USBMSD_HID::read(HID_REPORT *report)
+{
+    uint32_t bytesRead = 0;
+    bool result;
+    result = USBDevice::readEP(EPINT_OUT, report->data, &bytesRead, MAX_HID_REPORT_SIZE);
+    if(!readStart(EPINT_OUT, MAX_HID_REPORT_SIZE))
+        return false;
+    report->length = bytesRead;
+    return result;
+}
+
+
+bool USBMSD_HID::readNB(HID_REPORT *report)
+{
+    uint32_t bytesRead = 0;
+    bool result;
+    result = USBDevice::readEP_NB(EPINT_OUT, report->data, &bytesRead, MAX_HID_REPORT_SIZE);
+    report->length = bytesRead;
+    if(!readStart(EPINT_OUT, MAX_HID_REPORT_SIZE))
+        return false;
+    return result;
+}
+
+
+uint16_t USBMSD_HID::reportDescLength()
+{
+    reportDesc();
+    return reportLength;
+}
+
+
+// Called in ISR context to process a class specific request
+bool USBMSD_HID::USBCallback_request(void)
+{
+
+    bool success = false;
+    CONTROL_TRANSFER * transfer = getTransferPtr();
+    static uint8_t maxLUN[1] = {0};
+    uint8_t *hidDescriptor;
+
+    if (transfer->setup.bmRequestType.Type == CLASS_TYPE) {
+        switch (transfer->setup.bRequest) {
+            case MSC_REQUEST_RESET:
+                reset();
+                success = true;
+                break;
+            case MSC_REQUEST_GET_MAX_LUN:
+                transfer->remaining = 1;
+                transfer->ptr = maxLUN;
+                transfer->direction = DEVICE_TO_HOST;
+                success = true;
+                break;
+                
+             case SET_REPORT:
+                // First byte will be used for report ID
+                outputReport.data[0] = transfer->setup.wValue & 0xff;
+                outputReport.length = transfer->setup.wLength + 1;
+
+                transfer->remaining = sizeof(outputReport.data) - 1;
+                transfer->ptr = &outputReport.data[1];
+                transfer->direction = HOST_TO_DEVICE;
+                transfer->notify = true;
+                success = true;
+
+                break;
+            default:
+                break;
+        }
+    }
+    
+    if ((transfer->setup.bmRequestType.Type == STANDARD_TYPE))
+    {
+        switch (transfer->setup.bRequest)
+        {
+            case GET_DESCRIPTOR:
+                switch (DESCRIPTOR_TYPE(transfer->setup.wValue))
+                {
+                    case REPORT_DESCRIPTOR:
+                        if ((reportDesc() != NULL) \
+                            && (reportDescLength() != 0))
+                        {
+                            transfer->remaining = reportDescLength();
+                            transfer->ptr = reportDesc();
+                            transfer->direction = DEVICE_TO_HOST;
+                            success = true;
+                        }
+                        break;
+                    case HID_DESCRIPTOR:
+                            // Find the HID descriptor, after the configuration descriptor
+                            hidDescriptor = findDescriptor(HID_DESCRIPTOR);
+                            if (hidDescriptor != NULL)
+                            {
+                                transfer->remaining = HID_DESCRIPTOR_LENGTH;
+                                transfer->ptr = hidDescriptor;
+                                transfer->direction = DEVICE_TO_HOST;
+                                success = true;
+                            }
+                            break;
+                     
+                    default:
+                        break;
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    return success;
+}
+
+
+bool USBMSD_HID::connect()
+{
+
+    //disk initialization
+    if (disk_status() & NO_INIT) {
+        if (disk_initialize()) {
+            return false;
+        }
+    }
+
+    // get number of blocks
+    BlockCount = disk_sectors();
+
+    // get memory size
+    MemorySize = disk_size();
+
+    if (BlockCount > 0) {
+        BlockSize = MemorySize / BlockCount;
+        if (BlockSize != 0) {
+            page = (uint8_t *)malloc(BlockSize * sizeof(uint8_t));
+            if (page == NULL)
+                return false;
+        }
+    } else {
+        return false;
+    }
+
+    //connect the device
+    USBDevice::connect();
+    return true;
+}
+
+
+void USBMSD_HID::reset()
+{
+    stage = READ_CBW;
+}
+
+
+// Called in ISR context called when a data is received
+bool USBMSD_HID::EP2_OUT_callback()
+{
+    uint32_t size = 0;
+    uint8_t buf[MAX_PACKET_SIZE_EPBULK];
+    readEP(EPBULK_OUT, buf, &size, MAX_PACKET_SIZE_EPBULK);
+    switch (stage) {
+            // the device has to decode the CBW received
+        case READ_CBW:
+            CBWDecode(buf, size);
+            break;
+
+            // the device has to receive data from the host
+        case PROCESS_CBW:
+            switch (cbw.CB[0]) {
+                case WRITE10:
+                case WRITE12:
+                    memoryWrite(buf, size);
+                    break;
+                case VERIFY10:
+                    memoryVerify(buf, size);
+                    break;
+            }
+            break;
+
+            // an error has occured: stall endpoint and send CSW
+        default:
+            stallEndpoint(EPBULK_OUT);
+            csw.Status = CSW_ERROR;
+            sendCSW();
+            break;
+    }
+
+    //reactivate readings on the OUT bulk endpoint
+    readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
+    return true;
+}
+
+// Called in ISR context when a data has been transferred
+bool USBMSD_HID::EP2_IN_callback()
+{
+    switch (stage) {
+
+            // the device has to send data to the host
+        case PROCESS_CBW:
+            switch (cbw.CB[0]) {
+                case READ10:
+                case READ12:
+                    memoryRead();
+                    break;
+            }
+            break;
+
+            //the device has to send a CSW
+        case SEND_CSW:
+            sendCSW();
+            break;
+
+            // an error has occured
+        case ERROR:
+            stallEndpoint(EPBULK_IN);
+            sendCSW();
+            break;
+
+            // the host has received the CSW -> we wait a CBW
+        case WAIT_CSW:
+            stage = READ_CBW;
+            break;
+    }
+    return true;
+}
+
+
+void USBMSD_HID::memoryWrite (uint8_t * buf, uint16_t size)
+{
+
+    if ((addr + size) > MemorySize) {
+        size = MemorySize - addr;
+        stage = ERROR;
+        stallEndpoint(EPBULK_OUT);
+    }
+
+    // we fill an array in RAM of 1 block before writing it in memory
+    for (int i = 0; i < size; i++)
+        page[addr%BlockSize + i] = buf[i];
+
+    // if the array is filled, write it in memory
+    if (!((addr + size)%BlockSize)) {
+        if (!(disk_status() & WRITE_PROTECT)) {
+            disk_write(page, addr/BlockSize);
+        }
+    }
+
+    addr += size;
+    length -= size;
+    csw.DataResidue -= size;
+
+    if ((!length) || (stage != PROCESS_CBW)) {
+        csw.Status = (stage == ERROR) ? CSW_FAILED : CSW_PASSED;
+        sendCSW();
+    }
+}
+
+void USBMSD_HID::memoryVerify (uint8_t * buf, uint16_t size)
+{
+    uint32_t n;
+
+    if ((addr + size) > MemorySize) {
+        size = MemorySize - addr;
+        stage = ERROR;
+        stallEndpoint(EPBULK_OUT);
+    }
+
+    // beginning of a new block -> load a whole block in RAM
+    if (!(addr%BlockSize))
+        disk_read(page, addr/BlockSize);
+
+    // info are in RAM -> no need to re-read memory
+    for (n = 0; n < size; n++) {
+        if (page[addr%BlockSize + n] != buf[n]) {
+            memOK = false;
+            break;
+        }
+    }
+
+    addr += size;
+    length -= size;
+    csw.DataResidue -= size;
+
+    if ( !length || (stage != PROCESS_CBW)) {
+        csw.Status = (memOK && (stage == PROCESS_CBW)) ? CSW_PASSED : CSW_FAILED;
+        sendCSW();
+    }
+}
+
+
+bool USBMSD_HID::inquiryRequest (void)
+{
+    uint8_t inquiry[] = { 0x00, 0x80, 0x00, 0x01,
+                          36 - 4, 0x80, 0x00, 0x00,
+                          'M', 'B', 'E', 'D', '.', 'O', 'R', 'G',
+                          'M', 'B', 'E', 'D', ' ', 'U', 'S', 'B', ' ', 'D', 'I', 'S', 'K', ' ', ' ', ' ',
+                          '1', '.', '0', ' ',
+                        };
+    if (!write(inquiry, sizeof(inquiry))) {
+        return false;
+    }
+    return true;
+}
+
+
+bool USBMSD_HID::readFormatCapacity()
+{
+    uint8_t capacity[] = { 0x00, 0x00, 0x00, 0x08,
+                           (BlockCount >> 24) & 0xff,
+                           (BlockCount >> 16) & 0xff,
+                           (BlockCount >> 8) & 0xff,
+                           (BlockCount >> 0) & 0xff,
+
+                           0x02,
+                           (BlockSize >> 16) & 0xff,
+                           (BlockSize >> 8) & 0xff,
+                           (BlockSize >> 0) & 0xff,
+                         };
+    if (!write(capacity, sizeof(capacity))) {
+        return false;
+    }
+    return true;
+}
+
+
+bool USBMSD_HID::readCapacity (void)
+{
+    uint8_t capacity[] = {
+        ((BlockCount - 1) >> 24) & 0xff,
+        ((BlockCount - 1) >> 16) & 0xff,
+        ((BlockCount - 1) >> 8) & 0xff,
+        ((BlockCount - 1) >> 0) & 0xff,
+
+        (BlockSize >> 24) & 0xff,
+        (BlockSize >> 16) & 0xff,
+        (BlockSize >> 8) & 0xff,
+        (BlockSize >> 0) & 0xff,
+    };
+    if (!write(capacity, sizeof(capacity))) {
+        return false;
+    }
+    return true;
+}
+
+bool USBMSD_HID::write (uint8_t * buf, uint16_t size)
+{
+
+    if (size >= cbw.DataLength) {
+        size = cbw.DataLength;
+    }
+    stage = SEND_CSW;
+
+    if (!writeNB(EPBULK_IN, buf, size, MAX_PACKET_SIZE_EPBULK)) {
+        return false;
+    }
+
+    csw.DataResidue -= size;
+    csw.Status = CSW_PASSED;
+    return true;
+}
+
+
+bool USBMSD_HID::modeSense6 (void)
+{
+    uint8_t sense6[] = { 0x03, 0x00, 0x00, 0x00 };
+    if (!write(sense6, sizeof(sense6))) {
+        return false;
+    }
+    return true;
+}
+
+void USBMSD_HID::sendCSW()
+{
+    csw.Signature = CSW_Signature;
+    writeNB(EPBULK_IN, (uint8_t *)&csw, sizeof(CSW), MAX_PACKET_SIZE_EPBULK);
+    stage = WAIT_CSW;
+}
+
+bool USBMSD_HID::requestSense (void)
+{
+    uint8_t request_sense[] = {
+        0x70,
+        0x00,
+        0x05,   // Sense Key: illegal request
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        0x0A,
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        0x30,
+        0x01,
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+    };
+
+    if (!write(request_sense, sizeof(request_sense))) {
+        return false;
+    }
+
+    return true;
+}
+
+void USBMSD_HID::fail()
+{
+    csw.Status = CSW_FAILED;
+    sendCSW();
+}
+
+
+void USBMSD_HID::CBWDecode(uint8_t * buf, uint16_t size)
+{
+    if (size == sizeof(cbw)) {
+        memcpy((uint8_t *)&cbw, buf, size);
+        if (cbw.Signature == CBW_Signature) {
+            csw.Tag = cbw.Tag;
+            csw.DataResidue = cbw.DataLength;
+            if ((cbw.CBLength <  1) || (cbw.CBLength > 16) ) {
+                fail();
+            } else {
+                switch (cbw.CB[0]) {
+                    case TEST_UNIT_READY:
+                        testUnitReady();
+                        break;
+                    case REQUEST_SENSE:
+                        requestSense();
+                        break;
+                    case INQUIRY:
+                        inquiryRequest();
+                        break;
+                    case MODE_SENSE6:
+                        modeSense6();
+                        break;
+                    case READ_FORMAT_CAPACITIES:
+                        readFormatCapacity();
+                        break;
+                    case READ_CAPACITY:
+                        readCapacity();
+                        break;
+                    case READ10:
+                    case READ12:
+                        if (infoTransfer()) {
+                            if ((cbw.Flags & 0x80)) {
+                                stage = PROCESS_CBW;
+                                memoryRead();
+                            } else {
+                                stallEndpoint(EPBULK_OUT);
+                                csw.Status = CSW_ERROR;
+                                sendCSW();
+                            }
+                        }
+                        break;
+                    case WRITE10:
+                    case WRITE12:
+                        if (infoTransfer()) {
+                            if (!(cbw.Flags & 0x80)) {
+                                stage = PROCESS_CBW;
+                            } else {
+                                stallEndpoint(EPBULK_IN);
+                                csw.Status = CSW_ERROR;
+                                sendCSW();
+                            }
+                        }
+                        break;
+                    case VERIFY10:
+                        if (!(cbw.CB[1] & 0x02)) {
+                            csw.Status = CSW_PASSED;
+                            sendCSW();
+                            break;
+                        }
+                        if (infoTransfer()) {
+                            if (!(cbw.Flags & 0x80)) {
+                                stage = PROCESS_CBW;
+                                memOK = true;
+                            } else {
+                                stallEndpoint(EPBULK_IN);
+                                csw.Status = CSW_ERROR;
+                                sendCSW();
+                            }
+                        }
+                        break;
+                    case MEDIA_REMOVAL:
+                        csw.Status = CSW_PASSED;
+                        sendCSW();
+                        break;
+                    default:
+                        fail();
+                        break;
+                }
+            }
+        }
+    }
+}
+
+void USBMSD_HID::testUnitReady (void)
+{
+
+    if (cbw.DataLength != 0) {
+        if ((cbw.Flags & 0x80) != 0) {
+            stallEndpoint(EPBULK_IN);
+        } else {
+            stallEndpoint(EPBULK_OUT);
+        }
+    }
+
+    csw.Status = CSW_PASSED;
+    sendCSW();
+}
+
+
+void USBMSD_HID::memoryRead (void)
+{
+    uint32_t n;
+
+    n = (length > MAX_PACKET) ? MAX_PACKET : length;
+
+    if ((addr + n) > MemorySize) {
+        n = MemorySize - addr;
+        stage = ERROR;
+    }
+
+    // we read an entire block
+    if (!(addr%BlockSize))
+        disk_read(page, addr/BlockSize);
+
+    // write data which are in RAM
+    writeNB(EPBULK_IN, &page[addr%BlockSize], n, MAX_PACKET_SIZE_EPBULK);
+
+    addr += n;
+    length -= n;
+
+    csw.DataResidue -= n;
+
+    if ( !length || (stage != PROCESS_CBW)) {
+        csw.Status = (stage == PROCESS_CBW) ? CSW_PASSED : CSW_FAILED;
+        stage = (stage == PROCESS_CBW) ? SEND_CSW : stage;
+    }
+}
+
+
+bool USBMSD_HID::infoTransfer (void)
+{
+    uint32_t n;
+
+    // Logical Block Address of First Block
+    n = (cbw.CB[2] << 24) | (cbw.CB[3] << 16) | (cbw.CB[4] <<  8) | (cbw.CB[5] <<  0);
+
+    addr = n * BlockSize;
+
+    // Number of Blocks to transfer
+    switch (cbw.CB[0]) {
+        case READ10:
+        case WRITE10:
+        case VERIFY10:
+            n = (cbw.CB[7] <<  8) | (cbw.CB[8] <<  0);
+            break;
+
+        case READ12:
+        case WRITE12:
+            n = (cbw.CB[6] << 24) | (cbw.CB[7] << 16) | (cbw.CB[8] <<  8) | (cbw.CB[9] <<  0);
+            break;
+    }
+
+    length = n * BlockSize;
+
+    if (!cbw.DataLength) {              // host requests no data
+        csw.Status = CSW_FAILED;
+        sendCSW();
+        return false;
+    }
+
+    if (cbw.DataLength != length) {
+        if ((cbw.Flags & 0x80) != 0) {
+            stallEndpoint(EPBULK_IN);
+        } else {
+            stallEndpoint(EPBULK_OUT);
+        }
+
+        csw.Status = CSW_FAILED;
+        sendCSW();
+        return false;
+    }
+
+    return true;
+}
+
+
+
+
+
+// Called in ISR context
+// Set configuration. Return false if the
+// configuration is not supported.
+bool USBMSD_HID::USBCallback_setConfiguration(uint8_t configuration)
+{
+    if (configuration != DEFAULT_CONFIGURATION) {
+        return false;
+    }
+
+    // Configure endpoints > 0
+    addEndpoint(EPBULK_IN, MAX_PACKET_SIZE_EPBULK);
+    addEndpoint(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
+
+    //activate readings
+    readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
+    
+    // Configure endpoints > 0
+    addEndpoint(EPINT_IN, MAX_PACKET_SIZE_EPINT);
+    addEndpoint(EPINT_OUT, MAX_PACKET_SIZE_EPINT);
+
+    // We activate the endpoint to be able to recceive data
+    readStart(EPINT_OUT, MAX_PACKET_SIZE_EPINT);
+    return true;
+}
+
+
+uint8_t * USBMSD_HID::stringIinterfaceDesc()
+{
+    static uint8_t stringIinterfaceDescriptor[] = {
+        0x08,                           //bLength
+        STRING_DESCRIPTOR,              //bDescriptorType 0x03
+        'M',0,'S',0,'D',0               //bString iInterface - MSD
+    };
+    return stringIinterfaceDescriptor;
+}
+
+uint8_t * USBMSD_HID::stringIproductDesc()
+{
+    static uint8_t stringIproductDescriptor[] = {
+        0x12,                                           //bLength
+        STRING_DESCRIPTOR,                              //bDescriptorType 0x03
+        'M',0,'b',0,'e',0,'d',0,' ',0,'M',0,'S',0,'D',0 //bString iProduct - Mbed Audio
+    };
+    return stringIproductDescriptor;
+}
+
+
+uint8_t * USBMSD_HID::reportDesc() {
+    static uint8_t reportDescriptor[] = {
+        0x06, LSB(0xFFAB), MSB(0xFFAB),
+        0x0A, LSB(0x0200), MSB(0x0200),
+        0xA1, 0x01,         // Collection 0x01
+        0x75, 0x08,         // report size = 8 bits
+        0x15, 0x00,         // logical minimum = 0
+        0x26, 0xFF, 0x00,   // logical maximum = 255
+        0x95, input_length,           // report count
+        0x09, 0x01,         // usage
+        0x81, 0x02,         // Input (array)
+        0x95, output_length,           // report count
+        0x09, 0x02,         // usage
+        0x91, 0x02,         // Output (array)
+        0xC0                // end collection
+
+    };
+    reportLength = sizeof(reportDescriptor);
+    return reportDescriptor;
+}
+
+uint8_t * USBMSD_HID::deviceDesc() {
+    static uint8_t deviceDescriptor[] = {
+        DEVICE_DESCRIPTOR_LENGTH,       /* bLength */
+        DEVICE_DESCRIPTOR,              /* bDescriptorType */
+        0x10,           /* bcdUSB (LSB) */
+        0x01,           /* bcdUSB (MSB) */
+        0x00,                           /* bDeviceClass */
+        0x00,                           /* bDeviceSubClass */
+        0x00,                           /* bDeviceprotocol */
+        MAX_PACKET_SIZE_EP0,            /* bMaxPacketSize0 */
+        LSB(VENDOR_ID),                 /* idVendor (LSB) */
+        MSB(VENDOR_ID),                 /* idVendor (MSB) */
+        LSB(PRODUCT_ID),                /* idProduct (LSB) */
+        MSB(PRODUCT_ID),                /* idProduct (MSB) */
+        LSB(PRODUCT_RELEASE),           /* bcdDevice (LSB) */
+        MSB(PRODUCT_RELEASE),           /* bcdDevice (MSB) */
+        STRING_OFFSET_IMANUFACTURER,    /* iManufacturer */
+        STRING_OFFSET_IPRODUCT,         /* iProduct */
+        STRING_OFFSET_ISERIAL,          /* iSerialNumber */
+        0x01                            /* bNumConfigurations */
+    };
+    return deviceDescriptor;
+}
+
+
+uint8_t * USBMSD_HID::configurationDesc()
+{
+    static uint8_t configDescriptor[] = {
+
+        // Configuration 1
+        9,      // bLength
+        2,      // bDescriptorType
+        LSB(9 + 9 + 7 + 7    + 9 + 9 + 7 + 7), // wTotalLength
+        MSB(9 + 9 + 7 + 7    + 9 + 9 + 7 + 7),
+        0x02,   // bNumInterfaces
+        0x01,   // bConfigurationValue: 0x01 is used to select this configuration
+        0x00,   // iConfiguration: no string to describe this configuration
+        0xC0,   // bmAttributes
+        C_POWER(500),    // bMaxPower, device power consumption is 500 mA
+        
+        
+        
+        INTERFACE_DESCRIPTOR_LENGTH,    // bLength
+        INTERFACE_DESCRIPTOR,           // bDescriptorType
+        0x00,                           // bInterfaceNumber
+        0x00,                           // bAlternateSetting
+        0x02,                           // bNumEndpoints
+        HID_CLASS,                      // bInterfaceClass
+        HID_SUBCLASS_NONE,              // bInterfaceSubClass
+        HID_PROTOCOL_NONE,              // bInterfaceProtocol
+        0x00,                           // iInterface
+
+        HID_DESCRIPTOR_LENGTH,          // bLength
+        HID_DESCRIPTOR,                 // bDescriptorType
+        LSB(HID_VERSION_1_11),          // bcdHID (LSB)
+        MSB(HID_VERSION_1_11),          // bcdHID (MSB)
+        0x00,                           // bCountryCode
+        0x01,                           // bNumDescriptors
+        REPORT_DESCRIPTOR,              // bDescriptorType
+        LSB(this->reportDescLength()),  // wDescriptorLength (LSB)
+        MSB(this->reportDescLength()),  // wDescriptorLength (MSB)
+
+        ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
+        ENDPOINT_DESCRIPTOR,            // bDescriptorType
+        PHY_TO_DESC(EPINT_IN),          // bEndpointAddress
+        E_INTERRUPT,                    // bmAttributes
+        LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
+        MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
+        10,                             // bInterval (milliseconds)
+
+        ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
+        ENDPOINT_DESCRIPTOR,            // bDescriptorType
+        PHY_TO_DESC(EPINT_OUT),          // bEndpointAddress
+        E_INTERRUPT,                    // bmAttributes
+        LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
+        MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
+        10,                             // bInterval (milliseconds)
+
+        // Interface 0, Alternate Setting 0, MSC Class
+        9,      // bLength
+        4,      // bDescriptorType
+        0x01,   // bInterfaceNumber
+        0x00,   // bAlternateSetting
+        0x02,   // bNumEndpoints
+        0x08,   // bInterfaceClass
+        0x06,   // bInterfaceSubClass
+        0x50,   // bInterfaceProtocol
+        0x04,   // iInterface
+
+        // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
+        7,                          // bLength
+        5,                          // bDescriptorType
+        PHY_TO_DESC(EPBULK_IN),     // bEndpointAddress
+        0x02,                       // bmAttributes (0x02=bulk)
+        LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB)
+        MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB)
+        0,                          // bInterval
+
+        // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
+        7,                          // bLength
+        5,                          // bDescriptorType
+        PHY_TO_DESC(EPBULK_OUT),    // bEndpointAddress
+        0x02,                       // bmAttributes (0x02=bulk)
+        LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB)
+        MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB)
+        0,                          // bInterval
+        
+        
+    };
+    return configDescriptor;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBMSD_HID.h	Mon Jan 21 12:03:05 2013 +0000
@@ -0,0 +1,297 @@
+/* Copyright (c) 2010-2011 mbed.org, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef USBMSD_HID_H
+#define USBMSD_HID_H
+
+/* These headers are included for child class. */
+#include "USBEndpoints.h"
+#include "USBDescriptor.h"
+#include "USBDevice_Types.h"
+#include "USBHID_Types.h"
+
+#include "USBDevice.h"
+
+/**
+ * USBMSD class: generic class in order to use all kinds of blocks storage chip
+ *
+ * Introduction
+ *
+ * The USBMSD implements the MSD protocol. It permits to access a memory chip (flash, sdcard,...)
+ * from a computer over USB. But this class doesn't work standalone, you need to subclass this class
+ * and define virtual functions which are called in USBMSD.
+ *
+ * How to use this class with your chip ?
+ *
+ * You have to inherit and define some pure virtual functions (mandatory step):
+ *   - virtual int disk_read(char * data, int block): function to read a block
+ *   - virtual int disk_write(const char * data, int block): function to write a block
+ *   - virtual int disk_initialize(): function to initialize the memory
+ *   - virtual int disk_sectors(): return the number of blocks
+ *   - virtual int disk_size(): return the memory size
+ *   - virtual int disk_status(): return the status of the storage chip (0: OK, 1: not initialized, 2: no medium in the drive, 4: write protection)
+ *
+ * All functions names are compatible with the fat filesystem library. So you can imagine using your own class with
+ * USBMSD and the fat filesystem library in the same program. Just be careful because there are two different parts which
+ * will access the sd card. You can do a master/slave system using the disk_status method.
+ *
+ * Once these functions defined, you can call connect() (at the end of the constructor of your class for instance)
+ * of USBMSD to connect your mass storage device. connect() will first call disk_status() to test the status of the disk.
+ * If disk_status() returns 1 (disk not initialized), then disk_initialize() is called. After this step, connect() will collect information
+ * such as the number of blocks and the memory size.
+ */
+class USBMSD_HID: public USBDevice {
+public:
+
+    /**
+    * Constructor
+    *
+    * @param vendor_id Your vendor_id
+    * @param product_id Your product_id
+    * @param product_release Your preoduct_release
+    * @param output_report_length Maximum length of a sent report (up to 64 bytes) (default: 64 bytes)
+    * @param input_report_length Maximum length of a received report (up to 64 bytes) (default: 64 bytes)
+    */
+    USBMSD_HID(uint8_t output_report_length = 64, uint8_t input_report_length = 64, uint16_t vendor_id = 0x0853, uint16_t product_id = 0x0654, uint16_t product_release = 0x0001);
+
+    /**
+    * Connect the USB MSD device. Establish disk initialization before really connect the device.
+    *
+    * @returns true if successful
+    */
+    bool connect();
+    
+    /**
+    * Send a Report. warning: blocking
+    *
+    * @param report Report which will be sent (a report is defined by all data and the length)
+    * @returns true if successful
+    */
+    bool send(HID_REPORT *report);
+    
+    
+    /**
+    * Send a Report. warning: non blocking
+    *
+    * @param report Report which will be sent (a report is defined by all data and the length)
+    * @returns true if successful
+    */
+    bool sendNB(HID_REPORT *report);
+    
+    /**
+    * Read a report: blocking
+    *
+    * @param report pointer to the report to fill
+    * @returns true if successful
+    */
+    bool read(HID_REPORT * report);
+    
+    /**
+    * Read a report: non blocking
+    *
+    * @param report pointer to the report to fill
+    * @returns true if successful
+    */
+    bool readNB(HID_REPORT * report);
+
+
+protected:
+
+    uint16_t reportLength;
+    
+    /*
+    * Get the Report descriptor
+    *
+    * @returns pointer to the report descriptor
+    */
+    virtual uint8_t * reportDesc();
+
+    /*
+    * Get the length of the report descriptor
+    *
+    * @returns the length of the report descriptor
+    */
+    virtual uint16_t reportDescLength();
+
+    /*
+    * read a block on a storage chip
+    *
+    * @param data pointer where will be stored read data
+    * @param block block number
+    * @returns 0 if successful
+    */
+    virtual int disk_read(uint8_t * data, uint64_t block) = 0;
+
+    /*
+    * write a block on a storage chip
+    *
+    * @param data data to write
+    * @param block block number
+    * @returns 0 if successful
+    */
+    virtual int disk_write(const uint8_t * data, uint64_t block) = 0;
+
+    /*
+    * Disk initilization
+    */
+    virtual int disk_initialize() = 0;
+
+    /*
+    * Return the number of blocks
+    *
+    * @returns number of blocks
+    */
+    virtual uint64_t disk_sectors() = 0;
+
+    /*
+    * Return memory size
+    *
+    * @returns memory size
+    */
+    virtual uint64_t disk_size() = 0;
+
+
+    /*
+    * To check the status of the storage chip
+    *
+    * @returns status: 0: OK, 1: disk not initialized, 2: no medium in the drive, 4: write protected
+    */
+    virtual int disk_status() = 0;
+
+    /*
+    * Get string product descriptor
+    *
+    * @returns pointer to the string product descriptor
+    */
+    virtual uint8_t * stringIproductDesc();
+    
+    virtual uint8_t * deviceDesc();
+
+    /*
+    * Get string interface descriptor
+    *
+    * @returns pointer to the string interface descriptor
+    */
+    virtual uint8_t * stringIinterfaceDesc();
+
+    /*
+    * Get configuration descriptor
+    *
+    * @returns pointer to the configuration descriptor
+    */
+    virtual uint8_t * configurationDesc();
+
+    /*
+    * Callback called when a packet is received
+    */
+    virtual bool EP2_OUT_callback();
+
+    /*
+    * Callback called when a packet has been sent
+    */
+    virtual bool EP2_IN_callback();
+
+    /*
+    * Set configuration of device. Add endpoints
+    */
+    virtual bool USBCallback_setConfiguration(uint8_t configuration);
+
+    /*
+    * Callback called to process class specific requests
+    */
+    virtual bool USBCallback_request();
+
+
+private:
+
+    // MSC Bulk-only Stage
+    enum Stage {
+        READ_CBW,     // wait a CBW
+        ERROR,        // error
+        PROCESS_CBW,  // process a CBW request
+        SEND_CSW,     // send a CSW
+        WAIT_CSW,     // wait that a CSW has been effectively sent
+    };
+
+    // Bulk-only CBW
+    typedef __packed struct {
+        uint32_t Signature;
+        uint32_t Tag;
+        uint32_t DataLength;
+        uint8_t  Flags;
+        uint8_t  LUN;
+        uint8_t  CBLength;
+        uint8_t  CB[16];
+    } CBW;
+
+    // Bulk-only CSW
+    typedef __packed struct {
+        uint32_t Signature;
+        uint32_t Tag;
+        uint32_t DataResidue;
+        uint8_t  Status;
+    } CSW;
+
+    //state of the bulk-only state machine
+    Stage stage;
+
+    // current CBW
+    CBW cbw;
+
+    // CSW which will be sent
+    CSW csw;
+
+    // addr where will be read or written data
+    uint32_t addr;
+
+    // length of a reading or writing
+    uint32_t length;
+
+    // memory OK (after a memoryVerify)
+    bool memOK;
+
+    // cache in RAM before writing in memory. Useful also to read a block.
+    uint8_t * page;
+
+    int BlockSize;
+    uint64_t MemorySize;
+    uint64_t BlockCount;
+
+    void CBWDecode(uint8_t * buf, uint16_t size);
+    void sendCSW (void);
+    bool inquiryRequest (void);
+    bool write (uint8_t * buf, uint16_t size);
+    bool readFormatCapacity();
+    bool readCapacity (void);
+    bool infoTransfer (void);
+    void memoryRead (void);
+    bool modeSense6 (void);
+    void testUnitReady (void);
+    bool requestSense (void);
+    void memoryVerify (uint8_t * buf, uint16_t size);
+    void memoryWrite (uint8_t * buf, uint16_t size);
+    void reset();
+    void fail();
+    
+    HID_REPORT outputReport;
+    uint8_t output_length;
+    uint8_t input_length;
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBMSD_SD/USBMSD_SD.cpp	Mon Jan 21 12:03:05 2013 +0000
@@ -0,0 +1,475 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* Introduction
+ * ------------
+ * SD and MMC cards support a number of interfaces, but common to them all
+ * is one based on SPI. This is the one I'm implmenting because it means
+ * it is much more portable even though not so performant, and we already
+ * have the mbed SPI Interface!
+ *
+ * The main reference I'm using is Chapter 7, "SPI Mode" of:
+ *  http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
+ *
+ * SPI Startup
+ * -----------
+ * The SD card powers up in SD mode. The SPI interface mode is selected by
+ * asserting CS low and sending the reset command (CMD0). The card will
+ * respond with a (R1) response.
+ *
+ * CMD8 is optionally sent to determine the voltage range supported, and
+ * indirectly determine whether it is a version 1.x SD/non-SD card or
+ * version 2.x. I'll just ignore this for now.
+ *
+ * ACMD41 is repeatedly issued to initialise the card, until "in idle"
+ * (bit 0) of the R1 response goes to '0', indicating it is initialised.
+ *
+ * You should also indicate whether the host supports High Capicity cards,
+ * and check whether the card is high capacity - i'll also ignore this
+ *
+ * SPI Protocol
+ * ------------
+ * The SD SPI protocol is based on transactions made up of 8-bit words, with
+ * the host starting every bus transaction by asserting the CS signal low. The
+ * card always responds to commands, data blocks and errors.
+ *
+ * The protocol supports a CRC, but by default it is off (except for the
+ * first reset CMD0, where the CRC can just be pre-calculated, and CMD8)
+ * I'll leave the CRC off I think!
+ *
+ * Standard capacity cards have variable data block sizes, whereas High
+ * Capacity cards fix the size of data block to 512 bytes. I'll therefore
+ * just always use the Standard Capacity cards with a block size of 512 bytes.
+ * This is set with CMD16.
+ *
+ * You can read and write single blocks (CMD17, CMD25) or multiple blocks
+ * (CMD18, CMD25). For simplicity, I'll just use single block accesses. When
+ * the card gets a read command, it responds with a response token, and then
+ * a data token or an error.
+ *
+ * SPI Command Format
+ * ------------------
+ * Commands are 6-bytes long, containing the command, 32-bit argument, and CRC.
+ *
+ * +---------------+------------+------------+-----------+----------+--------------+
+ * | 01 | cmd[5:0] | arg[31:24] | arg[23:16] | arg[15:8] | arg[7:0] | crc[6:0] | 1 |
+ * +---------------+------------+------------+-----------+----------+--------------+
+ *
+ * As I'm not using CRC, I can fix that byte to what is needed for CMD0 (0x95)
+ *
+ * All Application Specific commands shall be preceded with APP_CMD (CMD55).
+ *
+ * SPI Response Format
+ * -------------------
+ * The main response format (R1) is a status byte (normally zero). Key flags:
+ *  idle - 1 if the card is in an idle state/initialising
+ *  cmd  - 1 if an illegal command code was detected
+ *
+ *    +-------------------------------------------------+
+ * R1 | 0 | arg | addr | seq | crc | cmd | erase | idle |
+ *    +-------------------------------------------------+
+ *
+ * R1b is the same, except it is followed by a busy signal (zeros) until
+ * the first non-zero byte when it is ready again.
+ *
+ * Data Response Token
+ * -------------------
+ * Every data block written to the card is acknowledged by a byte
+ * response token
+ *
+ * +----------------------+
+ * | xxx | 0 | status | 1 |
+ * +----------------------+
+ *              010 - OK!
+ *              101 - CRC Error
+ *              110 - Write Error
+ *
+ * Single Block Read and Write
+ * ---------------------------
+ *
+ * Block transfers have a byte header, followed by the data, followed
+ * by a 16-bit CRC. In our case, the data will always be 512 bytes.
+ *
+ * +------+---------+---------+- -  - -+---------+-----------+----------+
+ * | 0xFE | data[0] | data[1] |        | data[n] | crc[15:8] | crc[7:0] |
+ * +------+---------+---------+- -  - -+---------+-----------+----------+
+ */
+#include "USBMSD_SD.h"
+#include "mbed_debug.h"
+
+#define SD_COMMAND_TIMEOUT 5000
+
+#define SD_DBG             0
+
+USBMSD_SD::USBMSD_SD(PinName mosi, PinName miso, PinName sclk, PinName cs, uint8_t output_report_length, uint8_t input_report_length) : 
+    USBMSD_HID(output_report_length, input_report_length),
+    _spi(mosi, miso, sclk), 
+    _cs(cs)  {
+    _cs = 1;
+    
+    //no init
+    _status = 0x01;
+    
+    connect();
+}
+
+#define R1_IDLE_STATE           (1 << 0)
+#define R1_ERASE_RESET          (1 << 1)
+#define R1_ILLEGAL_COMMAND      (1 << 2)
+#define R1_COM_CRC_ERROR        (1 << 3)
+#define R1_ERASE_SEQUENCE_ERROR (1 << 4)
+#define R1_ADDRESS_ERROR        (1 << 5)
+#define R1_PARAMETER_ERROR      (1 << 6)
+
+// Types
+//  - v1.x Standard Capacity
+//  - v2.x Standard Capacity
+//  - v2.x High Capacity
+//  - Not recognised as an SD Card
+#define SDCARD_FAIL 0
+#define SDCARD_V1   1
+#define SDCARD_V2   2
+#define SDCARD_V2HC 3
+
+int USBMSD_SD::initialise_card() {
+    // Set to 100kHz for initialisation, and clock card with cs = 1
+    _spi.frequency(100000);
+    _cs = 1;
+    for (int i = 0; i < 16; i++) {
+        _spi.write(0xFF);
+    }
+    // send CMD0, should return with all zeros except IDLE STATE set (bit 0)
+    if (_cmd(0, 0) != R1_IDLE_STATE) {
+        debug("No disk, or could not put SD card in to SPI idle state\n");
+        return SDCARD_FAIL;
+    }
+    
+    // send CMD8 to determine whther it is ver 2.x
+    int r = _cmd8();
+    if (r == R1_IDLE_STATE) {
+        return initialise_card_v2();
+    } else if (r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) {
+        return initialise_card_v1();
+    } else {
+        debug("Not in idle state after sending CMD8 (not an SD card?)\n");
+        return SDCARD_FAIL;
+    }
+}
+
+int USBMSD_SD::initialise_card_v1() {
+    for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
+        _cmd(55, 0);
+        if (_cmd(41, 0) == 0) {
+            cdv = 512;
+            debug_if(SD_DBG, "\n\rInit: SEDCARD_V1\n\r");
+            return SDCARD_V1;
+        }
+    }
+    
+    debug("Timeout waiting for v1.x card\n");
+    return SDCARD_FAIL;
+}
+
+int USBMSD_SD::initialise_card_v2() {
+    for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
+        wait_ms(50);
+        _cmd58();
+        _cmd(55, 0);
+        if (_cmd(41, 0x40000000) == 0) {
+            _cmd58();
+            debug_if(SD_DBG, "\n\rInit: SDCARD_V2\n\r");
+            cdv = 1;
+            return SDCARD_V2;
+        }
+    }
+    
+    debug("Timeout waiting for v2.x card\n");
+    return SDCARD_FAIL;
+}
+
+int USBMSD_SD::disk_initialize() {
+    int i = initialise_card();
+    debug_if(SD_DBG, "init card = %d\n", i);
+    _sectors = _sd_sectors();
+    
+    // Set block length to 512 (CMD16)
+    if (_cmd(16, 512) != 0) {
+        debug("Set 512-byte block timed out\n");
+        return 1;
+    }
+    
+    _spi.frequency(5000000); // Set to 5MHz for data transfer
+    
+    // OK
+    _status = 0x00;
+    
+    return 0;
+}
+
+int USBMSD_SD::disk_write(const uint8_t *buffer, uint64_t block_number) {
+    // set write address for single block (CMD24)
+    if (_cmd(24, block_number * cdv) != 0) {
+        return 1;
+    }
+    
+    // send the data block
+    _write(buffer, 512);
+    return 0;
+}
+
+int USBMSD_SD::disk_read(uint8_t *buffer, uint64_t block_number) {
+    // set read address for single block (CMD17)
+    if (_cmd(17, block_number * cdv) != 0) {
+        return 1;
+    }
+    
+    // receive the data
+    _read(buffer, 512);
+    return 0;
+}
+
+int USBMSD_SD::disk_status() { return _status; }
+int USBMSD_SD::disk_sync() { return 0; }
+uint64_t USBMSD_SD::disk_sectors() { return _sectors; }
+
+
+// PRIVATE FUNCTIONS
+int USBMSD_SD::_cmd(int cmd, int arg) {
+    _cs = 0;
+    
+    // send a command
+    _spi.write(0x40 | cmd);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+    
+    // wait for the repsonse (response[7] == 0)
+    for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if (!(response & 0x80)) {
+            _cs = 1;
+            _spi.write(0xFF);
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+int USBMSD_SD::_cmdx(int cmd, int arg) {
+    _cs = 0;
+    
+    // send a command
+    _spi.write(0x40 | cmd);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+    
+    // wait for the repsonse (response[7] == 0)
+    for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if (!(response & 0x80)) {
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+
+int USBMSD_SD::_cmd58() {
+    _cs = 0;
+    int arg = 0;
+    
+    // send a command
+    _spi.write(0x40 | 58);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+    
+    // wait for the repsonse (response[7] == 0)
+    for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if (!(response & 0x80)) {
+            int ocr = _spi.write(0xFF) << 24;
+            ocr |= _spi.write(0xFF) << 16;
+            ocr |= _spi.write(0xFF) << 8;
+            ocr |= _spi.write(0xFF) << 0;
+            _cs = 1;
+            _spi.write(0xFF);
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+int USBMSD_SD::_cmd8() {
+    _cs = 0;
+    
+    // send a command
+    _spi.write(0x40 | 8); // CMD8
+    _spi.write(0x00);     // reserved
+    _spi.write(0x00);     // reserved
+    _spi.write(0x01);     // 3.3v
+    _spi.write(0xAA);     // check pattern
+    _spi.write(0x87);     // crc
+    
+    // wait for the repsonse (response[7] == 0)
+    for (int i = 0; i < SD_COMMAND_TIMEOUT * 1000; i++) {
+        char response[5];
+        response[0] = _spi.write(0xFF);
+        if (!(response[0] & 0x80)) {
+            for (int j = 1; j < 5; j++) {
+                response[i] = _spi.write(0xFF);
+            }
+            _cs = 1;
+            _spi.write(0xFF);
+            return response[0];
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+int USBMSD_SD::_read(uint8_t *buffer, uint32_t length) {
+    _cs = 0;
+    
+    // read until start byte (0xFF)
+    while (_spi.write(0xFF) != 0xFE);
+    
+    // read data
+    for (int i = 0; i < length; i++) {
+        buffer[i] = _spi.write(0xFF);
+    }
+    _spi.write(0xFF); // checksum
+    _spi.write(0xFF);
+    
+    _cs = 1;
+    _spi.write(0xFF);
+    return 0;
+}
+
+int USBMSD_SD::_write(const uint8_t*buffer, uint32_t length) {
+    _cs = 0;
+    
+    // indicate start of block
+    _spi.write(0xFE);
+    
+    // write the data
+    for (int i = 0; i < length; i++) {
+        _spi.write(buffer[i]);
+    }
+    
+    // write the checksum
+    _spi.write(0xFF);
+    _spi.write(0xFF);
+    
+    // check the response token
+    if ((_spi.write(0xFF) & 0x1F) != 0x05) {
+        _cs = 1;
+        _spi.write(0xFF);
+        return 1;
+    }
+    
+    // wait for write to finish
+    while (_spi.write(0xFF) == 0);
+    
+    _cs = 1;
+    _spi.write(0xFF);
+    return 0;
+}
+
+static uint32_t ext_bits(unsigned char *data, int msb, int lsb) {
+    uint32_t bits = 0;
+    uint32_t size = 1 + msb - lsb;
+    for (int i = 0; i < size; i++) {
+        uint32_t position = lsb + i;
+        uint32_t byte = 15 - (position >> 3);
+        uint32_t bit = position & 0x7;
+        uint32_t value = (data[byte] >> bit) & 1;
+        bits |= value << i;
+    }
+    return bits;
+}
+
+uint64_t USBMSD_SD::_sd_sectors() {
+    uint32_t c_size, c_size_mult, read_bl_len;
+    uint32_t block_len, mult, blocknr, capacity;
+    uint32_t hc_c_size;
+    uint64_t blocks;
+    
+    // CMD9, Response R2 (R1 byte + 16-byte block read)
+    if (_cmdx(9, 0) != 0) {
+        debug("Didn't get a response from the disk\n");
+        return 0;
+    }
+    
+    uint8_t csd[16];
+    if (_read(csd, 16) != 0) {
+        debug("Couldn't read csd response from disk\n");
+        return 0;
+    }
+    
+    // csd_structure : csd[127:126]
+    // c_size        : csd[73:62]
+    // c_size_mult   : csd[49:47]
+    // read_bl_len   : csd[83:80] - the *maximum* read block length
+    
+    int csd_structure = ext_bits(csd, 127, 126);
+    
+    switch (csd_structure) {
+        case 0:
+            cdv = 512;
+            c_size = ext_bits(csd, 73, 62);
+            c_size_mult = ext_bits(csd, 49, 47);
+            read_bl_len = ext_bits(csd, 83, 80);
+            
+            block_len = 1 << read_bl_len;
+            mult = 1 << (c_size_mult + 2);
+            blocknr = (c_size + 1) * mult;
+            capacity = blocknr * block_len;
+            blocks = capacity / 512;
+            debug_if(SD_DBG, "\n\rSDCard\n\rc_size: %d \n\rcapacity: %ld \n\rsectors: %lld\n\r", c_size, capacity, blocks);
+            break;
+        
+        case 1:
+            cdv = 1;
+            hc_c_size = ext_bits(csd, 63, 48);
+            blocks = (hc_c_size+1)*1024;
+            debug_if(SD_DBG, "\n\rSDHC Card \n\rhc_c_size: %d\n\rcapacity: %lld \n\rsectors: %lld\n\r", hc_c_size, blocks*512, blocks);
+            break;
+        
+        default:
+            debug("CSD struct unsupported\r\n");
+            return 0;
+    };
+    return blocks;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBMSD_SD/USBMSD_SD.h	Mon Jan 21 12:03:05 2013 +0000
@@ -0,0 +1,86 @@
+/* mbed USBMSD_SD Library, for providing file access to SD cards
+ * Copyright (c) 2008-2010, sford
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef USBMSD_SD_H
+#define USBMSD_SD_H
+
+#include "mbed.h"
+#include "USBMSD_HID.h"
+
+/** Use the SDcard as mass storage device using the USBMSD class
+ *
+ * @code
+ * #include "mbed.h"
+ * #include "USBMSD_SD.h"
+ *
+ * USBMSD_SD sd(p5, p6, p7, p8, 8, 8);
+ *
+ * int main() {
+ *   while(1);
+ * }
+ *
+ * @endcode
+ */
+class USBMSD_SD : public USBMSD_HID {
+public:
+
+    /** Create the File System for accessing an SD Card using SPI
+     *
+     * @param mosi SPI mosi pin connected to SD Card
+     * @param miso SPI miso pin conencted to SD Card
+     * @param sclk SPI sclk pin connected to SD Card
+     * @param cs   DigitalOut pin used as SD Card chip select
+     * @param name The name used to access the virtual filesystem
+     */
+    USBMSD_SD(PinName mosi, PinName miso, PinName sclk, PinName cs, uint8_t output_report_length = 64, uint8_t input_report_length = 64);
+    virtual int disk_initialize();
+    virtual int disk_status();
+    virtual int disk_read(uint8_t * buffer, uint64_t block_number);
+    virtual int disk_write(const uint8_t * buffer, uint64_t block_number);
+    virtual int disk_sync();
+    virtual uint64_t disk_sectors();
+    
+    virtual uint64_t disk_size(){return _sectors*512;};
+
+protected:
+
+    int _cmd(int cmd, int arg);
+    int _cmdx(int cmd, int arg);
+    int _cmd8();
+    int _cmd58();
+    int initialise_card();
+    int initialise_card_v1();
+    int initialise_card_v2();
+    
+    int _read(uint8_t * buffer, uint32_t length);
+    int _write(const uint8_t *buffer, uint32_t length);
+    uint64_t _sd_sectors();
+    uint64_t _sectors;
+    
+    uint8_t _status;
+    
+    SPI _spi;
+    DigitalOut _cs;
+    int cdv;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon Jan 21 12:03:05 2013 +0000
@@ -0,0 +1,32 @@
+#include "mbed.h"
+#include "USBMSD_SD.h"
+ 
+USBMSD_SD hid_sd(p5, p6, p7, p8, 8, 8);
+DigitalOut l1(LED1);
+
+//This report will contain data to be sent
+HID_REPORT send_report;
+HID_REPORT recv_report;
+ 
+int main() {
+    send_report.length = 8;
+ 
+    while (1) {
+        
+        //Fill the report
+        for (int i = 0; i < send_report.length; i++)
+            send_report.data[i] = rand() & 0xff;
+ 
+        //Send the report
+        hid_sd.send(&send_report);
+ 
+        //try to read a msg
+        if(hid_sd.readNB(&recv_report)) {
+            l1 = !l1;
+            for(int i = 1; i < recv_report.length; i++) {
+                printf("%d ", recv_report.data[i]);
+            }
+            printf("\r\n");
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Mon Jan 21 12:03:05 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/0480438fc29c
\ No newline at end of file