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
) {
68 memset((void *)&cbw
, 0, sizeof(CBW
));
69 memset((void *)&csw
, 0, sizeof(CSW
));
78 // Called in ISR context to process a class specific request
79 bool USBMSD::USBCallback_request(void) {
82 CONTROL_TRANSFER
* transfer
= getTransferPtr();
83 static uint8_t maxLUN
[1] = {0};
85 if (transfer
->setup
.bmRequestType
.Type
== CLASS_TYPE
) {
86 switch (transfer
->setup
.bRequest
) {
87 case MSC_REQUEST_RESET
:
91 case MSC_REQUEST_GET_MAX_LUN
:
92 transfer
->remaining
= 1;
93 transfer
->ptr
= maxLUN
;
94 transfer
->direction
= DEVICE_TO_HOST
;
106 bool USBMSD::connect(bool blocking
) {
107 //disk initialization
108 if (disk_status() & NO_INIT
) {
109 if (disk_initialize()) {
114 // get number of blocks
115 BlockCount
= disk_sectors();
118 MemorySize
= disk_size();
120 if (BlockCount
> 0) {
121 BlockSize
= MemorySize
/ BlockCount
;
122 if (BlockSize
!= 0) {
124 page
= (uint8_t *)malloc(BlockSize
* sizeof(uint8_t));
133 USBDevice::connect(blocking
);
137 void USBMSD::disconnect() {
138 USBDevice::disconnect();
139 //De-allocate MSD page size:
144 void USBMSD::reset() {
149 // Called in ISR context called when a data is received
150 bool USBMSD::EPBULK_OUT_callback() {
152 uint8_t buf
[MAX_PACKET_SIZE_EPBULK
];
153 readEP(EPBULK_OUT
, buf
, &size
, MAX_PACKET_SIZE_EPBULK
);
155 // the device has to decode the CBW received
157 CBWDecode(buf
, size
);
160 // the device has to receive data from the host
165 memoryWrite(buf
, size
);
168 memoryVerify(buf
, size
);
173 // an error has occured: stall endpoint and send CSW
175 stallEndpoint(EPBULK_OUT
);
176 csw
.Status
= CSW_ERROR
;
181 //reactivate readings on the OUT bulk endpoint
182 readStart(EPBULK_OUT
, MAX_PACKET_SIZE_EPBULK
);
186 // Called in ISR context when a data has been transferred
187 bool USBMSD::EPBULK_IN_callback() {
190 // the device has to send data to the host
200 //the device has to send a CSW
205 // the host has received the CSW -> we wait a CBW
210 // an error has occured
212 stallEndpoint(EPBULK_IN
);
220 void USBMSD::memoryWrite (uint8_t * buf
, uint16_t size
) {
222 if ((addr
+ size
) > MemorySize
) {
223 size
= MemorySize
- addr
;
225 stallEndpoint(EPBULK_OUT
);
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
];
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);
241 csw
.DataResidue
-= size
;
243 if ((!length
) || (stage
!= PROCESS_CBW
)) {
244 csw
.Status
= (stage
== ERROR
) ? CSW_FAILED
: CSW_PASSED
;
249 void USBMSD::memoryVerify (uint8_t * buf
, uint16_t size
) {
252 if ((addr
+ size
) > MemorySize
) {
253 size
= MemorySize
- addr
;
255 stallEndpoint(EPBULK_OUT
);
258 // beginning of a new block -> load a whole block in RAM
259 if (!(addr
%BlockSize
))
260 disk_read(page
, addr
/BlockSize
, 1);
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
]) {
272 csw
.DataResidue
-= size
;
274 if ( !length
|| (stage
!= PROCESS_CBW
)) {
275 csw
.Status
= (memOK
&& (stage
== PROCESS_CBW
)) ? CSW_PASSED
: CSW_FAILED
;
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', ' ', ' ', ' ',
288 if (!write(inquiry
, sizeof(inquiry
))) {
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),
303 (uint8_t)((BlockSize
>> 16) & 0xff),
304 (uint8_t)((BlockSize
>> 8) & 0xff),
305 (uint8_t)((BlockSize
>> 0) & 0xff),
307 if (!write(capacity
, sizeof(capacity
))) {
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),
321 (uint8_t)((BlockSize
>> 24) & 0xff),
322 (uint8_t)((BlockSize
>> 16) & 0xff),
323 (uint8_t)((BlockSize
>> 8) & 0xff),
324 (uint8_t)((BlockSize
>> 0) & 0xff),
326 if (!write(capacity
, sizeof(capacity
))) {
332 bool USBMSD::write (uint8_t * buf
, uint16_t size
) {
334 if (size
>= cbw
.DataLength
) {
335 size
= cbw
.DataLength
;
339 if (!writeNB(EPBULK_IN
, buf
, size
, MAX_PACKET_SIZE_EPBULK
)) {
343 csw
.DataResidue
-= size
;
344 csw
.Status
= CSW_PASSED
;
349 bool USBMSD::modeSense6 (void) {
350 uint8_t sense6
[] = { 0x03, 0x00, 0x00, 0x00 };
351 if (!write(sense6
, sizeof(sense6
))) {
357 void USBMSD::sendCSW() {
358 csw
.Signature
= CSW_Signature
;
359 writeNB(EPBULK_IN
, (uint8_t *)&csw
, sizeof(CSW
), MAX_PACKET_SIZE_EPBULK
);
363 bool USBMSD::requestSense (void) {
364 uint8_t request_sense
[] = {
367 0x05, // Sense Key: illegal request
385 if (!write(request_sense
, sizeof(request_sense
))) {
392 void USBMSD::fail() {
393 csw
.Status
= CSW_FAILED
;
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
) {
403 csw
.DataResidue
= cbw
.DataLength
;
404 if ((cbw
.CBLength
< 1) || (cbw
.CBLength
> 16) ) {
408 case TEST_UNIT_READY
:
420 case READ_FORMAT_CAPACITIES
:
421 readFormatCapacity();
428 if (infoTransfer()) {
429 if ((cbw
.Flags
& 0x80)) {
433 stallEndpoint(EPBULK_OUT
);
434 csw
.Status
= CSW_ERROR
;
441 if (infoTransfer()) {
442 if (!(cbw
.Flags
& 0x80)) {
445 stallEndpoint(EPBULK_IN
);
446 csw
.Status
= CSW_ERROR
;
452 if (!(cbw
.CB
[1] & 0x02)) {
453 csw
.Status
= CSW_PASSED
;
457 if (infoTransfer()) {
458 if (!(cbw
.Flags
& 0x80)) {
462 stallEndpoint(EPBULK_IN
);
463 csw
.Status
= CSW_ERROR
;
469 csw
.Status
= CSW_PASSED
;
481 void USBMSD::testUnitReady (void) {
483 if (cbw
.DataLength
!= 0) {
484 if ((cbw
.Flags
& 0x80) != 0) {
485 stallEndpoint(EPBULK_IN
);
487 stallEndpoint(EPBULK_OUT
);
491 csw
.Status
= CSW_PASSED
;
496 void USBMSD::memoryRead (void) {
499 n
= (length
> MAX_PACKET
) ? MAX_PACKET
: length
;
501 if ((addr
+ n
) > MemorySize
) {
502 n
= MemorySize
- addr
;
506 // we read an entire block
507 if (!(addr
%BlockSize
))
508 disk_read(page
, addr
/BlockSize
, 1);
510 // write data which are in RAM
511 writeNB(EPBULK_IN
, &page
[addr
%BlockSize
], n
, MAX_PACKET_SIZE_EPBULK
);
516 csw
.DataResidue
-= n
;
518 if ( !length
|| (stage
!= PROCESS_CBW
)) {
519 csw
.Status
= (stage
== PROCESS_CBW
) ? CSW_PASSED
: CSW_FAILED
;
520 stage
= (stage
== PROCESS_CBW
) ? SEND_CSW
: stage
;
525 bool USBMSD::infoTransfer (void) {
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);
531 addr
= n
* BlockSize
;
533 // Number of Blocks to transfer
538 n
= (cbw
.CB
[7] << 8) | (cbw
.CB
[8] << 0);
543 n
= (cbw
.CB
[6] << 24) | (cbw
.CB
[7] << 16) | (cbw
.CB
[8] << 8) | (cbw
.CB
[9] << 0);
547 length
= n
* BlockSize
;
549 if (!cbw
.DataLength
) { // host requests no data
550 csw
.Status
= CSW_FAILED
;
555 if (cbw
.DataLength
!= length
) {
556 if ((cbw
.Flags
& 0x80) != 0) {
557 stallEndpoint(EPBULK_IN
);
559 stallEndpoint(EPBULK_OUT
);
562 csw
.Status
= CSW_FAILED
;
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
) {
582 // Configure endpoints > 0
583 addEndpoint(EPBULK_IN
, MAX_PACKET_SIZE_EPBULK
);
584 addEndpoint(EPBULK_OUT
, MAX_PACKET_SIZE_EPBULK
);
587 readStart(EPBULK_OUT
, MAX_PACKET_SIZE_EPBULK
);
592 uint8_t * USBMSD::stringIinterfaceDesc() {
593 static uint8_t stringIinterfaceDescriptor
[] = {
595 STRING_DESCRIPTOR
, //bDescriptorType 0x03
596 'M',0,'S',0,'D',0 //bString iInterface - MSD
598 return stringIinterfaceDescriptor
;
601 uint8_t * USBMSD::stringIproductDesc() {
602 static uint8_t stringIproductDescriptor
[] = {
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
607 return stringIproductDescriptor
;
611 uint8_t * USBMSD::configurationDesc() {
612 static uint8_t configDescriptor
[] = {
616 2, // bDescriptorType
617 LSB(9 + 9 + 7 + 7), // wTotalLength
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
625 // Interface 0, Alternate Setting 0, MSC Class
627 4, // bDescriptorType
628 0x00, // bInterfaceNumber
629 0x00, // bAlternateSetting
630 0x02, // bNumEndpoints
631 0x08, // bInterfaceClass
632 0x06, // bInterfaceSubClass
633 0x50, // bInterfaceProtocol
636 // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
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)
645 // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
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)
654 return configDescriptor
;