]> git.gir.st - tmk_keyboard.git/blob - tmk_core/tool/mbed/mbed-sdk/libraries/USBDevice/USBMSD/USBMSD.cpp
Merge commit '1fe4406f374291ab2e86e95a97341fd9c475fcb8'
[tmk_keyboard.git] / tmk_core / 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 }
Imprint / Impressum