Norimasa Okamoto / USBLocalFileSystem

Dependencies:   USBDevice

Dependents:   KL46Z-lpc81isp lpcterm2

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USB_MSD.cpp Source File

USB_MSD.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 "USB_MSD.h"
00020 
00021 #if (DEBUG2 > 3)
00022 #define MSD_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");} while(0);
00023 #else
00024 #define MSD_DBG(...) while(0)
00025 #endif
00026 
00027 #define DISK_OK         0x00
00028 #define NO_INIT         0x01
00029 #define NO_DISK         0x02
00030 #define WRITE_PROTECT   0x04
00031 
00032 #define CBW_Signature   0x43425355
00033 #define CSW_Signature   0x53425355
00034 
00035 // SCSI Commands
00036 #define TEST_UNIT_READY            0x00
00037 #define REQUEST_SENSE              0x03
00038 #define FORMAT_UNIT                0x04
00039 #define INQUIRY                    0x12
00040 #define MODE_SELECT6               0x15
00041 #define MODE_SENSE6                0x1A
00042 #define START_STOP_UNIT            0x1B
00043 #define MEDIA_REMOVAL              0x1E
00044 #define READ_FORMAT_CAPACITIES     0x23
00045 #define READ_CAPACITY              0x25
00046 #define READ10                     0x28
00047 #define WRITE10                    0x2A
00048 #define VERIFY10                   0x2F
00049 #define READ12                     0xA8
00050 #define WRITE12                    0xAA
00051 #define MODE_SELECT10              0x55
00052 #define MODE_SENSE10               0x5A
00053 
00054 // MSC class specific requests
00055 #define MSC_REQUEST_RESET          0xFF
00056 #define MSC_REQUEST_GET_MAX_LUN    0xFE
00057 
00058 #define DEFAULT_CONFIGURATION (1)
00059 
00060 // max packet size
00061 #define MAX_PACKET  MAX_PACKET_SIZE_EPBULK
00062 
00063 // CSW Status
00064 enum Status {
00065     CSW_PASSED,
00066     CSW_FAILED,
00067     CSW_ERROR,
00068 };
00069 
00070 USB_MSD::USB_MSD(USBDevice* device, DiskInterface* disk) : _device(device),_disk(disk)
00071 {
00072     MSD_DBG("device=%p", device);
00073 
00074     stage = READ_CBW;
00075     memset((void *)&cbw, 0, sizeof(CBW));
00076     memset((void *)&csw, 0, sizeof(CSW));
00077     page = NULL;
00078 }
00079 
00080 bool USB_MSD::connect() {
00081 
00082     //disk initialization
00083     if (_disk->disk_status() & NO_INIT) {
00084         if (_disk->disk_initialize()) {
00085             return false;
00086         }
00087     }
00088 
00089     // get number of blocks
00090     BlockCount = _disk->disk_sectors();
00091 
00092     // get memory size
00093     MemorySize = _disk->disk_size();
00094 
00095     if (BlockCount > 0) {
00096         BlockSize = MemorySize / BlockCount;
00097         if (BlockSize != 0) {
00098             free(page);
00099             page = (uint8_t *)malloc(BlockSize * sizeof(uint8_t));
00100             if (page == NULL)
00101                 return false;
00102         }
00103     } else {
00104         return false;
00105     }
00106     return true;
00107 }
00108 
00109 void USB_MSD::disconnect() {
00110     //De-allocate MSD page size:
00111     free(page);
00112     page = NULL;
00113 }
00114 
00115 void USB_MSD::reset() {
00116     stage = READ_CBW;
00117 }
00118 
00119 bool USB_MSD::Request_callback(CONTROL_TRANSFER* transfer)
00120 {
00121     static uint8_t msc_maxLUN[1] = {0};
00122     
00123     if (transfer->setup.bmRequestType.Type == CLASS_TYPE) {
00124         switch (transfer->setup.bRequest) {
00125             case MSC_REQUEST_RESET:
00126                 reset();
00127                 return true;
00128 
00129             case MSC_REQUEST_GET_MAX_LUN:
00130                 transfer->remaining = 1;
00131                 transfer->ptr = msc_maxLUN;
00132                 transfer->direction = DEVICE_TO_HOST;
00133                 return true;
00134         }
00135     }
00136     return false;
00137 }
00138 
00139 // Called in ISR context called when a data is received
00140 bool USB_MSD::EPBULK_OUT_callback() {
00141     uint32_t size = 0;
00142     uint8_t buf[MAX_PACKET_SIZE_EPBULK];
00143     _device->readEP(EPBULK_OUT, buf, &size, MAX_PACKET_SIZE_EPBULK);
00144     switch (stage) {
00145             // the device has to decode the CBW received
00146         case READ_CBW:
00147             CBWDecode(buf, size);
00148             break;
00149 
00150             // the device has to receive data from the host
00151         case PROCESS_CBW:
00152             switch (cbw.CB[0]) {
00153                 case WRITE10:
00154                 case WRITE12:
00155                     memoryWrite(buf, size);
00156                     break;
00157                 case VERIFY10:
00158                     memoryVerify(buf, size);
00159                     break;
00160             }
00161             break;
00162 
00163             // an error has occured: stall endpoint and send CSW
00164         default:
00165             _device->stallEndpoint(EPBULK_OUT);
00166             csw.Status = CSW_ERROR;
00167             sendCSW();
00168             break;
00169     }
00170 
00171     //reactivate readings on the OUT bulk endpoint
00172     _device->readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
00173     return true;
00174 }
00175 
00176 // Called in ISR context when a data has been transferred
00177 bool USB_MSD::EPBULK_IN_callback() {
00178     switch (stage) {
00179 
00180             // the device has to send data to the host
00181         case PROCESS_CBW:
00182             switch (cbw.CB[0]) {
00183                 case READ10:
00184                 case READ12:
00185                     memoryRead();
00186                     break;
00187             }
00188             break;
00189 
00190             //the device has to send a CSW
00191         case SEND_CSW:
00192             sendCSW();
00193             break;
00194 
00195         // the host has received the CSW -> we wait a CBW
00196         case WAIT_CSW:
00197             stage = READ_CBW;
00198             break;
00199 
00200         // an error has occured
00201         default:
00202             _device->stallEndpoint(EPBULK_IN);
00203             sendCSW();
00204             break;
00205     }
00206     return true;
00207 }
00208 
00209 void USB_MSD::memoryWrite (uint8_t * buf, uint16_t size) {
00210 
00211     if ((addr + size) > MemorySize) {
00212         size = MemorySize - addr;
00213         stage = ERROR;
00214         _device->stallEndpoint(EPBULK_OUT);
00215     }
00216 
00217     // we fill an array in RAM of 1 block before writing it in memory
00218     for (int i = 0; i < size; i++)
00219         page[addr%BlockSize + i] = buf[i];
00220 
00221     // if the array is filled, write it in memory
00222     if (!((addr + size)%BlockSize)) {
00223         if (!(_disk->disk_status() & WRITE_PROTECT)) {
00224             _disk->disk_write(page, addr/BlockSize);
00225         }
00226     }
00227 
00228     addr += size;
00229     length -= size;
00230     csw.DataResidue -= size;
00231 
00232     if ((!length) || (stage != PROCESS_CBW)) {
00233         csw.Status = (stage == ERROR) ? CSW_FAILED : CSW_PASSED;
00234         sendCSW();
00235     }
00236 }
00237 
00238 void USB_MSD::memoryVerify (uint8_t * buf, uint16_t size) {
00239     uint32_t n;
00240 
00241     if ((addr + size) > MemorySize) {
00242         size = MemorySize - addr;
00243         stage = ERROR;
00244         _device->stallEndpoint(EPBULK_OUT);
00245     }
00246 
00247     // beginning of a new block -> load a whole block in RAM
00248     if (!(addr%BlockSize))
00249         _disk->disk_read(page, addr/BlockSize);
00250 
00251     // info are in RAM -> no need to re-read memory
00252     for (n = 0; n < size; n++) {
00253         if (page[addr%BlockSize + n] != buf[n]) {
00254             memOK = false;
00255             break;
00256         }
00257     }
00258 
00259     addr += size;
00260     length -= size;
00261     csw.DataResidue -= size;
00262 
00263     if ( !length || (stage != PROCESS_CBW)) {
00264         csw.Status = (memOK && (stage == PROCESS_CBW)) ? CSW_PASSED : CSW_FAILED;
00265         sendCSW();
00266     }
00267 }
00268 
00269 bool USB_MSD::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 bool USB_MSD::readFormatCapacity() {
00283     uint8_t capacity[] = { 0x00, 0x00, 0x00, 0x08,
00284                            (uint8_t)((BlockCount >> 24) & 0xff),
00285                            (uint8_t)((BlockCount >> 16) & 0xff),
00286                            (uint8_t)((BlockCount >> 8) & 0xff),
00287                            (uint8_t)((BlockCount >> 0) & 0xff),
00288 
00289                            0x02,
00290                            (uint8_t)((BlockSize >> 16) & 0xff),
00291                            (uint8_t)((BlockSize >> 8) & 0xff),
00292                            (uint8_t)((BlockSize >> 0) & 0xff),
00293                          };
00294     if (!write(capacity, sizeof(capacity))) {
00295         return false;
00296     }
00297     return true;
00298 }
00299 
00300 bool USB_MSD::readCapacity (void) {
00301     uint8_t capacity[] = {
00302         (uint8_t)(((BlockCount - 1) >> 24) & 0xff),
00303         (uint8_t)(((BlockCount - 1) >> 16) & 0xff),
00304         (uint8_t)(((BlockCount - 1) >> 8) & 0xff),
00305         (uint8_t)(((BlockCount - 1) >> 0) & 0xff),
00306 
00307         (uint8_t)((BlockSize >> 24) & 0xff),
00308         (uint8_t)((BlockSize >> 16) & 0xff),
00309         (uint8_t)((BlockSize >> 8) & 0xff),
00310         (uint8_t)((BlockSize >> 0) & 0xff),
00311     };
00312     if (!write(capacity, sizeof(capacity))) {
00313         return false;
00314     }
00315     return true;
00316 }
00317 
00318 bool USB_MSD::write (uint8_t * buf, uint16_t size) {
00319 
00320     if (size >= cbw.DataLength) {
00321         size = cbw.DataLength;
00322     }
00323     stage = SEND_CSW;
00324 
00325     if (!_device->writeNB(EPBULK_IN, buf, size, MAX_PACKET_SIZE_EPBULK)) {
00326         return false;
00327     }
00328 
00329     csw.DataResidue -= size;
00330     csw.Status = CSW_PASSED;
00331     return true;
00332 }
00333 
00334 bool USB_MSD::modeSense6 (void) {
00335     uint8_t sense6[] = { 0x03, 0x00, 0x00, 0x00 };
00336     if (!write(sense6, sizeof(sense6))) {
00337         return false;
00338     }
00339     return true;
00340 }
00341 
00342 void USB_MSD::sendCSW() {
00343     csw.Signature = CSW_Signature;
00344     _device->writeNB(EPBULK_IN, (uint8_t *)&csw, sizeof(CSW), MAX_PACKET_SIZE_EPBULK);
00345     stage = WAIT_CSW;
00346 }
00347 
00348 bool USB_MSD::requestSense (void) {
00349     uint8_t request_sense[] = {
00350         0x70,
00351         0x00,
00352         0x05,   // Sense Key: illegal request
00353         0x00,
00354         0x00,
00355         0x00,
00356         0x00,
00357         0x0A,
00358         0x00,
00359         0x00,
00360         0x00,
00361         0x00,
00362         0x30,
00363         0x01,
00364         0x00,
00365         0x00,
00366         0x00,
00367         0x00,
00368     };
00369 
00370     if (!write(request_sense, sizeof(request_sense))) {
00371         return false;
00372     }
00373 
00374     return true;
00375 }
00376 
00377 void USB_MSD::fail() {
00378     csw.Status = CSW_FAILED;
00379     sendCSW();
00380 }
00381 
00382 void USB_MSD::CBWDecode(uint8_t * buf, uint16_t size) {
00383     if (size == sizeof(cbw)) {
00384         memcpy((uint8_t *)&cbw, buf, size);
00385         if (cbw.Signature == CBW_Signature) {
00386             csw.Tag = cbw.Tag;
00387             csw.DataResidue = cbw.DataLength;
00388             if ((cbw.CBLength <  1) || (cbw.CBLength > 16) ) {
00389                 fail();
00390             } else {
00391                 switch (cbw.CB[0]) {
00392                     case TEST_UNIT_READY:
00393                         testUnitReady();
00394                         break;
00395                     case REQUEST_SENSE:
00396                         requestSense();
00397                         break;
00398                     case INQUIRY:
00399                         inquiryRequest();
00400                         break;
00401                     case MODE_SENSE6:
00402                         modeSense6();
00403                         break;
00404                     case READ_FORMAT_CAPACITIES:
00405                         readFormatCapacity();
00406                         break;
00407                     case READ_CAPACITY:
00408                         readCapacity();
00409                         break;
00410                     case READ10:
00411                     case READ12:
00412                         if (infoTransfer()) {
00413                             if ((cbw.Flags & 0x80)) {
00414                                 stage = PROCESS_CBW;
00415                                 memoryRead();
00416                             } else {
00417                                 _device->stallEndpoint(EPBULK_OUT);
00418                                 csw.Status = CSW_ERROR;
00419                                 sendCSW();
00420                             }
00421                         }
00422                         break;
00423                     case WRITE10:
00424                     case WRITE12:
00425                         if (infoTransfer()) {
00426                             if (!(cbw.Flags & 0x80)) {
00427                                 stage = PROCESS_CBW;
00428                             } else {
00429                                 _device->stallEndpoint(EPBULK_IN);
00430                                 csw.Status = CSW_ERROR;
00431                                 sendCSW();
00432                             }
00433                         }
00434                         break;
00435                     case VERIFY10:
00436                         if (!(cbw.CB[1] & 0x02)) {
00437                             csw.Status = CSW_PASSED;
00438                             sendCSW();
00439                             break;
00440                         }
00441                         if (infoTransfer()) {
00442                             if (!(cbw.Flags & 0x80)) {
00443                                 stage = PROCESS_CBW;
00444                                 memOK = true;
00445                             } else {
00446                                 _device->stallEndpoint(EPBULK_IN);
00447                                 csw.Status = CSW_ERROR;
00448                                 sendCSW();
00449                             }
00450                         }
00451                         break;
00452                     case MEDIA_REMOVAL:
00453                         csw.Status = CSW_PASSED;
00454                         sendCSW();
00455                         break;
00456                     default:
00457                         fail();
00458                         break;
00459                 }
00460             }
00461         }
00462     }
00463 }
00464 
00465 void USB_MSD::testUnitReady (void) {
00466 
00467     if (cbw.DataLength != 0) {
00468         if ((cbw.Flags & 0x80) != 0) {
00469             _device->stallEndpoint(EPBULK_IN);
00470         } else {
00471             _device->stallEndpoint(EPBULK_OUT);
00472         }
00473     }
00474 
00475     csw.Status = CSW_PASSED;
00476     sendCSW();
00477 }
00478 
00479 void USB_MSD::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->disk_read(page, addr/BlockSize);
00492 
00493     // write data which are in RAM
00494     _device->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 bool USB_MSD::infoTransfer (void) {
00508     uint32_t n;
00509 
00510     // Logical Block Address of First Block
00511     n = (cbw.CB[2] << 24) | (cbw.CB[3] << 16) | (cbw.CB[4] <<  8) | (cbw.CB[5] <<  0);
00512 
00513     addr = n * BlockSize;
00514 
00515     // Number of Blocks to transfer
00516     switch (cbw.CB[0]) {
00517         case READ10:
00518         case WRITE10:
00519         case VERIFY10:
00520             n = (cbw.CB[7] <<  8) | (cbw.CB[8] <<  0);
00521             break;
00522 
00523         case READ12:
00524         case WRITE12:
00525             n = (cbw.CB[6] << 24) | (cbw.CB[7] << 16) | (cbw.CB[8] <<  8) | (cbw.CB[9] <<  0);
00526             break;
00527     }
00528 
00529     length = n * BlockSize;
00530 
00531     if (!cbw.DataLength) {              // host requests no data
00532         csw.Status = CSW_FAILED;
00533         sendCSW();
00534         return false;
00535     }
00536 
00537     if (cbw.DataLength != length) {
00538         if ((cbw.Flags & 0x80) != 0) {
00539             _device->stallEndpoint(EPBULK_IN);
00540         } else {
00541             _device->stallEndpoint(EPBULK_OUT);
00542         }
00543 
00544         csw.Status = CSW_FAILED;
00545         sendCSW();
00546         return false;
00547     }
00548 
00549     return true;
00550 }