USB Composite support

Dependents:   mbed_cdc_hid_composite

Fork of USBDevice by mbed official

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBMSD.cpp Source File

USBMSD.cpp

00001 /* Copyright (c) 2010-2011 mbed.org, MIT License
00002 *
00003 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00004 * and associated documentation files (the "Software"), to deal in the Software without
00005 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
00006 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
00007 * Software is furnished to do so, subject to the following conditions:
00008 *
00009 * The above copyright notice and this permission notice shall be included in all copies or
00010 * substantial portions of the Software.
00011 *
00012 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00013 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00014 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00015 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00016 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00017 */
00018 
00019 #include "stdint.h"
00020 #include "USBMSD.h"
00021 
00022 #define DISK_OK         0x00
00023 #define NO_INIT         0x01
00024 #define NO_DISK         0x02
00025 #define WRITE_PROTECT   0x04
00026 
00027 #define CBW_Signature   0x43425355
00028 #define CSW_Signature   0x53425355
00029 
00030 // SCSI Commands
00031 #define TEST_UNIT_READY            0x00
00032 #define REQUEST_SENSE              0x03
00033 #define FORMAT_UNIT                0x04
00034 #define INQUIRY                    0x12
00035 #define MODE_SELECT6               0x15
00036 #define MODE_SENSE6                0x1A
00037 #define START_STOP_UNIT            0x1B
00038 #define MEDIA_REMOVAL              0x1E
00039 #define READ_FORMAT_CAPACITIES     0x23
00040 #define READ_CAPACITY              0x25
00041 #define READ10                     0x28
00042 #define WRITE10                    0x2A
00043 #define VERIFY10                   0x2F
00044 #define READ12                     0xA8
00045 #define WRITE12                    0xAA
00046 #define MODE_SELECT10              0x55
00047 #define MODE_SENSE10               0x5A
00048 
00049 // MSC class specific requests
00050 #define MSC_REQUEST_RESET          0xFF
00051 #define MSC_REQUEST_GET_MAX_LUN    0xFE
00052 
00053 #define DEFAULT_CONFIGURATION (1)
00054 
00055 // max packet size
00056 #define MAX_PACKET  MAX_PACKET_SIZE_EPBULK
00057 
00058 // CSW Status
00059 enum Status {
00060     CSW_PASSED,
00061     CSW_FAILED,
00062     CSW_ERROR,
00063 };
00064 
00065 
00066 USBMSD::USBMSD(uint16_t vendor_id, uint16_t product_id, uint16_t product_release): USBDevice(vendor_id, product_id, product_release) {
00067     stage = READ_CBW;
00068     memset((void *)&cbw, 0, sizeof(CBW));
00069     memset((void *)&csw, 0, sizeof(CSW));
00070     page = NULL;
00071 }
00072 
00073 USBMSD::~USBMSD() {
00074     disconnect();
00075 }
00076 
00077 
00078 // Called in ISR context to process a class specific request
00079 bool USBMSD::USBCallback_request(void) {
00080 
00081     bool success = false;
00082     CONTROL_TRANSFER * transfer = getTransferPtr();
00083     static uint8_t maxLUN[1] = {0};
00084 
00085     if (transfer->setup.bmRequestType.Type == CLASS_TYPE) {
00086         switch (transfer->setup.bRequest) {
00087             case MSC_REQUEST_RESET:
00088                 reset();
00089                 success = true;
00090                 break;
00091             case MSC_REQUEST_GET_MAX_LUN:
00092                 transfer->remaining = 1;
00093                 transfer->ptr = maxLUN;
00094                 transfer->direction = DEVICE_TO_HOST;
00095                 success = true;
00096                 break;
00097             default:
00098                 break;
00099         }
00100     }
00101 
00102     return success;
00103 }
00104 
00105 
00106 bool USBMSD::connect(bool blocking) {
00107     //disk initialization
00108     if (disk_status() & NO_INIT) {
00109         if (disk_initialize()) {
00110             return false;
00111         }
00112     }
00113 
00114     // get number of blocks
00115     BlockCount = disk_sectors();
00116 
00117     // get memory size
00118     MemorySize = disk_size();
00119 
00120     if (BlockCount > 0) {
00121         BlockSize = MemorySize / BlockCount;
00122         if (BlockSize != 0) {
00123             free(page);
00124             page = (uint8_t *)malloc(BlockSize * sizeof(uint8_t));
00125             if (page == NULL)
00126                 return false;
00127         }
00128     } else {
00129         return false;
00130     }
00131 
00132     //connect the device
00133     USBDevice::connect(blocking);
00134     return true;
00135 }
00136 
00137 void USBMSD::disconnect() {
00138     USBDevice::disconnect();
00139     //De-allocate MSD page size:
00140     free(page);
00141     page = NULL;
00142 }
00143 
00144 void USBMSD::reset() {
00145     stage = READ_CBW;
00146 }
00147 
00148 
00149 // Called in ISR context called when a data is received
00150 bool USBMSD::EPBULK_OUT_callback() {
00151     uint32_t size = 0;
00152     uint8_t buf[MAX_PACKET_SIZE_EPBULK];
00153     readEP(EPBULK_OUT, buf, &size, MAX_PACKET_SIZE_EPBULK);
00154     switch (stage) {
00155             // the device has to decode the CBW received
00156         case READ_CBW:
00157             CBWDecode(buf, size);
00158             break;
00159 
00160             // the device has to receive data from the host
00161         case PROCESS_CBW:
00162             switch (cbw.CB[0]) {
00163                 case WRITE10:
00164                 case WRITE12:
00165                     memoryWrite(buf, size);
00166                     break;
00167                 case VERIFY10:
00168                     memoryVerify(buf, size);
00169                     break;
00170             }
00171             break;
00172 
00173             // an error has occured: stall endpoint and send CSW
00174         default:
00175             stallEndpoint(EPBULK_OUT);
00176             csw.Status = CSW_ERROR;
00177             sendCSW();
00178             break;
00179     }
00180 
00181     //reactivate readings on the OUT bulk endpoint
00182     readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
00183     return true;
00184 }
00185 
00186 // Called in ISR context when a data has been transferred
00187 bool USBMSD::EPBULK_IN_callback() {
00188     switch (stage) {
00189 
00190             // the device has to send data to the host
00191         case PROCESS_CBW:
00192             switch (cbw.CB[0]) {
00193                 case READ10:
00194                 case READ12:
00195                     memoryRead();
00196                     break;
00197             }
00198             break;
00199 
00200             //the device has to send a CSW
00201         case SEND_CSW:
00202             sendCSW();
00203             break;
00204 
00205         // the host has received the CSW -> we wait a CBW
00206         case WAIT_CSW:
00207             stage = READ_CBW;
00208             break;
00209 
00210         // an error has occured
00211         default:
00212             stallEndpoint(EPBULK_IN);
00213             sendCSW();
00214             break;
00215     }
00216     return true;
00217 }
00218 
00219 
00220 void USBMSD::memoryWrite (uint8_t * buf, uint16_t size) {
00221 
00222     if ((addr + size) > MemorySize) {
00223         size = MemorySize - addr;
00224         stage = ERROR;
00225         stallEndpoint(EPBULK_OUT);
00226     }
00227 
00228     // we fill an array in RAM of 1 block before writing it in memory
00229     for (int i = 0; i < size; i++)
00230         page[addr%BlockSize + i] = buf[i];
00231 
00232     // if the array is filled, write it in memory
00233     if (!((addr + size)%BlockSize)) {
00234         if (!(disk_status() & WRITE_PROTECT)) {
00235             disk_write(page, addr/BlockSize, 1);
00236         }
00237     }
00238 
00239     addr += size;
00240     length -= size;
00241     csw.DataResidue -= size;
00242 
00243     if ((!length) || (stage != PROCESS_CBW)) {
00244         csw.Status = (stage == ERROR) ? CSW_FAILED : CSW_PASSED;
00245         sendCSW();
00246     }
00247 }
00248 
00249 void USBMSD::memoryVerify (uint8_t * buf, uint16_t size) {
00250     uint32_t n;
00251 
00252     if ((addr + size) > MemorySize) {
00253         size = MemorySize - addr;
00254         stage = ERROR;
00255         stallEndpoint(EPBULK_OUT);
00256     }
00257 
00258     // beginning of a new block -> load a whole block in RAM
00259     if (!(addr%BlockSize))
00260         disk_read(page, addr/BlockSize, 1);
00261 
00262     // info are in RAM -> no need to re-read memory
00263     for (n = 0; n < size; n++) {
00264         if (page[addr%BlockSize + n] != buf[n]) {
00265             memOK = false;
00266             break;
00267         }
00268     }
00269 
00270     addr += size;
00271     length -= size;
00272     csw.DataResidue -= size;
00273 
00274     if ( !length || (stage != PROCESS_CBW)) {
00275         csw.Status = (memOK && (stage == PROCESS_CBW)) ? CSW_PASSED : CSW_FAILED;
00276         sendCSW();
00277     }
00278 }
00279 
00280 
00281 bool USBMSD::inquiryRequest (void) {
00282     uint8_t inquiry[] = { 0x00, 0x80, 0x00, 0x01,
00283                           36 - 4, 0x80, 0x00, 0x00,
00284                           'M', 'B', 'E', 'D', '.', 'O', 'R', 'G',
00285                           'M', 'B', 'E', 'D', ' ', 'U', 'S', 'B', ' ', 'D', 'I', 'S', 'K', ' ', ' ', ' ',
00286                           '1', '.', '0', ' ',
00287                         };
00288     if (!write(inquiry, sizeof(inquiry))) {
00289         return false;
00290     }
00291     return true;
00292 }
00293 
00294 
00295 bool USBMSD::readFormatCapacity() {
00296     uint8_t capacity[] = { 0x00, 0x00, 0x00, 0x08,
00297                            (uint8_t)((BlockCount >> 24) & 0xff),
00298                            (uint8_t)((BlockCount >> 16) & 0xff),
00299                            (uint8_t)((BlockCount >> 8) & 0xff),
00300                            (uint8_t)((BlockCount >> 0) & 0xff),
00301 
00302                            0x02,
00303                            (uint8_t)((BlockSize >> 16) & 0xff),
00304                            (uint8_t)((BlockSize >> 8) & 0xff),
00305                            (uint8_t)((BlockSize >> 0) & 0xff),
00306                          };
00307     if (!write(capacity, sizeof(capacity))) {
00308         return false;
00309     }
00310     return true;
00311 }
00312 
00313 
00314 bool USBMSD::readCapacity (void) {
00315     uint8_t capacity[] = {
00316         (uint8_t)(((BlockCount - 1) >> 24) & 0xff),
00317         (uint8_t)(((BlockCount - 1) >> 16) & 0xff),
00318         (uint8_t)(((BlockCount - 1) >> 8) & 0xff),
00319         (uint8_t)(((BlockCount - 1) >> 0) & 0xff),
00320 
00321         (uint8_t)((BlockSize >> 24) & 0xff),
00322         (uint8_t)((BlockSize >> 16) & 0xff),
00323         (uint8_t)((BlockSize >> 8) & 0xff),
00324         (uint8_t)((BlockSize >> 0) & 0xff),
00325     };
00326     if (!write(capacity, sizeof(capacity))) {
00327         return false;
00328     }
00329     return true;
00330 }
00331 
00332 bool USBMSD::write (uint8_t * buf, uint16_t size) {
00333 
00334     if (size >= cbw.DataLength) {
00335         size = cbw.DataLength;
00336     }
00337     stage = SEND_CSW;
00338 
00339     if (!writeNB(EPBULK_IN, buf, size, MAX_PACKET_SIZE_EPBULK)) {
00340         return false;
00341     }
00342 
00343     csw.DataResidue -= size;
00344     csw.Status = CSW_PASSED;
00345     return true;
00346 }
00347 
00348 
00349 bool USBMSD::modeSense6 (void) {
00350     uint8_t sense6[] = { 0x03, 0x00, 0x00, 0x00 };
00351     if (!write(sense6, sizeof(sense6))) {
00352         return false;
00353     }
00354     return true;
00355 }
00356 
00357 void USBMSD::sendCSW() {
00358     csw.Signature = CSW_Signature;
00359     writeNB(EPBULK_IN, (uint8_t *)&csw, sizeof(CSW), MAX_PACKET_SIZE_EPBULK);
00360     stage = WAIT_CSW;
00361 }
00362 
00363 bool USBMSD::requestSense (void) {
00364     uint8_t request_sense[] = {
00365         0x70,
00366         0x00,
00367         0x05,   // Sense Key: illegal request
00368         0x00,
00369         0x00,
00370         0x00,
00371         0x00,
00372         0x0A,
00373         0x00,
00374         0x00,
00375         0x00,
00376         0x00,
00377         0x30,
00378         0x01,
00379         0x00,
00380         0x00,
00381         0x00,
00382         0x00,
00383     };
00384 
00385     if (!write(request_sense, sizeof(request_sense))) {
00386         return false;
00387     }
00388 
00389     return true;
00390 }
00391 
00392 void USBMSD::fail() {
00393     csw.Status = CSW_FAILED;
00394     sendCSW();
00395 }
00396 
00397 
00398 void USBMSD::CBWDecode(uint8_t * buf, uint16_t size) {
00399     if (size == sizeof(cbw)) {
00400         memcpy((uint8_t *)&cbw, buf, size);
00401         if (cbw.Signature == CBW_Signature) {
00402             csw.Tag = cbw.Tag;
00403             csw.DataResidue = cbw.DataLength;
00404             if ((cbw.CBLength <  1) || (cbw.CBLength > 16) ) {
00405                 fail();
00406             } else {
00407                 switch (cbw.CB[0]) {
00408                     case TEST_UNIT_READY:
00409                         testUnitReady();
00410                         break;
00411                     case REQUEST_SENSE:
00412                         requestSense();
00413                         break;
00414                     case INQUIRY:
00415                         inquiryRequest();
00416                         break;
00417                     case MODE_SENSE6:
00418                         modeSense6();
00419                         break;
00420                     case READ_FORMAT_CAPACITIES:
00421                         readFormatCapacity();
00422                         break;
00423                     case READ_CAPACITY:
00424                         readCapacity();
00425                         break;
00426                     case READ10:
00427                     case READ12:
00428                         if (infoTransfer()) {
00429                             if ((cbw.Flags & 0x80)) {
00430                                 stage = PROCESS_CBW;
00431                                 memoryRead();
00432                             } else {
00433                                 stallEndpoint(EPBULK_OUT);
00434                                 csw.Status = CSW_ERROR;
00435                                 sendCSW();
00436                             }
00437                         }
00438                         break;
00439                     case WRITE10:
00440                     case WRITE12:
00441                         if (infoTransfer()) {
00442                             if (!(cbw.Flags & 0x80)) {
00443                                 stage = PROCESS_CBW;
00444                             } else {
00445                                 stallEndpoint(EPBULK_IN);
00446                                 csw.Status = CSW_ERROR;
00447                                 sendCSW();
00448                             }
00449                         }
00450                         break;
00451                     case VERIFY10:
00452                         if (!(cbw.CB[1] & 0x02)) {
00453                             csw.Status = CSW_PASSED;
00454                             sendCSW();
00455                             break;
00456                         }
00457                         if (infoTransfer()) {
00458                             if (!(cbw.Flags & 0x80)) {
00459                                 stage = PROCESS_CBW;
00460                                 memOK = true;
00461                             } else {
00462                                 stallEndpoint(EPBULK_IN);
00463                                 csw.Status = CSW_ERROR;
00464                                 sendCSW();
00465                             }
00466                         }
00467                         break;
00468                     case MEDIA_REMOVAL:
00469                         csw.Status = CSW_PASSED;
00470                         sendCSW();
00471                         break;
00472                     default:
00473                         fail();
00474                         break;
00475                 }
00476             }
00477         }
00478     }
00479 }
00480 
00481 void USBMSD::testUnitReady (void) {
00482 
00483     if (cbw.DataLength != 0) {
00484         if ((cbw.Flags & 0x80) != 0) {
00485             stallEndpoint(EPBULK_IN);
00486         } else {
00487             stallEndpoint(EPBULK_OUT);
00488         }
00489     }
00490 
00491     csw.Status = CSW_PASSED;
00492     sendCSW();
00493 }
00494 
00495 
00496 void USBMSD::memoryRead (void) {
00497     uint32_t n;
00498 
00499     n = (length > MAX_PACKET) ? MAX_PACKET : length;
00500 
00501     if ((addr + n) > MemorySize) {
00502         n = MemorySize - addr;
00503         stage = ERROR;
00504     }
00505 
00506     // we read an entire block
00507     if (!(addr%BlockSize))
00508         disk_read(page, addr/BlockSize, 1);
00509 
00510     // write data which are in RAM
00511     writeNB(EPBULK_IN, &page[addr%BlockSize], n, MAX_PACKET_SIZE_EPBULK);
00512 
00513     addr += n;
00514     length -= n;
00515 
00516     csw.DataResidue -= n;
00517 
00518     if ( !length || (stage != PROCESS_CBW)) {
00519         csw.Status = (stage == PROCESS_CBW) ? CSW_PASSED : CSW_FAILED;
00520         stage = (stage == PROCESS_CBW) ? SEND_CSW : stage;
00521     }
00522 }
00523 
00524 
00525 bool USBMSD::infoTransfer (void) {
00526     uint32_t n;
00527 
00528     // Logical Block Address of First Block
00529     n = (cbw.CB[2] << 24) | (cbw.CB[3] << 16) | (cbw.CB[4] <<  8) | (cbw.CB[5] <<  0);
00530 
00531     addr = n * BlockSize;
00532 
00533     // Number of Blocks to transfer
00534     switch (cbw.CB[0]) {
00535         case READ10:
00536         case WRITE10:
00537         case VERIFY10:
00538             n = (cbw.CB[7] <<  8) | (cbw.CB[8] <<  0);
00539             break;
00540 
00541         case READ12:
00542         case WRITE12:
00543             n = (cbw.CB[6] << 24) | (cbw.CB[7] << 16) | (cbw.CB[8] <<  8) | (cbw.CB[9] <<  0);
00544             break;
00545     }
00546 
00547     length = n * BlockSize;
00548 
00549     if (!cbw.DataLength) {              // host requests no data
00550         csw.Status = CSW_FAILED;
00551         sendCSW();
00552         return false;
00553     }
00554 
00555     if (cbw.DataLength != length) {
00556         if ((cbw.Flags & 0x80) != 0) {
00557             stallEndpoint(EPBULK_IN);
00558         } else {
00559             stallEndpoint(EPBULK_OUT);
00560         }
00561 
00562         csw.Status = CSW_FAILED;
00563         sendCSW();
00564         return false;
00565     }
00566 
00567     return true;
00568 }
00569 
00570 
00571 
00572 
00573 
00574 // Called in ISR context
00575 // Set configuration. Return false if the
00576 // configuration is not supported.
00577 bool USBMSD::USBCallback_setConfiguration(uint8_t configuration) {
00578     if (configuration != DEFAULT_CONFIGURATION) {
00579         return false;
00580     }
00581 
00582     // Configure endpoints > 0
00583     addEndpoint(EPBULK_IN, MAX_PACKET_SIZE_EPBULK);
00584     addEndpoint(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
00585 
00586     //activate readings
00587     readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
00588     return true;
00589 }
00590 
00591 
00592 uint8_t * USBMSD::stringIinterfaceDesc() {
00593     static uint8_t stringIinterfaceDescriptor[] = {
00594         0x08,                           //bLength
00595         STRING_DESCRIPTOR,              //bDescriptorType 0x03
00596         'M',0,'S',0,'D',0               //bString iInterface - MSD
00597     };
00598     return stringIinterfaceDescriptor;
00599 }
00600 
00601 uint8_t * USBMSD::stringIproductDesc() {
00602     static uint8_t stringIproductDescriptor[] = {
00603         0x12,                                           //bLength
00604         STRING_DESCRIPTOR,                              //bDescriptorType 0x03
00605         'M',0,'b',0,'e',0,'d',0,' ',0,'M',0,'S',0,'D',0 //bString iProduct - Mbed Audio
00606     };
00607     return stringIproductDescriptor;
00608 }
00609 
00610 
00611 uint8_t * USBMSD::configurationDesc() {
00612     static uint8_t configDescriptor[] = {
00613 
00614         // Configuration 1
00615         9,      // bLength
00616         2,      // bDescriptorType
00617         LSB(9 + 9 + 7 + 7), // wTotalLength
00618         MSB(9 + 9 + 7 + 7),
00619         0x01,   // bNumInterfaces
00620         0x01,   // bConfigurationValue: 0x01 is used to select this configuration
00621         0x00,   // iConfiguration: no string to describe this configuration
00622         0xC0,   // bmAttributes
00623         100,    // bMaxPower, device power consumption is 100 mA
00624 
00625         // Interface 0, Alternate Setting 0, MSC Class
00626         9,      // bLength
00627         4,      // bDescriptorType
00628         0x00,   // bInterfaceNumber
00629         0x00,   // bAlternateSetting
00630         0x02,   // bNumEndpoints
00631         0x08,   // bInterfaceClass
00632         0x06,   // bInterfaceSubClass
00633         0x50,   // bInterfaceProtocol
00634         0x04,   // iInterface
00635 
00636         // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
00637         7,                          // bLength
00638         5,                          // bDescriptorType
00639         PHY_TO_DESC(EPBULK_IN),     // bEndpointAddress
00640         0x02,                       // bmAttributes (0x02=bulk)
00641         LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB)
00642         MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB)
00643         0,                          // bInterval
00644 
00645         // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
00646         7,                          // bLength
00647         5,                          // bDescriptorType
00648         PHY_TO_DESC(EPBULK_OUT),    // bEndpointAddress
00649         0x02,                       // bmAttributes (0x02=bulk)
00650         LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB)
00651         MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB)
00652         0                           // bInterval
00653     };
00654     return configDescriptor;
00655 }