NUC472_NUC442_BSP V3.03.005
The Board Support Package for NUC472/NUC442
lw_umass.c
Go to the documentation of this file.
1/**************************************************************************/
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16
17#include "NUC472_442.h"
18#include "diskio.h" // FATFS header
19#include "usb.h"
20#include "lw_usbh.h"
21#include "lw_umass.h"
22
23
37
38#ifdef __GNUC__
39#define umass_dbg_msg(...)
40#else
41#define umass_dbg_msg printf
42//#define umass_dbg_msg(...)
43#endif
44
45static int iface_num;
46static uint16_t bulk_in_ep_addr, bulk_out_ep_addr;
47static uint8_t bulk_in_toggle, bulk_out_toggle;
48
49int g_disk_lun, g_max_lun;
50
51#ifdef __ICCARM__
52
53#pragma data_alignment=4
54static struct bulk_cb_wrap g_cb;
55
56#pragma data_alignment=4
57static struct bulk_cs_wrap g_cs;
58
59#else
60static struct bulk_cb_wrap g_cb __attribute__((aligned(4)));
61static struct bulk_cs_wrap g_cs __attribute__((aligned(4)));
62#endif
63
64
65static uint32_t g_total_sector_num, g_sector_size;
66
67
68int umas_bulk_xfer(uint16_t ep_addr, uint8_t *toggle,
69 uint8_t *data_buff, int data_len, int timeout)
70{
71 int ret, retry = 3;
72
73 for ( ; retry; retry--)
74 {
75 ret = usbh_drv_bulk_xfer(ep_addr, toggle, data_buff, data_len, timeout);
76 if (ret == 0)
77 return 0;
78 }
79 return ret;
80}
81
82
83static void get_max_lun()
84{
85 int ret;
86 uint8_t buff[2];
87
88 g_max_lun = 0;
89
90 /*------------------------------------------------------------------------------------*/
91 /* Issue GET DESCRIPTOR command to get device descriptor */
92 /*------------------------------------------------------------------------------------*/
93
94 ret = usbh_drv_ctrl_req(0xA1, 0xFE, 0, 0, 1, 1, buff, 0);
95 if (ret < 0)
96 {
97 umass_dbg_msg("Get Max Lun command failed!\n");
98 if (ret == USBH_RET_STALL)
100 return;
101 }
102 g_max_lun = buff[0];
103 umass_dbg_msg("Max lun is %d\n", g_max_lun);
104}
105
106
107static void umass_reset()
108{
109#if 1
110 int ret;
111
112 printf("Reset UMAS device...\n");
113
114 ret = usbh_drv_ctrl_req(0x21, 0xFF, 0, 0, 1, 1, NULL, 1);
115 if (ret < 0)
116 {
117 umass_dbg_msg("UAMSS reset request failed!\n");
118 return;
119 }
120#endif
121
122 usbh_clear_halt(bulk_in_ep_addr);
123}
124
125static int __tag = 0x10e24388;
126
127static int umass_run_command(uint8_t *buff, int data_len, int is_data_in, int timeout)
128{
129 int ret;
130
131 g_cb.Signature = UMAS_BULK_CB_SIGN;
132 g_cb.Tag = __tag++;
133 g_cb.DataTransferLength = data_len;
134 g_cb.Lun = g_disk_lun;
135
136 ret = umas_bulk_xfer(bulk_out_ep_addr, &bulk_out_toggle, (uint8_t *)&g_cb, 31, 10000);
137 if (ret < 0)
138 return ret;
139
140 if (data_len > 0)
141 {
142 if (is_data_in)
143 ret = umas_bulk_xfer(bulk_in_ep_addr, &bulk_in_toggle, buff, data_len, timeout);
144 else
145 ret = umas_bulk_xfer(bulk_out_ep_addr, &bulk_out_toggle, buff, data_len, timeout);
146 }
147
148 if (ret < 0)
149 return ret;
150
151 ret = umas_bulk_xfer(bulk_in_ep_addr, &bulk_in_toggle, (uint8_t *)&g_cs, 13, 1000);
152 if (ret < 0)
153 return ret;
154
155 if (g_cs.Status != 0)
156 {
157 umass_dbg_msg("CSW status error.\n");
159 }
160
161 //umass_dbg_msg("command 0x%0x done.\n", g_cb.CDB[0]);
162
163 return ret;
164}
165
166
167static int umass_inquiry()
168{
169 int ret;
170
171 umass_dbg_msg("INQUIRY...\n");
172
173 memset((uint8_t *)&g_cb, 0, sizeof(g_cb));
174 g_cb.Flags = 0x80;
175 g_cb.Length = 6;
176 g_cb.CDB[0] = INQUIRY; /* INQUIRY */
177 g_cb.CDB[1] = g_disk_lun << 5;
178 g_cb.CDB[4] = 36;
179
180 ret = umass_run_command(_transfer_buffer, 36, 1, 10000);
181 if (ret < 0)
182 {
183 umass_dbg_msg("INQUIRY command failed. [%d]\n", ret);
184 return ret;
185 }
186 else
187 {
188 umass_dbg_msg("INQUIRY command success.\n");
189 }
190 return ret;
191}
192
193
194static int umass_request_sense()
195{
196 int ret;
197
198 umass_dbg_msg("REQUEST_SENSE...\n");
199
200 memset((uint8_t *)&g_cb, 0, sizeof(g_cb));
201 g_cb.Flags = 0x80;
202 g_cb.Length = 12;
203 g_cb.CDB[0] = REQUEST_SENSE;
204 g_cb.CDB[1] = g_disk_lun << 5;
205 g_cb.CDB[4] = 18;
206
207 ret = umass_run_command(_transfer_buffer, 18, 1, 10000);
208 if (ret < 0)
209 {
210 umass_dbg_msg("REQUEST_SENSE command failed.\n");
211 if (ret == USBH_RET_STALL)
212 umass_reset();
213 return ret;
214 }
215 else
216 {
217 umass_dbg_msg("REQUEST_SENSE command success.\n");
218 if (_transfer_buffer[2] != 0x6)
219 {
220 umass_dbg_msg("Device is still not attention. 0x%x\n", _transfer_buffer[2]);
221 return -1;
222 }
223 }
224
225 return ret;
226}
227
228
229static int umass_test_unit_ready()
230{
231 int ret;
232
233 umass_dbg_msg("TEST_UNIT_READY...\n");
234
235 memset((uint8_t *)&g_cb, 0, sizeof(g_cb));
236 g_cb.Flags = 0x80;
237 g_cb.Length = 6;
238 g_cb.CDB[0] = TEST_UNIT_READY;
239 g_cb.CDB[1] = g_disk_lun << 5;
240
241 ret = umass_run_command(NULL, 0, 1, 10000);
242 if (ret < 0)
243 {
244 if (ret == USBH_RET_STALL)
245 umass_reset();
246 return ret;
247 }
248 else
249 {
250 umass_dbg_msg("TEST_UNIT_READY command success.\n");
251 }
252 return ret;
253}
254
255
256DRESULT usbh_umas_read(uint8_t *buff, uint32_t sector_no, int number_of_sector)
257{
258 int ret;
259
260 //umass_dbg_msg("read sector 0x%x\n", sector_no);
261
262 memset((uint8_t *)&g_cb, 0, sizeof(g_cb));
263 g_cb.Flags = 0x80;
264 g_cb.Length = 10;
265 g_cb.CDB[0] = READ_10;
266 g_cb.CDB[1] = g_disk_lun << 5;
267 g_cb.CDB[2] = (sector_no >> 24) & 0xFF;
268 g_cb.CDB[3] = (sector_no >> 16) & 0xFF;
269 g_cb.CDB[4] = (sector_no >> 8) & 0xFF;
270 g_cb.CDB[5] = sector_no & 0xFF;
271 g_cb.CDB[7] = (number_of_sector >> 8) & 0xFF;
272 g_cb.CDB[8] = number_of_sector & 0xFF;
273
274 ret = umass_run_command(buff, number_of_sector * 512, 1, 3000);
275 if (ret < 0)
276 {
277 umass_dbg_msg("usbh_umas_read failed!\n");
278 return RES_ERROR;
279 }
280 return RES_OK;
281}
282
283
284DRESULT usbh_umas_write(uint8_t *buff, uint32_t sector_no, int number_of_sector)
285{
286 int ret;
287
288 memset((uint8_t *)&g_cb, 0, sizeof(g_cb));
289 g_cb.Flags = 0;
290 g_cb.Length = 10;
291 g_cb.CDB[0] = WRITE_10;
292 g_cb.CDB[1] = g_disk_lun << 5;
293 g_cb.CDB[2] = (sector_no >> 24) & 0xFF;
294 g_cb.CDB[3] = (sector_no >> 16) & 0xFF;
295 g_cb.CDB[4] = (sector_no >> 8) & 0xFF;
296 g_cb.CDB[5] = sector_no & 0xFF;
297 g_cb.CDB[7] = (number_of_sector >> 8) & 0xFF;
298 g_cb.CDB[8] = number_of_sector & 0xFF;
299
300 ret = umass_run_command(buff, number_of_sector * 512, 0, 3000);
301 if (ret < 0)
302 {
303 umass_dbg_msg("usbh_umas_write failed!\n");
304 return RES_ERROR;
305 }
306 return RES_OK;
307}
308
309
310DRESULT usbh_umas_ioctl(int cmd, void *buff)
311{
312 switch (cmd)
313 {
314 case CTRL_SYNC:
315 return RES_OK;
316
317 case GET_SECTOR_COUNT:
318 *(uint32_t *)buff = g_total_sector_num;
319 return RES_OK;
320
321 case GET_SECTOR_SIZE:
322 *(uint32_t *)buff = g_sector_size;
323 return RES_OK;
324
325 case GET_BLOCK_SIZE:
326 *(uint32_t *)buff = g_sector_size;
327 return RES_OK;
328
329#if (_FATFS == 82786)
330 case CTRL_ERASE_SECTOR:
331 return RES_OK;
332#else
333 case CTRL_TRIM:
334 return RES_OK;
335#endif
336 }
337 return RES_PARERR;
338}
339
340
341int usbh_umas_disk_status(void)
342{
345 return STA_NODISK;
346 return 0;
347}
348
349
350static int umass_init_device(void)
351{
352 int retries, ret;
353 volatile int i;
354 int8_t bHasMedia = 0;
355
356 for (g_disk_lun = 0; g_disk_lun <= g_max_lun; g_disk_lun++)
357 {
358 umass_dbg_msg("\n\n\n******* Read lun %d ******\n\n", g_disk_lun);
359
360 bHasMedia = 0;
361 for (retries = 0; retries < 3; retries++)
362 {
363 if (umass_inquiry() == USBH_RET_STALL)
364 umass_reset();
365
366 if (umass_test_unit_ready() == USBH_RET_NO_ERR)
367 {
368 bHasMedia = 1;
369 break;
370 }
371
372 if (umass_request_sense() == USBH_RET_NO_ERR)
373 {
374 bHasMedia = 1;
375 break;
376 }
377
378 for (i = 0; i < MINISEC_100; i++);
379 }
380
381 if (!bHasMedia)
382 continue;
383
384 for (retries = 0; retries < 3; retries++)
385 {
386 umass_dbg_msg("READ CAPACITY ==>\n");
387
388 memset((uint8_t *)&g_cb, 0, sizeof(g_cb));
389 g_cb.Flags = 0x80;
390 g_cb.Length = 10;
391 g_cb.CDB[0] = READ_CAPACITY;
392 g_cb.CDB[1] = g_disk_lun << 5;
393
394 ret = umass_run_command(_transfer_buffer, 8, 1, 1000);
395 if (ret < 0)
396 {
397 umass_dbg_msg("READ_CAPACITY failed!\n");
398 if (ret == USBH_RET_STALL)
399 umass_reset();
400 continue;
401 }
402 else
403 break;
404 }
405
406 if (retries >= 3)
408
409 g_total_sector_num = (_transfer_buffer[0] << 24) | (_transfer_buffer[1] << 16) |
410 (_transfer_buffer[2] << 8) | _transfer_buffer[3];
411 g_sector_size = (_transfer_buffer[4] << 24) | (_transfer_buffer[5] << 16) |
412 (_transfer_buffer[6] << 8) | _transfer_buffer[7];
413 umass_dbg_msg("USB disk found: size=%d MB, uTotalSectorN=%d\n", g_total_sector_num / 2048, g_total_sector_num);
414 break;
415 }
416
417 if (bHasMedia)
418 {
419 umass_dbg_msg("g_disk_lun = %d\n", g_disk_lun);
420 return 0;
421 }
423}
424
426
427
435{
436 USB_CONFIG_DESC_T *cfg_desc;
437 USB_IF_DESC_T *if_desc;
438 USB_EP_DESC_T *ep_desc;
439 uint8_t *bptr;
440 int tlen;
441 int ret;
442
443 /*------------------------------------------------------------------------------------*/
444 /* Issue GET DESCRIPTOR command to get configuration descriptor */
445 /*------------------------------------------------------------------------------------*/
446 ret = get_config_descriptor(_transfer_buffer);
447 if (ret < 0)
448 {
449 umass_dbg_msg("GET Config Descriptor command failed!!\n");
450 return ret;
451 }
452
453 /*------------------------------------------------------------------------------------*/
454 /* Parsing configuration descriptor and find an USB Mass Storage class interface */
455 /*------------------------------------------------------------------------------------*/
456 iface_num = -1;
457 bulk_in_ep_addr = 0;
458 bulk_out_ep_addr = 0;
459
460 cfg_desc = (USB_CONFIG_DESC_T *)_transfer_buffer;
461 tlen = cfg_desc->wTotalLength;
462 bptr = (uint8_t *)cfg_desc;
463
464 while (tlen > 0)
465 {
466 switch (bptr[1])
467 {
468 case USB_DT_INTERFACE:
469 if_desc = (USB_IF_DESC_T *)bptr;
470 if ((if_desc->bInterfaceClass == USB_CLASS_MASS_STORAGE) &&
471 ((if_desc->bInterfaceSubClass == UMAS_SC_SCSI) || (if_desc->bInterfaceSubClass == UMAS_SC_8070)) &&
472 (if_desc->bInterfaceProtocol == UMAS_PR_BULK))
473 iface_num = if_desc->bInterfaceNumber;
474 else
475 {
476 iface_num = -1;
477 bulk_in_ep_addr = 0;
478 bulk_out_ep_addr = 0;
479 }
480 break;
481
482 case USB_DT_ENDPOINT:
483 ep_desc = (USB_EP_DESC_T *)bptr;
484 if ((iface_num != -1) && ((ep_desc->bmAttributes & 0x3) == 0x2))
485 {
486 if (ep_desc->bEndpointAddress & 0x80)
487 bulk_in_ep_addr = ep_desc->bEndpointAddress;
488 else
489 bulk_out_ep_addr = ep_desc->bEndpointAddress;
490 }
491 break;
492 }
493 if (bptr[0] == 0)
494 break;
495 tlen -= bptr[0];
496 bptr += bptr[0];
497 }
498
499 if ((iface_num == -1) || (bulk_in_ep_addr == 0) || (bulk_out_ep_addr == 0))
500 return USBH_RET_UNSUPPORT;
501
502 bulk_in_toggle = 0;
503 bulk_out_toggle = 0;
504
505 umass_dbg_msg("USB Mass Storage device found.\n");
506
507 /* Set configuration */
508 ret = usbh_set_configuration(cfg_desc->bConfigurationValue);
509 if (ret < 0)
510 return ret;
511
512 get_max_lun();
513
514 return umass_init_device();
515}
516 /* end of group NUC472_442_LWHCD_EXPORTED_FUNCTIONS */
518 /* end of group NUC472_442_LWHCD_Driver */
520 /* end of group NUC472_442_Device_Driver */
522
523/*** (C) COPYRIGHT 2014 Nuvoton Technology Corp. ***/
524
525
void *__dso_handle __attribute__((weak))
Definition: _syscalls.c:35
NUC472/NUC442 peripheral access layer header file. This file contains all the peripheral register's d...
#define USBH_RET_STALL
Definition: lw_usbh.h:43
#define USBH_RET_UNSUPPORT
Definition: lw_usbh.h:45
#define USBH_RET_ERR_DEV_INIT
Definition: lw_usbh.h:48
#define USBH_RET_DEV_CONN_KEEP
Definition: lw_usbh.h:40
#define USBH_RET_NO_ERR
Definition: lw_usbh.h:36
#define USBH_RET_ERR_CLASS_CMD
Definition: lw_usbh.h:47
int usbh_probe_port(uint32_t port)
Probe USB root-hub port connect/disconnect status. A newly connected device will be initialized in th...
Definition: lw_usbh.c:590
int usbh_set_configuration(int conf_val)
Issue a standard request SET_CONFIGURATION to USB device.
Definition: lw_usbh.c:528
int usbh_drv_ctrl_req(uint8_t requesttype, uint8_t request, uint16_t value, uint16_t index, uint16_t length, int data_len, uint8_t *buffer, int dir)
Execute a control transfer request.
Definition: lw_usbh.c:305
int usbh_probe_umass(void)
Try to probe and initialize an USB mass storage device.
Definition: lw_umass.c:434
int usbh_clear_halt(uint16_t ep_addr)
Issue a standard request SET_FEATURE to clear USB device endpoint halt state.
Definition: lw_usbh.c:542
int usbh_drv_bulk_xfer(uint16_t ep_addr, uint8_t *toggle, uint8_t *data_buff, int data_len, int timeout)
Execute a control transfer request.
Definition: lw_usbh.c:389
int get_config_descriptor(uint8_t *desc_buff)
Get configuration descriptor from the USB device.
Definition: lw_usbh.c:493
USB_IF_DESC_T
Definition: usbh_core.h:335
USB_CONFIG_DESC_T
Definition: usbh_core.h:366
USB_EP_DESC_T
Definition: usbh_core.h:300
#define NULL
NULL pointer.
Definition: NUC472_442.h:29018