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