Paparazzi UAS v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
Loading...
Searching...
No Matches
usb_msd.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2014 Gautier Hattenberger, Alexandre Bustico
3 *
4 * This file is part of paparazzi.
5 *
6 * paparazzi is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * paparazzi is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with paparazzi; see the file COPYING. If not, write to
18 * the Free Software Foundation, 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
22/*
23 * @file modules/loggers/sdlog_chibios/usb_msd.c
24 *
25 */
26
28#include "mcu_periph/ram_arch.h"
29
30
32
34/* Request types */
35#define MSD_REQ_RESET 0xFF
36#define MSD_GET_MAX_LUN 0xFE
37
38/* CBW/CSW block signatures */
39#define MSD_CBW_SIGNATURE 0x43425355
40#define MSD_CSW_SIGNATURE 0x53425355
41
42/* Setup packet access macros */
43#define MSD_SETUP_WORD(setup, index) (uint16_t)(((uint16_t)setup[index + 1] << 8) | (setup[index] & 0x00FF))
44#define MSD_SETUP_VALUE(setup) MSD_SETUP_WORD(setup, 2)
45#define MSD_SETUP_INDEX(setup) MSD_SETUP_WORD(setup, 4)
46#define MSD_SETUP_LENGTH(setup) MSD_SETUP_WORD(setup, 6)
47
48/* Command statuses */
49#define MSD_COMMAND_PASSED 0x00
50#define MSD_COMMAND_FAILED 0x01
51#define MSD_COMMAND_PHASE_ERROR 0x02
52
53/* SCSI commands */
54#define SCSI_CMD_TEST_UNIT_READY 0x00
55#define SCSI_CMD_REQUEST_SENSE 0x03
56#define SCSI_CMD_FORMAT_UNIT 0x04
57#define SCSI_CMD_INQUIRY 0x12
58#define SCSI_CMD_MODE_SENSE_6 0x1A
59#define SCSI_CMD_START_STOP_UNIT 0x1B
60#define SCSI_CMD_SEND_DIAGNOSTIC 0x1D
61#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
62#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23
63#define SCSI_CMD_READ_CAPACITY_10 0x25
64#define SCSI_CMD_READ_10 0x28
65#define SCSI_CMD_WRITE_10 0x2A
66#define SCSI_CMD_VERIFY_10 0x2F
67
68/* SCSI sense keys */
69#define SCSI_SENSE_KEY_GOOD 0x00
70#define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01
71#define SCSI_SENSE_KEY_NOT_READY 0x02
72#define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03
73#define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04
74#define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05
75#define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06
76#define SCSI_SENSE_KEY_DATA_PROTECT 0x07
77#define SCSI_SENSE_KEY_BLANK_CHECK 0x08
78#define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09
79#define SCSI_SENSE_KEY_COPY_ABORTED 0x0A
80#define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B
81#define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D
82#define SCSI_SENSE_KEY_MISCOMPARE 0x0E
83
84#define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION 0x00
85#define SCSI_ASENSE_WRITE_FAULT 0x03
86#define SCSI_ASENSE_LOGICAL_UNIT_NOT_READY 0x04
87#define SCSI_ASENSE_READ_ERROR 0x11
88#define SCSI_ASENSE_INVALID_COMMAND 0x20
89#define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21
90#define SCSI_ASENSE_INVALID_FIELD_IN_CDB 0x24
91#define SCSI_ASENSE_WRITE_PROTECTED 0x27
92#define SCSI_ASENSE_NOT_READY_TO_READY_CHANGE 0x28
93#define SCSI_ASENSE_FORMAT_ERROR 0x31
94#define SCSI_ASENSE_MEDIUM_NOT_PRESENT 0x3A
95
96#define SCSI_ASENSEQ_NO_QUALIFIER 0x00
97#define SCSI_ASENSEQ_FORMAT_COMMAND_FAILED 0x01
98#define SCSI_ASENSEQ_INITIALIZING_COMMAND_REQUIRED 0x02
99#define SCSI_ASENSEQ_OPERATION_IN_PROGRESS 0x07
100
101
102
103static void mass_storage_thread(void *arg);
107
108
117
121PACK_STRUCT_BEGIN typedef struct {
122 uint8_t reserved[3];
127
132
135
140static inline DWORD swap_uint32(const DWORD val)
141{
142 DWORD v = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF);
143 return ((v << 16) & 0xFFFF0000) | ((v >> 16) & 0x0000FFFF);
144}
149static inline WORD swap_uint16(const WORD val)
150{
151 return (((val >> 8) & 0xff) | ((val & 0xff) << 8));
152}
154
159
164
180
189{
190 usbInitEndpointI(msdp->config->usbp, msdp->config->bulk_ep, &ep_data_config);
191 chBSemSignalI(&msdp->bsem);
194 chEvtBroadcastI(&msdp->evt_connected);
195}
196
206{
207
208 /* check that the request is of type Class / Interface */
209 if (((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) &&
211
212 /* check that the request is for interface 0 */
213 if (MSD_SETUP_INDEX(usbp->setup) != 0) {
214 return false;
215 }
216
217 /* act depending on bRequest = setup[1] */
218 switch (usbp->setup[1]) {
219 case MSD_REQ_RESET:
220 /* check that it is a HOST2DEV request */
221 if (((usbp->setup[0] & USB_RTYPE_DIR_MASK) != USB_RTYPE_DIR_HOST2DEV) ||
222 (MSD_SETUP_LENGTH(usbp->setup) != 0) ||
223 (MSD_SETUP_VALUE(usbp->setup) != 0)) {
224 return false;
225 }
226
227 /*
228 As required by the BOT specification, the Bulk-only mass storage reset request (classspecific
229 request) is implemented. This request is used to reset the mass storage device and
230 its associated interface. This class-specific request should prepare the device for the next
231 CBW from the host.
232 To generate the BOT Mass Storage Reset, the host must send a device request on the
233 default pipe of:
234 • bmRequestType: Class, interface, host to device
235 • bRequest field set to 255 (FFh)
236 • wValue field set to ‘0’
237 • wIndex field set to the interface number
238 • wLength field set to ‘0’
239 */
240 UMSD.bot_reset = true;
242
243 /* release and abandon current transmission */
244 chBSemResetI(&UMSD.bsem, false);
247 /* The device shall NAK the status stage of the device request until
248 * the Bulk-Only Mass Storage Reset is complete.
249 * NAK EP1 in and out */
250 UMSD.config->usbp->otg->ie[UMSD.config->bulk_ep].DIEPCTL = DIEPCTL_SNAK;
251 UMSD.config->usbp->otg->oe[UMSD.config->bulk_ep].DOEPCTL = DOEPCTL_SNAK;
252
255
256 /* response to this request using EP0 */
257 usbSetupTransfer(usbp, 0, 0, NULL);
259
260 return true;
261 case MSD_GET_MAX_LUN:
262 /* check that it is a DEV2HOST request */
263 if (((usbp->setup[0] & USB_RTYPE_DIR_MASK) != USB_RTYPE_DIR_DEV2HOST) ||
264 (MSD_SETUP_LENGTH(usbp->setup) != 1) ||
265 (MSD_SETUP_VALUE(usbp->setup) != 0)) {
266 return false;
267 }
268
269 static uint8_t len_buf[1] = {0};
270 /* stall to indicate that we don't support LUN */
271 usbSetupTransfer(usbp, len_buf, 1, NULL);
272 return true;
273 default:
274 return false;
275 break;
276 }
277 }
278
279 return false;
280}
281
286{
287 /* sleep until it completes */
288 chSysLock();
289 chBSemWaitS(&msdp->bsem);
291 SEM_TAKEN;
292 chSysUnlock();
293}
294
299{
300
301 (void)usbp;
303 chBSemSignalI(&((USBMassStorageDriver *)usbp->in_params[ep])->bsem);
306}
307
311static void msd_start_transmit(USBMassStorageDriver *msdp, const uint8_t *buffer, size_t size)
312{
313
314 chSysLock();
315 if (msdp->bot_reset) {
316 msdp->config->usbp->transmitting = 0;
317 }
318 usbStartTransmitI(msdp->config->usbp, msdp->config->bulk_ep, buffer, size);
319 chSysUnlock();
320}
321
325static void msd_start_receive(USBMassStorageDriver *msdp, uint8_t *buffer, size_t size)
326{
327
328 chSysLock();
329 if (msdp->bot_reset) {
330 msdp->config->usbp->receiving = 0;
331 }
332 usbStartReceiveI(msdp->config->usbp, msdp->config->bulk_ep, buffer, size);
333 chSysUnlock();
334}
335
340{
341 msdp->sense.byte[2] = key;
342 msdp->sense.byte[12] = acode;
343 msdp->sense.byte[13] = aqual;
344}
345
350{
351
353
354 msd_cbw_t *cbw = &(msdp->cbw);
355
356 /* check the EVPD bit (Vital Product Data) */
357 if (cbw->scsi_cmd_data[1] & 0x01) {
358
359 /* check the Page Code byte to know the type of product data to reply */
360 switch (cbw->scsi_cmd_data[2]) {
361
362 /* unit serial number */
363 case 0x80: {
364 uint8_t response[] = {'0'}; /* TODO */
366 msdp->result = true;
367 /* wait for ISR */
368 return true;
369 }
370
371 /* unhandled */
372 default:
377 return false;
378 }
379 } else {
380 msd_start_transmit(msdp, (const uint8_t *)&msdp->inquiry, sizeof(msdp->inquiry));
381 msdp->result = true;
382
383 /* wait for ISR */
384 return true;
385 }
386}
387
392{
393
394 msd_start_transmit(msdp, (const uint8_t *)&msdp->sense, sizeof(msdp->sense));
395 msdp->result = true;
396
397 /* wait for ISR immediately, otherwise the caller may reset the sense bytes before they are sent to the host! */
399
400 /* ... don't wait for ISR, we just did it */
401 return false;
402}
403
408{
411
412 response.block_size = swap_uint32(msdp->block_dev_info.blk_size);
413 response.last_block_addr = swap_uint32(msdp->block_dev_info.blk_num - 1);
414
415 msd_start_transmit(msdp, (const uint8_t *)&response, sizeof(response));
416 msdp->result = true;
417
418 /* wait for ISR */
419 return true;
420}
421
426{
427 msd_cbw_t *cbw = &(msdp->cbw);
428
429 if (!(cbw->scsi_cmd_data[1] & (1 << 2))) {
430 /* only self-test supported - update SENSE key and fail the command */
435 msdp->result = false;
436 return false;
437 }
438
439 /* TODO: actually perform the test */
440 msdp->result = true;
441
442 /* don't wait for ISR */
443 return false;
444}
445
450{
452 msd_cbw_t *cbw = &(msdp->cbw);
453
454 if ((cbw->scsi_cmd_data[0] == SCSI_CMD_WRITE_10) && blkIsWriteProtected(msdp->config->bbdp)) {
455 /* device is write protected and a write has been issued */
456 /* block address is invalid, update SENSE key and return command fail */
461 msdp->result = false;
462
463 /* don't wait for ISR */
464 return false;
465 }
466
467 uint32_t rw_block_address = swap_uint32(*(DWORD *)&cbw->scsi_cmd_data[2]);
468 uint16_t total = swap_uint16(*(WORD *)&cbw->scsi_cmd_data[7]);
469 uint16_t i = 0;
470
471 if (rw_block_address >= msdp->block_dev_info.blk_num) {
472 /* block address is invalid, update SENSE key and return command fail */
477 msdp->result = false;
478
479 /* don't wait for ISR */
480 return false;
481 }
482
483 if (cbw->scsi_cmd_data[0] == SCSI_CMD_WRITE_10) {
484 /* process a write command */
485
486 /* get the first packet */
487 msd_start_receive(msdp, rw_buf[i % 2], msdp->block_dev_info.blk_size);
489
490 /* loop over each block */
491 for (i = 0; i < total; i++) {
492
493 if (i < (total - 1)) {
494 /* there is at least one block of data left to be read over USB */
495 /* queue this read before issuing the blocking write */
496 msd_start_receive(msdp, rw_buf[(i + 1) % 2], msdp->block_dev_info.blk_size);
497 }
498
499 /* now write the block to the block device */
500 if (blkWrite(msdp->config->bbdp, rw_block_address++, rw_buf[i % 2], 1) == HAL_FAILED) {
501 /* write failed */
506 msdp->result = false;
507
508 /* don't wait for ISR */
509 return false;
510 }
511
512 if (i < (total - 1)) {
513 /* now wait for the USB event to complete */
515 }
516 }
517 } else {
518 /* process a read command */
519
520 i = 0;
521
522 /* read the first block from block device */
523 if (blkRead(msdp->config->bbdp, rw_block_address++, rw_buf[i % 2], 1) == HAL_FAILED) {
524 /* read failed */
529 msdp->result = false;
530
531 /* don't wait for ISR */
532 return false;
533 }
534
535 /* loop over each block */
536 for (i = 0; i < total; i++) {
537 /* transmit the block */
538 msd_start_transmit(msdp, rw_buf[i % 2], msdp->block_dev_info.blk_size);
539
540 if (i < (total - 1)) {
541 /* there is at least one more block to be read from device */
542 /* so read that whilst the USB transfer takes place */
543 if (blkRead(msdp->config->bbdp, rw_block_address++, rw_buf[(i + 1) % 2], 1) == HAL_FAILED) {
544 /* read failed */
549 msdp->result = false;
550
551 /* wait for ISR (the previous transmission is still running) */
552 return true;
553 }
554 }
555
556 /* wait for the USB event to complete */
558 }
559 }
560
561 msdp->result = true;
562
563 /* don't wait for ISR */
564 return false;
565}
566
571{
572
573 if ((msdp->cbw.scsi_cmd_data[4] & 0x03) == 0x02) {
574 /* device has been ejected */
575 chEvtBroadcast(&msdp->evt_ejected);
576 msdp->state = MSD_EJECTED;
577 }
578
579 msdp->result = true;
580
581 /* don't wait for ISR */
582 return false;
583}
584
589{
591 static uint8_t response[4] = {
592 0x03, /* number of bytes that follow */
593 0x00, /* medium type is SBC */
594 0x00, /* not write protected (TODO handle it correctly) */
595 0x00 /* no block descriptor */
596 };
597
599 msdp->result = true;
600
601 /* wait for ISR */
602 return true;
603}
604
609{
610
613 response.capacity_list_length = 1;
614 response.block_count = swap_uint32(msdp->block_dev_info.blk_num);
615 response.desc_and_block_length = swap_uint32((0x02 << 24) | (msdp->block_dev_info.blk_size & 0x00FFFFFF));
616
617 msd_start_transmit(msdp, (const uint8_t *)&response, sizeof(response));
618 msdp->result = true;
619
620 /* wait for ISR */
621 return true;
622}
623
628{
630 if (blkIsInserted(msdp->config->bbdp)) {
631 /* device inserted and ready */
632 msdp->result = true;
633 /* device not present or not ready */
638 } else {
639 /* device not present or not ready */
644 msdp->result = false;
645 }
646
647 /* don't wait for ISR */
648 return false;
649}
650
655{
657
658 msd_start_receive(msdp, (uint8_t *)&msdp->cbw, sizeof(msdp->cbw));
659
661
662 /* wait for ISR */
663 return true;
664}
665
670{
671
672 msd_cbw_t *cbw = &(msdp->cbw);
673
674 /* by default transition back to the idle state */
675 msdp->state = MSD_IDLE;
676
677
678 /* check the command */
679 if ((cbw->signature != MSD_CBW_SIGNATURE) ||
680 (cbw->lun > 0) ||
681 ((cbw->data_len > 0) && (cbw->flags & 0x1F)) ||
682 (cbw->scsi_cmd_len == 0) ||
683 (cbw->scsi_cmd_len > 16)) {
684
685 /* stall both IN and OUT endpoints */
686 chSysLock();
687 usbStallReceiveI(msdp->config->usbp, msdp->config->bulk_ep);
688 usbStallTransmitI(msdp->config->usbp, msdp->config->bulk_ep);
689 chSysUnlock();
690
695
696 /* don't wait for ISR */
697 msdp->result = false;
698 return false;
699 }
700
701 bool sleep = false;
702
703
704 /* check the command */
705 if (cbw->signature != MSD_CBW_SIGNATURE) {
707 }
708 //if (msdp->result == true)
709 /* check the command */
710 switch (cbw->scsi_cmd_data[0]) {
711 case SCSI_CMD_INQUIRY:
713 break;
716 break;
719 break;
720 case SCSI_CMD_READ_10:
722 if (msdp->config->rw_activity_callback) {
723 msdp->config->rw_activity_callback(true);
724 }
726 if (msdp->config->rw_activity_callback) {
727 msdp->config->rw_activity_callback(false);
728 }
729 break;
732 break;
735 break;
738 break;
741 break;
744 break;
746 /* don't handle */
747 msdp->result = true;
748 break;
750 /* don't handle */
751 msdp->result = true;
752 break;
754 /* don't handle */
755 msdp->result = true;
756 break;
757 default:
762
763 /* stall IN endpoint */
764 chSysLock();
765 usbStallTransmitI(msdp->config->usbp, msdp->config->bulk_ep);
766 chSysUnlock();
767
768 return false;
769 }
770
771 if (msdp->result) {
772 /* update sense with success status */
777
778 /* reset data length left */
779 cbw->data_len = 0;
780 }
781
782 /* wait for ISR if needed */
783 if (sleep & !msdp->bot_reset) {
785 }
786
787 msd_csw_t *csw = &(msdp->csw);
788
789 if (!msdp->result && cbw->data_len) {
790 /* still bytes left to send, this is too early to send CSW? */
791 chSysLock();
792 usbStallReceiveI(msdp->config->usbp, msdp->config->bulk_ep);
793 usbStallTransmitI(msdp->config->usbp, msdp->config->bulk_ep);
794 chSysUnlock();
795
796 return false;
797 }
798
799 /* update the command status wrapper and send it to the host */
800 csw->status = (msdp->result) ? MSD_COMMAND_PASSED : MSD_COMMAND_FAILED;
801 csw->signature = MSD_CSW_SIGNATURE;
802 csw->data_residue = cbw->data_len;
803 csw->tag = cbw->tag;
804
805 msd_start_transmit(msdp, (const uint8_t *)csw, sizeof(*csw));
806
807 /* wait for ISR */
808 return true;
809}
810
811
816{
817
818 chDbgCheck(msdp != NULL);
819 msdp->bot_reset = false;
820 msdp->reconfigured_or_reset_event = false;
821 msdp->config = NULL;
822 msdp->thread = NULL;
823 msdp->state = MSD_IDLE;
824
825 /* initialize the driver events */
826 chEvtObjectInit(&msdp->evt_connected);
827 chEvtObjectInit(&msdp->evt_ejected);
828
829 /* initialise the binary semaphore as taken */
830 chBSemObjectInit(&msdp->bsem, true);
832
833 /* initialise the sense data structure */
834 size_t i;
835 for (i = 0; i < sizeof(msdp->sense.byte); i++) {
836 msdp->sense.byte[i] = 0x00;
837 }
838 msdp->sense.byte[0] = 0x70; /* response code */
839 msdp->sense.byte[7] = 0x0A; /* additional sense length */
840
841 /* initialize the inquiry data structure */
842 msdp->inquiry.peripheral = 0x00; /* direct access block device */
843 msdp->inquiry.removable = 0x80; /* removable */
844 msdp->inquiry.version = 0x04; /* SPC-2 */
845 msdp->inquiry.response_data_format = 0x02; /* response data format */
846 msdp->inquiry.additional_length = 0x20; /* response has 0x20 + 4 bytes */
847 msdp->inquiry.sccstp = 0x00;
848 msdp->inquiry.bqueetc = 0x00;
849 msdp->inquiry.cmdque = 0x00;
850}
851
856{
857
858 chDbgCheck(msdp != NULL);
860 chDbgCheck(msdp->thread == NULL);
861
862 /* save the configuration */
863 msdp->config = config;
864
865 /* copy the config strings to the inquiry response structure */
866 size_t i;
867 for (i = 0; i < sizeof(msdp->config->short_vendor_id); ++i) {
868 msdp->inquiry.vendor_id[i] = config->short_vendor_id[i];
869 }
870 for (i = 0; i < sizeof(msdp->config->short_product_id); ++i) {
871 msdp->inquiry.product_id[i] = config->short_product_id[i];
872 }
873 for (i = 0; i < sizeof(msdp->config->short_product_version); ++i) {
874 msdp->inquiry.product_rev[i] = config->short_product_version[i];
875 }
876
877 /* set the initial state */
878 msdp->state = MSD_IDLE;
879
880 /* make sure block device is working */
881 while (blkGetDriverState(config->bbdp) != BLK_READY) {
883 }
884
885 /* get block device information */
886 blkGetInfo(config->bbdp, &msdp->block_dev_info);
887
888 /* store the pointer to the mass storage driver into the user param
889 of the USB driver, so that we can find it back in callbacks */
890 config->usbp->in_params[config->bulk_ep] = (void *)msdp;
891 config->usbp->out_params[config->bulk_ep] = (void *)msdp;
892
893 /* run the thread */
895}
896
901{
902
903 chDbgCheck(msdp->thread != NULL);
904
905 /* notify the thread that it's over */
906 chThdTerminate(msdp->thread);
907
908 /* wake the thread up and wait until it ends */
909 chBSemSignal(&msdp->bsem);
910 chThdWait(msdp->thread);
911 msdp->thread = NULL;
912
913 /* release the user params in the USB driver */
914 msdp->config->usbp->in_params[msdp->config->bulk_ep] = NULL;
915 msdp->config->usbp->out_params[msdp->config->bulk_ep] = NULL;
916}
917
918
919
920
929
931{
932 if (dbg_printer != NULL) {
934 }
935}
936
938{
939 if (dbg_printer != NULL) {
941 }
942}
943
944/* Handles global events of the USB driver */
946{
947 (void) usbp;
948 switch (event) {
954 break;
955
956 case USB_EVENT_RESET:
959 break;
962 case USB_EVENT_WAKEUP:
964 break;
965 default:
966 break;
967 }
968}
969
970/* USB device descriptor */
973 (
974 0x0200, /* supported USB version (2.0) */
975 0x00, /* interface class */
976 0x00, /* interface sub-class */
977 0x00, /* interface protocol */
978 64, /* max packet size of control end-point */
979 0x0483, /* vendor ID (ST) */
980 0xBABE, /* product ID (Babe) */
981 0x0100, /* device release number */
982 1, /* index of manufacturer string descriptor */
983 2, /* index of product string descriptor */
984 3, /* index of serial number string descriptor */
985 1 /* number of possible configurations */
986 )
987};
992
993/* configuration descriptor */
995 /* configuration descriptor */
997 (
998 32, /* total length */
999 1, /* number of interfaces */
1000 1, /* value that selects this configuration */
1001 0, /* index of string descriptor describing this configuration */
1002 0xC0, /* attributes (self-powered) */
1003 100 /* max power (100 mA) */
1004 ),
1005
1006 /* interface descriptor */
1008 (
1009 0, /* interface number */
1010 0, /* value used to select alternative setting */
1011 2, /* number of end-points used by this interface */
1012 0x08, /* interface class (Mass Storage) */
1013 0x06, /* interface sub-class (SCSI Transparent Storage) */
1014 0x50, /* interface protocol (Bulk Only) */
1015 0 /* index of string descriptor describing this interface */
1016 ),
1017
1018 /* end-point descriptor */
1020 (
1021 USB_MS_DATA_EP | 0x80, /* address (end point index | OUT direction) */
1022 USB_EP_MODE_TYPE_BULK, /* attributes (bulk) */
1023 64, /* max packet size */
1024 0x05 /* polling interval (ignored for bulk end-points) */
1025 ),
1026
1027 /* end-point descriptor */
1029 (
1030 USB_MS_DATA_EP | 0x00, /* address (end point index | IN direction) */
1031 USB_EP_MODE_TYPE_BULK, /* attributes (bulk) */
1032 64, /* max packet size */
1033 0x05 /* polling interval (ignored for bulk end-points) */
1034 )
1035};
1040
1041/* Language descriptor */
1043 USB_DESC_BYTE(4),
1045 USB_DESC_WORD(0x0409) /* U.S. english */
1046};
1051
1052/* Vendor descriptor */
1054 USB_DESC_BYTE(22),
1056 'S', 0, 'T', 0, 'M', 0, 'i', 0, 'c', 0, 'r', 0, 'o', 0, 'M', 0, 'S', 0, 'D', 0
1057};
1062
1063/* Product descriptor */
1065 USB_DESC_BYTE(24),
1067 'M', 0, 'S', 0, 'D', 0, ' ', 0, 'E', 0, 'x', 0, 'a', 0, 'm', 0, 'p', 0, 'l', 0, 'e', 0
1068};
1073
1074/* Serial number descriptor */
1076 USB_DESC_BYTE(26),
1078 '0', 0, '1', 0, '4', 0, '2', 0, '3', 0, '0', 0, 'F', 0, 'K', 0, '0', 0, '0', 0, '0', 0, '1', 0
1079};
1084
1085
1086/* Handles GET_DESCRIPTOR requests from the USB host */
1088{
1089 (void)usbp;
1090 (void)lang;
1091
1092 switch (type) {
1094 return &deviceDescriptor;
1095
1098
1100 switch (index) {
1101 case 0: return &languageDescriptor;
1102 case 1: return &vendorDescriptor;
1103 case 2: return &productDescriptor;
1104 case 3: return &serialNumberDescriptor;
1105 }
1106 }
1107
1108 return 0;
1109}
1110
1111/* Configuration of the USB driver */
1112static const USBConfig usbConfig = {
1113 usbEvent,
1116 0
1117};
1118
1119
1120
1122{
1123 msdStop(&UMSD);
1124}
1125
1127{
1128 usbStop(&USBD);
1130
1131 msdInit(&UMSD);
1132 /* start the USB mass storage service */
1134
1136
1137 /* start the USB driver */
1142}
1143
1148
1153
1154
1158static void mass_storage_thread(void *arg)
1159{
1160
1162
1163 chRegSetThreadName("USB-MSD");
1164
1165 bool wait_for_isr = false;
1166
1167 /* wait for the usb to be initialised */
1169
1170 while (!chThdShouldTerminateX()) {
1171
1172 if (msdp->reconfigured_or_reset_event) {
1173 /*If the devices is unplugged and re-plugged but did not have a CPU reset,
1174 * we must set the state back to idle.*/
1175 msdp->reconfigured_or_reset_event = false;
1176 msdp->state = MSD_IDLE;
1181 }
1182
1183
1184
1185 wait_for_isr = false;
1186
1187 /* wait on data depending on the current state */
1188 switch (msdp->state) {
1189 case MSD_IDLE:
1191 break;
1194 break;
1195 case MSD_EJECTED:
1196 /* disconnect usb device */
1197 usbDisconnectBus(msdp->config->usbp);
1198 usbStop(msdp->config->usbp);
1199 chThdExit(0);
1200 return;
1201 case MSD_BOT_RESET:
1203 chSysLock();
1204 usb_lld_disable_endpoints(msdp->config->usbp);
1205 chSysUnlock();
1207 chSysLock();
1208 msdp->config->usbp->epc[USB_MS_DATA_EP] = &ep_data_config;
1210 chBSemReset(&msdp->bsem, false);
1211 chSysUnlock();
1212
1214 wait_for_isr = true;
1215 break;
1216 }
1217
1218 /* wait until the ISR wakes thread */
1219 if (wait_for_isr) {
1221 }
1222 }
1223
1224 return;
1225}
uint16_t foo
Definition main_demo5.c:58
Specific RAM section for DMA usage on F7.
#define IN_DMA_SECTION_CLEAR(var)
Definition ram_arch.h:86
static const struct usb_config_descriptor config
Definition usb_ser_hw.c:200
Driver configuration structure.
Definition usb_msd.h:123
usbep_t bulk_ep
Index of the USB endpoint to use for transfers.
Definition usb_msd.h:137
USBDriver * usbp
USB driver to use for communication.
Definition usb_msd.h:127
uint16_t val[TCOUPLE_NB]
static USBMassStorageConfig msdConfig
Definition usbStorage.c:64
static void msd_start_transmit(USBMassStorageDriver *msdp, const uint8_t *buffer, size_t size)
Starts sending data.
Definition usb_msd.c:311
static const USBDescriptor productDescriptor
Definition usb_msd.c:1069
#define MSD_GET_MAX_LUN
Definition usb_msd.c:36
static const uint8_t vendorDescriptorData[]
Definition usb_msd.c:1053
#define SCSI_SENSE_KEY_GOOD
Definition usb_msd.c:69
#define SCSI_CMD_READ_FORMAT_CAPACITIES
Definition usb_msd.c:62
static THD_WORKING_AREA(mass_storage_thread_wa, 1024)
#define SCSI_CMD_START_STOP_UNIT
Definition usb_msd.c:59
#define SCSI_CMD_SEND_DIAGNOSTIC
Definition usb_msd.c:60
#define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION
Definition usb_msd.c:84
#define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE
Definition usb_msd.c:89
#define SCSI_CMD_READ_CAPACITY_10
Definition usb_msd.c:63
bool msdRequestsHook(USBDriver *usbp)
Default requests hook.
Definition usb_msd.c:205
static void usbEvent(USBDriver *usbp, usbevent_t event)
Definition usb_msd.c:945
#define MSD_REQ_RESET
Definition usb_msd.c:35
void debug_snd_evt_i(eventmask_t evt)
Definition usb_msd.c:921
void debug_snd_evt_inl(eventmask_t evt)
Definition usb_msd.c:930
#define MSD_COMMAND_PASSED
Definition usb_msd.c:49
static const USBDescriptor languageDescriptor
Definition usb_msd.c:1047
void init_msd_driver(void *dbgThreadPtr, USBMassStorageConfig *msdConfig)
Definition usb_msd.c:1126
static DWORD swap_uint32(const DWORD val)
Byte-swap a 32 bits unsigned integer.
Definition usb_msd.c:140
#define SCSI_ASENSE_INVALID_FIELD_IN_CDB
Definition usb_msd.c:90
#define SCSI_SENSE_KEY_RECOVERED_ERROR
Definition usb_msd.c:70
static void msd_wait_for_isr(USBMassStorageDriver *msdp)
Wait until the end-point interrupt handler has been called.
Definition usb_msd.c:285
#define SCSI_ASENSE_MEDIUM_NOT_PRESENT
Definition usb_msd.c:94
static void msd_handle_end_point_notification(USBDriver *usbp, usbep_t ep)
Called when data can be read or written on the endpoint – wakes the thread up.
Definition usb_msd.c:298
static const USBDescriptor vendorDescriptor
Definition usb_msd.c:1058
static WORD swap_uint16(const WORD val)
Byte-swap a 16 bits unsigned integer.
Definition usb_msd.c:149
bool msd_scsi_process_inquiry(USBMassStorageDriver *msdp)
Processes an INQUIRY SCSI command.
Definition usb_msd.c:349
#define MSD_COMMAND_FAILED
Definition usb_msd.c:50
static const USBDescriptor * getDescriptor(USBDriver *usbp, uint8_t type, uint8_t index, uint16_t lang)
Definition usb_msd.c:1087
#define SCSI_ASENSE_WRITE_PROTECTED
Definition usb_msd.c:91
#define SCSI_SENSE_KEY_DATA_PROTECT
Definition usb_msd.c:76
static const USBDescriptor serialNumberDescriptor
Definition usb_msd.c:1080
#define MSD_SETUP_INDEX(setup)
Definition usb_msd.c:45
#define MSD_SETUP_LENGTH(setup)
Definition usb_msd.c:46
#define SCSI_ASENSEQ_NO_QUALIFIER
Definition usb_msd.c:96
#define MSD_CBW_SIGNATURE
Definition usb_msd.c:39
thread_t * dbg_printer
Definition usb_msd.c:109
static const USBDescriptor deviceDescriptor
Definition usb_msd.c:988
#define MSD_CSW_SIGNATURE
Definition usb_msd.c:40
bool msd_scsi_process_mode_sense_6(USBMassStorageDriver *msdp)
Processes a MODE_SENSE_6 SCSI command.
Definition usb_msd.c:588
static USBMassStorageDriver UMSD
Definition usb_msd.c:33
#define SCSI_SENSE_KEY_NOT_READY
Definition usb_msd.c:71
void msdStart(USBMassStorageDriver *msdp, const USBMassStorageConfig *config)
Starts a USB mass storage driver.
Definition usb_msd.c:855
bool msd_scsi_process_start_read_write_10(USBMassStorageDriver *msdp)
Processes a READ_WRITE_10 SCSI command.
Definition usb_msd.c:449
#define SCSI_CMD_VERIFY_10
Definition usb_msd.c:66
bool msd_scsi_process_read_capacity_10(USBMassStorageDriver *msdp)
Processes a READ_CAPACITY_10 SCSI command.
Definition usb_msd.c:407
void msdInit(USBMassStorageDriver *msdp)
Initializse a USB mass storage driver.
Definition usb_msd.c:815
void msdConfigureHookI(USBMassStorageDriver *msdp)
USB device configured handler.
Definition usb_msd.c:188
#define SCSI_ASENSE_INVALID_COMMAND
Definition usb_msd.c:88
void msd_register_evt_connected(event_listener_t *elp, eventmask_t mask)
register connected event source in local event mask
Definition usb_msd.c:1144
bool msd_scsi_process_start_stop_unit(USBMassStorageDriver *msdp)
Processes a START_STOP_UNIT SCSI command.
Definition usb_msd.c:570
#define SCSI_SENSE_KEY_ILLEGAL_REQUEST
Definition usb_msd.c:74
void msd_register_evt_ejected(event_listener_t *elp, eventmask_t mask)
register ejected event source in local event mask
Definition usb_msd.c:1149
static void msd_scsi_set_sense(USBMassStorageDriver *msdp, uint8_t key, uint8_t acode, uint8_t aqual)
Changes the SCSI sense information.
Definition usb_msd.c:339
static void msd_start_receive(USBMassStorageDriver *msdp, uint8_t *buffer, size_t size)
Starts receiving data.
Definition usb_msd.c:325
static USBOutEndpointState ep1_out_state
OUT end-point 1 state.
Definition usb_msd.c:163
bool msd_wait_for_command_block(USBMassStorageDriver *msdp)
Waits for a new command block.
Definition usb_msd.c:654
static const USBDescriptor configurationDescriptor
Definition usb_msd.c:1036
#define MSD_SETUP_VALUE(setup)
Definition usb_msd.c:44
static const uint8_t deviceDescriptorData[]
Definition usb_msd.c:971
#define SCSI_CMD_TEST_UNIT_READY
Definition usb_msd.c:54
static USBInEndpointState ep1_in_state
IN end-point 1 state.
Definition usb_msd.c:158
void msdStop(USBMassStorageDriver *msdp)
Stops a USB mass storage driver.
Definition usb_msd.c:900
static const uint8_t serialNumberDescriptorData[]
Definition usb_msd.c:1075
bool msd_read_command_block(USBMassStorageDriver *msdp)
Reads a newly received command block.
Definition usb_msd.c:669
#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL
Definition usb_msd.c:61
uint16_t WORD
Definition usb_msd.c:134
#define SCSI_CMD_MODE_SENSE_6
Definition usb_msd.c:58
#define SCSI_ASENSE_WRITE_FAULT
Definition usb_msd.c:85
#define SCSI_CMD_INQUIRY
Definition usb_msd.c:57
#define SCSI_CMD_FORMAT_UNIT
Definition usb_msd.c:56
static const uint8_t languageDescriptorData[]
Definition usb_msd.c:1042
bool msd_scsi_process_read_format_capacities(USBMassStorageDriver *msdp)
Processes a READ_FORMAT_CAPACITIES SCSI command.
Definition usb_msd.c:608
void debug_snd_evt_nl(eventmask_t evt)
Definition usb_msd.c:937
#define SCSI_CMD_REQUEST_SENSE
Definition usb_msd.c:55
#define SCSI_CMD_WRITE_10
Definition usb_msd.c:65
#define SCSI_CMD_READ_10
Definition usb_msd.c:64
#define SCSI_ASENSE_READ_ERROR
Definition usb_msd.c:87
bool msd_scsi_process_test_unit_ready(USBMassStorageDriver *msdp)
Processes a TEST_UNIT_READY SCSI command.
Definition usb_msd.c:627
static const USBEndpointConfig ep_data_config
End-point 1 initialization structure.
Definition usb_msd.c:168
bool msd_scsi_process_request_sense(USBMassStorageDriver *msdp)
Processes a REQUEST_SENSE SCSI command.
Definition usb_msd.c:391
bool msd_scsi_process_send_diagnostic(USBMassStorageDriver *msdp)
Processes a SEND_DIAGNOSTIC SCSI command.
Definition usb_msd.c:425
static const uint8_t productDescriptorData[]
Definition usb_msd.c:1064
static const uint8_t configurationDescriptorData[]
Definition usb_msd.c:994
#define SCSI_SENSE_KEY_MEDIUM_ERROR
Definition usb_msd.c:72
uint32_t DWORD
Definition usb_msd.c:133
void deinit_msd_driver(void)
Definition usb_msd.c:1121
static void mass_storage_thread(void *arg)
Mass storage thread that processes commands.
Definition usb_msd.c:1158
static const USBConfig usbConfig
Definition usb_msd.c:1112
uint32_t last_block_addr
Definition usb_msd.c:114
#define EVT_SCSI_PROC_INQ
Definition usb_msd.h:61
#define SEM_RELEASED
Definition usb_msd.h:47
const USBMassStorageConfig * config
Definition usb_msd.h:173
#define EVT_SCSI_REQ_TEST_UNIT_READY
Definition usb_msd.h:54
bool reconfigured_or_reset_event
Definition usb_msd.h:183
#define PACK_STRUCT_END
Definition usb_msd.h:37
msd_state_t state
Definition usb_msd.h:178
#define EVT_WAIT_FOR_COMMAND_BLOCK
Definition usb_msd.h:58
#define EVT_SEM_TAKEN
Definition usb_msd.h:51
#define EVT_SCSI_REQ_READ_CAP10
Definition usb_msd.h:60
event_source_t evt_ejected
Definition usb_msd.h:176
uint8_t capacity_list_length
Definition usb_msd.c:123
#define PACK_STRUCT_BEGIN
Definition usb_msd.h:36
#define USB_MS_DATA_EP
Definition usb_msd.h:40
#define EVT_SCSI_REQ_READ_FMT_CAP
Definition usb_msd.h:55
#define EVT_SCSI_REQ_SENSE6
Definition usb_msd.h:56
#define EVT_BOT_RESET
Definition usb_msd.h:50
#define EVT_SEM_RELEASED
Definition usb_msd.h:52
uint32_t block_size
Definition usb_msd.c:115
event_source_t evt_connected
Definition usb_msd.h:176
#define SEM_TAKEN
Definition usb_msd.h:46
#define USBD
Definition usb_msd.h:44
uint32_t block_count
Definition usb_msd.c:124
#define EVT_USB_RESET
Definition usb_msd.h:49
#define EVT_SCSI_REQ_SENSE10
Definition usb_msd.h:57
uint32_t desc_and_block_length
Definition usb_msd.c:125
binary_semaphore_t bsem
Definition usb_msd.h:174
@ MSD_READ_COMMAND_BLOCK
Definition usb_msd.h:115
@ MSD_IDLE
Definition usb_msd.h:114
@ MSD_EJECTED
Definition usb_msd.h:116
@ MSD_BOT_RESET
Definition usb_msd.h:117
Response to a READ_CAPACITY_10 SCSI command.
Definition usb_msd.c:113
USB mass storage driver structure.
Definition usb_msd.h:172
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.