USB device stack - modified

Dependents:   shaun_larada

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