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