1 /* Copyright (c) 2010-2011 mbed.org, MIT License
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:
9 * The above copyright notice and this permission notice shall be included in all copies or
10 * substantial portions of the Software.
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.
25 #define WRITE_PROTECT 0x04
27 #define CBW_Signature 0x43425355
28 #define CSW_Signature 0x53425355
31 #define TEST_UNIT_READY 0x00
32 #define REQUEST_SENSE 0x03
33 #define FORMAT_UNIT 0x04
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
46 #define MODE_SELECT10 0x55
47 #define MODE_SENSE10 0x5A
49 // MSC class specific requests
50 #define MSC_REQUEST_RESET 0xFF
51 #define MSC_REQUEST_GET_MAX_LUN 0xFE
53 #define DEFAULT_CONFIGURATION (1)
56 #define MAX_PACKET MAX_PACKET_SIZE_EPBULK
66 USBMSD::USBMSD(uint16_t vendor_id
, uint16_t product_id
, uint16_t product_release
): USBDevice(vendor_id
, product_id
, product_release
) {
71 // Called in ISR context to process a class specific request
72 bool USBMSD::USBCallback_request(void) {
75 CONTROL_TRANSFER
* transfer
= getTransferPtr();
76 static uint8_t maxLUN
[1] = {0};
78 if (transfer
->setup
.bmRequestType
.Type
== CLASS_TYPE
) {
79 switch (transfer
->setup
.bRequest
) {
80 case MSC_REQUEST_RESET
:
84 case MSC_REQUEST_GET_MAX_LUN
:
85 transfer
->remaining
= 1;
86 transfer
->ptr
= maxLUN
;
87 transfer
->direction
= DEVICE_TO_HOST
;
99 bool USBMSD::connect() {
101 //disk initialization
102 if (disk_status() & NO_INIT
) {
103 if (disk_initialize()) {
108 // get number of blocks
109 BlockCount
= disk_sectors();
112 MemorySize
= disk_size();
114 if (BlockCount
>= 0) {
115 BlockSize
= MemorySize
/ BlockCount
;
116 if (BlockSize
!= 0) {
117 page
= (uint8_t *)malloc(BlockSize
* sizeof(uint8_t));
126 USBDevice::connect();
131 void USBMSD::reset() {
136 // Called in ISR context called when a data is received
137 bool USBMSD::EP2_OUT_callback() {
139 uint8_t buf
[MAX_PACKET_SIZE_EPBULK
];
140 readEP(EPBULK_OUT
, buf
, &size
, MAX_PACKET_SIZE_EPBULK
);
142 // the device has to decode the CBW received
144 CBWDecode(buf
, size
);
147 // the device has to receive data from the host
152 memoryWrite(buf
, size
);
155 memoryVerify(buf
, size
);
160 // an error has occured: stall endpoint and send CSW
162 stallEndpoint(EPBULK_OUT
);
163 csw
.Status
= CSW_ERROR
;
168 //reactivate readings on the OUT bulk endpoint
169 readStart(EPBULK_OUT
, MAX_PACKET_SIZE_EPBULK
);
173 // Called in ISR context when a data has been transferred
174 bool USBMSD::EP2_IN_callback() {
177 // the device has to send data to the host
187 //the device has to send a CSW
192 // an error has occured
194 stallEndpoint(EPBULK_IN
);
198 // the host has received the CSW -> we wait a CBW
207 void USBMSD::memoryWrite (uint8_t * buf
, uint16_t size
) {
209 if ((addr
+ size
) > MemorySize
) {
210 size
= MemorySize
- addr
;
212 stallEndpoint(EPBULK_OUT
);
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
];
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
);
228 csw
.DataResidue
-= size
;
230 if ((!length
) || (stage
!= PROCESS_CBW
)) {
231 csw
.Status
= (stage
== ERROR
) ? CSW_FAILED
: CSW_PASSED
;
236 void USBMSD::memoryVerify (uint8_t * buf
, uint16_t size
) {
239 if ((addr
+ size
) > MemorySize
) {
240 size
= MemorySize
- addr
;
242 stallEndpoint(EPBULK_OUT
);
245 // beginning of a new block -> load a whole block in RAM
246 if (!(addr
%BlockSize
))
247 disk_read((char *)page
, addr
/BlockSize
);
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
]) {
259 csw
.DataResidue
-= size
;
261 if ( !length
|| (stage
!= PROCESS_CBW
)) {
262 csw
.Status
= (memOK
&& (stage
== PROCESS_CBW
)) ? CSW_PASSED
: CSW_FAILED
;
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', ' ', ' ', ' ',
275 if (!write(inquiry
, sizeof(inquiry
))) {
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,
290 (BlockSize
>> 16) & 0xff,
291 (BlockSize
>> 8) & 0xff,
292 (BlockSize
>> 0) & 0xff,
294 if (!write(capacity
, sizeof(capacity
))) {
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,
308 (BlockSize
>> 24) & 0xff,
309 (BlockSize
>> 16) & 0xff,
310 (BlockSize
>> 8) & 0xff,
311 (BlockSize
>> 0) & 0xff,
313 if (!write(capacity
, sizeof(capacity
))) {
319 bool USBMSD::write (uint8_t * buf
, uint16_t size
) {
321 if (size
>= cbw
.DataLength
) {
322 size
= cbw
.DataLength
;
326 if (!writeNB(EPBULK_IN
, buf
, size
, MAX_PACKET_SIZE_EPBULK
)) {
330 csw
.DataResidue
-= size
;
331 csw
.Status
= CSW_PASSED
;
336 bool USBMSD::modeSense6 (void) {
337 uint8_t sense6
[] = { 0x03, 0x00, 0x00, 0x00 };
338 if (!write(sense6
, sizeof(sense6
))) {
344 void USBMSD::sendCSW() {
345 csw
.Signature
= CSW_Signature
;
346 writeNB(EPBULK_IN
, (uint8_t *)&csw
, sizeof(CSW
), MAX_PACKET_SIZE_EPBULK
);
350 bool USBMSD::requestSense (void) {
351 uint8_t request_sense
[] = {
354 0x05, // Sense Key: illegal request
372 if (!write(request_sense
, sizeof(request_sense
))) {
379 void USBMSD::fail() {
380 csw
.Status
= CSW_FAILED
;
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
) {
390 csw
.DataResidue
= cbw
.DataLength
;
391 if ((cbw
.CBLength
< 1) || (cbw
.CBLength
> 16) ) {
395 case TEST_UNIT_READY
:
407 case READ_FORMAT_CAPACITIES
:
408 readFormatCapacity();
415 if (infoTransfer()) {
416 if ((cbw
.Flags
& 0x80)) {
420 stallEndpoint(EPBULK_OUT
);
421 csw
.Status
= CSW_ERROR
;
428 if (infoTransfer()) {
429 if (!(cbw
.Flags
& 0x80)) {
432 stallEndpoint(EPBULK_IN
);
433 csw
.Status
= CSW_ERROR
;
439 if (!(cbw
.CB
[1] & 0x02)) {
440 csw
.Status
= CSW_PASSED
;
444 if (infoTransfer()) {
445 if (!(cbw
.Flags
& 0x80)) {
449 stallEndpoint(EPBULK_IN
);
450 csw
.Status
= CSW_ERROR
;
464 void USBMSD::testUnitReady (void) {
466 if (cbw
.DataLength
!= 0) {
467 if ((cbw
.Flags
& 0x80) != 0) {
468 stallEndpoint(EPBULK_IN
);
470 stallEndpoint(EPBULK_OUT
);
474 csw
.Status
= CSW_PASSED
;
479 void USBMSD::memoryRead (void) {
482 n
= (length
> MAX_PACKET
) ? MAX_PACKET
: length
;
484 if ((addr
+ n
) > MemorySize
) {
485 n
= MemorySize
- addr
;
489 // we read an entire block
490 if (!(addr
%BlockSize
))
491 disk_read((char *)page
, addr
/BlockSize
);
493 // write data which are in RAM
494 writeNB(EPBULK_IN
, &page
[addr
%BlockSize
], n
, MAX_PACKET_SIZE_EPBULK
);
499 csw
.DataResidue
-= n
;
501 if ( !length
|| (stage
!= PROCESS_CBW
)) {
502 csw
.Status
= (stage
== PROCESS_CBW
) ? CSW_PASSED
: CSW_FAILED
;
503 stage
= (stage
== PROCESS_CBW
) ? SEND_CSW
: stage
;
508 bool USBMSD::infoTransfer (void) {
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);
514 addr
= n
* BlockSize
;
516 // Number of Blocks to transfer
521 n
= (cbw
.CB
[7] << 8) | (cbw
.CB
[8] << 0);
526 n
= (cbw
.CB
[6] << 24) | (cbw
.CB
[7] << 16) | (cbw
.CB
[8] << 8) | (cbw
.CB
[9] << 0);
530 length
= n
* BlockSize
;
532 if (!cbw
.DataLength
) { // host requests no data
533 csw
.Status
= CSW_FAILED
;
538 if (cbw
.DataLength
!= length
) {
539 if ((cbw
.Flags
& 0x80) != 0) {
540 stallEndpoint(EPBULK_IN
);
542 stallEndpoint(EPBULK_OUT
);
545 csw
.Status
= CSW_FAILED
;
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
) {
565 // Configure endpoints > 0
566 addEndpoint(EPBULK_IN
, MAX_PACKET_SIZE_EPBULK
);
567 addEndpoint(EPBULK_OUT
, MAX_PACKET_SIZE_EPBULK
);
570 readStart(EPBULK_OUT
, MAX_PACKET_SIZE_EPBULK
);
575 uint8_t * USBMSD::stringIinterfaceDesc() {
576 static uint8_t stringIinterfaceDescriptor
[] = {
578 STRING_DESCRIPTOR
, //bDescriptorType 0x03
579 'M',0,'S',0,'D',0 //bString iInterface - MSD
581 return stringIinterfaceDescriptor
;
584 uint8_t * USBMSD::stringIproductDesc() {
585 static uint8_t stringIproductDescriptor
[] = {
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
590 return stringIproductDescriptor
;
594 uint8_t * USBMSD::configurationDesc() {
595 static uint8_t configDescriptor
[] = {
599 2, // bDescriptorType
600 LSB(9 + 9 + 7 + 7), // wTotalLength
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
608 // Interface 0, Alternate Setting 0, MSC Class
610 4, // bDescriptorType
611 0x00, // bInterfaceNumber
612 0x00, // bAlternateSetting
613 0x02, // bNumEndpoints
614 0x08, // bInterfaceClass
615 0x06, // bInterfaceSubClass
616 0x50, // bInterfaceProtocol
619 // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
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)
628 // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
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)
637 return configDescriptor
;