ok
Revision 0:8db2bcdf4574, committed 2012-08-24
- Comitter:
- sherckuith
- Date:
- Fri Aug 24 02:01:52 2012 +0000
- Commit message:
- [mbed] converted /USB_CDC_MSD_Hello/USBCDCMSC
Changed in this revision
USBCDCMSC.cpp | Show annotated file Show diff for this revision Revisions of this file |
USBCDCMSC.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 000000000000 -r 8db2bcdf4574 USBCDCMSC.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBCDCMSC.cpp Fri Aug 24 02:01:52 2012 +0000 @@ -0,0 +1,881 @@ +/* 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 "USBCDCMSC.h" +#include "USBBusInterface.h" + +static uint8_t cdc_line_coding[7]= {0x80, 0x25, 0x00, 0x00, 0x00, 0x00, 0x08}; + +#define DEFAULT_CONFIGURATION (1) + +#define CDC_SET_LINE_CODING 0x20 +#define CDC_GET_LINE_CODING 0x21 +#define CDC_SET_CONTROL_LINE_STATE 0x22 +#define CDC_SEND_BREAK 0x23 + +#define MAX_CDC_REPORT_SIZE MAX_PACKET_SIZE_EPBULK + + + +#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, +}; + + +USBCDCMSC::USBCDCMSC(SDFileSystem *sd, uint16_t vendor_id, uint16_t product_id, uint16_t product_release): USBDevice(vendor_id, product_id, product_release), cdcbuf(128), _sd(sd) { + cdcbreak = 0; + _status = NO_INIT; + connect(); +// USBDevice::connect(); + USBHAL::connect(); +} + +bool USBCDCMSC::USBCallback_request(void) { + /* Called in ISR context */ + + bool success = false; + CONTROL_TRANSFER * transfer = getTransferPtr(); + static uint8_t maxLUN[1] = {0}; + + /* Process class-specific requests */ + + if (transfer->setup.bmRequestType.Type == CLASS_TYPE) { + switch (transfer->setup.bRequest) { + case CDC_GET_LINE_CODING: + transfer->remaining = 7; + transfer->ptr = cdc_line_coding; + transfer->direction = DEVICE_TO_HOST; + success = true; + break; + case CDC_SET_LINE_CODING: + transfer->remaining = 7; + success = true; + break; + case CDC_SET_CONTROL_LINE_STATE: + success = true; + break; + case CDC_SEND_BREAK: + cdcbreak = 1; + success = true; + break; + 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; + default: + break; + } + } + + return success; +} + + +// Called in ISR context +// Set configuration. Return false if the +// configuration is not supported. +bool USBCDCMSC::USBCallback_setConfiguration(uint8_t configuration) { + if (configuration != DEFAULT_CONFIGURATION) { + return false; + } + + // Configure endpoints > 0 + addEndpoint(EPINT_IN, MAX_PACKET_SIZE_EPINT); + addEndpoint(EPBULK_IN, MAX_PACKET_SIZE_EPBULK); + addEndpoint(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK); + + // Configure endpoints > 0 + addEndpoint(MSDBULK_IN, MAX_PACKET_SIZE_MSDBULK); + addEndpoint(MSDBULK_OUT, MAX_PACKET_SIZE_MSDBULK); + + // We activate the endpoint to be able to recceive data + readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK); + + //activate readings + readStart(MSDBULK_OUT, MAX_PACKET_SIZE_MSDBULK); + return true; +} + +bool USBCDCMSC::send(uint8_t * buffer, uint16_t size) { + return USBDevice::write(EPBULK_IN, buffer, size, MAX_CDC_REPORT_SIZE); +} + +bool USBCDCMSC::readEP(uint8_t * buffer, uint16_t * size) { + if (!USBDevice::readEP(EPBULK_OUT, buffer, size, MAX_CDC_REPORT_SIZE)) + return false; + if (!readStart(EPBULK_OUT, MAX_CDC_REPORT_SIZE)) + return false; + return true; +} + +bool USBCDCMSC::readEP_NB(uint8_t * buffer, uint16_t * size) { + if (!USBDevice::readEP_NB(EPBULK_OUT, buffer, size, MAX_CDC_REPORT_SIZE)) + return false; + if (!readStart(EPBULK_OUT, MAX_CDC_REPORT_SIZE)) + return false; + return true; +} + + +uint8_t * USBCDCMSC::deviceDesc() { + static uint8_t deviceDescriptor[] = { + 18, // bLength + 1, // bDescriptorType + 0x10, 0x01, // bcdUSB + 0xef, // bDeviceClass + 0x02, // bDeviceSubClass + 0x01, // bDeviceProtocol + MAX_PACKET_SIZE_EP0, // bMaxPacketSize0 + LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor + LSB(PRODUCT_ID), MSB(PRODUCT_ID),// idProduct + 0x00, 0x01, // bcdDevice + 1, // iManufacturer + 2, // iProduct + 3, // iSerialNumber + 1 // bNumConfigurations + }; + return deviceDescriptor; +} + +uint8_t * USBCDCMSC::stringIinterfaceDesc() { + static uint8_t stringIinterfaceDescriptor[] = { + 0x0e, + STRING_DESCRIPTOR, + 'C',0,'D',0,'C',0,'M',0,'S',0,'C',0, + }; + return stringIinterfaceDescriptor; +} + +uint8_t * USBCDCMSC::stringIproductDesc() { + static uint8_t stringIproductDescriptor[] = { + 0x1c, + STRING_DESCRIPTOR, + 'C',0,'D',0,'C',0,'M',0,'S',0,'C',0,' ',0,'D',0,'E',0,'V',0,'I',0,'C',0,'E',0 + }; + return stringIproductDescriptor; +} + + +uint8_t * USBCDCMSC::configurationDesc() { + static uint8_t configDescriptor[] = { + 9, // bLength; + 2, // bDescriptorType; + LSB(0x62), // wTotalLength + MSB(0x62), + 3, // bNumInterfaces + 1, // bConfigurationValue + 0, // iConfiguration + 0xc0, // bmAttributes + 50, // bMaxPower + + // IAD +// 0x08, 0x0B, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, + 0x08, 0x0B, 0x00, 0x02, 0x02, 0x02, 0x01, 0x00, + + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + 0, // bInterfaceNumber + 0, // bAlternateSetting + 1, // bNumEndpoints + 0x02, // bInterfaceClass + 0x02, // bInterfaceSubClass + 0x01, // bInterfaceProtocol + 0, // iInterface + + // CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26 + 5, // bFunctionLength + 0x24, // bDescriptorType + 0x00, // bDescriptorSubtype + 0x10, 0x01, // bcdCDC + + // Call Management Functional Descriptor, CDC Spec 5.2.3.2, Table 27 + 5, // bFunctionLength + 0x24, // bDescriptorType + 0x01, // bDescriptorSubtype + 0x03, // bmCapabilities + 1, // bDataInterface + + // Abstract Control Management Functional Descriptor, CDC Spec 5.2.3.3, Table 28 + 4, // bFunctionLength + 0x24, // bDescriptorType + 0x02, // bDescriptorSubtype + 0x06, // bmCapabilities + + // Union Functional Descriptor, CDC Spec 5.2.3.8, Table 33 + 5, // bFunctionLength + 0x24, // bDescriptorType + 0x06, // bDescriptorSubtype + 0, // bMasterInterface + 1, // bSlaveInterface0 + + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + ENDPOINT_DESCRIPTOR_LENGTH, // bLength + ENDPOINT_DESCRIPTOR, // bDescriptorType + PHY_TO_DESC(EPINT_IN), // bEndpointAddress + E_INTERRUPT, // bmAttributes (0x03=intr) + LSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (LSB) + MSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (MSB) + 16, // bInterval + + + + + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + 1, // bInterfaceNumber + 0, // bAlternateSetting + 2, // bNumEndpoints + 0x0A, // bInterfaceClass + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0, // 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 + + // Interface 2, Alternate Setting 0, MSC Class + 9, // bLength + 4, // bDescriptorType + 0x02, // 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(MSDBULK_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(MSDBULK_OUT), // bEndpointAddress + 0x02, // bmAttributes (0x02=bulk) + LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB) + MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB) + 0 // bInterval + }; + return configDescriptor; +} + +int USBCDCMSC::_putc(int c) { + send((uint8_t *)&c, 1); + return 1; +} + +int USBCDCMSC::_getc() { + uint8_t c; + while (cdcbuf.isEmpty()); + cdcbuf.dequeue(&c); + return c; +} + + +bool USBCDCMSC::writeBlock(uint8_t * buf, uint16_t size) { + if(size > MAX_PACKET_SIZE_EPBULK) { + return false; + } + if(!send(buf, size)) { + return false; + } + return true; +} + + + +bool USBCDCMSC::EP2_OUT_callback() { + uint8_t c[65]; + uint16_t size = 0; + + //we read the packet received and put it on the circular buffer + readEP(c, &size); + for (int i = 0; i < size; i++) { + cdcbuf.queue(c[i]); + } + + //call a potential handler + rx.call(); + + // We reactivate the endpoint to receive next characters + readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK); + return true; +} + +uint8_t USBCDCMSC::available() { + return cdcbuf.available(); +} + + +bool USBCDCMSC::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 USBCDCMSC::reset() { + stage = READ_CBW; +} + + +// Called in ISR context called when a data is received +bool USBCDCMSC::EP5_OUT_callback() { + uint16_t size = 0; + uint8_t buf[MAX_PACKET_SIZE_EPBULK]; + USBDevice::readEP(MSDBULK_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(MSDBULK_OUT); + csw.Status = CSW_ERROR; + sendCSW(); + break; + } + + //reactivate readings on the OUT bulk endpoint + readStart(MSDBULK_OUT, MAX_PACKET_SIZE_EPBULK); + return true; +} + +// Called in ISR context when a data has been transferred +bool USBCDCMSC::EP5_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(MSDBULK_IN); + sendCSW(); + break; + + // the host has received the CSW -> we wait a CBW + case WAIT_CSW: + stage = READ_CBW; + break; + } + return true; +} + + +void USBCDCMSC::memoryWrite (uint8_t * buf, uint16_t size) { + + if ((addr + size) > MemorySize) { + size = MemorySize - addr; + stage = ERROR; + stallEndpoint(MSDBULK_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((const char *)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 USBCDCMSC::memoryVerify (uint8_t * buf, uint16_t size) { + uint32_t n; + + if ((addr + size) > MemorySize) { + size = MemorySize - addr; + stage = ERROR; + stallEndpoint(MSDBULK_OUT); + } + + // beginning of a new block -> load a whole block in RAM + if (!(addr%BlockSize)) + disk_read((char *)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 USBCDCMSC::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 (!msd_write(inquiry, sizeof(inquiry))) { + return false; + } + return true; +} + + +bool USBCDCMSC::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 (!msd_write(capacity, sizeof(capacity))) { + return false; + } + return true; +} + + +bool USBCDCMSC::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 (!msd_write(capacity, sizeof(capacity))) { + return false; + } + return true; +} + +bool USBCDCMSC::msd_write (uint8_t * buf, uint16_t size) { + + if (size >= cbw.DataLength) { + size = cbw.DataLength; + } + stage = SEND_CSW; + + if (!writeNB(MSDBULK_IN, buf, size, MAX_PACKET_SIZE_EPBULK)) { + return false; + } + + csw.DataResidue -= size; + csw.Status = CSW_PASSED; + return true; +} + + +bool USBCDCMSC::modeSense6 (void) { + uint8_t sense6[] = { 0x03, 0x00, 0x00, 0x00 }; + if (!msd_write(sense6, sizeof(sense6))) { + return false; + } + return true; +} + +void USBCDCMSC::sendCSW() { + csw.Signature = CSW_Signature; + writeNB(MSDBULK_IN, (uint8_t *)&csw, sizeof(CSW), MAX_PACKET_SIZE_EPBULK); + stage = WAIT_CSW; +} + +bool USBCDCMSC::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 (!msd_write(request_sense, sizeof(request_sense))) { + return false; + } + + return true; +} + +void USBCDCMSC::fail() { + csw.Status = CSW_FAILED; + sendCSW(); +} + + +void USBCDCMSC::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(MSDBULK_OUT); + csw.Status = CSW_ERROR; + sendCSW(); + } + } + break; + case WRITE10: + case WRITE12: + if (infoTransfer()) { + if (!(cbw.Flags & 0x80)) { + stage = PROCESS_CBW; + } else { + stallEndpoint(MSDBULK_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(MSDBULK_IN); + csw.Status = CSW_ERROR; + sendCSW(); + } + } + break; + default: + fail(); + break; + } + } + } + } +} + +void USBCDCMSC::testUnitReady (void) { + + if (cbw.DataLength != 0) { + if ((cbw.Flags & 0x80) != 0) { + stallEndpoint(MSDBULK_IN); + } else { + stallEndpoint(MSDBULK_OUT); + } + } + + csw.Status = CSW_PASSED; + sendCSW(); +} + + +void USBCDCMSC::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((char *)page, addr/BlockSize); + + // write data which are in RAM + writeNB(MSDBULK_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 USBCDCMSC::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(MSDBULK_IN); + } else { + stallEndpoint(MSDBULK_OUT); + } + + csw.Status = CSW_FAILED; + sendCSW(); + return false; + } + + return true; +} + +int USBCDCMSC::isBreak () { + int ret = cdcbreak; + cdcbreak = 0; + return ret; +} + +int USBCDCMSC::disk_initialize() { + if (_sd->disk_initialize()) { + _status |= NO_DISK; + return 1; + } else { + _status = DISK_OK; + return 0; + } +} + +int USBCDCMSC::disk_write(const char *buffer, int block_number) { + return _sd->disk_write(buffer, block_number); +} + +int USBCDCMSC::disk_read(char *buffer, int block_number) { + return _sd->disk_read(buffer, block_number); +} + +int USBCDCMSC::disk_status() { + return _status; +} + +int USBCDCMSC::disk_sectors() { + return _sd->disk_sectors(); +} +int USBCDCMSC::disk_size() { + return _sd->disk_sectors() * 512; +}
diff -r 000000000000 -r 8db2bcdf4574 USBCDCMSC.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBCDCMSC.h Fri Aug 24 02:01:52 2012 +0000 @@ -0,0 +1,279 @@ +/* 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 USBCDCMSC_H +#define USBCDCMSC_H + +/* These headers are included for child class. */ +#include "USBEndpoints.h" +#include "USBDescriptor.h" +#include "USBDevice_Types.h" + +#include "USBDevice.h" + +#include "Stream.h" +#include "CircBuffer.h" + +#include "SDFileSystem.h" + + +class USBCDCMSC: public USBDevice, public Stream { +public: + + /* + * Constructor + * + * @param vendor_id Your vendor_id + * @param product_id Your product_id + * @param product_release Your preoduct_release + */ + USBCDCMSC(SDFileSystem *sd, uint16_t vendor_id = 0x1f00, uint16_t product_id = 0x2012, uint16_t product_release = 0x0001); + + /** + * Send a character. You can use puts, printf. + * + * @param c character to be sent + * @returns true if there is no error, false otherwise + */ + virtual int _putc(int c); + + /** + * Read a character: blocking + * + * @returns character read + */ + virtual int _getc(); + + /** + * Check the number of bytes available. + * + * @returns the number of bytes available + */ + uint8_t available(); + + /** + * Write a block of data. + * + * For more efficiency, a block of size 64 (maximum size of a bulk endpoint) has to be written. + * + * @param buf pointer on data which will be written + * @param size size of the buffer. The maximum size of a block is limited by the size of the endpoint (64 bytes) + * + * @returns true if successfull + */ + bool writeBlock(uint8_t * buf, uint16_t size); + + /** + * Attach a member function to call when a packet is received. + * + * @param tptr pointer to the object to call the member function on + * @param mptr pointer to the member function to be called + */ + template<typename T> + void attach(T* tptr, void (T::*mptr)(void)) { + if((mptr != NULL) && (tptr != NULL)) { + rx.attach(tptr, mptr); + } + } + + /** + * Attach a callback called when a packet is received + * + * @param fptr function pointer + */ + void attach(void (*fn)(void)) { + if(fn != NULL) { + rx.attach(fn); + } + } + + + /** + * Connect the USB MSD device. Establish disk initialization before really connect the device. + * + * @returns true if successful + */ + bool connect(); + +protected: + + /* + * Get device descriptor. Warning: this method has to store the length of the report descriptor in reportLength. + * + * @returns pointer to the device descriptor + */ + virtual uint8_t * deviceDesc(); + + /* + * Get string product descriptor + * + * @returns pointer to the string product descriptor + */ + virtual uint8_t * stringIproductDesc(); + + /* + * 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(); + + /* + * Send a buffer + * + * @param endpoint endpoint which will be sent the buffer + * @param buffer buffer to be sent + * @param size length of the buffer + * @returns true if successful + */ + bool send(uint8_t * buffer, uint16_t size); + + /* + * Read a buffer from a certain endpoint. Warning: blocking + * + * @param endpoint endpoint to read + * @param buffer buffer where will be stored bytes + * @param size the number of bytes read will be stored in *size + * @param maxSize the maximum length that can be read + * @returns true if successful + */ + bool readEP(uint8_t * buffer, uint16_t * size); + + /* + * Read a buffer from a certain endpoint. Warning: non blocking + * + * @param endpoint endpoint to read + * @param buffer buffer where will be stored bytes + * @param size the number of bytes read will be stored in *size + * @param maxSize the maximum length that can be read + * @returns true if successful + */ + bool readEP_NB(uint8_t * buffer, uint16_t * size); + + virtual bool USBCallback_request(); + virtual bool USBCallback_setConfiguration(uint8_t configuration); + + virtual bool EP2_OUT_callback(); + + /* + * Callback called when a packet is received + */ + virtual bool EP5_OUT_callback(); + + /* + * Callback called when a packet has been sent + */ + virtual bool EP5_IN_callback(); + +private: + + FunctionPointer rx; + CircBuffer<uint8_t> cdcbuf; + int cdcbreak; + + // 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; + int MemorySize; + int BlockCount; + + int _status; + SDFileSystem *_sd; + + void CBWDecode(uint8_t * buf, uint16_t size); + void sendCSW (void); + bool inquiryRequest (void); + bool msd_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(); + + int isBreak(); + + int disk_initialize(); + int disk_write(const char *buffer, int block_number); + int disk_read(char *buffer, int block_number); + int disk_status(); + int disk_sectors(); + int disk_size(); + +}; + +#endif