M480 BSP  V3.05.001
The Board Support Package for M480 Series
msc_driver.c
Go to the documentation of this file.
1 /**************************************************************************/
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 
14 #include "NuMicro.h"
15 #include "diskio.h" // FATFS header
16 #include "usb.h"
17 #include "msc.h"
18 #include "ff.h"
19 #include "diskio.h"
20 
21 
23 
24 
25 MSC_T *g_msc_list; /* Global list of Mass Storage Class device. A multi-lun device can have
26  several instances appeared with different lun. */
27 
28 static volatile uint8_t g_fat_drv_used[USBDRV_CNT];
29 static TCHAR _path[3] = { '3', ':', 0 };
30 
31 static void fatfs_drive_int()
32 {
33  memset((uint8_t *)g_fat_drv_used, 0, sizeof(g_fat_drv_used));
34 }
35 
36 static int fatfs_drive_alloc()
37 {
38  int i;
39 
40  for (i = 0; i < USBDRV_CNT; i++)
41  {
42  if (g_fat_drv_used[i] == 0)
43  {
44  g_fat_drv_used[i] = 1;
45  return USBDRV_0+i;
46  }
47  }
48  msc_debug_msg("Memory out! No free FATFS USB drive slots!\n");
49  return USBH_ERR_MEMORY_OUT;
50 }
51 
52 static void fatfs_drive_free(int drv_no)
53 {
54  _path[0] = drv_no + '0';
55  f_mount(NULL, _path, 1);
56  g_fat_drv_used[drv_no-USBDRV_0] = 0;
57 }
58 
59 static MSC_T * find_msc_by_drive(int drv_no)
60 {
61  MSC_T *msc = g_msc_list;
62 
63  while (msc != NULL)
64  {
65  if (msc->drv_no == drv_no)
66  return msc;
67  msc = msc->next;
68  }
69  return NULL;
70 }
71 
72 static void msc_list_add(MSC_T *msc)
73 {
74  if (g_msc_list == NULL)
75  {
76  msc->next = NULL;
77  g_msc_list = msc;
78  }
79  else
80  {
81  msc->next = g_msc_list;
82  g_msc_list = msc;
83  }
84 }
85 
86 static void msc_list_remove(MSC_T *msc)
87 {
88  MSC_T *p;
89 
90  if (g_msc_list == msc)
91  {
92  g_msc_list = msc->next;
93  }
94  else
95  {
96  p = g_msc_list;
97  while ((p->next != msc) && (p->next != NULL))
98  {
99  p = p->next;
100  }
101 
102  if (p->next == msc)
103  {
104  p->next = msc->next;
105  }
106  }
107 }
108 
109 
110 static void get_max_lun(MSC_T *msc)
111 {
112  UDEV_T *udev = msc->iface->udev;
113  uint32_t read_len;
114  uint8_t buff[2];
115  int ret;
116 
117  msc->max_lun = 0;
118 
119  /*------------------------------------------------------------------------------------*/
120  /* Issue GET MAXLUN MSC class command to get the maximum lun number */
121  /*------------------------------------------------------------------------------------*/
122  ret = usbh_ctrl_xfer(udev, REQ_TYPE_IN | REQ_TYPE_CLASS_DEV | REQ_TYPE_TO_IFACE,
123  0xFE, 0, 0, msc->iface->if_num, buff, &read_len, 200);
124  if (ret < 0)
125  {
126  msc_debug_msg("Get Max Lun command failed! Assign 0...\n");
127  msc->max_lun = 0;
128  if (ret == USBH_ERR_STALL)
129  usbh_clear_halt(udev, 0);
130  return;
131  }
132  msc->max_lun = buff[0];
133  msc_debug_msg("Max lun is %d\n", msc->max_lun);
134 }
135 
136 void msc_reset(MSC_T *msc)
137 {
138  UDEV_T *udev = msc->iface->udev;
139  uint32_t read_len;
140  int ret;
141 
142  msc_debug_msg("Reset MSC device...\n");
143 
144  ret = usbh_ctrl_xfer(udev, REQ_TYPE_OUT | REQ_TYPE_CLASS_DEV | REQ_TYPE_TO_IFACE,
145  0xFF, 0, msc->iface->if_num, 0, NULL, &read_len, 100);
146  if (ret < 0)
147  {
148  msc_debug_msg("UAMSS reset request failed!\n");
149  }
150  usbh_clear_halt(udev, msc->ep_bulk_out->bEndpointAddress);
151  usbh_clear_halt(udev, msc->ep_bulk_in->bEndpointAddress);
152 }
153 
154 static int msc_inquiry(MSC_T *msc)
155 {
156  struct bulk_cb_wrap *cmd_blk = &msc->cmd_blk; /* MSC Bulk-only command block */
157  int ret;
158 
159  msc_debug_msg("INQUIRY...\n");
160  memset(cmd_blk, 0, sizeof(*cmd_blk));
161 
162  cmd_blk->Flags = 0x80;
163  cmd_blk->Length = 6;
164  cmd_blk->CDB[0] = INQUIRY; /* INQUIRY */
165  cmd_blk->CDB[1] = msc->lun << 5;
166  cmd_blk->CDB[4] = 36;
167 
168  ret = run_scsi_command(msc, msc->scsi_buff, 36, 1, 100);
169  if (ret < 0)
170  {
171  msc_debug_msg("INQUIRY command failed. [%d]\n", ret);
172  return ret;
173  }
174  else
175  {
176  msc_debug_msg("INQUIRY command success.\n");
177  }
178  return ret;
179 }
180 
181 static int msc_request_sense(MSC_T *msc)
182 {
183  struct bulk_cb_wrap *cmd_blk = &msc->cmd_blk; /* MSC Bulk-only command block */
184  int ret;
185 
186  msc_debug_msg("REQUEST_SENSE...\n");
187  memset(cmd_blk, 0, sizeof(*cmd_blk));
188 
189  cmd_blk->Flags = 0x80;
190  cmd_blk->Length = 6;
191  cmd_blk->CDB[0] = REQUEST_SENSE;
192  cmd_blk->CDB[1] = msc->lun << 5;
193  cmd_blk->CDB[4] = 18;
194 
195  ret = run_scsi_command(msc, msc->scsi_buff, 18, 1, 100);
196  if (ret < 0)
197  {
198  msc_debug_msg("REQUEST_SENSE command failed.\n");
199  if (ret == USBH_ERR_STALL)
200  msc_reset(msc);
201  return ret;
202  }
203  else
204  {
205  msc_debug_msg("REQUEST_SENSE command success.\n");
206  if (msc->scsi_buff[2] != 0x6)
207  {
208  msc_debug_msg("Device is still not attention. 0x%x\n", msc->scsi_buff[2]);
209  return -1;
210  }
211  }
212  return ret;
213 }
214 
215 static int msc_test_unit_ready(MSC_T *msc)
216 {
217  struct bulk_cb_wrap *cmd_blk = &msc->cmd_blk; /* MSC Bulk-only command block */
218  int ret;
219 
220  msc_debug_msg("TEST_UNIT_READY...\n");
221  memset(cmd_blk, 0, sizeof(*cmd_blk));
222 
223  cmd_blk->Flags = 0x80;
224  cmd_blk->Length = 6;
225  cmd_blk->CDB[0] = TEST_UNIT_READY;
226  cmd_blk->CDB[1] = msc->lun << 5;
227 
228  ret = run_scsi_command(msc, msc->scsi_buff, 0, 1, 100);
229  if (ret < 0)
230  {
231  if (ret == USBH_ERR_STALL)
232  msc_reset(msc);
233  return ret;
234  }
235  else
236  {
237  msc_debug_msg("TEST_UNIT_READY command success.\n");
238  }
239  return ret;
240 }
241 
254 int usbh_umas_read(int drv_no, uint32_t sec_no, int sec_cnt, uint8_t *buff)
255 {
256  MSC_T *msc;
257  struct bulk_cb_wrap *cmd_blk; /* MSC Bulk-only command block */
258  int ret;
259 
260  //msc_debug_msg("usbh_umas_read - %d, %d\n", sec_no, sec_cnt);
261 
262  msc = find_msc_by_drive(drv_no);
263  if (msc == NULL)
265 
266  cmd_blk = &msc->cmd_blk;
267 
268  //msc_debug_msg("read sector 0x%x\n", sector_no);
269  memset(cmd_blk, 0, sizeof(*cmd_blk));
270 
271  cmd_blk->Flags = 0x80;
272  cmd_blk->Length = 10;
273  cmd_blk->CDB[0] = READ_10;
274  cmd_blk->CDB[1] = msc->lun << 5;
275  cmd_blk->CDB[2] = (sec_no >> 24) & 0xFF;
276  cmd_blk->CDB[3] = (sec_no >> 16) & 0xFF;
277  cmd_blk->CDB[4] = (sec_no >> 8) & 0xFF;
278  cmd_blk->CDB[5] = sec_no & 0xFF;
279  cmd_blk->CDB[7] = (sec_cnt >> 8) & 0xFF;
280  cmd_blk->CDB[8] = sec_cnt & 0xFF;
281 
282  ret = run_scsi_command(msc, buff, sec_cnt * 512, 1, 500);
283  if (ret != 0)
284  {
285  msc_debug_msg("usbh_umas_read failed! [%d]\n", ret);
286  return UMAS_ERR_IO;
287  }
288  return 0;
289 }
290 
303 int usbh_umas_write(int drv_no, uint32_t sec_no, int sec_cnt, uint8_t *buff)
304 {
305  MSC_T *msc;
306  struct bulk_cb_wrap *cmd_blk; /* MSC Bulk-only command block */
307  int ret;
308 
309  //msc_debug_msg("usbh_umas_write - %d, %d\n", sec_no, sec_cnt);
310 
311  msc = find_msc_by_drive(drv_no);
312  if (msc == NULL)
314 
315  cmd_blk = &msc->cmd_blk;
316  memset((uint8_t *)&(msc->cmd_blk), 0, sizeof(msc->cmd_blk));
317 
318  cmd_blk->Flags = 0;
319  cmd_blk->Length = 10;
320  cmd_blk->CDB[0] = WRITE_10;
321  cmd_blk->CDB[1] = msc->lun << 5;
322  cmd_blk->CDB[2] = (sec_no >> 24) & 0xFF;
323  cmd_blk->CDB[3] = (sec_no >> 16) & 0xFF;
324  cmd_blk->CDB[4] = (sec_no >> 8) & 0xFF;
325  cmd_blk->CDB[5] = sec_no & 0xFF;
326  cmd_blk->CDB[7] = (sec_cnt >> 8) & 0xFF;
327  cmd_blk->CDB[8] = sec_cnt & 0xFF;
328 
329  ret = run_scsi_command(msc, buff, sec_cnt * 512, 0, 500);
330  if (ret < 0)
331  {
332  msc_debug_msg("usbh_umas_write failed!\n");
333  return UMAS_ERR_IO;
334  }
335  return 0;
336 }
337 
349 int usbh_umas_ioctl(int drv_no, int cmd, void *buff)
350 {
351  MSC_T *msc;
352 
353  msc = find_msc_by_drive(drv_no);
354  if (msc == NULL)
356 
357  switch (cmd)
358  {
359  case CTRL_SYNC:
360  return RES_OK;
361 
362  case GET_SECTOR_COUNT:
363  *(uint32_t *)buff = msc->uTotalSectorN;
364  return RES_OK;
365 
366  case GET_SECTOR_SIZE:
367  *(uint32_t *)buff = msc->nSectorSize;
368  return RES_OK;
369 
370  case GET_BLOCK_SIZE:
371  *(uint32_t *)buff = msc->nSectorSize;
372  return RES_OK;
373 
374  //case CTRL_ERASE_SECTOR:
375  // return RES_OK;
376  }
377  return UMAS_ERR_IVALID_PARM;
378 }
379 
386 int usbh_umas_disk_status(int drv_no)
387 {
388  if (find_msc_by_drive(drv_no) == NULL)
389  return STA_NODISK;
390  return 0;
391 }
392 
399 int usbh_umas_reset_disk(int drv_no)
400 {
401  MSC_T *msc;
402  UDEV_T *udev;
403 
404  msc_debug_msg("usbh_umas_reset_disk ...\n");
405 
406  msc = find_msc_by_drive(drv_no);
407  if (msc == NULL)
409 
410  udev = msc->iface->udev;
411 
412  usbh_reset_device(udev);
413 
414  return 0;
415 }
416 
417 static int umass_init_device(MSC_T *msc)
418 {
419  MSC_T *try_msc = msc;
420  struct bulk_cb_wrap *cmd_blk; /* MSC Bulk-only command block */
421  int retries, lun;
422  int8_t bHasMedia = 0;
423  int ret = USBH_ERR_NOT_FOUND;
424 
425  for (lun = 0; lun <= msc->max_lun; lun++)
426  {
427  msc_debug_msg("\n******* Read lun %d ******\n\n", lun);
428 
429  try_msc->lun = lun;
430  cmd_blk = &try_msc->cmd_blk;
431 
432  for (retries = 0; retries < 3; retries++)
433  {
434  if (msc_inquiry(try_msc) == USBH_ERR_STALL)
435  msc_reset(try_msc);
436 
437  if (msc_inquiry(try_msc) == USBH_ERR_STALL)
438  msc_reset(try_msc);
439 
440  if (msc_test_unit_ready(try_msc) == 0)
441  goto disk_found;
442 
443  if (msc_request_sense(try_msc) == 0)
444  {
445  goto disk_found;
446  }
447 
448  delay_us(100000); /* delay 100ms, retry later */
449  }
450 
451  continue;
452 
453 disk_found:
454  /*
455  * Valid disk found in this lun. Go...
456  */
457  for (retries = 0; retries < 3; retries++)
458  {
459  msc_debug_msg("READ CAPACITY ==>\n");
460 
461  memset(cmd_blk, 0, sizeof(*cmd_blk));
462 
463  cmd_blk->Flags = 0x80;
464  cmd_blk->Length = 10;
465  cmd_blk->CDB[0] = READ_CAPACITY;
466  cmd_blk->CDB[1] = lun << 5;
467 
468  ret = run_scsi_command(try_msc, try_msc->scsi_buff, 8, 1, 100);
469  if (ret < 0)
470  {
471  msc_debug_msg("READ_CAPACITY failed!\n");
472  if (ret == USBH_ERR_STALL)
473  msc_reset(try_msc);
474  continue;
475  }
476  else
477  break;
478  }
479 
480  if (retries >= 3)
481  continue; /* try next lun */
482 
483  try_msc->uTotalSectorN = (try_msc->scsi_buff[0] << 24) | (try_msc->scsi_buff[1] << 16) |
484  (try_msc->scsi_buff[2] << 8) | try_msc->scsi_buff[3];
485  try_msc->nSectorSize = (try_msc->scsi_buff[4] << 24) | (try_msc->scsi_buff[5] << 16) |
486  (try_msc->scsi_buff[6] << 8) | try_msc->scsi_buff[7];
487 
488  try_msc->drv_no = fatfs_drive_alloc();
489  if (try_msc->drv_no < 0) /* should be failed, unless drive free slot is empty */
490  {
491  ret = USBH_ERR_MEMORY_OUT;
492  break;
493  }
494 
495  msc_debug_msg("USB disk [%c] found: size=%d MB, uTotalSectorN=%d\n", msc->drv_no+'0', try_msc->uTotalSectorN / 2048, try_msc->uTotalSectorN);
496 
497  msc_list_add(try_msc);
498 
499  _path[0] = try_msc->drv_no + '0';
500  f_mount(&try_msc->fatfs_vol, _path, 1);
501  bHasMedia = 1;
502 
503 
504  /*
505  * duplicate another MSC for next try
506  */
507  try_msc = usbh_alloc_mem(sizeof(*try_msc));
508  if (try_msc == NULL)
509  {
510  ret = USBH_ERR_MEMORY_OUT;
511  break;
512  }
513  memcpy(try_msc, msc, sizeof(*msc));
514  }
515 
516  if (bHasMedia)
517  {
518  if (try_msc)
519  usbh_free_mem(try_msc, sizeof(*try_msc));
520  return 0;
521  }
522  return ret;
523 }
524 
525 static int msc_probe(IFACE_T *iface)
526 {
527  ALT_IFACE_T *aif = iface->aif;
528  DESC_IF_T *ifd;
529  MSC_T *msc;
530  int i;
531 
532  ifd = aif->ifd;
533 
534  /* Is this interface mass storage class? */
535  if (ifd->bInterfaceClass != USB_CLASS_MASS_STORAGE)
536  return USBH_ERR_NOT_MATCHED;
537 
538  /* Is supported sub-class? */
539  if ((ifd->bInterfaceSubClass != MSC_SCLASS_SCSI) && (ifd->bInterfaceSubClass != MSC_SCLASS_8070) &&
540  (ifd->bInterfaceSubClass != MSC_SCLASS_RBC))
541  return USBH_ERR_NOT_SUPPORTED;
542 
543  /* Is bulk-only protocol? */
544  if (ifd->bInterfaceProtocol != MSC_SPROTO_BULK)
545  {
546  msc_debug_msg("Not bulk-only MSC device!\n");
547  return USBH_ERR_NOT_SUPPORTED;
548  }
549 
550  msc = usbh_alloc_mem(sizeof(*msc));
551  if (msc == NULL)
552  return USBH_ERR_MEMORY_OUT;
553  msc->uid = get_ticks();
554 
555  /* Find the bulk in and out endpoints */
556  for (i = 0; i < aif->ifd->bNumEndpoints; i++)
557  {
558  if ((aif->ep[i].bmAttributes & EP_ATTR_TT_MASK) == EP_ATTR_TT_BULK)
559  {
560  if ((aif->ep[i].bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_IN)
561  msc->ep_bulk_in = &aif->ep[i];
562  else
563  msc->ep_bulk_out = &aif->ep[i];
564  }
565  }
566 
567  if ((msc->ep_bulk_in == NULL) || (msc->ep_bulk_out == NULL))
568  {
569  usbh_free_mem(msc, sizeof(*msc));
570  return USBH_ERR_NOT_EXPECTED;
571  }
572 
573  msc->iface = iface;
574 
575  msc_debug_msg("USB Mass Storage device found. Iface:%d, Alt Iface:%d, bep_in:0x%x, bep_out:0x%x\n", ifd->bInterfaceNumber, ifd->bAlternateSetting, msc->ep_bulk_in->bEndpointAddress, msc->ep_bulk_out->bEndpointAddress);
576 
577  get_max_lun(msc);
578 
579  return umass_init_device(msc);
580 }
581 
582 static void msc_disconnect(IFACE_T *iface)
583 {
584  int i;
585  MSC_T *msc_p, *msc;
586 
587  /*
588  * Remove any hardware EP/QH from Host Controller hardware list.
589  * This will finally result in all transfers aborted.
590  */
591  for (i = 0; i < iface->aif->ifd->bNumEndpoints; i++)
592  {
593  iface->udev->hc_driver->quit_xfer(NULL, &(iface->aif->ep[i]));
594  }
595 
596  /*
597  * unmount drive and remove it from MSC device list
598  */
599  msc = g_msc_list;
600  while (msc != NULL)
601  {
602  msc_p = msc->next;
603  if (msc->iface == iface)
604  {
605  fatfs_drive_free(msc->drv_no);
606  msc_list_remove(msc);
607  usbh_free_mem(msc, sizeof(*msc));
608  }
609  msc = msc_p;
610  }
611 }
612 
613 UDEV_DRV_T msc_driver =
614 {
615  msc_probe,
616  msc_disconnect,
617  NULL,
618  NULL
619 };
620 
621 
623 
624 
631 int usbh_umas_init(void)
632 {
633  fatfs_drive_int();
634  g_msc_list = NULL;
635  return usbh_register_driver(&msc_driver);
636 }
637 
638 
639 
640 
641 /*** (C) COPYRIGHT 2017 Nuvoton Technology Corp. ***/
642 
643 
#define USBH_ERR_NOT_SUPPORTED
Definition: usbh_lib.h:35
#define USBH_ERR_NOT_FOUND
Definition: usbh_lib.h:39
#define UMAS_ERR_DRIVE_NOT_FOUND
Definition: usbh_lib.h:83
NuMicro peripheral access layer header file.
#define USBH_ERR_STALL
Definition: usbh_lib.h:60
int usbh_umas_ioctl(int drv_no, int cmd, void *buff)
int usbh_umas_disk_status(int drv_no)
M480 MCU USB Host mass storage class header.
int usbh_umas_write(int drv_no, uint32_t sec_no, int sec_cnt, uint8_t *buff)
uint32_t get_ticks(void)
A function return current tick count.
#define UMAS_ERR_IO
Definition: usbh_lib.h:79
int usbh_umas_read(int drv_no, uint32_t sec_no, int sec_cnt, uint8_t *buff)
#define USBH_ERR_MEMORY_OUT
Definition: usbh_lib.h:32
int run_scsi_command(MSC_T *msc, uint8_t *buff, uint32_t data_len, int bIsDataIn, int timeout_ticks)
Definition: msc_xfer.c:113
USB Host library header file.
#define NULL
NULL pointer.
Definition: M480.h:604
#define USBH_ERR_NOT_MATCHED
Definition: usbh_lib.h:36
HIDDEN_SYMBOLS int usbh_umas_init(void)
Register and initialize USB Host Mass Storage driver.
Definition: msc_driver.c:631
#define UMAS_ERR_IVALID_PARM
Definition: usbh_lib.h:82
#define USBH_ERR_NOT_EXPECTED
Definition: usbh_lib.h:37