renamed class CircBuffer to CircularBuffer WiflyInterface library already has a class named CircBuffer. When using this USBDevice library with WiflyInterface library, compilation error occurs stating that CircBuffer is already defined.

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