Paparazzi UAS  v5.10_stable-5-g83a0da5-dirty
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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 
29 /* Request types */
30 #define MSD_REQ_RESET 0xFF
31 #define MSD_GET_MAX_LUN 0xFE
32 
33 /* CBW/CSW block signatures */
34 #define MSD_CBW_SIGNATURE 0x43425355
35 #define MSD_CSW_SIGNATURE 0x53425355
36 
37 /* Setup packet access macros */
38 #define MSD_SETUP_WORD(setup, index) (uint16_t)(((uint16_t)setup[index + 1] << 8) | (setup[index] & 0x00FF))
39 #define MSD_SETUP_VALUE(setup) MSD_SETUP_WORD(setup, 2)
40 #define MSD_SETUP_INDEX(setup) MSD_SETUP_WORD(setup, 4)
41 #define MSD_SETUP_LENGTH(setup) MSD_SETUP_WORD(setup, 6)
42 
43 /* Command statuses */
44 #define MSD_COMMAND_PASSED 0x00
45 #define MSD_COMMAND_FAILED 0x01
46 #define MSD_COMMAND_PHASE_ERROR 0x02
47 
48 /* SCSI commands */
49 #define SCSI_CMD_TEST_UNIT_READY 0x00
50 #define SCSI_CMD_REQUEST_SENSE 0x03
51 #define SCSI_CMD_FORMAT_UNIT 0x04
52 #define SCSI_CMD_INQUIRY 0x12
53 #define SCSI_CMD_MODE_SENSE_6 0x1A
54 #define SCSI_CMD_START_STOP_UNIT 0x1B
55 #define SCSI_CMD_SEND_DIAGNOSTIC 0x1D
56 #define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
57 #define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23
58 #define SCSI_CMD_READ_CAPACITY_10 0x25
59 #define SCSI_CMD_READ_10 0x28
60 #define SCSI_CMD_WRITE_10 0x2A
61 #define SCSI_CMD_VERIFY_10 0x2F
62 
63 /* SCSI sense keys */
64 #define SCSI_SENSE_KEY_GOOD 0x00
65 #define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01
66 #define SCSI_SENSE_KEY_NOT_READY 0x02
67 #define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03
68 #define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04
69 #define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05
70 #define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06
71 #define SCSI_SENSE_KEY_DATA_PROTECT 0x07
72 #define SCSI_SENSE_KEY_BLANK_CHECK 0x08
73 #define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09
74 #define SCSI_SENSE_KEY_COPY_ABORTED 0x0A
75 #define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B
76 #define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D
77 #define SCSI_SENSE_KEY_MISCOMPARE 0x0E
78 
79 #define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION 0x00
80 #define SCSI_ASENSE_WRITE_FAULT 0x03
81 #define SCSI_ASENSE_LOGICAL_UNIT_NOT_READY 0x04
82 #define SCSI_ASENSE_READ_ERROR 0x11
83 #define SCSI_ASENSE_INVALID_COMMAND 0x20
84 #define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21
85 #define SCSI_ASENSE_INVALID_FIELD_IN_CDB 0x24
86 #define SCSI_ASENSE_WRITE_PROTECTED 0x27
87 #define SCSI_ASENSE_NOT_READY_TO_READY_CHANGE 0x28
88 #define SCSI_ASENSE_FORMAT_ERROR 0x31
89 #define SCSI_ASENSE_MEDIUM_NOT_PRESENT 0x3A
90 
91 #define SCSI_ASENSEQ_NO_QUALIFIER 0x00
92 #define SCSI_ASENSEQ_FORMAT_COMMAND_FAILED 0x01
93 #define SCSI_ASENSEQ_INITIALIZING_COMMAND_REQUIRED 0x02
94 #define SCSI_ASENSEQ_OPERATION_IN_PROGRESS 0x07
95 
99 PACK_STRUCT_BEGIN typedef struct {
102 } PACK_STRUCT_STRUCT msd_scsi_read_capacity_10_response_t PACK_STRUCT_END;
103 
107 PACK_STRUCT_BEGIN typedef struct {
108  uint8_t reserved[3];
112 } PACK_STRUCT_STRUCT msd_scsi_read_format_capacities_response_t PACK_STRUCT_END;
113 
117 static uint8_t rw_buf[2][512];
118 
119 typedef uint32_t DWORD __attribute__((__may_alias__));;
120 typedef uint16_t WORD __attribute__((__may_alias__));
121 
122 
126 static inline DWORD swap_uint32(DWORD val);
127 
128 static inline DWORD swap_uint32(DWORD val)
129 {
130  val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF);
131  return ((val << 16) & 0xFFFF0000) | ((val >> 16) & 0x0000FFFF);
132 }
136 #define swap_uint16(x) (((((WORD)(x)) >> 8) & 0xff) | ((((WORD)(x)) & 0xff) << 8))
137 
138 static void msd_handle_end_point_notification(USBDriver *usbp, usbep_t ep);
139 
143 static USBInEndpointState ep1_in_state;
144 
148 static USBOutEndpointState ep1_out_state;
149 
153 static const USBEndpointConfig ep_data_config = {
154  USB_EP_MODE_TYPE_BULK,
155  NULL,
158  64,
159  64,
160  &ep1_in_state,
161  &ep1_out_state,
162  1,
163  NULL
164 };
165 
174 {
175  usbInitEndpointI(msdp->config->usbp, msdp->config->bulk_ep, &ep_data_config);
176  chBSemSignalI(&msdp->bsem);
177  chEvtBroadcastI(&msdp->evt_connected);
178 }
179 
188 bool msdRequestsHook(USBDriver *usbp)
189 {
190 
191  /* check that the request is of type Class / Interface */
192  if (((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) &&
193  ((usbp->setup[0] & USB_RTYPE_RECIPIENT_MASK) == USB_RTYPE_RECIPIENT_INTERFACE)) {
194 
195  /* check that the request is for interface 0 */
196  if (MSD_SETUP_INDEX(usbp->setup) != 0) {
197  return false;
198  }
199 
200  /* act depending on bRequest = setup[1] */
201  switch (usbp->setup[1]) {
202  case MSD_REQ_RESET:
203  /* check that it is a HOST2DEV request */
204  if (((usbp->setup[0] & USB_RTYPE_DIR_MASK) != USB_RTYPE_DIR_HOST2DEV) ||
205  (MSD_SETUP_LENGTH(usbp->setup) != 0) ||
206  (MSD_SETUP_VALUE(usbp->setup) != 0)) {
207  return false;
208  }
209 
210  /* reset all endpoints */
211  /* TODO!*/
212  /* The device shall NAK the status stage of the device request until
213  * the Bulk-Only Mass Storage Reset is complete.
214  */
215  return true;
216  case MSD_GET_MAX_LUN:
217  /* check that it is a DEV2HOST request */
218  if (((usbp->setup[0] & USB_RTYPE_DIR_MASK) != USB_RTYPE_DIR_DEV2HOST) ||
219  (MSD_SETUP_LENGTH(usbp->setup) != 1) ||
220  (MSD_SETUP_VALUE(usbp->setup) != 0)) {
221  return false;
222  }
223 
224  static uint8_t len_buf[1] = {0};
225  /* stall to indicate that we don't support LUN */
226  usbSetupTransfer(usbp, len_buf, 1, NULL);
227  return true;
228  default:
229  return false;
230  break;
231  }
232  }
233 
234  return false;
235 }
236 
241 {
242 
243  /* sleep until it completes */
244  chSysLock();
245  chBSemWaitS(&msdp->bsem);
246  chSysUnlock();
247 }
248 
252 static void msd_handle_end_point_notification(USBDriver *usbp, usbep_t ep)
253 {
254 
255  (void)usbp;
256  (void)ep;
257 
258  chSysLockFromISR();
259  chBSemSignalI(&((USBMassStorageDriver *)usbp->in_params[ep])->bsem);
260  chSysUnlockFromISR();
261 }
262 
266 static void msd_start_transmit(USBMassStorageDriver *msdp, const uint8_t *buffer, size_t size)
267 {
268  chSysLock();
269  usbStartTransmitI(msdp->config->usbp, msdp->config->bulk_ep, buffer, size);
270  chSysUnlock();
271 }
272 
276 static void msd_start_receive(USBMassStorageDriver *msdp, uint8_t *buffer, size_t size)
277 {
278  chSysLock();
279  usbStartReceiveI(msdp->config->usbp, msdp->config->bulk_ep, buffer, size);
280  chSysUnlock();
281 }
282 
286 static inline void msd_scsi_set_sense(USBMassStorageDriver *msdp, uint8_t key, uint8_t acode, uint8_t aqual)
287 {
288  msdp->sense.byte[2] = key;
289  msdp->sense.byte[12] = acode;
290  msdp->sense.byte[13] = aqual;
291 }
292 
297 {
298 
299  msd_cbw_t *cbw = &(msdp->cbw);
300 
301  /* check the EVPD bit (Vital Product Data) */
302  if (cbw->scsi_cmd_data[1] & 0x01) {
303 
304  /* check the Page Code byte to know the type of product data to reply */
305  switch (cbw->scsi_cmd_data[2]) {
306 
307  /* unit serial number */
308  case 0x80: {
309  uint8_t response[] = {'0'}; /* TODO */
310  msd_start_transmit(msdp, response, sizeof(response));
311  msdp->result = true;
312 
313  /* wait for ISR */
314  return true;
315  }
316 
317  /* unhandled */
318  default:
319  msd_scsi_set_sense(msdp,
323  return false;
324  }
325  } else {
326  msd_start_transmit(msdp, (const uint8_t *)&msdp->inquiry, sizeof(msdp->inquiry));
327  msdp->result = true;
328 
329  /* wait for ISR */
330  return true;
331  }
332 }
333 
338 {
339 
340  msd_start_transmit(msdp, (const uint8_t *)&msdp->sense, sizeof(msdp->sense));
341  msdp->result = true;
342 
343  /* wait for ISR immediately, otherwise the caller may reset the sense bytes before they are sent to the host! */
344  msd_wait_for_isr(msdp);
345 
346  /* ... don't wait for ISR, we just did it */
347  return false;
348 }
349 
354 {
355 
356  static msd_scsi_read_capacity_10_response_t response;
357 
358  response.block_size = swap_uint32(msdp->block_dev_info.blk_size);
359  response.last_block_addr = swap_uint32(msdp->block_dev_info.blk_num - 1);
360 
361  msd_start_transmit(msdp, (const uint8_t *)&response, sizeof(response));
362  msdp->result = true;
363 
364  /* wait for ISR */
365  return true;
366 }
367 
372 {
373 
374  msd_cbw_t *cbw = &(msdp->cbw);
375 
376  if (!(cbw->scsi_cmd_data[1] & (1 << 2))) {
377  /* only self-test supported - update SENSE key and fail the command */
378  msd_scsi_set_sense(msdp,
382  msdp->result = false;
383  return false;
384  }
385 
386  /* TODO: actually perform the test */
387  msdp->result = true;
388 
389  /* don't wait for ISR */
390  return false;
391 }
392 
397 {
398 
399  msd_cbw_t *cbw = &(msdp->cbw);
400 
401  if ((cbw->scsi_cmd_data[0] == SCSI_CMD_WRITE_10) && blkIsWriteProtected(msdp->config->bbdp)) {
402  /* device is write protected and a write has been issued */
403  /* block address is invalid, update SENSE key and return command fail */
404  msd_scsi_set_sense(msdp,
408  msdp->result = false;
409 
410  /* don't wait for ISR */
411  return false;
412  }
413 
414  uint32_t rw_block_address = swap_uint32(*(DWORD *)&cbw->scsi_cmd_data[2]);
415  uint16_t total = swap_uint16(*(WORD *)&cbw->scsi_cmd_data[7]);
416  uint16_t i = 0;
417 
418  if (rw_block_address >= msdp->block_dev_info.blk_num) {
419  /* block address is invalid, update SENSE key and return command fail */
420  msd_scsi_set_sense(msdp,
424  msdp->result = false;
425 
426  /* don't wait for ISR */
427  return false;
428  }
429 
430  if (cbw->scsi_cmd_data[0] == SCSI_CMD_WRITE_10) {
431  /* process a write command */
432 
433  /* get the first packet */
434  msd_start_receive(msdp, rw_buf[i % 2], msdp->block_dev_info.blk_size);
435  msd_wait_for_isr(msdp);
436 
437  /* loop over each block */
438  for (i = 0; i < total; i++) {
439 
440  if (i < (total - 1)) {
441  /* there is at least one block of data left to be read over USB */
442  /* queue this read before issuing the blocking write */
443  msd_start_receive(msdp, rw_buf[(i + 1) % 2], msdp->block_dev_info.blk_size);
444  }
445 
446  /* now write the block to the block device */
447  if (blkWrite(msdp->config->bbdp, rw_block_address++, rw_buf[i % 2], 1) == HAL_FAILED) {
448  /* write failed */
449  msd_scsi_set_sense(msdp,
453  msdp->result = false;
454 
455  /* don't wait for ISR */
456  return false;
457  }
458 
459  if (i < (total - 1)) {
460  /* now wait for the USB event to complete */
461  msd_wait_for_isr(msdp);
462  }
463  }
464  } else {
465  /* process a read command */
466 
467  i = 0;
468 
469  /* read the first block from block device */
470  if (blkRead(msdp->config->bbdp, rw_block_address++, rw_buf[i % 2], 1) == HAL_FAILED) {
471  /* read failed */
472  msd_scsi_set_sense(msdp,
476  msdp->result = false;
477 
478  /* don't wait for ISR */
479  return false;
480  }
481 
482  /* loop over each block */
483  for (i = 0; i < total; i++) {
484  /* transmit the block */
485  msd_start_transmit(msdp, rw_buf[i % 2], msdp->block_dev_info.blk_size);
486 
487  if (i < (total - 1)) {
488  /* there is at least one more block to be read from device */
489  /* so read that whilst the USB transfer takes place */
490  if (blkRead(msdp->config->bbdp, rw_block_address++, rw_buf[(i + 1) % 2], 1) == HAL_FAILED) {
491  /* read failed */
492  msd_scsi_set_sense(msdp,
496  msdp->result = false;
497 
498  /* wait for ISR (the previous transmission is still running) */
499  return true;
500  }
501  }
502 
503  /* wait for the USB event to complete */
504  msd_wait_for_isr(msdp);
505  }
506  }
507 
508  msdp->result = true;
509 
510  /* don't wait for ISR */
511  return false;
512 }
513 
518 {
519 
520  if ((msdp->cbw.scsi_cmd_data[4] & 0x03) == 0x02) {
521  /* device has been ejected */
522  chEvtBroadcast(&msdp->evt_ejected);
523  msdp->state = MSD_EJECTED;
524  }
525 
526  msdp->result = true;
527 
528  /* don't wait for ISR */
529  return false;
530 }
531 
536 {
537 
538  static uint8_t response[4] = {
539  0x03, /* number of bytes that follow */
540  0x00, /* medium type is SBC */
541  0x00, /* not write protected (TODO handle it correctly) */
542  0x00 /* no block descriptor */
543  };
544 
545  msd_start_transmit(msdp, response, sizeof(response));
546  msdp->result = true;
547 
548  /* wait for ISR */
549  return true;
550 }
551 
556 {
557 
558  msd_scsi_read_format_capacities_response_t response;
559  response.capacity_list_length = 1;
560  response.block_count = swap_uint32(msdp->block_dev_info.blk_num);
561  response.desc_and_block_length = swap_uint32((0x02 << 24) | (msdp->block_dev_info.blk_size & 0x00FFFFFF));
562 
563  msd_start_transmit(msdp, (const uint8_t *)&response, sizeof(response));
564  msdp->result = true;
565 
566  /* wait for ISR */
567  return true;
568 }
569 
574 {
575 
576  if (blkIsInserted(msdp->config->bbdp)) {
577  /* device inserted and ready */
578  msdp->result = true;
579  } else {
580  /* device not present or not ready */
581  msd_scsi_set_sense(msdp,
585  msdp->result = false;
586  }
587 
588  /* don't wait for ISR */
589  return false;
590 }
591 
596 {
597 
598  msd_start_receive(msdp, (uint8_t *)&msdp->cbw, sizeof(msdp->cbw));
600 
601  /* wait for ISR */
602  return true;
603 }
604 
609 {
610 
611  msd_cbw_t *cbw = &(msdp->cbw);
612 
613  /* by default transition back to the idle state */
614  msdp->state = MSD_IDLE;
615 
616  /* check the command */
617  if ((cbw->signature != MSD_CBW_SIGNATURE) ||
618  (cbw->lun > 0) ||
619  ((cbw->data_len > 0) && (cbw->flags & 0x1F)) ||
620  (cbw->scsi_cmd_len == 0) ||
621  (cbw->scsi_cmd_len > 16)) {
622 
623  /* stall both IN and OUT endpoints */
624  chSysLock();
625  usbStallReceiveI(msdp->config->usbp, msdp->config->bulk_ep);
626  usbStallTransmitI(msdp->config->usbp, msdp->config->bulk_ep);
627  chSysUnlock();
628 
629  /* don't wait for ISR */
630  return false;
631  }
632 
633  bool sleep = false;
634 
635  /* check the command */
636  switch (cbw->scsi_cmd_data[0]) {
637  case SCSI_CMD_INQUIRY:
638  sleep = msd_scsi_process_inquiry(msdp);
639  break;
641  sleep = msd_scsi_process_request_sense(msdp);
642  break;
644  sleep = msd_scsi_process_read_capacity_10(msdp);
645  break;
646  case SCSI_CMD_READ_10:
647  case SCSI_CMD_WRITE_10:
648  if (msdp->config->rw_activity_callback) {
649  msdp->config->rw_activity_callback(true);
650  }
652  if (msdp->config->rw_activity_callback) {
653  msdp->config->rw_activity_callback(false);
654  }
655  break;
657  sleep = msd_scsi_process_send_diagnostic(msdp);
658  break;
660  sleep = msd_scsi_process_mode_sense_6(msdp);
661  break;
663  sleep = msd_scsi_process_start_stop_unit(msdp);
664  break;
667  break;
669  sleep = msd_scsi_process_test_unit_ready(msdp);
670  break;
672  /* don't handle */
673  msdp->result = true;
674  break;
676  /* don't handle */
677  msdp->result = true;
678  break;
679  case SCSI_CMD_VERIFY_10:
680  /* don't handle */
681  msdp->result = true;
682  break;
683  default:
684  msd_scsi_set_sense(msdp,
688 
689  /* stall IN endpoint */
690  chSysLock();
691  usbStallTransmitI(msdp->config->usbp, msdp->config->bulk_ep);
692  chSysUnlock();
693 
694  return false;
695  }
696 
697  if (msdp->result) {
698  /* update sense with success status */
699  msd_scsi_set_sense(msdp,
703 
704  /* reset data length left */
705  cbw->data_len = 0;
706  }
707 
708  /* wait for ISR if needed */
709  if (sleep) {
710  msd_wait_for_isr(msdp);
711  }
712 
713  msd_csw_t *csw = &(msdp->csw);
714 
715  if (!msdp->result && cbw->data_len) {
716  /* still bytes left to send, this is too early to send CSW? */
717  chSysLock();
718  usbStallReceiveI(msdp->config->usbp, msdp->config->bulk_ep);
719  usbStallTransmitI(msdp->config->usbp, msdp->config->bulk_ep);
720  chSysUnlock();
721 
722  /*return false;*/
723  }
724 
725  /* update the command status wrapper and send it to the host */
726  csw->status = (msdp->result) ? MSD_COMMAND_PASSED : MSD_COMMAND_FAILED;
727  csw->signature = MSD_CSW_SIGNATURE;
728  csw->data_residue = cbw->data_len;
729  csw->tag = cbw->tag;
730 
731  msd_start_transmit(msdp, (const uint8_t *)csw, sizeof(*csw));
732 
733  /* wait for ISR */
734  return true;
735 }
736 
740 static THD_WORKING_AREA(mass_storage_thread_wa, 1024);
741 static void mass_storage_thread(void *arg)
742 {
743 
745 
746  chRegSetThreadName("USB-MSD");
747 
748  bool wait_for_isr = false;
749 
750  /* wait for the usb to be initialised */
751  msd_wait_for_isr(msdp);
752 
753  while (!chThdShouldTerminateX()) {
754  wait_for_isr = false;
755 
756  /* wait on data depending on the current state */
757  switch (msdp->state) {
758  case MSD_IDLE:
759  wait_for_isr = msd_wait_for_command_block(msdp);
760  break;
762  wait_for_isr = msd_read_command_block(msdp);
763  break;
764  case MSD_EJECTED:
765  /* disconnect usb device */
766  usbDisconnectBus(msdp->config->usbp);
767  usbStop(msdp->config->usbp);
768  chThdExit(0);
769  }
770 
771  /* wait until the ISR wakes thread */
772  if (wait_for_isr) {
773  msd_wait_for_isr(msdp);
774  }
775  }
776 
777 }
778 
783 {
784 
785  chDbgAssert(msdp != NULL, "msdInit");
786 
787  msdp->config = NULL;
788  msdp->thread = NULL;
789  msdp->state = MSD_IDLE;
790 
791  /* initialize the driver events */
792  chEvtObjectInit(&msdp->evt_connected);
793  chEvtObjectInit(&msdp->evt_ejected);
794 
795  /* initialise the binary semaphore as taken */
796  chBSemObjectInit(&msdp->bsem, true);
797 
798  /* initialise the sense data structure */
799  size_t i;
800  for (i = 0; i < sizeof(msdp->sense.byte); i++) {
801  msdp->sense.byte[i] = 0x00;
802  }
803  msdp->sense.byte[0] = 0x70; /* response code */
804  msdp->sense.byte[7] = 0x0A; /* additional sense length */
805 
806  /* initialize the inquiry data structure */
807  msdp->inquiry.peripheral = 0x00; /* direct access block device */
808  msdp->inquiry.removable = 0x80; /* removable */
809  msdp->inquiry.version = 0x04; /* SPC-2 */
810  msdp->inquiry.response_data_format = 0x02; /* response data format */
811  msdp->inquiry.additional_length = 0x20; /* response has 0x20 + 4 bytes */
812  msdp->inquiry.sccstp = 0x00;
813  msdp->inquiry.bqueetc = 0x00;
814  msdp->inquiry.cmdque = 0x00;
815 }
816 
821 {
822 
823  chDbgAssert(msdp != NULL, "msdStart");
824  chDbgAssert(config != NULL, "msdStart");
825  chDbgAssert(msdp->thread == NULL, "msdStart");
826 
827  /* save the configuration */
828  msdp->config = config;
829 
830  /* copy the config strings to the inquiry response structure */
831  size_t i;
832  for (i = 0; i < sizeof(msdp->config->short_vendor_id); ++i) {
833  msdp->inquiry.vendor_id[i] = config->short_vendor_id[i];
834  }
835  for (i = 0; i < sizeof(msdp->config->short_product_id); ++i) {
836  msdp->inquiry.product_id[i] = config->short_product_id[i];
837  }
838  for (i = 0; i < sizeof(msdp->config->short_product_version); ++i) {
839  msdp->inquiry.product_rev[i] = config->short_product_version[i];
840  }
841 
842  /* set the initial state */
843  msdp->state = MSD_IDLE;
844 
845  /* make sure block device is working */
846  while (blkGetDriverState(config->bbdp) != BLK_READY) {
847  chThdSleepMilliseconds(50);
848  }
849 
850  /* get block device information */
851  blkGetInfo(config->bbdp, &msdp->block_dev_info);
852 
853  /* store the pointer to the mass storage driver into the user param
854  of the USB driver, so that we can find it back in callbacks */
855  config->usbp->in_params[config->bulk_ep] = (void *)msdp;
856  config->usbp->out_params[config->bulk_ep] = (void *)msdp;
857 
858  /* run the thread */
859  msdp->thread = chThdCreateStatic(mass_storage_thread_wa, sizeof(mass_storage_thread_wa), NORMALPRIO + 1,
860  mass_storage_thread, msdp);
861 }
862 
867 {
868 
869  chDbgAssert(msdp->thread != NULL, "msdStop");
870 
871  /* notify the thread that it's over */
872  chThdTerminate(msdp->thread);
873 
874  /* wake the thread up and wait until it ends */
875  chBSemSignal(&msdp->bsem);
876  chThdWait(msdp->thread);
877  msdp->thread = NULL;
878 
879  /* release the user params in the USB driver */
880  msdp->config->usbp->in_params[msdp->config->bulk_ep] = NULL;
881  msdp->config->usbp->out_params[msdp->config->bulk_ep] = NULL;
882 }
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:252
unsigned short uint16_t
Definition: types.h:16
#define SCSI_CMD_REQUEST_SENSE
Definition: usb_msd.c:50
bool msd_scsi_process_read_capacity_10(USBMassStorageDriver *msdp)
Processes a READ_CAPACITY_10 SCSI command.
Definition: usb_msd.c:353
static const USBEndpointConfig ep_data_config
End-point 1 initialization structure.
Definition: usb_msd.c:153
void msdStop(USBMassStorageDriver *msdp)
Stops a USB mass storage driver.
Definition: usb_msd.c:866
static uint8_t rw_buf[2][512]
Read-write buffers (TODO: need a way of specifying the size of this)
Definition: usb_msd.c:117
uint16_t WORD
Definition: usb_msd.c:119
#define MSD_REQ_RESET
Definition: usb_msd.c:30
#define SCSI_SENSE_KEY_DATA_PROTECT
Definition: usb_msd.c:71
void msdConfigureHookI(USBMassStorageDriver *msdp)
USB device configured handler.
Definition: usb_msd.c:173
BlockDeviceInfo block_dev_info
Definition: usb_msd.h:158
static THD_WORKING_AREA(mass_storage_thread_wa, 1024)
Mass storage thread that processes commands.
static USBOutEndpointState ep1_out_state
OUT end-point 1 state.
Definition: usb_msd.c:148
#define SCSI_SENSE_KEY_ILLEGAL_REQUEST
Definition: usb_msd.c:69
bool msd_scsi_process_start_read_write_10(USBMassStorageDriver *msdp)
Processes a READ_WRITE_10 SCSI command.
Definition: usb_msd.c:396
msd_state_t state
Definition: usb_msd.h:159
static DWORD swap_uint32(DWORD val)
Byte-swap a 32 bits unsigned integer.
Definition: usb_msd.c:128
static void mass_storage_thread(void *arg)
Definition: usb_msd.c:741
#define SCSI_CMD_READ_CAPACITY_10
Definition: usb_msd.c:58
#define SCSI_ASENSE_WRITE_FAULT
Definition: usb_msd.c:80
uint8_t capacity_list_length
Definition: usb_msd.c:109
void msdInit(USBMassStorageDriver *msdp)
Initializse a USB mass storage driver.
Definition: usb_msd.c:782
#define MSD_SETUP_INDEX(setup)
Definition: usb_msd.c:40
usbep_t bulk_ep
Index of the USB endpoint to use for transfers.
Definition: usb_msd.h:118
static USBInEndpointState ep1_in_state
IN end-point 1 state.
Definition: usb_msd.c:143
#define SCSI_SENSE_KEY_MEDIUM_ERROR
Definition: usb_msd.c:67
#define MSD_COMMAND_FAILED
Definition: usb_msd.c:45
bool msd_scsi_process_request_sense(USBMassStorageDriver *msdp)
Processes a REQUEST_SENSE SCSI command.
Definition: usb_msd.c:337
#define SCSI_ASENSE_INVALID_FIELD_IN_CDB
Definition: usb_msd.c:85
bool msd_scsi_process_send_diagnostic(USBMassStorageDriver *msdp)
Processes a SEND_DIAGNOSTIC SCSI command.
Definition: usb_msd.c:371
Response to a READ_CAPACITY_10 SCSI command.
Definition: usb_msd.c:99
event_source_t evt_connected
Definition: usb_msd.h:157
thread_t * thread
Definition: usb_msd.h:156
const USBMassStorageConfig * config
Definition: usb_msd.h:154
bool msd_scsi_process_mode_sense_6(USBMassStorageDriver *msdp)
Processes a MODE_SENSE_6 SCSI command.
Definition: usb_msd.c:535
#define SCSI_SENSE_KEY_GOOD
Definition: usb_msd.c:64
event_source_t evt_ejected
Definition: usb_msd.h:157
#define SCSI_CMD_FORMAT_UNIT
Definition: usb_msd.c:51
#define SCSI_CMD_READ_10
Definition: usb_msd.c:59
uint8_t short_product_version[4]
Short product revision.
Definition: usb_msd.h:144
#define MSD_CSW_SIGNATURE
Definition: usb_msd.c:35
uint32_t DWORD
Definition: usb_msd.c:119
uint32_t desc_and_block_length
Definition: usb_msd.c:111
#define SCSI_CMD_MODE_SENSE_6
Definition: usb_msd.c:53
#define SCSI_CMD_TEST_UNIT_READY
Definition: usb_msd.c:49
#define MSD_COMMAND_PASSED
Definition: usb_msd.c:44
#define MSD_SETUP_LENGTH(setup)
Definition: usb_msd.c:41
#define SCSI_CMD_VERIFY_10
Definition: usb_msd.c:61
static void msd_start_receive(USBMassStorageDriver *msdp, uint8_t *buffer, size_t size)
Starts receiving data.
Definition: usb_msd.c:276
#define SCSI_ASENSE_INVALID_COMMAND
Definition: usb_msd.c:83
#define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION
Definition: usb_msd.c:79
USB mass storage driver structure.
Definition: usb_msd.h:153
Driver configuration structure.
Definition: usb_msd.h:104
uint16_t val[TCOUPLE_NB]
unsigned long uint32_t
Definition: types.h:18
#define SCSI_SENSE_KEY_NOT_READY
Definition: usb_msd.c:66
uint32_t block_count
Definition: usb_msd.c:110
#define SCSI_ASENSE_READ_ERROR
Definition: usb_msd.c:82
uint32_t last_block_addr
Definition: usb_msd.c:100
#define MSD_GET_MAX_LUN
Definition: usb_msd.c:31
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:286
#define SCSI_CMD_WRITE_10
Definition: usb_msd.c:60
#define SCSI_ASENSE_MEDIUM_NOT_PRESENT
Definition: usb_msd.c:89
USBDriver * usbp
USB driver to use for communication.
Definition: usb_msd.h:108
static void msd_start_transmit(USBMassStorageDriver *msdp, const uint8_t *buffer, size_t size)
Starts sending data.
Definition: usb_msd.c:266
#define SCSI_CMD_INQUIRY
Definition: usb_msd.c:52
bool msd_read_command_block(USBMassStorageDriver *msdp)
Reads a newly received command block.
Definition: usb_msd.c:608
#define SCSI_CMD_SEND_DIAGNOSTIC
Definition: usb_msd.c:55
#define PACK_STRUCT_BEGIN
Definition: usb_msd.h:34
#define MSD_SETUP_VALUE(setup)
Definition: usb_msd.c:39
#define SCSI_ASENSEQ_NO_QUALIFIER
Definition: usb_msd.c:91
unsigned char uint8_t
Definition: types.h:14
bool msd_wait_for_command_block(USBMassStorageDriver *msdp)
Waits for a new command block.
Definition: usb_msd.c:595
static const struct usb_config_descriptor config
Definition: usb_ser_hw.c:199
#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL
Definition: usb_msd.c:56
bool msd_scsi_process_read_format_capacities(USBMassStorageDriver *msdp)
Processes a READ_FORMAT_CAPACITIES SCSI command.
Definition: usb_msd.c:555
uint8_t short_vendor_id[8]
Short vendor identification.
Definition: usb_msd.h:132
#define PACK_STRUCT_END
Definition: usb_msd.h:38
#define SCSI_ASENSE_WRITE_PROTECTED
Definition: usb_msd.c:86
bool msd_scsi_process_start_stop_unit(USBMassStorageDriver *msdp)
Processes a START_STOP_UNIT SCSI command.
Definition: usb_msd.c:517
binary_semaphore_t bsem
Definition: usb_msd.h:155
uint32_t block_size
Definition: usb_msd.c:101
#define SCSI_CMD_START_STOP_UNIT
Definition: usb_msd.c:54
bool msd_scsi_process_test_unit_ready(USBMassStorageDriver *msdp)
Processes a TEST_UNIT_READY SCSI command.
Definition: usb_msd.c:573
void(* rw_activity_callback)(bool)
Optional callback that will be called whenever there is read/write activity.
Definition: usb_msd.h:126
static void msd_wait_for_isr(USBMassStorageDriver *msdp)
Wait until the end-point interrupt handler has been called.
Definition: usb_msd.c:240
#define swap_uint16(x)
Byte-swap a 16 bits unsigned integer.
Definition: usb_msd.c:136
void msdStart(USBMassStorageDriver *msdp, const USBMassStorageConfig *config)
Starts a USB mass storage driver.
Definition: usb_msd.c:820
msd_scsi_inquiry_response_t inquiry
Definition: usb_msd.h:163
BaseBlockDevice * bbdp
Block device to use for storage.
Definition: usb_msd.h:113
#define MSD_CBW_SIGNATURE
Definition: usb_msd.c:34
#define SCSI_CMD_READ_FORMAT_CAPACITIES
Definition: usb_msd.c:57
bool msd_scsi_process_inquiry(USBMassStorageDriver *msdp)
Processes an INQUIRY SCSI command.
Definition: usb_msd.c:296
bool msdRequestsHook(USBDriver *usbp)
Default requests hook.
Definition: usb_msd.c:188
#define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE
Definition: usb_msd.c:84
uint8_t short_product_id[16]
Short product identification.
Definition: usb_msd.h:138
msd_scsi_sense_response_t sense
Definition: usb_msd.h:162