libopencm3
A free/libre/open-source firmware library for various ARM Cortex-M3 microcontrollers.
usb_msc.c
Go to the documentation of this file.
1/*
2 * This file is part of the libopencm3 project.
3 *
4 * Copyright (C) 2013 Weston Schmidt <weston_schmidt@alumni.purdue.edu>
5 * Copyright (C) 2013 Pavol Rusnak <stick@gk2.sk>
6 *
7 * This library is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <stdint.h>
22#include <stdlib.h>
23#include <string.h>
25#include <libopencm3/usb/usbd.h>
26#include <libopencm3/usb/msc.h>
27#include "usb_private.h"
28
29/* Definitions of Mass Storage Class from:
30 *
31 * (A) "Universal Serial Bus Mass Storage Class Bulk-Only Transport
32 * Revision 1.0"
33 *
34 * (B) "Universal Serial Bus Mass Storage Class Specification Overview
35 * Revision 1.0"
36 */
37
38/* Command Block Wrapper */
39#define CBW_SIGNATURE 0x43425355
40#define CBW_STATUS_SUCCESS 0
41#define CBW_STATUS_FAILED 1
42#define CBW_STATUS_PHASE_ERROR 2
43
44/* Command Status Wrapper */
45#define CSW_SIGNATURE 0x53425355
46#define CSW_STATUS_SUCCESS 0
47#define CSW_STATUS_FAILED 1
48#define CSW_STATUS_PHASE_ERROR 2
49
50/* Implemented SCSI Commands */
51#define SCSI_TEST_UNIT_READY 0x00
52#define SCSI_REQUEST_SENSE 0x03
53#define SCSI_FORMAT_UNIT 0x04
54#define SCSI_READ_6 0x08
55#define SCSI_WRITE_6 0x0A
56#define SCSI_INQUIRY 0x12
57#define SCSI_MODE_SENSE_6 0x1A
58#define SCSI_SEND_DIAGNOSTIC 0x1D
59#define SCSI_READ_CAPACITY 0x25
60#define SCSI_READ_10 0x28
61
62
63/* Required SCSI Commands */
64
65/* Optional SCSI Commands */
66#define SCSI_REPORT_LUNS 0xA0
67#define SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
68#define SCSI_MODE_SELECT_6 0x15
69#define SCSI_MODE_SELECT_10 0x55
70#define SCSI_MODE_SENSE_10 0x5A
71#define SCSI_READ_12 0xA8
72#define SCSI_READ_FORMAT_CAPACITIES 0x23
73#define SCSI_READ_TOC_PMA_ATIP 0x43
74#define SCSI_START_STOP_UNIT 0x1B
75#define SCSI_SYNCHRONIZE_CACHE 0x35
76#define SCSI_VERIFY 0x2F
77#define SCSI_WRITE_10 0x2A
78#define SCSI_WRITE_12 0xAA
79
80/* The sense codes */
96};
97
98enum sbc_asc {
111
118
123
126 uint32_t dCBWTag;
128 uint8_t bmCBWFlags;
129 uint8_t bCBWLUN;
131 uint8_t CBWCB[16];
132} __attribute__((packed));
133
136 uint32_t dCSWTag;
138 uint8_t bCSWStatus;
139} __attribute__((packed));
140
142 uint8_t key;
143 uint8_t asc;
144 uint8_t ascq;
145};
146
148 uint8_t cbw_cnt; /* Read until 31 bytes */
149 union {
151 uint8_t buf[1];
153
156 uint32_t byte_count; /* Either read until equal to
157 bytes_to_read or write until equal
158 to bytes_to_write. */
159 uint32_t lba_start;
160 uint32_t block_count;
162
163 uint8_t msd_buf[512];
164
166 uint8_t csw_sent; /* Write until 13 bytes */
167 union {
169 uint8_t buf[1];
171};
172
175 uint8_t ep_in;
176 uint8_t ep_in_size;
177 uint8_t ep_out;
178 uint8_t ep_out_size;
179
180 const char *vendor_id;
181 const char *product_id;
183 uint32_t block_count;
184
185 int (*read_block)(uint32_t lba, uint8_t *copy_to);
186 int (*write_block)(uint32_t lba, const uint8_t *copy_from);
187
188 void (*lock)(void);
189 void (*unlock)(void);
190
193};
194
196
197/*-- SCSI Base Responses -----------------------------------------------------*/
198
199static const uint8_t _spc3_inquiry_response[36] = {
200 0x00, /* Byte 0: Peripheral Qualifier = 0, Peripheral Device Type = 0 */
201 0x80, /* Byte 1: RMB = 1, Reserved = 0 */
202 0x04, /* Byte 2: Version = 0 */
203 0x02, /* Byte 3: Obsolete = 0, NormACA = 0, HiSup = 0, Response Data Format = 2 */
204 0x20, /* Byte 4: Additional Length (n-4) = 31 + 4 */
205 0x00, /* Byte 5: SCCS = 0, ACC = 0, TPGS = 0, 3PC = 0, Reserved = 0, Protect = 0 */
206 0x00, /* Byte 6: BQue = 0, EncServ = 0, VS = 0, MultiP = 0, MChngr = 0, Obsolete = 0, Addr16 = 0 */
207 0x00, /* Byte 7: Obsolete = 0, Wbus16 = 0, Sync = 0, Linked = 0, CmdQue = 0, VS = 0 */
208 /* Byte 8 - Byte 15: Vendor Identification */
209 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
210 /* Byte 16 - Byte 31: Product Identification */
211 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
212 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
213 /* Byte 32 - Byte 35: Product Revision Level */
214 0x20, 0x20, 0x20, 0x20
215};
216
217static const uint8_t _spc3_request_sense[18] = {
218 0x70, /* Byte 0: VALID = 0, Response Code = 112 */
219 0x00, /* Byte 1: Obsolete = 0 */
220 0x00, /* Byte 2: Filemark = 0, EOM = 0, ILI = 0, Reserved = 0, Sense Key = 0 */
221 /* Byte 3 - Byte 6: Information = 0 */
222 0, 0, 0, 0,
223 0x0a, /* Byte 7: Additional Sense Length = 10 */
224 /* Byte 8 - Byte 11: Command Specific Info = 0 */
225 0, 0, 0, 0,
226 0x00, /* Byte 12: Additional Sense Code (ASC) = 0 */
227 0x00, /* Byte 13: Additional Sense Code Qualifier (ASCQ) = 0 */
228 0x00, /* Byte 14: Field Replaceable Unit Code (FRUC) = 0 */
229 0x00, /* Byte 15: SKSV = 0, SenseKeySpecific[0] = 0 */
230 0x00, /* Byte 16: SenseKeySpecific[0] = 0 */
231 0x00 /* Byte 17: SenseKeySpecific[0] = 0 */
232};
233
234/*-- SCSI Layer --------------------------------------------------------------*/
235
237 enum sbc_sense_key key,
238 enum sbc_asc asc,
239 enum sbc_ascq ascq)
240{
241 ms->sense.key = (uint8_t) key;
242 ms->sense.asc = (uint8_t) asc;
243 ms->sense.ascq = (uint8_t) ascq;
244}
245
247{
252}
253
254static uint8_t *get_cbw_buf(struct usb_msc_trans *trans)
255{
256 return &trans->cbw.cbw.CBWCB[0];
257}
258
260 struct usb_msc_trans *trans,
261 enum trans_event event)
262{
263 if (EVENT_CBW_VALID == event) {
264 uint8_t *buf;
265
266 buf = get_cbw_buf(trans);
267
268 trans->lba_start = (buf[2] << 8) | buf[3];
269 trans->block_count = buf[4];
270 trans->current_block = 0;
271
272 /* TODO: Check the lba & block_count for range. */
273
274 /* both are in terms of 512 byte blocks, so shift by 9 */
275 trans->bytes_to_write = trans->block_count << 9;
276
278 }
279}
280
282 struct usb_msc_trans *trans,
283 enum trans_event event)
284{
285 (void) ms;
286
287 if (EVENT_CBW_VALID == event) {
288 uint8_t *buf;
289
290 buf = get_cbw_buf(trans);
291
292 trans->lba_start = ((0x1f & buf[1]) << 16)
293 | (buf[2] << 8) | buf[3];
294 trans->block_count = buf[4];
295 trans->current_block = 0;
296
297 trans->bytes_to_read = trans->block_count << 9;
298 }
299}
300
302 struct usb_msc_trans *trans,
303 enum trans_event event)
304{
305 (void) ms;
306
307 if (EVENT_CBW_VALID == event) {
308 uint8_t *buf;
309
310 buf = get_cbw_buf(trans);
311
312 trans->lba_start = (buf[2] << 24) | (buf[3] << 16) |
313 (buf[4] << 8) | buf[5];
314 trans->block_count = (buf[7] << 8) | buf[8];
315 trans->current_block = 0;
316
317 trans->bytes_to_read = trans->block_count << 9;
318 }
319}
320
322 struct usb_msc_trans *trans,
323 enum trans_event event)
324{
325 if (EVENT_CBW_VALID == event) {
326 uint8_t *buf;
327
328 buf = get_cbw_buf(trans);
329
330 trans->lba_start = (buf[2] << 24) | (buf[3] << 16)
331 | (buf[4] << 8) | buf[5];
332 trans->block_count = (buf[7] << 8) | buf[8];
333
334 /* TODO: Check the lba & block_count for range. */
335
336 /* both are in terms of 512 byte blocks, so shift by 9 */
337 trans->bytes_to_write = trans->block_count << 9;
338
340 }
341}
342
344 struct usb_msc_trans *trans,
345 enum trans_event event)
346{
347 if (EVENT_CBW_VALID == event) {
348 trans->msd_buf[0] = ms->block_count >> 24;
349 trans->msd_buf[1] = 0xff & (ms->block_count >> 16);
350 trans->msd_buf[2] = 0xff & (ms->block_count >> 8);
351 trans->msd_buf[3] = 0xff & ms->block_count;
352
353 /* Block size: 512 */
354 trans->msd_buf[4] = 0;
355 trans->msd_buf[5] = 0;
356 trans->msd_buf[6] = 2;
357 trans->msd_buf[7] = 0;
358 trans->bytes_to_write = 8;
360 }
361}
362
364 struct usb_msc_trans *trans,
365 enum trans_event event)
366{
367 if (EVENT_CBW_VALID == event) {
368 uint32_t i;
369
370 memset(trans->msd_buf, 0, 512);
371
372 for (i = 0; i < ms->block_count; i++) {
373 (*ms->write_block)(i, trans->msd_buf);
374 }
375
377 }
378}
379
381 struct usb_msc_trans *trans,
382 enum trans_event event)
383{
384 if (EVENT_CBW_VALID == event) {
385 uint8_t *buf;
386
387 buf = &trans->cbw.cbw.CBWCB[0];
388
389 trans->bytes_to_write = buf[4]; /* allocation length */
390 memcpy(trans->msd_buf, _spc3_request_sense,
391 sizeof(_spc3_request_sense));
392
393 trans->msd_buf[2] = ms->sense.key;
394 trans->msd_buf[12] = ms->sense.asc;
395 trans->msd_buf[13] = ms->sense.ascq;
396 }
397}
398
400 struct usb_msc_trans *trans,
401 enum trans_event event)
402{
403 (void) ms;
404
405 if (EVENT_CBW_VALID == event) {
406#if 0
407 uint8_t *buf;
408 uint8_t page_code;
409 uint8_t allocation_length;
410
411 buf = &trans->cbw.cbw.CBWCB[0];
412 page_code = buf[2];
413 allocation_length = buf[4];
414
415 if (0x1C == page_code) { /* Informational Exceptions */
416#endif
417 trans->bytes_to_write = 4;
418
419 trans->msd_buf[0] = 3; /* Num bytes that follow */
420 trans->msd_buf[1] = 0; /* Medium Type */
421 trans->msd_buf[2] = 0; /* Device specific param */
422 trans->csw.csw.dCSWDataResidue = 4;
423#if 0
424 } else if (0x01 == page_code) { /* Error recovery */
425 } else if (0x3F == page_code) { /* All */
426 } else {
427 /* Error */
428 trans->csw.csw.bCSWStatus = CSW_STATUS_FAILED;
433 }
434#endif
435 }
436}
437
439 struct usb_msc_trans *trans,
440 enum trans_event event)
441{
442 if (EVENT_CBW_VALID == event) {
443 uint8_t evpd;
444 uint8_t *buf;
445
446 buf = get_cbw_buf(trans);
447 evpd = 1 & buf[1];
448
449 if (0 == evpd) {
450 size_t len;
451 trans->bytes_to_write = sizeof(_spc3_inquiry_response);
452 memcpy(trans->msd_buf, _spc3_inquiry_response,
453 sizeof(_spc3_inquiry_response));
454
455 len = strlen(ms->vendor_id);
456 len = MIN(len, 8);
457 memcpy(&trans->msd_buf[8], ms->vendor_id, len);
458
459 len = strlen(ms->product_id);
460 len = MIN(len, 16);
461 memcpy(&trans->msd_buf[16], ms->product_id, len);
462
463 len = strlen(ms->product_revision_level);
464 len = MIN(len, 4);
465 memcpy(&trans->msd_buf[32], ms->product_revision_level,
466 len);
467
468 trans->csw.csw.dCSWDataResidue =
470
472 } else {
473 /* TODO: Add VPD 0x83 support */
474 /* TODO: Add VPD 0x00 support */
475 }
476 }
477}
478
480 struct usb_msc_trans *trans,
481 enum trans_event event)
482{
483 if (EVENT_CBW_VALID == event) {
484 /* Setup the default success */
485 trans->csw_sent = 0;
486 trans->csw.csw.dCSWSignature = CSW_SIGNATURE;
487 trans->csw.csw.dCSWTag = trans->cbw.cbw.dCBWTag;
488 trans->csw.csw.dCSWDataResidue = 0;
489 trans->csw.csw.bCSWStatus = CSW_STATUS_SUCCESS;
490
491 trans->bytes_to_write = 0;
492 trans->bytes_to_read = 0;
493 trans->byte_count = 0;
494 }
495
496 switch (trans->cbw.cbw.CBWCB[0]) {
499 /* Do nothing, just send the success. */
501 break;
502 case SCSI_FORMAT_UNIT:
503 scsi_format_unit(ms, trans, event);
504 break;
506 scsi_request_sense(ms, trans, event);
507 break;
509 scsi_mode_sense_6(ms, trans, event);
510 break;
511 case SCSI_READ_6:
512 scsi_read_6(ms, trans, event);
513 break;
514 case SCSI_INQUIRY:
515 scsi_inquiry(ms, trans, event);
516 break;
518 scsi_read_capacity(ms, trans, event);
519 break;
520 case SCSI_READ_10:
521 scsi_read_10(ms, trans, event);
522 break;
523 case SCSI_WRITE_6:
524 scsi_write_6(ms, trans, event);
525 break;
526 case SCSI_WRITE_10:
527 scsi_write_10(ms, trans, event);
528 break;
529 default:
533
534 trans->bytes_to_write = 0;
535 trans->bytes_to_read = 0;
536 trans->csw.csw.bCSWStatus = CSW_STATUS_FAILED;
537 break;
538 }
539}
540
541/*-- USB Mass Storage Layer --------------------------------------------------*/
542
543/** @brief Handle the USB 'OUT' requests. */
544static void msc_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
545{
547 struct usb_msc_trans *trans;
548 int len, max_len, left;
549 void *p;
550
551 ms = &_mass_storage;
552 trans = &ms->trans;
553
554 /* RX only */
555 left = sizeof(struct usb_msc_cbw) - trans->cbw_cnt;
556 if (0 < left) {
557 max_len = MIN(ms->ep_out_size, left);
558 p = &trans->cbw.buf[0x1ff & trans->cbw_cnt];
559 len = usbd_ep_read_packet(usbd_dev, ep, p, max_len);
560 trans->cbw_cnt += len;
561
562 if (sizeof(struct usb_msc_cbw) == trans->cbw_cnt) {
563 scsi_command(ms, trans, EVENT_CBW_VALID);
564 if (trans->byte_count < trans->bytes_to_read) {
565 /* We must wait until there is something to
566 * read again. */
567 return;
568 }
569 }
570 }
571
572 if (trans->byte_count < trans->bytes_to_read) {
573 if (0 < trans->block_count) {
574 if ((0 == trans->byte_count) && (NULL != ms->lock)) {
575 (*ms->lock)();
576 }
577 }
578
579 left = trans->bytes_to_read - trans->byte_count;
580 max_len = MIN(ms->ep_out_size, left);
581 p = &trans->msd_buf[0x1ff & trans->byte_count];
582 len = usbd_ep_read_packet(usbd_dev, ep, p, max_len);
583 trans->byte_count += len;
584
585 if (0 < trans->block_count) {
586 if (0 == (0x1ff & trans->byte_count)) {
587 uint32_t lba;
588
589 lba = trans->lba_start + trans->current_block;
590 if (0 != (*ms->write_block)(lba,
591 trans->msd_buf)) {
592 /* Error */
593 }
594 trans->current_block++;
595 }
596 }
597
598 /* Fix "writes aren't acknowledged" bug on Linux (PR #409) */
599 if (false == trans->csw_valid) {
601 trans->csw_valid = true;
602 }
603 left = sizeof(struct usb_msc_csw) - trans->csw_sent;
604 if (0 < left) {
605 max_len = MIN(ms->ep_out_size, left);
606 p = &trans->csw.buf[trans->csw_sent];
607 len = usbd_ep_write_packet(usbd_dev, ms->ep_in, p,
608 max_len);
609 trans->csw_sent += len;
610 }
611
612 } else if (trans->byte_count < trans->bytes_to_write) {
613 if (0 < trans->block_count) {
614 if ((0 == trans->byte_count) && (NULL != ms->lock)) {
615 (*ms->lock)();
616 }
617
618 if (0 == (0x1ff & trans->byte_count)) {
619 uint32_t lba;
620
621 lba = trans->lba_start + trans->current_block;
622 if (0 != (*ms->read_block)(lba,
623 trans->msd_buf)) {
624 /* Error */
625 }
626 trans->current_block++;
627 }
628 }
629
630 left = trans->bytes_to_write - trans->byte_count;
631 max_len = MIN(ms->ep_out_size, left);
632 p = &trans->msd_buf[0x1ff & trans->byte_count];
633 len = usbd_ep_write_packet(usbd_dev, ms->ep_in, p, max_len);
634 trans->byte_count += len;
635 } else {
636 if (0 < trans->block_count) {
637 if (trans->current_block == trans->block_count) {
638 uint32_t lba;
639
640 lba = trans->lba_start + trans->current_block;
641 if (0 != (*ms->write_block)(lba,
642 trans->msd_buf)) {
643 /* Error */
644 }
645
646 trans->current_block = 0;
647 if (NULL != ms->unlock) {
648 (*ms->unlock)();
649 }
650 }
651 }
652 if (false == trans->csw_valid) {
654 trans->csw_valid = true;
655 }
656
657 left = sizeof(struct usb_msc_csw) - trans->csw_sent;
658 if (0 < left) {
659 max_len = MIN(ms->ep_out_size, left);
660 p = &trans->csw.buf[trans->csw_sent];
661 len = usbd_ep_write_packet(usbd_dev, ms->ep_in, p,
662 max_len);
663 trans->csw_sent += len;
664 }
665 }
666}
667
668/** @brief Handle the USB 'IN' requests. */
669static void msc_data_tx_cb(usbd_device *usbd_dev, uint8_t ep)
670{
672 struct usb_msc_trans *trans;
673 int len, max_len, left;
674 void *p;
675
676 ms = &_mass_storage;
677 trans = &ms->trans;
678
679 if (trans->byte_count < trans->bytes_to_write) {
680 if (0 < trans->block_count) {
681 if (0 == (0x1ff & trans->byte_count)) {
682 uint32_t lba;
683
684 lba = trans->lba_start + trans->current_block;
685 if (0 != (*ms->read_block)(lba,
686 trans->msd_buf)) {
687 /* Error */
688 }
689 trans->current_block++;
690 }
691 }
692
693 left = trans->bytes_to_write - trans->byte_count;
694 max_len = MIN(ms->ep_out_size, left);
695 p = &trans->msd_buf[0x1ff & trans->byte_count];
696 len = usbd_ep_write_packet(usbd_dev, ep, p, max_len);
697 trans->byte_count += len;
698 } else {
699 if (0 < trans->block_count) {
700 if (trans->current_block == trans->block_count) {
701 trans->current_block = 0;
702 if (NULL != ms->unlock) {
703 (*ms->unlock)();
704 }
705 }
706 }
707 if (false == trans->csw_valid) {
709 trans->csw_valid = true;
710 }
711
712 left = sizeof(struct usb_msc_csw) - trans->csw_sent;
713 if (0 < left) {
714 max_len = MIN(ms->ep_out_size, left);
715 p = &trans->csw.buf[trans->csw_sent];
716 len = usbd_ep_write_packet(usbd_dev, ep, p, max_len);
717 trans->csw_sent += len;
718 } else if (sizeof(struct usb_msc_csw) == trans->csw_sent) {
719 /* End of transaction */
720 trans->lba_start = 0xffffffff;
721 trans->block_count = 0;
722 trans->current_block = 0;
723 trans->cbw_cnt = 0;
724 trans->bytes_to_read = 0;
725 trans->bytes_to_write = 0;
726 trans->byte_count = 0;
727 trans->csw_sent = 0;
728 trans->csw_valid = false;
729 }
730 }
731}
732
733/** @brief Handle various control requests related to the msc storage
734 * interface.
735 */
738 struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
740{
741 (void)complete;
742 (void)usbd_dev;
743
744 switch (req->bRequest) {
746 /* Do any special reset code here. */
747 return USBD_REQ_HANDLED;
749 /* Return the number of LUNs. We use 0. */
750 *buf[0] = 0;
751 *len = 1;
752 return USBD_REQ_HANDLED;
753 }
754
755 return USBD_REQ_NOTSUPP;
756}
757
758/** @brief Setup the endpoints to be bulk & register the callbacks. */
759static void msc_set_config(usbd_device *usbd_dev, uint16_t wValue)
760{
762
763 (void)wValue;
764
769
771 usbd_dev,
775}
776
777/** @addtogroup usb_msc */
778/** @{ */
779
780/** @brief Initializes the USB Mass Storage subsystem.
781
782@note Currently you can only have this profile active.
783
784@param[in] usbd_dev The USB device to associate the Mass Storage with.
785@param[in] ep_in The USB 'IN' endpoint.
786@param[in] ep_in_size The maximum endpoint size. Valid values: 8, 16, 32 or 64
787@param[in] ep_out The USB 'OUT' endpoint.
788@param[in] ep_out_size The maximum endpoint size. Valid values: 8, 16, 32 or 64
789@param[in] vendor_id The SCSI vendor ID to return. Maximum used length is 8.
790@param[in] product_id The SCSI product ID to return. Maximum used length is 16.
791@param[in] product_revision_level The SCSI product revision level to return.
792 Maximum used length is 4.
793@param[in] block_count The number of 512-byte blocks available.
794@param[in] read_block The function called when the host requests to read a LBA
795 block. Must _NOT_ be NULL.
796@param[in] write_block The function called when the host requests to write a
797 LBA block. Must _NOT_ be NULL.
798
799@return Pointer to the usbd_mass_storage struct.
800*/
802 uint8_t ep_in, uint8_t ep_in_size,
803 uint8_t ep_out, uint8_t ep_out_size,
804 const char *vendor_id,
805 const char *product_id,
806 const char *product_revision_level,
807 const uint32_t block_count,
808 int (*read_block)(uint32_t lba,
809 uint8_t *copy_to),
810 int (*write_block)(uint32_t lba,
811 const uint8_t *copy_from))
812{
814 _mass_storage.ep_in = ep_in;
815 _mass_storage.ep_in_size = ep_in_size;
816 _mass_storage.ep_out = ep_out;
817 _mass_storage.ep_out_size = ep_out_size;
818 _mass_storage.vendor_id = vendor_id;
819 _mass_storage.product_id = product_id;
820 _mass_storage.product_revision_level = product_revision_level;
821 _mass_storage.block_count = block_count - 1;
822 _mass_storage.read_block = read_block;
823 _mass_storage.write_block = write_block;
824 _mass_storage.lock = NULL;
825 _mass_storage.unlock = NULL;
826
827 _mass_storage.trans.lba_start = 0xffffffff;
836
838
840
841 return &_mass_storage;
842}
843
844/** @} */
struct _usbd_device usbd_device
Definition: usbd.h:53
int usbd_register_control_callback(usbd_device *usbd_dev, uint8_t type, uint8_t type_mask, usbd_control_callback callback)
Registers a control callback.
Definition: usb_control.c:73
uint16_t usbd_ep_write_packet(usbd_device *usbd_dev, uint8_t addr, const void *buf, uint16_t len)
Write a packet.
Definition: usb.c:146
void usbd_ep_setup(usbd_device *usbd_dev, uint8_t addr, uint8_t type, uint16_t max_size, usbd_endpoint_callback callback)
Setup an endpoint.
Definition: usb.c:140
uint16_t usbd_ep_read_packet(usbd_device *usbd_dev, uint8_t addr, void *buf, uint16_t len)
Read a packet.
Definition: usb.c:152
int usbd_register_set_config_callback(usbd_device *usbd_dev, usbd_set_config_callback callback)
Registers a "Set Config" callback.
Definition: usb_standard.c:42
usbd_request_return_codes
Definition: usbd.h:46
void(* usbd_control_complete_callback)(usbd_device *usbd_dev, struct usb_setup_data *req)
Definition: usbd.h:117
@ USBD_REQ_HANDLED
Definition: usbd.h:48
@ USBD_REQ_NOTSUPP
Definition: usbd.h:47
#define USB_MSC_REQ_BULK_ONLY_RESET
Definition: msc.h:81
#define USB_MSC_REQ_GET_MAX_LUN
Definition: msc.h:82
usbd_mass_storage * usb_msc_init(usbd_device *usbd_dev, uint8_t ep_in, uint8_t ep_in_size, uint8_t ep_out, uint8_t ep_out_size, const char *vendor_id, const char *product_id, const char *product_revision_level, const uint32_t block_count, int(*read_block)(uint32_t lba, uint8_t *copy_to), int(*write_block)(uint32_t lba, const uint8_t *copy_from))
Initializes the USB Mass Storage subsystem.
Definition: usb_msc.c:801
#define USB_ENDPOINT_ATTR_BULK
Definition: usbstd.h:234
#define USB_REQ_TYPE_RECIPIENT
Definition: usbstd.h:78
#define USB_REQ_TYPE_TYPE
Definition: usbstd.h:73
#define USB_REQ_TYPE_INTERFACE
Definition: usbstd.h:80
#define USB_REQ_TYPE_CLASS
Definition: usbstd.h:75
uint8_t ep_in_size
Definition: usb_msc.c:176
struct usb_msc_trans trans
Definition: usb_msc.c:191
uint8_t ep_out
Definition: usb_msc.c:177
uint8_t ep_out_size
Definition: usb_msc.c:178
struct sbc_sense_info sense
Definition: usb_msc.c:192
const char * vendor_id
Definition: usb_msc.c:180
int(* write_block)(uint32_t lba, const uint8_t *copy_from)
Definition: usb_msc.c:186
uint32_t block_count
Definition: usb_msc.c:183
usbd_device * usbd_dev
Definition: usb_msc.c:174
const char * product_revision_level
Definition: usb_msc.c:182
int(* read_block)(uint32_t lba, uint8_t *copy_to)
Definition: usb_msc.c:185
const char * product_id
Definition: usb_msc.c:181
void(* unlock)(void)
Definition: usb_msc.c:189
void(* lock)(void)
Definition: usb_msc.c:188
uint8_t ascq
Definition: usb_msc.c:144
uint8_t asc
Definition: usb_msc.c:143
uint8_t key
Definition: usb_msc.c:142
uint32_t dCBWSignature
Definition: usb_msc.c:125
uint8_t bCBWLUN
Definition: usb_msc.c:129
uint32_t dCBWTag
Definition: usb_msc.c:126
uint8_t bmCBWFlags
Definition: usb_msc.c:128
uint8_t CBWCB[16]
Definition: usb_msc.c:131
uint8_t bCBWCBLength
Definition: usb_msc.c:130
uint32_t dCBWDataTransferLength
Definition: usb_msc.c:127
uint32_t dCSWTag
Definition: usb_msc.c:136
uint8_t bCSWStatus
Definition: usb_msc.c:138
uint32_t dCSWSignature
Definition: usb_msc.c:135
uint32_t dCSWDataResidue
Definition: usb_msc.c:137
uint32_t current_block
Definition: usb_msc.c:161
uint8_t cbw_cnt
Definition: usb_msc.c:148
uint32_t bytes_to_read
Definition: usb_msc.c:154
struct usb_msc_csw csw
Definition: usb_msc.c:168
uint32_t bytes_to_write
Definition: usb_msc.c:155
uint8_t msd_buf[512]
Definition: usb_msc.c:163
uint32_t lba_start
Definition: usb_msc.c:159
uint32_t block_count
Definition: usb_msc.c:160
uint32_t byte_count
Definition: usb_msc.c:156
uint8_t csw_sent
Definition: usb_msc.c:166
uint8_t buf[1]
Definition: usb_msc.c:151
bool csw_valid
Definition: usb_msc.c:165
struct usb_msc_cbw cbw
Definition: usb_msc.c:150
uint8_t bRequest
Definition: usbstd.h:58
static struct _usbd_device usbd_dev
Definition: usb_f107.c:34
static uint8_t * get_cbw_buf(struct usb_msc_trans *trans)
Definition: usb_msc.c:254
#define CSW_STATUS_SUCCESS
Definition: usb_msc.c:46
static void scsi_format_unit(usbd_mass_storage *ms, struct usb_msc_trans *trans, enum trans_event event)
Definition: usb_msc.c:363
static void msc_set_config(usbd_device *usbd_dev, uint16_t wValue)
Setup the endpoints to be bulk & register the callbacks.
Definition: usb_msc.c:759
static void set_sbc_status(usbd_mass_storage *ms, enum sbc_sense_key key, enum sbc_asc asc, enum sbc_ascq ascq)
Definition: usb_msc.c:236
#define SCSI_SEND_DIAGNOSTIC
Definition: usb_msc.c:58
static void scsi_mode_sense_6(usbd_mass_storage *ms, struct usb_msc_trans *trans, enum trans_event event)
Definition: usb_msc.c:399
#define SCSI_READ_CAPACITY
Definition: usb_msc.c:59
static void scsi_read_capacity(usbd_mass_storage *ms, struct usb_msc_trans *trans, enum trans_event event)
Definition: usb_msc.c:343
static void msc_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
Handle the USB 'OUT' requests.
Definition: usb_msc.c:544
static void scsi_request_sense(usbd_mass_storage *ms, struct usb_msc_trans *trans, enum trans_event event)
Definition: usb_msc.c:380
static void scsi_write_10(usbd_mass_storage *ms, struct usb_msc_trans *trans, enum trans_event event)
Definition: usb_msc.c:301
static const uint8_t _spc3_inquiry_response[36]
Definition: usb_msc.c:199
static void scsi_read_6(usbd_mass_storage *ms, struct usb_msc_trans *trans, enum trans_event event)
Definition: usb_msc.c:259
sbc_asc
Definition: usb_msc.c:98
@ SBC_ASC_FORMAT_ERROR
Definition: usb_msc.c:108
@ SBC_ASC_NOT_READY_TO_READY_CHANGE
Definition: usb_msc.c:107
@ SBC_ASC_PERIPHERAL_DEVICE_WRITE_FAULT
Definition: usb_msc.c:100
@ SBC_ASC_INVALID_COMMAND_OPERATION_CODE
Definition: usb_msc.c:103
@ SBC_ASC_MEDIUM_NOT_PRESENT
Definition: usb_msc.c:109
@ SBC_ASC_LBA_OUT_OF_RANGE
Definition: usb_msc.c:104
@ SBC_ASC_NO_ADDITIONAL_SENSE_INFORMATION
Definition: usb_msc.c:99
@ SBC_ASC_INVALID_FIELD_IN_CDB
Definition: usb_msc.c:105
@ SBC_ASC_WRITE_PROTECTED
Definition: usb_msc.c:106
@ SBC_ASC_UNRECOVERED_READ_ERROR
Definition: usb_msc.c:102
@ SBC_ASC_LOGICAL_UNIT_NOT_READY
Definition: usb_msc.c:101
static void scsi_inquiry(usbd_mass_storage *ms, struct usb_msc_trans *trans, enum trans_event event)
Definition: usb_msc.c:438
static void msc_data_tx_cb(usbd_device *usbd_dev, uint8_t ep)
Handle the USB 'IN' requests.
Definition: usb_msc.c:669
#define SCSI_READ_10
Definition: usb_msc.c:60
static const uint8_t _spc3_request_sense[18]
Definition: usb_msc.c:217
#define CSW_SIGNATURE
Definition: usb_msc.c:45
static void scsi_read_10(usbd_mass_storage *ms, struct usb_msc_trans *trans, enum trans_event event)
Definition: usb_msc.c:321
#define SCSI_READ_6
Definition: usb_msc.c:54
sbc_ascq
Definition: usb_msc.c:112
@ SBC_ASCQ_INITIALIZING_COMMAND_REQUIRED
Definition: usb_msc.c:115
@ SBC_ASCQ_FORMAT_COMMAND_FAILED
Definition: usb_msc.c:114
@ SBC_ASCQ_OPERATION_IN_PROGRESS
Definition: usb_msc.c:116
@ SBC_ASCQ_NA
Definition: usb_msc.c:113
#define SCSI_INQUIRY
Definition: usb_msc.c:56
#define SCSI_REQUEST_SENSE
Definition: usb_msc.c:52
#define CSW_STATUS_FAILED
Definition: usb_msc.c:47
#define SCSI_WRITE_6
Definition: usb_msc.c:55
#define SCSI_WRITE_10
Definition: usb_msc.c:77
#define SCSI_MODE_SENSE_6
Definition: usb_msc.c:57
static void set_sbc_status_good(usbd_mass_storage *ms)
Definition: usb_msc.c:246
#define SCSI_FORMAT_UNIT
Definition: usb_msc.c:53
static void scsi_command(usbd_mass_storage *ms, struct usb_msc_trans *trans, enum trans_event event)
Definition: usb_msc.c:479
trans_event
Definition: usb_msc.c:119
@ EVENT_NEED_STATUS
Definition: usb_msc.c:121
@ EVENT_CBW_VALID
Definition: usb_msc.c:120
#define SCSI_TEST_UNIT_READY
Definition: usb_msc.c:51
static void scsi_write_6(usbd_mass_storage *ms, struct usb_msc_trans *trans, enum trans_event event)
Definition: usb_msc.c:281
sbc_sense_key
Definition: usb_msc.c:81
@ SBC_SENSE_KEY_ABORTED_COMMAND
Definition: usb_msc.c:93
@ SBC_SENSE_KEY_HARDWARE_ERROR
Definition: usb_msc.c:86
@ SBC_SENSE_KEY_BLANK_CHECK
Definition: usb_msc.c:90
@ SBC_SENSE_KEY_MISCOMPARE
Definition: usb_msc.c:95
@ SBC_SENSE_KEY_UNIT_ATTENTION
Definition: usb_msc.c:88
@ SBC_SENSE_KEY_RECOVERED_ERROR
Definition: usb_msc.c:83
@ SBC_SENSE_KEY_NO_SENSE
Definition: usb_msc.c:82
@ SBC_SENSE_KEY_VOLUME_OVERFLOW
Definition: usb_msc.c:94
@ SBC_SENSE_KEY_ILLEGAL_REQUEST
Definition: usb_msc.c:87
@ SBC_SENSE_KEY_VENDOR_SPECIFIC
Definition: usb_msc.c:91
@ SBC_SENSE_KEY_MEDIUM_ERROR
Definition: usb_msc.c:85
@ SBC_SENSE_KEY_DATA_PROTECT
Definition: usb_msc.c:89
@ SBC_SENSE_KEY_NOT_READY
Definition: usb_msc.c:84
@ SBC_SENSE_KEY_COPY_ABORTED
Definition: usb_msc.c:92
static usbd_mass_storage _mass_storage
Definition: usb_msc.c:195
static enum usbd_request_return_codes msc_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete)
Handle various control requests related to the msc storage interface.
Definition: usb_msc.c:737