USB composite device example program, drag-and-drop flash writer.

Dependencies:   SWD USBDevice mbed BaseDAP

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