USBDevice stack

Dependents:   erg USBSerial_HelloWorld Slingshot SuperScanner ... more

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 }
00068 
00069 
00070 
00071 // Called in ISR context to process a class specific request
00072 bool USBMSD::USBCallback_request(void) {
00073 
00074     bool success = false;
00075     CONTROL_TRANSFER * transfer = getTransferPtr();
00076     static uint8_t maxLUN[1] = {0};
00077 
00078     if (transfer->setup.bmRequestType.Type == CLASS_TYPE) {
00079         switch (transfer->setup.bRequest) {
00080             case MSC_REQUEST_RESET:
00081                 reset();
00082                 success = true;
00083                 break;
00084             case MSC_REQUEST_GET_MAX_LUN:
00085                 transfer->remaining = 1;
00086                 transfer->ptr = maxLUN;
00087                 transfer->direction = DEVICE_TO_HOST;
00088                 success = true;
00089                 break;
00090             default:
00091                 break;
00092         }
00093     }
00094 
00095     return success;
00096 }
00097 
00098 
00099 bool USBMSD::connect() {
00100 
00101     //disk initialization
00102     if (disk_status() & NO_INIT) {
00103         if (disk_initialize()) {
00104             return false;
00105         }
00106     }
00107 
00108     // get number of blocks
00109     BlockCount = disk_sectors();
00110 
00111     // get memory size
00112     MemorySize = disk_size();
00113 
00114     if (BlockCount >= 0) {
00115         BlockSize = MemorySize / BlockCount;
00116         if (BlockSize != 0) {
00117             page = (uint8_t *)malloc(BlockSize * sizeof(uint8_t));
00118             if (page == NULL)
00119                 return false;
00120         }
00121     } else {
00122         return false;
00123     }
00124 
00125     //connect the device
00126     USBDevice::connect();
00127     return true;
00128 }
00129 
00130 
00131 void USBMSD::reset() {
00132     stage = READ_CBW;
00133 }
00134 
00135 
00136 // Called in ISR context called when a data is received
00137 bool USBMSD::EP2_OUT_callback() {
00138     uint32_t size = 0;
00139     uint8_t buf[MAX_PACKET_SIZE_EPBULK];
00140     readEP(EPBULK_OUT, buf, &size, MAX_PACKET_SIZE_EPBULK);
00141     switch (stage) {
00142             // the device has to decode the CBW received
00143         case READ_CBW:
00144             CBWDecode(buf, size);
00145             break;
00146 
00147             // the device has to receive data from the host
00148         case PROCESS_CBW:
00149             switch (cbw.CB[0]) {
00150                 case WRITE10:
00151                 case WRITE12:
00152                     memoryWrite(buf, size);
00153                     break;
00154                 case VERIFY10:
00155                     memoryVerify(buf, size);
00156                     break;
00157             }
00158             break;
00159 
00160             // an error has occured: stall endpoint and send CSW
00161         default:
00162             stallEndpoint(EPBULK_OUT);
00163             csw.Status = CSW_ERROR;
00164             sendCSW();
00165             break;
00166     }
00167 
00168     //reactivate readings on the OUT bulk endpoint
00169     readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
00170     return true;
00171 }
00172 
00173 // Called in ISR context when a data has been transferred
00174 bool USBMSD::EP2_IN_callback() {
00175     switch (stage) {
00176 
00177             // the device has to send data to the host
00178         case PROCESS_CBW:
00179             switch (cbw.CB[0]) {
00180                 case READ10:
00181                 case READ12:
00182                     memoryRead();
00183                     break;
00184             }
00185             break;
00186 
00187             //the device has to send a CSW
00188         case SEND_CSW:
00189             sendCSW();
00190             break;
00191 
00192             // an error has occured
00193         case ERROR:
00194             stallEndpoint(EPBULK_IN);
00195             sendCSW();
00196             break;
00197 
00198             // the host has received the CSW -> we wait a CBW
00199         case WAIT_CSW:
00200             stage = READ_CBW;
00201             break;
00202     }
00203     return true;
00204 }
00205 
00206 
00207 void USBMSD::memoryWrite (uint8_t * buf, uint16_t size) {
00208 
00209     if ((addr + size) > MemorySize) {
00210         size = MemorySize - addr;
00211         stage = ERROR;
00212         stallEndpoint(EPBULK_OUT);
00213     }
00214 
00215     // we fill an array in RAM of 1 block before writing it in memory
00216     for (int i = 0; i < size; i++)
00217         page[addr%BlockSize + i] = buf[i];
00218 
00219     // if the array is filled, write it in memory
00220     if (!((addr + size)%BlockSize)) {
00221         if (!(disk_status() & WRITE_PROTECT)) {
00222             disk_write((const char *)page, addr/BlockSize);
00223         }
00224     }
00225 
00226     addr += size;
00227     length -= size;
00228     csw.DataResidue -= size;
00229 
00230     if ((!length) || (stage != PROCESS_CBW)) {
00231         csw.Status = (stage == ERROR) ? CSW_FAILED : CSW_PASSED;
00232         sendCSW();
00233     }
00234 }
00235 
00236 void USBMSD::memoryVerify (uint8_t * buf, uint16_t size) {
00237     uint32_t n;
00238 
00239     if ((addr + size) > MemorySize) {
00240         size = MemorySize - addr;
00241         stage = ERROR;
00242         stallEndpoint(EPBULK_OUT);
00243     }
00244 
00245     // beginning of a new block -> load a whole block in RAM
00246     if (!(addr%BlockSize))
00247         disk_read((char *)page, addr/BlockSize);
00248 
00249     // info are in RAM -> no need to re-read memory
00250     for (n = 0; n < size; n++) {
00251         if (page[addr%BlockSize + n] != buf[n]) {
00252             memOK = false;
00253             break;
00254         }
00255     }
00256 
00257     addr += size;
00258     length -= size;
00259     csw.DataResidue -= size;
00260 
00261     if ( !length || (stage != PROCESS_CBW)) {
00262         csw.Status = (memOK && (stage == PROCESS_CBW)) ? CSW_PASSED : CSW_FAILED;
00263         sendCSW();
00264     }
00265 }
00266 
00267 
00268 bool USBMSD::inquiryRequest (void) {
00269     uint8_t inquiry[] = { 0x00, 0x80, 0x00, 0x01,
00270                           36 - 4, 0x80, 0x00, 0x00,
00271                           'M', 'B', 'E', 'D', '.', 'O', 'R', 'G',
00272                           'M', 'B', 'E', 'D', ' ', 'U', 'S', 'B', ' ', 'D', 'I', 'S', 'K', ' ', ' ', ' ',
00273                           '1', '.', '0', ' ',
00274                         };
00275     if (!write(inquiry, sizeof(inquiry))) {
00276         return false;
00277     }
00278     return true;
00279 }
00280 
00281 
00282 bool USBMSD::readFormatCapacity() {
00283     uint8_t capacity[] = { 0x00, 0x00, 0x00, 0x08,
00284                            (BlockCount >> 24) & 0xff,
00285                            (BlockCount >> 16) & 0xff,
00286                            (BlockCount >> 8) & 0xff,
00287                            (BlockCount >> 0) & 0xff,
00288 
00289                            0x02,
00290                            (BlockSize >> 16) & 0xff,
00291                            (BlockSize >> 8) & 0xff,
00292                            (BlockSize >> 0) & 0xff,
00293                          };
00294     if (!write(capacity, sizeof(capacity))) {
00295         return false;
00296     }
00297     return true;
00298 }
00299 
00300 
00301 bool USBMSD::readCapacity (void) {
00302     uint8_t capacity[] = {
00303         ((BlockCount - 1) >> 24) & 0xff,
00304         ((BlockCount - 1) >> 16) & 0xff,
00305         ((BlockCount - 1) >> 8) & 0xff,
00306         ((BlockCount - 1) >> 0) & 0xff,
00307 
00308         (BlockSize >> 24) & 0xff,
00309         (BlockSize >> 16) & 0xff,
00310         (BlockSize >> 8) & 0xff,
00311         (BlockSize >> 0) & 0xff,
00312     };
00313     if (!write(capacity, sizeof(capacity))) {
00314         return false;
00315     }
00316     return true;
00317 }
00318 
00319 bool USBMSD::write (uint8_t * buf, uint16_t size) {
00320 
00321     if (size >= cbw.DataLength) {
00322         size = cbw.DataLength;
00323     }
00324     stage = SEND_CSW;
00325 
00326     if (!writeNB(EPBULK_IN, buf, size, MAX_PACKET_SIZE_EPBULK)) {
00327         return false;
00328     }
00329 
00330     csw.DataResidue -= size;
00331     csw.Status = CSW_PASSED;
00332     return true;
00333 }
00334 
00335 
00336 bool USBMSD::modeSense6 (void) {
00337     uint8_t sense6[] = { 0x03, 0x00, 0x00, 0x00 };
00338     if (!write(sense6, sizeof(sense6))) {
00339         return false;
00340     }
00341     return true;
00342 }
00343 
00344 void USBMSD::sendCSW() {
00345     csw.Signature = CSW_Signature;
00346     writeNB(EPBULK_IN, (uint8_t *)&csw, sizeof(CSW), MAX_PACKET_SIZE_EPBULK);
00347     stage = WAIT_CSW;
00348 }
00349 
00350 bool USBMSD::requestSense (void) {
00351     uint8_t request_sense[] = {
00352         0x70,
00353         0x00,
00354         0x05,   // Sense Key: illegal request
00355         0x00,
00356         0x00,
00357         0x00,
00358         0x00,
00359         0x0A,
00360         0x00,
00361         0x00,
00362         0x00,
00363         0x00,
00364         0x30,
00365         0x01,
00366         0x00,
00367         0x00,
00368         0x00,
00369         0x00,
00370     };
00371 
00372     if (!write(request_sense, sizeof(request_sense))) {
00373         return false;
00374     }
00375 
00376     return true;
00377 }
00378 
00379 void USBMSD::fail() {
00380     csw.Status = CSW_FAILED;
00381     sendCSW();
00382 }
00383 
00384 
00385 void USBMSD::CBWDecode(uint8_t * buf, uint16_t size) {
00386     if (size == sizeof(cbw)) {
00387         memcpy((uint8_t *)&cbw, buf, size);
00388         if (cbw.Signature == CBW_Signature) {
00389             csw.Tag = cbw.Tag;
00390             csw.DataResidue = cbw.DataLength;
00391             if ((cbw.CBLength <  1) || (cbw.CBLength > 16) ) {
00392                 fail();
00393             } else {
00394                 switch (cbw.CB[0]) {
00395                     case TEST_UNIT_READY:
00396                         testUnitReady();
00397                         break;
00398                     case REQUEST_SENSE:
00399                         requestSense();
00400                         break;
00401                     case INQUIRY:
00402                         inquiryRequest();
00403                         break;
00404                     case MODE_SENSE6:
00405                         modeSense6();
00406                         break;
00407                     case READ_FORMAT_CAPACITIES:
00408                         readFormatCapacity();
00409                         break;
00410                     case READ_CAPACITY:
00411                         readCapacity();
00412                         break;
00413                     case READ10:
00414                     case READ12:
00415                         if (infoTransfer()) {
00416                             if ((cbw.Flags & 0x80)) {
00417                                 stage = PROCESS_CBW;
00418                                 memoryRead();
00419                             } else {
00420                                 stallEndpoint(EPBULK_OUT);
00421                                 csw.Status = CSW_ERROR;
00422                                 sendCSW();
00423                             }
00424                         }
00425                         break;
00426                     case WRITE10:
00427                     case WRITE12:
00428                         if (infoTransfer()) {
00429                             if (!(cbw.Flags & 0x80)) {
00430                                 stage = PROCESS_CBW;
00431                             } else {
00432                                 stallEndpoint(EPBULK_IN);
00433                                 csw.Status = CSW_ERROR;
00434                                 sendCSW();
00435                             }
00436                         }
00437                         break;
00438                     case VERIFY10:
00439                         if (!(cbw.CB[1] & 0x02)) {
00440                             csw.Status = CSW_PASSED;
00441                             sendCSW();
00442                             break;
00443                         }
00444                         if (infoTransfer()) {
00445                             if (!(cbw.Flags & 0x80)) {
00446                                 stage = PROCESS_CBW;
00447                                 memOK = true;
00448                             } else {
00449                                 stallEndpoint(EPBULK_IN);
00450                                 csw.Status = CSW_ERROR;
00451                                 sendCSW();
00452                             }
00453                         }
00454                         break;
00455                     default:
00456                         fail();
00457                         break;
00458                 }
00459             }
00460         }
00461     }
00462 }
00463 
00464 void USBMSD::testUnitReady (void) {
00465 
00466     if (cbw.DataLength != 0) {
00467         if ((cbw.Flags & 0x80) != 0) {
00468             stallEndpoint(EPBULK_IN);
00469         } else {
00470             stallEndpoint(EPBULK_OUT);
00471         }
00472     }
00473 
00474     csw.Status = CSW_PASSED;
00475     sendCSW();
00476 }
00477 
00478 
00479 void USBMSD::memoryRead (void) {
00480     uint32_t n;
00481 
00482     n = (length > MAX_PACKET) ? MAX_PACKET : length;
00483 
00484     if ((addr + n) > MemorySize) {
00485         n = MemorySize - addr;
00486         stage = ERROR;
00487     }
00488 
00489     // we read an entire block
00490     if (!(addr%BlockSize))
00491         disk_read((char *)page, addr/BlockSize);
00492 
00493     // write data which are in RAM
00494     writeNB(EPBULK_IN, &page[addr%BlockSize], n, MAX_PACKET_SIZE_EPBULK);
00495 
00496     addr += n;
00497     length -= n;
00498 
00499     csw.DataResidue -= n;
00500 
00501     if ( !length || (stage != PROCESS_CBW)) {
00502         csw.Status = (stage == PROCESS_CBW) ? CSW_PASSED : CSW_FAILED;
00503         stage = (stage == PROCESS_CBW) ? SEND_CSW : stage;
00504     }
00505 }
00506 
00507 
00508 bool USBMSD::infoTransfer (void) {
00509     uint32_t n;
00510 
00511     // Logical Block Address of First Block
00512     n = (cbw.CB[2] << 24) | (cbw.CB[3] << 16) | (cbw.CB[4] <<  8) | (cbw.CB[5] <<  0);
00513 
00514     addr = n * BlockSize;
00515 
00516     // Number of Blocks to transfer
00517     switch (cbw.CB[0]) {
00518         case READ10:
00519         case WRITE10:
00520         case VERIFY10:
00521             n = (cbw.CB[7] <<  8) | (cbw.CB[8] <<  0);
00522             break;
00523 
00524         case READ12:
00525         case WRITE12:
00526             n = (cbw.CB[6] << 24) | (cbw.CB[7] << 16) | (cbw.CB[8] <<  8) | (cbw.CB[9] <<  0);
00527             break;
00528     }
00529 
00530     length = n * BlockSize;
00531 
00532     if (!cbw.DataLength) {              // host requests no data
00533         csw.Status = CSW_FAILED;
00534         sendCSW();
00535         return false;
00536     }
00537 
00538     if (cbw.DataLength != length) {
00539         if ((cbw.Flags & 0x80) != 0) {
00540             stallEndpoint(EPBULK_IN);
00541         } else {
00542             stallEndpoint(EPBULK_OUT);
00543         }
00544 
00545         csw.Status = CSW_FAILED;
00546         sendCSW();
00547         return false;
00548     }
00549 
00550     return true;
00551 }
00552 
00553 
00554 
00555 
00556 
00557 // Called in ISR context
00558 // Set configuration. Return false if the
00559 // configuration is not supported.
00560 bool USBMSD::USBCallback_setConfiguration(uint8_t configuration) {
00561     if (configuration != DEFAULT_CONFIGURATION) {
00562         return false;
00563     }
00564 
00565     // Configure endpoints > 0
00566     addEndpoint(EPBULK_IN, MAX_PACKET_SIZE_EPBULK);
00567     addEndpoint(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
00568 
00569     //activate readings
00570     readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
00571     return true;
00572 }
00573 
00574 
00575 uint8_t * USBMSD::stringIinterfaceDesc() {
00576     static uint8_t stringIinterfaceDescriptor[] = {
00577         0x08,                           //bLength
00578         STRING_DESCRIPTOR,              //bDescriptorType 0x03
00579         'M',0,'S',0,'D',0               //bString iInterface - MSD
00580     };
00581     return stringIinterfaceDescriptor;
00582 }
00583 
00584 uint8_t * USBMSD::stringIproductDesc() {
00585     static uint8_t stringIproductDescriptor[] = {
00586         0x12,                                           //bLength
00587         STRING_DESCRIPTOR,                              //bDescriptorType 0x03
00588         'M',0,'b',0,'e',0,'d',0,' ',0,'M',0,'S',0,'D',0 //bString iProduct - Mbed Audio
00589     };
00590     return stringIproductDescriptor;
00591 }
00592 
00593 
00594 uint8_t * USBMSD::configurationDesc() {
00595     static uint8_t configDescriptor[] = {
00596 
00597         // Configuration 1
00598         9,      // bLength
00599         2,      // bDescriptorType
00600         LSB(9 + 9 + 7 + 7), // wTotalLength
00601         MSB(9 + 9 + 7 + 7),
00602         0x01,   // bNumInterfaces
00603         0x01,   // bConfigurationValue: 0x01 is used to select this configuration
00604         0x00,   // iConfiguration: no string to describe this configuration
00605         0xC0,   // bmAttributes
00606         100,    // bMaxPower, device power consumption is 100 mA
00607 
00608         // Interface 0, Alternate Setting 0, MSC Class
00609         9,      // bLength
00610         4,      // bDescriptorType
00611         0x00,   // bInterfaceNumber
00612         0x00,   // bAlternateSetting
00613         0x02,   // bNumEndpoints
00614         0x08,   // bInterfaceClass
00615         0x06,   // bInterfaceSubClass
00616         0x50,   // bInterfaceProtocol
00617         0x04,   // iInterface
00618 
00619         // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
00620         7,                          // bLength
00621         5,                          // bDescriptorType
00622         PHY_TO_DESC(EPBULK_IN),     // bEndpointAddress
00623         0x02,                       // bmAttributes (0x02=bulk)
00624         LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB)
00625         MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB)
00626         0,                          // bInterval
00627 
00628         // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
00629         7,                          // bLength
00630         5,                          // bDescriptorType
00631         PHY_TO_DESC(EPBULK_OUT),    // bEndpointAddress
00632         0x02,                       // bmAttributes (0x02=bulk)
00633         LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB)
00634         MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB)
00635         0                           // bInterval
00636     };
00637     return configDescriptor;
00638 }