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