updsted the USB to persuade it to build for the Dragonfly platfom

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