SD card interface

Committer:
lharoon
Date:
Mon Oct 08 11:14:07 2012 +0000
Revision:
0:22612ae617a0
1st edition

Who changed what in which revision?

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