USB device stack - modified
Fork of USBDevice by
USBMSD/USBMSD.cpp@12:a9671b78d24e, 2013-07-22 (annotated)
- Committer:
- setcom_001
- Date:
- Mon Jul 22 21:16:27 2013 +0000
- Revision:
- 12:a9671b78d24e
docs update
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
setcom_001 | 12:a9671b78d24e | 1 | /* Copyright (c) 2010-2011 mbed.org, MIT License |
setcom_001 | 12:a9671b78d24e | 2 | * |
setcom_001 | 12:a9671b78d24e | 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software |
setcom_001 | 12:a9671b78d24e | 4 | * and associated documentation files (the "Software"), to deal in the Software without |
setcom_001 | 12:a9671b78d24e | 5 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, |
setcom_001 | 12:a9671b78d24e | 6 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the |
setcom_001 | 12:a9671b78d24e | 7 | * Software is furnished to do so, subject to the following conditions: |
setcom_001 | 12:a9671b78d24e | 8 | * |
setcom_001 | 12:a9671b78d24e | 9 | * The above copyright notice and this permission notice shall be included in all copies or |
setcom_001 | 12:a9671b78d24e | 10 | * substantial portions of the Software. |
setcom_001 | 12:a9671b78d24e | 11 | * |
setcom_001 | 12:a9671b78d24e | 12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING |
setcom_001 | 12:a9671b78d24e | 13 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
setcom_001 | 12:a9671b78d24e | 14 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
setcom_001 | 12:a9671b78d24e | 15 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
setcom_001 | 12:a9671b78d24e | 16 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
setcom_001 | 12:a9671b78d24e | 17 | */ |
setcom_001 | 12:a9671b78d24e | 18 | |
setcom_001 | 12:a9671b78d24e | 19 | #include "stdint.h" |
setcom_001 | 12:a9671b78d24e | 20 | #include "USBMSD.h" |
setcom_001 | 12:a9671b78d24e | 21 | |
setcom_001 | 12:a9671b78d24e | 22 | #define DISK_OK 0x00 |
setcom_001 | 12:a9671b78d24e | 23 | #define NO_INIT 0x01 |
setcom_001 | 12:a9671b78d24e | 24 | #define NO_DISK 0x02 |
setcom_001 | 12:a9671b78d24e | 25 | #define WRITE_PROTECT 0x04 |
setcom_001 | 12:a9671b78d24e | 26 | |
setcom_001 | 12:a9671b78d24e | 27 | #define CBW_Signature 0x43425355 |
setcom_001 | 12:a9671b78d24e | 28 | #define CSW_Signature 0x53425355 |
setcom_001 | 12:a9671b78d24e | 29 | |
setcom_001 | 12:a9671b78d24e | 30 | // SCSI Commands |
setcom_001 | 12:a9671b78d24e | 31 | #define TEST_UNIT_READY 0x00 |
setcom_001 | 12:a9671b78d24e | 32 | #define REQUEST_SENSE 0x03 |
setcom_001 | 12:a9671b78d24e | 33 | #define FORMAT_UNIT 0x04 |
setcom_001 | 12:a9671b78d24e | 34 | #define INQUIRY 0x12 |
setcom_001 | 12:a9671b78d24e | 35 | #define MODE_SELECT6 0x15 |
setcom_001 | 12:a9671b78d24e | 36 | #define MODE_SENSE6 0x1A |
setcom_001 | 12:a9671b78d24e | 37 | #define START_STOP_UNIT 0x1B |
setcom_001 | 12:a9671b78d24e | 38 | #define MEDIA_REMOVAL 0x1E |
setcom_001 | 12:a9671b78d24e | 39 | #define READ_FORMAT_CAPACITIES 0x23 |
setcom_001 | 12:a9671b78d24e | 40 | #define READ_CAPACITY 0x25 |
setcom_001 | 12:a9671b78d24e | 41 | #define READ10 0x28 |
setcom_001 | 12:a9671b78d24e | 42 | #define WRITE10 0x2A |
setcom_001 | 12:a9671b78d24e | 43 | #define VERIFY10 0x2F |
setcom_001 | 12:a9671b78d24e | 44 | #define READ12 0xA8 |
setcom_001 | 12:a9671b78d24e | 45 | #define WRITE12 0xAA |
setcom_001 | 12:a9671b78d24e | 46 | #define MODE_SELECT10 0x55 |
setcom_001 | 12:a9671b78d24e | 47 | #define MODE_SENSE10 0x5A |
setcom_001 | 12:a9671b78d24e | 48 | |
setcom_001 | 12:a9671b78d24e | 49 | // MSC class specific requests |
setcom_001 | 12:a9671b78d24e | 50 | #define MSC_REQUEST_RESET 0xFF |
setcom_001 | 12:a9671b78d24e | 51 | #define MSC_REQUEST_GET_MAX_LUN 0xFE |
setcom_001 | 12:a9671b78d24e | 52 | |
setcom_001 | 12:a9671b78d24e | 53 | #define DEFAULT_CONFIGURATION (1) |
setcom_001 | 12:a9671b78d24e | 54 | |
setcom_001 | 12:a9671b78d24e | 55 | // max packet size |
setcom_001 | 12:a9671b78d24e | 56 | #define MAX_PACKET MAX_PACKET_SIZE_EPBULK |
setcom_001 | 12:a9671b78d24e | 57 | |
setcom_001 | 12:a9671b78d24e | 58 | // CSW Status |
setcom_001 | 12:a9671b78d24e | 59 | enum Status |
setcom_001 | 12:a9671b78d24e | 60 | { |
setcom_001 | 12:a9671b78d24e | 61 | CSW_PASSED, |
setcom_001 | 12:a9671b78d24e | 62 | CSW_FAILED, |
setcom_001 | 12:a9671b78d24e | 63 | CSW_ERROR, |
setcom_001 | 12:a9671b78d24e | 64 | }; |
setcom_001 | 12:a9671b78d24e | 65 | |
setcom_001 | 12:a9671b78d24e | 66 | |
setcom_001 | 12:a9671b78d24e | 67 | USBMSD::USBMSD( uint16_t vendor_id, uint16_t product_id, uint16_t product_release ): USBDevice( vendor_id, product_id, product_release ) |
setcom_001 | 12:a9671b78d24e | 68 | { |
setcom_001 | 12:a9671b78d24e | 69 | } |
setcom_001 | 12:a9671b78d24e | 70 | |
setcom_001 | 12:a9671b78d24e | 71 | |
setcom_001 | 12:a9671b78d24e | 72 | |
setcom_001 | 12:a9671b78d24e | 73 | // Called in ISR context to process a class specific request |
setcom_001 | 12:a9671b78d24e | 74 | bool USBMSD::USBCallback_request( void ) |
setcom_001 | 12:a9671b78d24e | 75 | { |
setcom_001 | 12:a9671b78d24e | 76 | bool success = false; |
setcom_001 | 12:a9671b78d24e | 77 | CONTROL_TRANSFER *transfer = getTransferPtr(); |
setcom_001 | 12:a9671b78d24e | 78 | static uint8_t maxLUN[1] = {0}; |
setcom_001 | 12:a9671b78d24e | 79 | |
setcom_001 | 12:a9671b78d24e | 80 | if ( transfer->setup.bmRequestType.Type == CLASS_TYPE ) |
setcom_001 | 12:a9671b78d24e | 81 | { |
setcom_001 | 12:a9671b78d24e | 82 | switch ( transfer->setup.bRequest ) |
setcom_001 | 12:a9671b78d24e | 83 | { |
setcom_001 | 12:a9671b78d24e | 84 | case MSC_REQUEST_RESET: |
setcom_001 | 12:a9671b78d24e | 85 | reset(); |
setcom_001 | 12:a9671b78d24e | 86 | success = true; |
setcom_001 | 12:a9671b78d24e | 87 | break; |
setcom_001 | 12:a9671b78d24e | 88 | |
setcom_001 | 12:a9671b78d24e | 89 | case MSC_REQUEST_GET_MAX_LUN: |
setcom_001 | 12:a9671b78d24e | 90 | transfer->remaining = 1; |
setcom_001 | 12:a9671b78d24e | 91 | transfer->ptr = maxLUN; |
setcom_001 | 12:a9671b78d24e | 92 | transfer->direction = DEVICE_TO_HOST; |
setcom_001 | 12:a9671b78d24e | 93 | success = true; |
setcom_001 | 12:a9671b78d24e | 94 | break; |
setcom_001 | 12:a9671b78d24e | 95 | |
setcom_001 | 12:a9671b78d24e | 96 | default: |
setcom_001 | 12:a9671b78d24e | 97 | break; |
setcom_001 | 12:a9671b78d24e | 98 | } |
setcom_001 | 12:a9671b78d24e | 99 | } |
setcom_001 | 12:a9671b78d24e | 100 | |
setcom_001 | 12:a9671b78d24e | 101 | return success; |
setcom_001 | 12:a9671b78d24e | 102 | } |
setcom_001 | 12:a9671b78d24e | 103 | |
setcom_001 | 12:a9671b78d24e | 104 | |
setcom_001 | 12:a9671b78d24e | 105 | bool USBMSD::connect() |
setcom_001 | 12:a9671b78d24e | 106 | { |
setcom_001 | 12:a9671b78d24e | 107 | //disk initialization |
setcom_001 | 12:a9671b78d24e | 108 | if ( disk_status() & NO_INIT ) |
setcom_001 | 12:a9671b78d24e | 109 | { |
setcom_001 | 12:a9671b78d24e | 110 | if ( disk_initialize() ) |
setcom_001 | 12:a9671b78d24e | 111 | { |
setcom_001 | 12:a9671b78d24e | 112 | return false; |
setcom_001 | 12:a9671b78d24e | 113 | } |
setcom_001 | 12:a9671b78d24e | 114 | } |
setcom_001 | 12:a9671b78d24e | 115 | |
setcom_001 | 12:a9671b78d24e | 116 | // get number of blocks |
setcom_001 | 12:a9671b78d24e | 117 | BlockCount = disk_sectors(); |
setcom_001 | 12:a9671b78d24e | 118 | // get memory size |
setcom_001 | 12:a9671b78d24e | 119 | MemorySize = disk_size(); |
setcom_001 | 12:a9671b78d24e | 120 | |
setcom_001 | 12:a9671b78d24e | 121 | if ( BlockCount >= 0 ) |
setcom_001 | 12:a9671b78d24e | 122 | { |
setcom_001 | 12:a9671b78d24e | 123 | BlockSize = MemorySize / BlockCount; |
setcom_001 | 12:a9671b78d24e | 124 | |
setcom_001 | 12:a9671b78d24e | 125 | if ( BlockSize != 0 ) |
setcom_001 | 12:a9671b78d24e | 126 | { |
setcom_001 | 12:a9671b78d24e | 127 | page = ( uint8_t * )malloc( BlockSize * sizeof( uint8_t ) ); |
setcom_001 | 12:a9671b78d24e | 128 | |
setcom_001 | 12:a9671b78d24e | 129 | if ( page == NULL ) |
setcom_001 | 12:a9671b78d24e | 130 | { |
setcom_001 | 12:a9671b78d24e | 131 | return false; |
setcom_001 | 12:a9671b78d24e | 132 | } |
setcom_001 | 12:a9671b78d24e | 133 | } |
setcom_001 | 12:a9671b78d24e | 134 | } |
setcom_001 | 12:a9671b78d24e | 135 | else |
setcom_001 | 12:a9671b78d24e | 136 | { |
setcom_001 | 12:a9671b78d24e | 137 | return false; |
setcom_001 | 12:a9671b78d24e | 138 | } |
setcom_001 | 12:a9671b78d24e | 139 | |
setcom_001 | 12:a9671b78d24e | 140 | //connect the device |
setcom_001 | 12:a9671b78d24e | 141 | USBDevice::connect(); |
setcom_001 | 12:a9671b78d24e | 142 | return true; |
setcom_001 | 12:a9671b78d24e | 143 | } |
setcom_001 | 12:a9671b78d24e | 144 | |
setcom_001 | 12:a9671b78d24e | 145 | |
setcom_001 | 12:a9671b78d24e | 146 | void USBMSD::reset() |
setcom_001 | 12:a9671b78d24e | 147 | { |
setcom_001 | 12:a9671b78d24e | 148 | stage = READ_CBW; |
setcom_001 | 12:a9671b78d24e | 149 | } |
setcom_001 | 12:a9671b78d24e | 150 | |
setcom_001 | 12:a9671b78d24e | 151 | |
setcom_001 | 12:a9671b78d24e | 152 | // Called in ISR context called when a data is received |
setcom_001 | 12:a9671b78d24e | 153 | bool USBMSD::EP2_OUT_callback() |
setcom_001 | 12:a9671b78d24e | 154 | { |
setcom_001 | 12:a9671b78d24e | 155 | uint32_t size = 0; |
setcom_001 | 12:a9671b78d24e | 156 | uint8_t buf[MAX_PACKET_SIZE_EPBULK]; |
setcom_001 | 12:a9671b78d24e | 157 | readEP( EPBULK_OUT, buf, &size, MAX_PACKET_SIZE_EPBULK ); |
setcom_001 | 12:a9671b78d24e | 158 | |
setcom_001 | 12:a9671b78d24e | 159 | switch ( stage ) |
setcom_001 | 12:a9671b78d24e | 160 | { |
setcom_001 | 12:a9671b78d24e | 161 | // the device has to decode the CBW received |
setcom_001 | 12:a9671b78d24e | 162 | case READ_CBW: |
setcom_001 | 12:a9671b78d24e | 163 | CBWDecode( buf, size ); |
setcom_001 | 12:a9671b78d24e | 164 | break; |
setcom_001 | 12:a9671b78d24e | 165 | |
setcom_001 | 12:a9671b78d24e | 166 | // the device has to receive data from the host |
setcom_001 | 12:a9671b78d24e | 167 | case PROCESS_CBW: |
setcom_001 | 12:a9671b78d24e | 168 | switch ( cbw.CB[0] ) |
setcom_001 | 12:a9671b78d24e | 169 | { |
setcom_001 | 12:a9671b78d24e | 170 | case WRITE10: |
setcom_001 | 12:a9671b78d24e | 171 | case WRITE12: |
setcom_001 | 12:a9671b78d24e | 172 | memoryWrite( buf, size ); |
setcom_001 | 12:a9671b78d24e | 173 | break; |
setcom_001 | 12:a9671b78d24e | 174 | |
setcom_001 | 12:a9671b78d24e | 175 | case VERIFY10: |
setcom_001 | 12:a9671b78d24e | 176 | memoryVerify( buf, size ); |
setcom_001 | 12:a9671b78d24e | 177 | break; |
setcom_001 | 12:a9671b78d24e | 178 | } |
setcom_001 | 12:a9671b78d24e | 179 | |
setcom_001 | 12:a9671b78d24e | 180 | break; |
setcom_001 | 12:a9671b78d24e | 181 | |
setcom_001 | 12:a9671b78d24e | 182 | // an error has occured: stall endpoint and send CSW |
setcom_001 | 12:a9671b78d24e | 183 | default: |
setcom_001 | 12:a9671b78d24e | 184 | stallEndpoint( EPBULK_OUT ); |
setcom_001 | 12:a9671b78d24e | 185 | csw.Status = CSW_ERROR; |
setcom_001 | 12:a9671b78d24e | 186 | sendCSW(); |
setcom_001 | 12:a9671b78d24e | 187 | break; |
setcom_001 | 12:a9671b78d24e | 188 | } |
setcom_001 | 12:a9671b78d24e | 189 | |
setcom_001 | 12:a9671b78d24e | 190 | //reactivate readings on the OUT bulk endpoint |
setcom_001 | 12:a9671b78d24e | 191 | readStart( EPBULK_OUT, MAX_PACKET_SIZE_EPBULK ); |
setcom_001 | 12:a9671b78d24e | 192 | return true; |
setcom_001 | 12:a9671b78d24e | 193 | } |
setcom_001 | 12:a9671b78d24e | 194 | |
setcom_001 | 12:a9671b78d24e | 195 | // Called in ISR context when a data has been transferred |
setcom_001 | 12:a9671b78d24e | 196 | bool USBMSD::EP2_IN_callback() |
setcom_001 | 12:a9671b78d24e | 197 | { |
setcom_001 | 12:a9671b78d24e | 198 | switch ( stage ) |
setcom_001 | 12:a9671b78d24e | 199 | { |
setcom_001 | 12:a9671b78d24e | 200 | // the device has to send data to the host |
setcom_001 | 12:a9671b78d24e | 201 | case PROCESS_CBW: |
setcom_001 | 12:a9671b78d24e | 202 | switch ( cbw.CB[0] ) |
setcom_001 | 12:a9671b78d24e | 203 | { |
setcom_001 | 12:a9671b78d24e | 204 | case READ10: |
setcom_001 | 12:a9671b78d24e | 205 | case READ12: |
setcom_001 | 12:a9671b78d24e | 206 | memoryRead(); |
setcom_001 | 12:a9671b78d24e | 207 | break; |
setcom_001 | 12:a9671b78d24e | 208 | } |
setcom_001 | 12:a9671b78d24e | 209 | |
setcom_001 | 12:a9671b78d24e | 210 | break; |
setcom_001 | 12:a9671b78d24e | 211 | |
setcom_001 | 12:a9671b78d24e | 212 | //the device has to send a CSW |
setcom_001 | 12:a9671b78d24e | 213 | case SEND_CSW: |
setcom_001 | 12:a9671b78d24e | 214 | sendCSW(); |
setcom_001 | 12:a9671b78d24e | 215 | break; |
setcom_001 | 12:a9671b78d24e | 216 | |
setcom_001 | 12:a9671b78d24e | 217 | // an error has occured |
setcom_001 | 12:a9671b78d24e | 218 | case ERROR: |
setcom_001 | 12:a9671b78d24e | 219 | stallEndpoint( EPBULK_IN ); |
setcom_001 | 12:a9671b78d24e | 220 | sendCSW(); |
setcom_001 | 12:a9671b78d24e | 221 | break; |
setcom_001 | 12:a9671b78d24e | 222 | |
setcom_001 | 12:a9671b78d24e | 223 | // the host has received the CSW -> we wait a CBW |
setcom_001 | 12:a9671b78d24e | 224 | case WAIT_CSW: |
setcom_001 | 12:a9671b78d24e | 225 | stage = READ_CBW; |
setcom_001 | 12:a9671b78d24e | 226 | break; |
setcom_001 | 12:a9671b78d24e | 227 | } |
setcom_001 | 12:a9671b78d24e | 228 | |
setcom_001 | 12:a9671b78d24e | 229 | return true; |
setcom_001 | 12:a9671b78d24e | 230 | } |
setcom_001 | 12:a9671b78d24e | 231 | |
setcom_001 | 12:a9671b78d24e | 232 | |
setcom_001 | 12:a9671b78d24e | 233 | void USBMSD::memoryWrite ( uint8_t *buf, uint16_t size ) |
setcom_001 | 12:a9671b78d24e | 234 | { |
setcom_001 | 12:a9671b78d24e | 235 | if ( ( addr + size ) > MemorySize ) |
setcom_001 | 12:a9671b78d24e | 236 | { |
setcom_001 | 12:a9671b78d24e | 237 | size = MemorySize - addr; |
setcom_001 | 12:a9671b78d24e | 238 | stage = ERROR; |
setcom_001 | 12:a9671b78d24e | 239 | stallEndpoint( EPBULK_OUT ); |
setcom_001 | 12:a9671b78d24e | 240 | } |
setcom_001 | 12:a9671b78d24e | 241 | |
setcom_001 | 12:a9671b78d24e | 242 | // we fill an array in RAM of 1 block before writing it in memory |
setcom_001 | 12:a9671b78d24e | 243 | for ( int i = 0; i < size; i++ ) |
setcom_001 | 12:a9671b78d24e | 244 | { |
setcom_001 | 12:a9671b78d24e | 245 | page[addr % BlockSize + i] = buf[i]; |
setcom_001 | 12:a9671b78d24e | 246 | } |
setcom_001 | 12:a9671b78d24e | 247 | |
setcom_001 | 12:a9671b78d24e | 248 | // if the array is filled, write it in memory |
setcom_001 | 12:a9671b78d24e | 249 | if ( !( ( addr + size ) % BlockSize ) ) |
setcom_001 | 12:a9671b78d24e | 250 | { |
setcom_001 | 12:a9671b78d24e | 251 | if ( !( disk_status() & WRITE_PROTECT ) ) |
setcom_001 | 12:a9671b78d24e | 252 | { |
setcom_001 | 12:a9671b78d24e | 253 | disk_write( ( const char * )page, addr / BlockSize ); |
setcom_001 | 12:a9671b78d24e | 254 | } |
setcom_001 | 12:a9671b78d24e | 255 | } |
setcom_001 | 12:a9671b78d24e | 256 | |
setcom_001 | 12:a9671b78d24e | 257 | addr += size; |
setcom_001 | 12:a9671b78d24e | 258 | length -= size; |
setcom_001 | 12:a9671b78d24e | 259 | csw.DataResidue -= size; |
setcom_001 | 12:a9671b78d24e | 260 | |
setcom_001 | 12:a9671b78d24e | 261 | if ( ( !length ) || ( stage != PROCESS_CBW ) ) |
setcom_001 | 12:a9671b78d24e | 262 | { |
setcom_001 | 12:a9671b78d24e | 263 | csw.Status = ( stage == ERROR ) ? CSW_FAILED : CSW_PASSED; |
setcom_001 | 12:a9671b78d24e | 264 | sendCSW(); |
setcom_001 | 12:a9671b78d24e | 265 | } |
setcom_001 | 12:a9671b78d24e | 266 | } |
setcom_001 | 12:a9671b78d24e | 267 | |
setcom_001 | 12:a9671b78d24e | 268 | void USBMSD::memoryVerify ( uint8_t *buf, uint16_t size ) |
setcom_001 | 12:a9671b78d24e | 269 | { |
setcom_001 | 12:a9671b78d24e | 270 | uint32_t n; |
setcom_001 | 12:a9671b78d24e | 271 | |
setcom_001 | 12:a9671b78d24e | 272 | if ( ( addr + size ) > MemorySize ) |
setcom_001 | 12:a9671b78d24e | 273 | { |
setcom_001 | 12:a9671b78d24e | 274 | size = MemorySize - addr; |
setcom_001 | 12:a9671b78d24e | 275 | stage = ERROR; |
setcom_001 | 12:a9671b78d24e | 276 | stallEndpoint( EPBULK_OUT ); |
setcom_001 | 12:a9671b78d24e | 277 | } |
setcom_001 | 12:a9671b78d24e | 278 | |
setcom_001 | 12:a9671b78d24e | 279 | // beginning of a new block -> load a whole block in RAM |
setcom_001 | 12:a9671b78d24e | 280 | if ( !( addr % BlockSize ) ) |
setcom_001 | 12:a9671b78d24e | 281 | { |
setcom_001 | 12:a9671b78d24e | 282 | disk_read( ( char * )page, addr / BlockSize ); |
setcom_001 | 12:a9671b78d24e | 283 | } |
setcom_001 | 12:a9671b78d24e | 284 | |
setcom_001 | 12:a9671b78d24e | 285 | // info are in RAM -> no need to re-read memory |
setcom_001 | 12:a9671b78d24e | 286 | for ( n = 0; n < size; n++ ) |
setcom_001 | 12:a9671b78d24e | 287 | { |
setcom_001 | 12:a9671b78d24e | 288 | if ( page[addr % BlockSize + n] != buf[n] ) |
setcom_001 | 12:a9671b78d24e | 289 | { |
setcom_001 | 12:a9671b78d24e | 290 | memOK = false; |
setcom_001 | 12:a9671b78d24e | 291 | break; |
setcom_001 | 12:a9671b78d24e | 292 | } |
setcom_001 | 12:a9671b78d24e | 293 | } |
setcom_001 | 12:a9671b78d24e | 294 | |
setcom_001 | 12:a9671b78d24e | 295 | addr += size; |
setcom_001 | 12:a9671b78d24e | 296 | length -= size; |
setcom_001 | 12:a9671b78d24e | 297 | csw.DataResidue -= size; |
setcom_001 | 12:a9671b78d24e | 298 | |
setcom_001 | 12:a9671b78d24e | 299 | if ( !length || ( stage != PROCESS_CBW ) ) |
setcom_001 | 12:a9671b78d24e | 300 | { |
setcom_001 | 12:a9671b78d24e | 301 | csw.Status = ( memOK && ( stage == PROCESS_CBW ) ) ? CSW_PASSED : CSW_FAILED; |
setcom_001 | 12:a9671b78d24e | 302 | sendCSW(); |
setcom_001 | 12:a9671b78d24e | 303 | } |
setcom_001 | 12:a9671b78d24e | 304 | } |
setcom_001 | 12:a9671b78d24e | 305 | |
setcom_001 | 12:a9671b78d24e | 306 | |
setcom_001 | 12:a9671b78d24e | 307 | bool USBMSD::inquiryRequest ( void ) |
setcom_001 | 12:a9671b78d24e | 308 | { |
setcom_001 | 12:a9671b78d24e | 309 | uint8_t inquiry[] = { 0x00, 0x80, 0x00, 0x01, |
setcom_001 | 12:a9671b78d24e | 310 | 36 - 4, 0x80, 0x00, 0x00, |
setcom_001 | 12:a9671b78d24e | 311 | 'M', 'B', 'E', 'D', '.', 'O', 'R', 'G', |
setcom_001 | 12:a9671b78d24e | 312 | 'M', 'B', 'E', 'D', ' ', 'U', 'S', 'B', ' ', 'D', 'I', 'S', 'K', ' ', ' ', ' ', |
setcom_001 | 12:a9671b78d24e | 313 | '1', '.', '0', ' ', |
setcom_001 | 12:a9671b78d24e | 314 | }; |
setcom_001 | 12:a9671b78d24e | 315 | |
setcom_001 | 12:a9671b78d24e | 316 | if ( !write( inquiry, sizeof( inquiry ) ) ) |
setcom_001 | 12:a9671b78d24e | 317 | { |
setcom_001 | 12:a9671b78d24e | 318 | return false; |
setcom_001 | 12:a9671b78d24e | 319 | } |
setcom_001 | 12:a9671b78d24e | 320 | |
setcom_001 | 12:a9671b78d24e | 321 | return true; |
setcom_001 | 12:a9671b78d24e | 322 | } |
setcom_001 | 12:a9671b78d24e | 323 | |
setcom_001 | 12:a9671b78d24e | 324 | |
setcom_001 | 12:a9671b78d24e | 325 | bool USBMSD::readFormatCapacity() |
setcom_001 | 12:a9671b78d24e | 326 | { |
setcom_001 | 12:a9671b78d24e | 327 | uint8_t capacity[] = { 0x00, 0x00, 0x00, 0x08, |
setcom_001 | 12:a9671b78d24e | 328 | ( BlockCount >> 24 ) & 0xff, |
setcom_001 | 12:a9671b78d24e | 329 | ( BlockCount >> 16 ) & 0xff, |
setcom_001 | 12:a9671b78d24e | 330 | ( BlockCount >> 8 ) & 0xff, |
setcom_001 | 12:a9671b78d24e | 331 | ( BlockCount >> 0 ) & 0xff, |
setcom_001 | 12:a9671b78d24e | 332 | |
setcom_001 | 12:a9671b78d24e | 333 | 0x02, |
setcom_001 | 12:a9671b78d24e | 334 | ( BlockSize >> 16 ) & 0xff, |
setcom_001 | 12:a9671b78d24e | 335 | ( BlockSize >> 8 ) & 0xff, |
setcom_001 | 12:a9671b78d24e | 336 | ( BlockSize >> 0 ) & 0xff, |
setcom_001 | 12:a9671b78d24e | 337 | }; |
setcom_001 | 12:a9671b78d24e | 338 | |
setcom_001 | 12:a9671b78d24e | 339 | if ( !write( capacity, sizeof( capacity ) ) ) |
setcom_001 | 12:a9671b78d24e | 340 | { |
setcom_001 | 12:a9671b78d24e | 341 | return false; |
setcom_001 | 12:a9671b78d24e | 342 | } |
setcom_001 | 12:a9671b78d24e | 343 | |
setcom_001 | 12:a9671b78d24e | 344 | return true; |
setcom_001 | 12:a9671b78d24e | 345 | } |
setcom_001 | 12:a9671b78d24e | 346 | |
setcom_001 | 12:a9671b78d24e | 347 | |
setcom_001 | 12:a9671b78d24e | 348 | bool USBMSD::readCapacity ( void ) |
setcom_001 | 12:a9671b78d24e | 349 | { |
setcom_001 | 12:a9671b78d24e | 350 | uint8_t capacity[] = |
setcom_001 | 12:a9671b78d24e | 351 | { |
setcom_001 | 12:a9671b78d24e | 352 | ( ( BlockCount - 1 ) >> 24 ) & 0xff, |
setcom_001 | 12:a9671b78d24e | 353 | ( ( BlockCount - 1 ) >> 16 ) & 0xff, |
setcom_001 | 12:a9671b78d24e | 354 | ( ( BlockCount - 1 ) >> 8 ) & 0xff, |
setcom_001 | 12:a9671b78d24e | 355 | ( ( BlockCount - 1 ) >> 0 ) & 0xff, |
setcom_001 | 12:a9671b78d24e | 356 | |
setcom_001 | 12:a9671b78d24e | 357 | ( BlockSize >> 24 ) & 0xff, |
setcom_001 | 12:a9671b78d24e | 358 | ( BlockSize >> 16 ) & 0xff, |
setcom_001 | 12:a9671b78d24e | 359 | ( BlockSize >> 8 ) & 0xff, |
setcom_001 | 12:a9671b78d24e | 360 | ( BlockSize >> 0 ) & 0xff, |
setcom_001 | 12:a9671b78d24e | 361 | }; |
setcom_001 | 12:a9671b78d24e | 362 | |
setcom_001 | 12:a9671b78d24e | 363 | if ( !write( capacity, sizeof( capacity ) ) ) |
setcom_001 | 12:a9671b78d24e | 364 | { |
setcom_001 | 12:a9671b78d24e | 365 | return false; |
setcom_001 | 12:a9671b78d24e | 366 | } |
setcom_001 | 12:a9671b78d24e | 367 | |
setcom_001 | 12:a9671b78d24e | 368 | return true; |
setcom_001 | 12:a9671b78d24e | 369 | } |
setcom_001 | 12:a9671b78d24e | 370 | |
setcom_001 | 12:a9671b78d24e | 371 | bool USBMSD::write ( uint8_t *buf, uint16_t size ) |
setcom_001 | 12:a9671b78d24e | 372 | { |
setcom_001 | 12:a9671b78d24e | 373 | if ( size >= cbw.DataLength ) |
setcom_001 | 12:a9671b78d24e | 374 | { |
setcom_001 | 12:a9671b78d24e | 375 | size = cbw.DataLength; |
setcom_001 | 12:a9671b78d24e | 376 | } |
setcom_001 | 12:a9671b78d24e | 377 | |
setcom_001 | 12:a9671b78d24e | 378 | stage = SEND_CSW; |
setcom_001 | 12:a9671b78d24e | 379 | |
setcom_001 | 12:a9671b78d24e | 380 | if ( !writeNB( EPBULK_IN, buf, size, MAX_PACKET_SIZE_EPBULK ) ) |
setcom_001 | 12:a9671b78d24e | 381 | { |
setcom_001 | 12:a9671b78d24e | 382 | return false; |
setcom_001 | 12:a9671b78d24e | 383 | } |
setcom_001 | 12:a9671b78d24e | 384 | |
setcom_001 | 12:a9671b78d24e | 385 | csw.DataResidue -= size; |
setcom_001 | 12:a9671b78d24e | 386 | csw.Status = CSW_PASSED; |
setcom_001 | 12:a9671b78d24e | 387 | return true; |
setcom_001 | 12:a9671b78d24e | 388 | } |
setcom_001 | 12:a9671b78d24e | 389 | |
setcom_001 | 12:a9671b78d24e | 390 | |
setcom_001 | 12:a9671b78d24e | 391 | bool USBMSD::modeSense6 ( void ) |
setcom_001 | 12:a9671b78d24e | 392 | { |
setcom_001 | 12:a9671b78d24e | 393 | uint8_t sense6[] = { 0x03, 0x00, 0x00, 0x00 }; |
setcom_001 | 12:a9671b78d24e | 394 | |
setcom_001 | 12:a9671b78d24e | 395 | if ( !write( sense6, sizeof( sense6 ) ) ) |
setcom_001 | 12:a9671b78d24e | 396 | { |
setcom_001 | 12:a9671b78d24e | 397 | return false; |
setcom_001 | 12:a9671b78d24e | 398 | } |
setcom_001 | 12:a9671b78d24e | 399 | |
setcom_001 | 12:a9671b78d24e | 400 | return true; |
setcom_001 | 12:a9671b78d24e | 401 | } |
setcom_001 | 12:a9671b78d24e | 402 | |
setcom_001 | 12:a9671b78d24e | 403 | void USBMSD::sendCSW() |
setcom_001 | 12:a9671b78d24e | 404 | { |
setcom_001 | 12:a9671b78d24e | 405 | csw.Signature = CSW_Signature; |
setcom_001 | 12:a9671b78d24e | 406 | writeNB( EPBULK_IN, ( uint8_t * )&csw, sizeof( CSW ), MAX_PACKET_SIZE_EPBULK ); |
setcom_001 | 12:a9671b78d24e | 407 | stage = WAIT_CSW; |
setcom_001 | 12:a9671b78d24e | 408 | } |
setcom_001 | 12:a9671b78d24e | 409 | |
setcom_001 | 12:a9671b78d24e | 410 | bool USBMSD::requestSense ( void ) |
setcom_001 | 12:a9671b78d24e | 411 | { |
setcom_001 | 12:a9671b78d24e | 412 | uint8_t request_sense[] = |
setcom_001 | 12:a9671b78d24e | 413 | { |
setcom_001 | 12:a9671b78d24e | 414 | 0x70, |
setcom_001 | 12:a9671b78d24e | 415 | 0x00, |
setcom_001 | 12:a9671b78d24e | 416 | 0x05, // Sense Key: illegal request |
setcom_001 | 12:a9671b78d24e | 417 | 0x00, |
setcom_001 | 12:a9671b78d24e | 418 | 0x00, |
setcom_001 | 12:a9671b78d24e | 419 | 0x00, |
setcom_001 | 12:a9671b78d24e | 420 | 0x00, |
setcom_001 | 12:a9671b78d24e | 421 | 0x0A, |
setcom_001 | 12:a9671b78d24e | 422 | 0x00, |
setcom_001 | 12:a9671b78d24e | 423 | 0x00, |
setcom_001 | 12:a9671b78d24e | 424 | 0x00, |
setcom_001 | 12:a9671b78d24e | 425 | 0x00, |
setcom_001 | 12:a9671b78d24e | 426 | 0x30, |
setcom_001 | 12:a9671b78d24e | 427 | 0x01, |
setcom_001 | 12:a9671b78d24e | 428 | 0x00, |
setcom_001 | 12:a9671b78d24e | 429 | 0x00, |
setcom_001 | 12:a9671b78d24e | 430 | 0x00, |
setcom_001 | 12:a9671b78d24e | 431 | 0x00, |
setcom_001 | 12:a9671b78d24e | 432 | }; |
setcom_001 | 12:a9671b78d24e | 433 | |
setcom_001 | 12:a9671b78d24e | 434 | if ( !write( request_sense, sizeof( request_sense ) ) ) |
setcom_001 | 12:a9671b78d24e | 435 | { |
setcom_001 | 12:a9671b78d24e | 436 | return false; |
setcom_001 | 12:a9671b78d24e | 437 | } |
setcom_001 | 12:a9671b78d24e | 438 | |
setcom_001 | 12:a9671b78d24e | 439 | return true; |
setcom_001 | 12:a9671b78d24e | 440 | } |
setcom_001 | 12:a9671b78d24e | 441 | |
setcom_001 | 12:a9671b78d24e | 442 | void USBMSD::fail() |
setcom_001 | 12:a9671b78d24e | 443 | { |
setcom_001 | 12:a9671b78d24e | 444 | csw.Status = CSW_FAILED; |
setcom_001 | 12:a9671b78d24e | 445 | sendCSW(); |
setcom_001 | 12:a9671b78d24e | 446 | } |
setcom_001 | 12:a9671b78d24e | 447 | |
setcom_001 | 12:a9671b78d24e | 448 | |
setcom_001 | 12:a9671b78d24e | 449 | void USBMSD::CBWDecode( uint8_t *buf, uint16_t size ) |
setcom_001 | 12:a9671b78d24e | 450 | { |
setcom_001 | 12:a9671b78d24e | 451 | if ( size == sizeof( cbw ) ) |
setcom_001 | 12:a9671b78d24e | 452 | { |
setcom_001 | 12:a9671b78d24e | 453 | memcpy( ( uint8_t * )&cbw, buf, size ); |
setcom_001 | 12:a9671b78d24e | 454 | |
setcom_001 | 12:a9671b78d24e | 455 | if ( cbw.Signature == CBW_Signature ) |
setcom_001 | 12:a9671b78d24e | 456 | { |
setcom_001 | 12:a9671b78d24e | 457 | csw.Tag = cbw.Tag; |
setcom_001 | 12:a9671b78d24e | 458 | csw.DataResidue = cbw.DataLength; |
setcom_001 | 12:a9671b78d24e | 459 | |
setcom_001 | 12:a9671b78d24e | 460 | if ( ( cbw.CBLength < 1 ) || ( cbw.CBLength > 16 ) ) |
setcom_001 | 12:a9671b78d24e | 461 | { |
setcom_001 | 12:a9671b78d24e | 462 | fail(); |
setcom_001 | 12:a9671b78d24e | 463 | } |
setcom_001 | 12:a9671b78d24e | 464 | else |
setcom_001 | 12:a9671b78d24e | 465 | { |
setcom_001 | 12:a9671b78d24e | 466 | switch ( cbw.CB[0] ) |
setcom_001 | 12:a9671b78d24e | 467 | { |
setcom_001 | 12:a9671b78d24e | 468 | case TEST_UNIT_READY: |
setcom_001 | 12:a9671b78d24e | 469 | testUnitReady(); |
setcom_001 | 12:a9671b78d24e | 470 | break; |
setcom_001 | 12:a9671b78d24e | 471 | |
setcom_001 | 12:a9671b78d24e | 472 | case REQUEST_SENSE: |
setcom_001 | 12:a9671b78d24e | 473 | requestSense(); |
setcom_001 | 12:a9671b78d24e | 474 | break; |
setcom_001 | 12:a9671b78d24e | 475 | |
setcom_001 | 12:a9671b78d24e | 476 | case INQUIRY: |
setcom_001 | 12:a9671b78d24e | 477 | inquiryRequest(); |
setcom_001 | 12:a9671b78d24e | 478 | break; |
setcom_001 | 12:a9671b78d24e | 479 | |
setcom_001 | 12:a9671b78d24e | 480 | case MODE_SENSE6: |
setcom_001 | 12:a9671b78d24e | 481 | modeSense6(); |
setcom_001 | 12:a9671b78d24e | 482 | break; |
setcom_001 | 12:a9671b78d24e | 483 | |
setcom_001 | 12:a9671b78d24e | 484 | case READ_FORMAT_CAPACITIES: |
setcom_001 | 12:a9671b78d24e | 485 | readFormatCapacity(); |
setcom_001 | 12:a9671b78d24e | 486 | break; |
setcom_001 | 12:a9671b78d24e | 487 | |
setcom_001 | 12:a9671b78d24e | 488 | case READ_CAPACITY: |
setcom_001 | 12:a9671b78d24e | 489 | readCapacity(); |
setcom_001 | 12:a9671b78d24e | 490 | break; |
setcom_001 | 12:a9671b78d24e | 491 | |
setcom_001 | 12:a9671b78d24e | 492 | case READ10: |
setcom_001 | 12:a9671b78d24e | 493 | case READ12: |
setcom_001 | 12:a9671b78d24e | 494 | if ( infoTransfer() ) |
setcom_001 | 12:a9671b78d24e | 495 | { |
setcom_001 | 12:a9671b78d24e | 496 | if ( ( cbw.Flags & 0x80 ) ) |
setcom_001 | 12:a9671b78d24e | 497 | { |
setcom_001 | 12:a9671b78d24e | 498 | stage = PROCESS_CBW; |
setcom_001 | 12:a9671b78d24e | 499 | memoryRead(); |
setcom_001 | 12:a9671b78d24e | 500 | } |
setcom_001 | 12:a9671b78d24e | 501 | else |
setcom_001 | 12:a9671b78d24e | 502 | { |
setcom_001 | 12:a9671b78d24e | 503 | stallEndpoint( EPBULK_OUT ); |
setcom_001 | 12:a9671b78d24e | 504 | csw.Status = CSW_ERROR; |
setcom_001 | 12:a9671b78d24e | 505 | sendCSW(); |
setcom_001 | 12:a9671b78d24e | 506 | } |
setcom_001 | 12:a9671b78d24e | 507 | } |
setcom_001 | 12:a9671b78d24e | 508 | |
setcom_001 | 12:a9671b78d24e | 509 | break; |
setcom_001 | 12:a9671b78d24e | 510 | |
setcom_001 | 12:a9671b78d24e | 511 | case WRITE10: |
setcom_001 | 12:a9671b78d24e | 512 | case WRITE12: |
setcom_001 | 12:a9671b78d24e | 513 | if ( infoTransfer() ) |
setcom_001 | 12:a9671b78d24e | 514 | { |
setcom_001 | 12:a9671b78d24e | 515 | if ( !( cbw.Flags & 0x80 ) ) |
setcom_001 | 12:a9671b78d24e | 516 | { |
setcom_001 | 12:a9671b78d24e | 517 | stage = PROCESS_CBW; |
setcom_001 | 12:a9671b78d24e | 518 | } |
setcom_001 | 12:a9671b78d24e | 519 | else |
setcom_001 | 12:a9671b78d24e | 520 | { |
setcom_001 | 12:a9671b78d24e | 521 | stallEndpoint( EPBULK_IN ); |
setcom_001 | 12:a9671b78d24e | 522 | csw.Status = CSW_ERROR; |
setcom_001 | 12:a9671b78d24e | 523 | sendCSW(); |
setcom_001 | 12:a9671b78d24e | 524 | } |
setcom_001 | 12:a9671b78d24e | 525 | } |
setcom_001 | 12:a9671b78d24e | 526 | |
setcom_001 | 12:a9671b78d24e | 527 | break; |
setcom_001 | 12:a9671b78d24e | 528 | |
setcom_001 | 12:a9671b78d24e | 529 | case VERIFY10: |
setcom_001 | 12:a9671b78d24e | 530 | if ( !( cbw.CB[1] & 0x02 ) ) |
setcom_001 | 12:a9671b78d24e | 531 | { |
setcom_001 | 12:a9671b78d24e | 532 | csw.Status = CSW_PASSED; |
setcom_001 | 12:a9671b78d24e | 533 | sendCSW(); |
setcom_001 | 12:a9671b78d24e | 534 | break; |
setcom_001 | 12:a9671b78d24e | 535 | } |
setcom_001 | 12:a9671b78d24e | 536 | |
setcom_001 | 12:a9671b78d24e | 537 | if ( infoTransfer() ) |
setcom_001 | 12:a9671b78d24e | 538 | { |
setcom_001 | 12:a9671b78d24e | 539 | if ( !( cbw.Flags & 0x80 ) ) |
setcom_001 | 12:a9671b78d24e | 540 | { |
setcom_001 | 12:a9671b78d24e | 541 | stage = PROCESS_CBW; |
setcom_001 | 12:a9671b78d24e | 542 | memOK = true; |
setcom_001 | 12:a9671b78d24e | 543 | } |
setcom_001 | 12:a9671b78d24e | 544 | else |
setcom_001 | 12:a9671b78d24e | 545 | { |
setcom_001 | 12:a9671b78d24e | 546 | stallEndpoint( EPBULK_IN ); |
setcom_001 | 12:a9671b78d24e | 547 | csw.Status = CSW_ERROR; |
setcom_001 | 12:a9671b78d24e | 548 | sendCSW(); |
setcom_001 | 12:a9671b78d24e | 549 | } |
setcom_001 | 12:a9671b78d24e | 550 | } |
setcom_001 | 12:a9671b78d24e | 551 | |
setcom_001 | 12:a9671b78d24e | 552 | break; |
setcom_001 | 12:a9671b78d24e | 553 | |
setcom_001 | 12:a9671b78d24e | 554 | default: |
setcom_001 | 12:a9671b78d24e | 555 | fail(); |
setcom_001 | 12:a9671b78d24e | 556 | break; |
setcom_001 | 12:a9671b78d24e | 557 | } |
setcom_001 | 12:a9671b78d24e | 558 | } |
setcom_001 | 12:a9671b78d24e | 559 | } |
setcom_001 | 12:a9671b78d24e | 560 | } |
setcom_001 | 12:a9671b78d24e | 561 | } |
setcom_001 | 12:a9671b78d24e | 562 | |
setcom_001 | 12:a9671b78d24e | 563 | void USBMSD::testUnitReady ( void ) |
setcom_001 | 12:a9671b78d24e | 564 | { |
setcom_001 | 12:a9671b78d24e | 565 | if ( cbw.DataLength != 0 ) |
setcom_001 | 12:a9671b78d24e | 566 | { |
setcom_001 | 12:a9671b78d24e | 567 | if ( ( cbw.Flags & 0x80 ) != 0 ) |
setcom_001 | 12:a9671b78d24e | 568 | { |
setcom_001 | 12:a9671b78d24e | 569 | stallEndpoint( EPBULK_IN ); |
setcom_001 | 12:a9671b78d24e | 570 | } |
setcom_001 | 12:a9671b78d24e | 571 | else |
setcom_001 | 12:a9671b78d24e | 572 | { |
setcom_001 | 12:a9671b78d24e | 573 | stallEndpoint( EPBULK_OUT ); |
setcom_001 | 12:a9671b78d24e | 574 | } |
setcom_001 | 12:a9671b78d24e | 575 | } |
setcom_001 | 12:a9671b78d24e | 576 | |
setcom_001 | 12:a9671b78d24e | 577 | csw.Status = CSW_PASSED; |
setcom_001 | 12:a9671b78d24e | 578 | sendCSW(); |
setcom_001 | 12:a9671b78d24e | 579 | } |
setcom_001 | 12:a9671b78d24e | 580 | |
setcom_001 | 12:a9671b78d24e | 581 | |
setcom_001 | 12:a9671b78d24e | 582 | void USBMSD::memoryRead ( void ) |
setcom_001 | 12:a9671b78d24e | 583 | { |
setcom_001 | 12:a9671b78d24e | 584 | uint32_t n; |
setcom_001 | 12:a9671b78d24e | 585 | n = ( length > MAX_PACKET ) ? MAX_PACKET : length; |
setcom_001 | 12:a9671b78d24e | 586 | |
setcom_001 | 12:a9671b78d24e | 587 | if ( ( addr + n ) > MemorySize ) |
setcom_001 | 12:a9671b78d24e | 588 | { |
setcom_001 | 12:a9671b78d24e | 589 | n = MemorySize - addr; |
setcom_001 | 12:a9671b78d24e | 590 | stage = ERROR; |
setcom_001 | 12:a9671b78d24e | 591 | } |
setcom_001 | 12:a9671b78d24e | 592 | |
setcom_001 | 12:a9671b78d24e | 593 | // we read an entire block |
setcom_001 | 12:a9671b78d24e | 594 | if ( !( addr % BlockSize ) ) |
setcom_001 | 12:a9671b78d24e | 595 | { |
setcom_001 | 12:a9671b78d24e | 596 | disk_read( ( char * )page, addr / BlockSize ); |
setcom_001 | 12:a9671b78d24e | 597 | } |
setcom_001 | 12:a9671b78d24e | 598 | |
setcom_001 | 12:a9671b78d24e | 599 | // write data which are in RAM |
setcom_001 | 12:a9671b78d24e | 600 | writeNB( EPBULK_IN, &page[addr % BlockSize], n, MAX_PACKET_SIZE_EPBULK ); |
setcom_001 | 12:a9671b78d24e | 601 | addr += n; |
setcom_001 | 12:a9671b78d24e | 602 | length -= n; |
setcom_001 | 12:a9671b78d24e | 603 | csw.DataResidue -= n; |
setcom_001 | 12:a9671b78d24e | 604 | |
setcom_001 | 12:a9671b78d24e | 605 | if ( !length || ( stage != PROCESS_CBW ) ) |
setcom_001 | 12:a9671b78d24e | 606 | { |
setcom_001 | 12:a9671b78d24e | 607 | csw.Status = ( stage == PROCESS_CBW ) ? CSW_PASSED : CSW_FAILED; |
setcom_001 | 12:a9671b78d24e | 608 | stage = ( stage == PROCESS_CBW ) ? SEND_CSW : stage; |
setcom_001 | 12:a9671b78d24e | 609 | } |
setcom_001 | 12:a9671b78d24e | 610 | } |
setcom_001 | 12:a9671b78d24e | 611 | |
setcom_001 | 12:a9671b78d24e | 612 | |
setcom_001 | 12:a9671b78d24e | 613 | bool USBMSD::infoTransfer ( void ) |
setcom_001 | 12:a9671b78d24e | 614 | { |
setcom_001 | 12:a9671b78d24e | 615 | uint32_t n; |
setcom_001 | 12:a9671b78d24e | 616 | // Logical Block Address of First Block |
setcom_001 | 12:a9671b78d24e | 617 | n = ( cbw.CB[2] << 24 ) | ( cbw.CB[3] << 16 ) | ( cbw.CB[4] << 8 ) | ( cbw.CB[5] << 0 ); |
setcom_001 | 12:a9671b78d24e | 618 | addr = n * BlockSize; |
setcom_001 | 12:a9671b78d24e | 619 | |
setcom_001 | 12:a9671b78d24e | 620 | // Number of Blocks to transfer |
setcom_001 | 12:a9671b78d24e | 621 | switch ( cbw.CB[0] ) |
setcom_001 | 12:a9671b78d24e | 622 | { |
setcom_001 | 12:a9671b78d24e | 623 | case READ10: |
setcom_001 | 12:a9671b78d24e | 624 | case WRITE10: |
setcom_001 | 12:a9671b78d24e | 625 | case VERIFY10: |
setcom_001 | 12:a9671b78d24e | 626 | n = ( cbw.CB[7] << 8 ) | ( cbw.CB[8] << 0 ); |
setcom_001 | 12:a9671b78d24e | 627 | break; |
setcom_001 | 12:a9671b78d24e | 628 | |
setcom_001 | 12:a9671b78d24e | 629 | case READ12: |
setcom_001 | 12:a9671b78d24e | 630 | case WRITE12: |
setcom_001 | 12:a9671b78d24e | 631 | n = ( cbw.CB[6] << 24 ) | ( cbw.CB[7] << 16 ) | ( cbw.CB[8] << 8 ) | ( cbw.CB[9] << 0 ); |
setcom_001 | 12:a9671b78d24e | 632 | break; |
setcom_001 | 12:a9671b78d24e | 633 | } |
setcom_001 | 12:a9671b78d24e | 634 | |
setcom_001 | 12:a9671b78d24e | 635 | length = n * BlockSize; |
setcom_001 | 12:a9671b78d24e | 636 | |
setcom_001 | 12:a9671b78d24e | 637 | if ( !cbw.DataLength ) // host requests no data |
setcom_001 | 12:a9671b78d24e | 638 | { |
setcom_001 | 12:a9671b78d24e | 639 | csw.Status = CSW_FAILED; |
setcom_001 | 12:a9671b78d24e | 640 | sendCSW(); |
setcom_001 | 12:a9671b78d24e | 641 | return false; |
setcom_001 | 12:a9671b78d24e | 642 | } |
setcom_001 | 12:a9671b78d24e | 643 | |
setcom_001 | 12:a9671b78d24e | 644 | if ( cbw.DataLength != length ) |
setcom_001 | 12:a9671b78d24e | 645 | { |
setcom_001 | 12:a9671b78d24e | 646 | if ( ( cbw.Flags & 0x80 ) != 0 ) |
setcom_001 | 12:a9671b78d24e | 647 | { |
setcom_001 | 12:a9671b78d24e | 648 | stallEndpoint( EPBULK_IN ); |
setcom_001 | 12:a9671b78d24e | 649 | } |
setcom_001 | 12:a9671b78d24e | 650 | else |
setcom_001 | 12:a9671b78d24e | 651 | { |
setcom_001 | 12:a9671b78d24e | 652 | stallEndpoint( EPBULK_OUT ); |
setcom_001 | 12:a9671b78d24e | 653 | } |
setcom_001 | 12:a9671b78d24e | 654 | |
setcom_001 | 12:a9671b78d24e | 655 | csw.Status = CSW_FAILED; |
setcom_001 | 12:a9671b78d24e | 656 | sendCSW(); |
setcom_001 | 12:a9671b78d24e | 657 | return false; |
setcom_001 | 12:a9671b78d24e | 658 | } |
setcom_001 | 12:a9671b78d24e | 659 | |
setcom_001 | 12:a9671b78d24e | 660 | return true; |
setcom_001 | 12:a9671b78d24e | 661 | } |
setcom_001 | 12:a9671b78d24e | 662 | |
setcom_001 | 12:a9671b78d24e | 663 | |
setcom_001 | 12:a9671b78d24e | 664 | |
setcom_001 | 12:a9671b78d24e | 665 | |
setcom_001 | 12:a9671b78d24e | 666 | |
setcom_001 | 12:a9671b78d24e | 667 | // Called in ISR context |
setcom_001 | 12:a9671b78d24e | 668 | // Set configuration. Return false if the |
setcom_001 | 12:a9671b78d24e | 669 | // configuration is not supported. |
setcom_001 | 12:a9671b78d24e | 670 | bool USBMSD::USBCallback_setConfiguration( uint8_t configuration ) |
setcom_001 | 12:a9671b78d24e | 671 | { |
setcom_001 | 12:a9671b78d24e | 672 | if ( configuration != DEFAULT_CONFIGURATION ) |
setcom_001 | 12:a9671b78d24e | 673 | { |
setcom_001 | 12:a9671b78d24e | 674 | return false; |
setcom_001 | 12:a9671b78d24e | 675 | } |
setcom_001 | 12:a9671b78d24e | 676 | |
setcom_001 | 12:a9671b78d24e | 677 | // Configure endpoints > 0 |
setcom_001 | 12:a9671b78d24e | 678 | addEndpoint( EPBULK_IN, MAX_PACKET_SIZE_EPBULK ); |
setcom_001 | 12:a9671b78d24e | 679 | addEndpoint( EPBULK_OUT, MAX_PACKET_SIZE_EPBULK ); |
setcom_001 | 12:a9671b78d24e | 680 | //activate readings |
setcom_001 | 12:a9671b78d24e | 681 | readStart( EPBULK_OUT, MAX_PACKET_SIZE_EPBULK ); |
setcom_001 | 12:a9671b78d24e | 682 | return true; |
setcom_001 | 12:a9671b78d24e | 683 | } |
setcom_001 | 12:a9671b78d24e | 684 | |
setcom_001 | 12:a9671b78d24e | 685 | |
setcom_001 | 12:a9671b78d24e | 686 | uint8_t *USBMSD::stringIinterfaceDesc() |
setcom_001 | 12:a9671b78d24e | 687 | { |
setcom_001 | 12:a9671b78d24e | 688 | static uint8_t stringIinterfaceDescriptor[] = |
setcom_001 | 12:a9671b78d24e | 689 | { |
setcom_001 | 12:a9671b78d24e | 690 | 0x08, //bLength |
setcom_001 | 12:a9671b78d24e | 691 | STRING_DESCRIPTOR, //bDescriptorType 0x03 |
setcom_001 | 12:a9671b78d24e | 692 | 'M', 0, 'S', 0, 'D', 0 //bString iInterface - MSD |
setcom_001 | 12:a9671b78d24e | 693 | }; |
setcom_001 | 12:a9671b78d24e | 694 | return stringIinterfaceDescriptor; |
setcom_001 | 12:a9671b78d24e | 695 | } |
setcom_001 | 12:a9671b78d24e | 696 | |
setcom_001 | 12:a9671b78d24e | 697 | uint8_t *USBMSD::stringIproductDesc() |
setcom_001 | 12:a9671b78d24e | 698 | { |
setcom_001 | 12:a9671b78d24e | 699 | static uint8_t stringIproductDescriptor[] = |
setcom_001 | 12:a9671b78d24e | 700 | { |
setcom_001 | 12:a9671b78d24e | 701 | 0x12, //bLength |
setcom_001 | 12:a9671b78d24e | 702 | STRING_DESCRIPTOR, //bDescriptorType 0x03 |
setcom_001 | 12:a9671b78d24e | 703 | 'M', 0, 'b', 0, 'e', 0, 'd', 0, ' ', 0, 'M', 0, 'S', 0, 'D', 0 //bString iProduct - Mbed Audio |
setcom_001 | 12:a9671b78d24e | 704 | }; |
setcom_001 | 12:a9671b78d24e | 705 | return stringIproductDescriptor; |
setcom_001 | 12:a9671b78d24e | 706 | } |
setcom_001 | 12:a9671b78d24e | 707 | |
setcom_001 | 12:a9671b78d24e | 708 | |
setcom_001 | 12:a9671b78d24e | 709 | uint8_t *USBMSD::configurationDesc() |
setcom_001 | 12:a9671b78d24e | 710 | { |
setcom_001 | 12:a9671b78d24e | 711 | static uint8_t configDescriptor[] = |
setcom_001 | 12:a9671b78d24e | 712 | { |
setcom_001 | 12:a9671b78d24e | 713 | |
setcom_001 | 12:a9671b78d24e | 714 | // Configuration 1 |
setcom_001 | 12:a9671b78d24e | 715 | 9, // bLength |
setcom_001 | 12:a9671b78d24e | 716 | 2, // bDescriptorType |
setcom_001 | 12:a9671b78d24e | 717 | LSB( 9 + 9 + 7 + 7 ), // wTotalLength |
setcom_001 | 12:a9671b78d24e | 718 | MSB( 9 + 9 + 7 + 7 ), |
setcom_001 | 12:a9671b78d24e | 719 | 0x01, // bNumInterfaces |
setcom_001 | 12:a9671b78d24e | 720 | 0x01, // bConfigurationValue: 0x01 is used to select this configuration |
setcom_001 | 12:a9671b78d24e | 721 | 0x00, // iConfiguration: no string to describe this configuration |
setcom_001 | 12:a9671b78d24e | 722 | 0xC0, // bmAttributes |
setcom_001 | 12:a9671b78d24e | 723 | 100, // bMaxPower, device power consumption is 100 mA |
setcom_001 | 12:a9671b78d24e | 724 | |
setcom_001 | 12:a9671b78d24e | 725 | // Interface 0, Alternate Setting 0, MSC Class |
setcom_001 | 12:a9671b78d24e | 726 | 9, // bLength |
setcom_001 | 12:a9671b78d24e | 727 | 4, // bDescriptorType |
setcom_001 | 12:a9671b78d24e | 728 | 0x00, // bInterfaceNumber |
setcom_001 | 12:a9671b78d24e | 729 | 0x00, // bAlternateSetting |
setcom_001 | 12:a9671b78d24e | 730 | 0x02, // bNumEndpoints |
setcom_001 | 12:a9671b78d24e | 731 | 0x08, // bInterfaceClass |
setcom_001 | 12:a9671b78d24e | 732 | 0x06, // bInterfaceSubClass |
setcom_001 | 12:a9671b78d24e | 733 | 0x50, // bInterfaceProtocol |
setcom_001 | 12:a9671b78d24e | 734 | 0x04, // iInterface |
setcom_001 | 12:a9671b78d24e | 735 | |
setcom_001 | 12:a9671b78d24e | 736 | // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 |
setcom_001 | 12:a9671b78d24e | 737 | 7, // bLength |
setcom_001 | 12:a9671b78d24e | 738 | 5, // bDescriptorType |
setcom_001 | 12:a9671b78d24e | 739 | PHY_TO_DESC( EPBULK_IN ), // bEndpointAddress |
setcom_001 | 12:a9671b78d24e | 740 | 0x02, // bmAttributes (0x02=bulk) |
setcom_001 | 12:a9671b78d24e | 741 | LSB( MAX_PACKET_SIZE_EPBULK ), // wMaxPacketSize (LSB) |
setcom_001 | 12:a9671b78d24e | 742 | MSB( MAX_PACKET_SIZE_EPBULK ), // wMaxPacketSize (MSB) |
setcom_001 | 12:a9671b78d24e | 743 | 0, // bInterval |
setcom_001 | 12:a9671b78d24e | 744 | |
setcom_001 | 12:a9671b78d24e | 745 | // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 |
setcom_001 | 12:a9671b78d24e | 746 | 7, // bLength |
setcom_001 | 12:a9671b78d24e | 747 | 5, // bDescriptorType |
setcom_001 | 12:a9671b78d24e | 748 | PHY_TO_DESC( EPBULK_OUT ), // bEndpointAddress |
setcom_001 | 12:a9671b78d24e | 749 | 0x02, // bmAttributes (0x02=bulk) |
setcom_001 | 12:a9671b78d24e | 750 | LSB( MAX_PACKET_SIZE_EPBULK ), // wMaxPacketSize (LSB) |
setcom_001 | 12:a9671b78d24e | 751 | MSB( MAX_PACKET_SIZE_EPBULK ), // wMaxPacketSize (MSB) |
setcom_001 | 12:a9671b78d24e | 752 | 0 // bInterval |
setcom_001 | 12:a9671b78d24e | 753 | }; |
setcom_001 | 12:a9671b78d24e | 754 | return configDescriptor; |
setcom_001 | 12:a9671b78d24e | 755 | } |
setcom_001 | 12:a9671b78d24e | 756 |