Slingshot Controller

Dependencies:   ADXL345 DebounceIn USBDevice mbed

Committer:
Brandon
Date:
Wed Oct 17 16:33:04 2012 +0000
Revision:
1:2721dc2acc2c
Parent:
0:cf17ea89fd09
Updated comments, added names, cleaned old code.

Who changed what in which revision?

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