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