1 /*
2 * Copyright (c) 2006-2018, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2011-12-12 Yi Qiu first version
9 */
10
11 #include <rtthread.h>
12 #include <drivers/usb_host.h>
13 #include "mass.h"
14
15 #ifdef RT_USBH_MSTORAGE
16
17 extern rt_err_t rt_udisk_run(struct uhintf* intf);
18 extern rt_err_t rt_udisk_stop(struct uhintf* intf);
19
20 static struct uclass_driver storage_driver;
21
22 /**
23 * This function will do USBREQ_GET_MAX_LUN request for the usb interface instance.
24 *
25 * @param intf the interface instance.
26 * @param max_lun the buffer to save max_lun.
27 *
28 * @return the error code, RT_EOK on successfully.
29 */
_pipe_check(struct uhintf * intf,upipe_t pipe)30 static rt_err_t _pipe_check(struct uhintf* intf, upipe_t pipe)
31 {
32 struct uinstance* device;
33 rt_err_t ret;
34 ustor_t stor;
35 int size = 0;
36 struct ustorage_csw csw;
37
38 if(intf == RT_NULL || pipe == RT_NULL)
39 {
40 rt_kprintf("the interface is not available\n");
41 return -RT_EIO;
42 }
43
44 /* get usb device instance from the interface instance */
45 device = intf->device;
46
47 /* get storage instance from the interface instance */
48 stor = (ustor_t)intf->user_data;
49
50 /* check pipe status */
51 if(pipe->status == UPIPE_STATUS_OK) return RT_EOK;
52
53 if(pipe->status == UPIPE_STATUS_ERROR)
54 {
55 rt_kprintf("pipe status error\n");
56 return -RT_EIO;
57 }
58 if(pipe->status == UPIPE_STATUS_STALL)
59 {
60 /* clear the pipe stall status */
61 ret = rt_usbh_clear_feature(device, pipe->ep.bEndpointAddress,
62 USB_FEATURE_ENDPOINT_HALT);
63 if(ret != RT_EOK) return ret;
64 }
65
66
67 rt_thread_delay(50);
68
69 rt_kprintf("pipes1 0x%x, 0x%x\n", stor->pipe_in, stor->pipe_out);
70
71 stor->pipe_in->status = UPIPE_STATUS_OK;
72
73 RT_DEBUG_LOG(RT_DEBUG_USB, ("clean storage in pipe stall\n"));
74
75 /* it should receive csw after clear the stall feature */
76 size = rt_usb_hcd_pipe_xfer(stor->pipe_in->inst->hcd,
77 stor->pipe_in, &csw, SIZEOF_CSW, 100);
78 if(size != SIZEOF_CSW)
79 {
80 rt_kprintf("receive the csw after stall failed\n");
81 return -RT_EIO;
82 }
83
84 return -RT_ERROR;
85 }
86
87 /**
88 * This function will do USBREQ_GET_MAX_LUN request for the usb interface instance.
89 *
90 * @param intf the interface instance.
91 * @param max_lun the buffer to save max_lun.
92 *
93 * @return the error code, RT_EOK on successfully.
94 */
rt_usb_bulk_only_xfer(struct uhintf * intf,ustorage_cbw_t cmd,rt_uint8_t * buffer,int timeout)95 static rt_err_t rt_usb_bulk_only_xfer(struct uhintf* intf,
96 ustorage_cbw_t cmd, rt_uint8_t* buffer, int timeout)
97 {
98 rt_size_t size;
99 rt_err_t ret;
100 upipe_t pipe;
101 struct ustorage_csw csw;
102 ustor_t stor;
103
104 RT_ASSERT(cmd != RT_NULL);
105
106 if(intf == RT_NULL)
107 {
108 rt_kprintf("the interface is not available\n");
109 return -RT_EIO;
110 }
111
112 /* get storage instance from the interface instance */
113 stor = (ustor_t)intf->user_data;
114
115 do
116 {
117 /* send the cbw */
118 size = rt_usb_hcd_pipe_xfer(stor->pipe_out->inst->hcd, stor->pipe_out,
119 cmd, SIZEOF_CBW, timeout);
120 if(size != SIZEOF_CBW)
121 {
122 rt_kprintf("CBW size error\n");
123 return -RT_EIO;
124 }
125 if(cmd->xfer_len != 0)
126 {
127 pipe = (cmd->dflags == CBWFLAGS_DIR_IN) ? stor->pipe_in :
128 stor->pipe_out;
129 size = rt_usb_hcd_pipe_xfer(pipe->inst->hcd, pipe, (void*)buffer,
130 cmd->xfer_len, timeout);
131 if(size != cmd->xfer_len)
132 {
133 rt_kprintf("request size %d, transfer size %d\n",
134 cmd->xfer_len, size);
135 break;
136 }
137 }
138
139 /* receive the csw */
140 size = rt_usb_hcd_pipe_xfer(stor->pipe_in->inst->hcd, stor->pipe_in,
141 &csw, SIZEOF_CSW, timeout);
142 if(size != SIZEOF_CSW)
143 {
144 rt_kprintf("csw size error\n");
145 return -RT_EIO;
146 }
147 }while(0);
148
149 /* check in pipes status */
150 ret = _pipe_check(intf, stor->pipe_in);
151 if(ret != RT_EOK)
152 {
153 rt_kprintf("in pipe error\n");
154 return ret;
155 }
156
157 /* check out pipes status */
158 ret = _pipe_check(intf, stor->pipe_out);
159 if(ret != RT_EOK)
160 {
161 rt_kprintf("out pipe error\n");
162 return ret;
163 }
164
165 /* check csw status */
166 if(csw.signature != CSW_SIGNATURE || csw.tag != CBW_TAG_VALUE)
167 {
168 rt_kprintf("csw signature error\n");
169 return -RT_EIO;
170 }
171
172 if(csw.status != 0)
173 {
174 //rt_kprintf("csw status error:%d\n",csw.status);
175 return -RT_ERROR;
176 }
177
178 return RT_EOK;
179 }
180
181 /**
182 * This function will do USBREQ_GET_MAX_LUN request for the usb interface instance.
183 *
184 * @param intf the interface instance.
185 * @param max_lun the buffer to save max_lun.
186 *
187 * @return the error code, RT_EOK on successfully.
188 */
rt_usbh_storage_get_max_lun(struct uhintf * intf,rt_uint8_t * max_lun)189 rt_err_t rt_usbh_storage_get_max_lun(struct uhintf* intf, rt_uint8_t* max_lun)
190 {
191 struct uinstance* device;
192 struct urequest setup;
193 int timeout = USB_TIMEOUT_BASIC;
194
195 if(intf == RT_NULL)
196 {
197 rt_kprintf("the interface is not available\n");
198 return -RT_EIO;
199 }
200
201 /* parameter check */
202 RT_ASSERT(intf->device != RT_NULL);
203 RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_storage_get_max_lun\n"));
204
205 /* get usb device instance from the interface instance */
206 device = intf->device;
207
208 /* construct the request */
209 setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS |
210 USB_REQ_TYPE_INTERFACE;
211 setup.bRequest = USBREQ_GET_MAX_LUN;
212 setup.wValue = intf->intf_desc->bInterfaceNumber;
213 setup.wIndex = 0;
214 setup.wLength = 1;
215
216 /* do control transfer request */
217 if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
218 {
219 return -RT_EIO;
220 }
221 if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, max_lun, 1, timeout) != 1)
222 {
223 return -RT_EIO;
224 }
225 if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) != 0)
226 {
227 return -RT_EIO;
228 }
229 return RT_EOK;
230 }
231
232 /**
233 * This function will do USBREQ_MASS_STORAGE_RESET request for the usb interface instance.
234 *
235 * @param intf the interface instance.
236 *
237 * @return the error code, RT_EOK on successfully.
238 */
rt_usbh_storage_reset(struct uhintf * intf)239 rt_err_t rt_usbh_storage_reset(struct uhintf* intf)
240 {
241 struct urequest setup;
242 struct uinstance* device;
243 int timeout = USB_TIMEOUT_BASIC;
244
245 /* parameter check */
246 if(intf == RT_NULL)
247 {
248 rt_kprintf("the interface is not available\n");
249 return -RT_EIO;
250 }
251
252 RT_ASSERT(intf->device != RT_NULL);
253 RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_storage_reset\n"));
254
255 /* get usb device instance from the interface instance */
256 device = intf->device;
257
258 /* construct the request */
259 setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
260 USB_REQ_TYPE_INTERFACE;
261 setup.bRequest = USBREQ_MASS_STORAGE_RESET;
262 setup.wIndex = intf->intf_desc->bInterfaceNumber;
263 setup.wLength = 0;
264 setup.wValue = 0;
265
266 if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
267 {
268 return -RT_EIO;
269 }
270 if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) != 0)
271 {
272 return -RT_EIO;
273 }
274 return RT_EOK;
275 }
276
277 /**
278 * This function will execute SCSI_READ_10 command to read data from the usb device.
279 *
280 * @param intf the interface instance.
281 * @param buffer the data buffer to save read data
282 * @param sector the start sector address to read.
283 * @param sector the sector count to read.
284 *
285 * @return the error code, RT_EOK on successfully.
286 */
rt_usbh_storage_read10(struct uhintf * intf,rt_uint8_t * buffer,rt_uint32_t sector,rt_size_t count,int timeout)287 rt_err_t rt_usbh_storage_read10(struct uhintf* intf, rt_uint8_t *buffer,
288 rt_uint32_t sector, rt_size_t count, int timeout)
289 {
290 struct ustorage_cbw cmd;
291
292 /* parameter check */
293 if(intf == RT_NULL)
294 {
295 rt_kprintf("interface is not available\n");
296 return -RT_EIO;
297 }
298
299 RT_ASSERT(intf->device != RT_NULL);
300 RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_storage_read10\n"));
301
302 /* construct the command block wrapper */
303 rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
304 cmd.signature = CBW_SIGNATURE;
305 cmd.tag = CBW_TAG_VALUE;
306 cmd.xfer_len = SECTOR_SIZE * count;
307 cmd.dflags = CBWFLAGS_DIR_IN;
308 cmd.lun = 0;
309 cmd.cb_len = 10;
310 cmd.cb[0] = SCSI_READ_10;
311 cmd.cb[1] = 0;
312 cmd.cb[2] = (rt_uint8_t)(sector >> 24);
313 cmd.cb[3] = (rt_uint8_t)(sector >> 16);
314 cmd.cb[4] = (rt_uint8_t)(sector >> 8);
315 cmd.cb[5] = (rt_uint8_t)sector;
316 cmd.cb[6] = 0;
317 cmd.cb[7] = (count & 0xff00) >> 8;
318 cmd.cb[8] = (rt_uint8_t) count & 0xff;
319
320 return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
321 }
322
323 /**
324 * This function will execute SCSI_WRITE_10 command to write data to the usb device.
325 *
326 * @param intf the interface instance.
327 * @param buffer the data buffer to save write data
328 * @param sector the start sector address to write.
329 * @param sector the sector count to write.
330 *
331 * @return the error code, RT_EOK on successfully.
332 */
rt_usbh_storage_write10(struct uhintf * intf,rt_uint8_t * buffer,rt_uint32_t sector,rt_size_t count,int timeout)333 rt_err_t rt_usbh_storage_write10(struct uhintf* intf, rt_uint8_t *buffer,
334 rt_uint32_t sector, rt_size_t count, int timeout)
335 {
336 struct ustorage_cbw cmd;
337
338 /* parameter check */
339 if(intf == RT_NULL)
340 {
341 rt_kprintf("the interface is not available\n");
342 return -RT_EIO;
343 }
344
345 RT_ASSERT(intf->device != RT_NULL);
346 RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_storage_write10\n"));
347
348 /* construct the command block wrapper */
349 rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
350 cmd.signature = CBW_SIGNATURE;
351 cmd.tag = CBW_TAG_VALUE;
352 cmd.xfer_len = SECTOR_SIZE * count;
353 cmd.dflags = CBWFLAGS_DIR_OUT;
354 cmd.lun = 0;
355 cmd.cb_len = 10;
356 cmd.cb[0] = SCSI_WRITE_10;
357 cmd.cb[1] = 0;
358 cmd.cb[2] = (rt_uint8_t)(sector >> 24);
359 cmd.cb[3] = (rt_uint8_t)(sector >> 16);
360 cmd.cb[4] = (rt_uint8_t)(sector >> 8);
361 cmd.cb[5] = (rt_uint8_t)sector;
362 cmd.cb[6] = 0;
363 cmd.cb[7] = (count & 0xff00) >> 8;
364 cmd.cb[8] = (rt_uint8_t) count & 0xff;
365
366 return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
367 }
368
369 /**
370 * This function will execute SCSI_REQUEST_SENSE command to get sense data.
371 *
372 * @param intf the interface instance.
373 * @param buffer the data buffer to save sense data
374 *
375 * @return the error code, RT_EOK on successfully.
376 */
rt_usbh_storage_request_sense(struct uhintf * intf,rt_uint8_t * buffer)377 rt_err_t rt_usbh_storage_request_sense(struct uhintf* intf, rt_uint8_t* buffer)
378 {
379 struct ustorage_cbw cmd;
380 int timeout = USB_TIMEOUT_LONG;
381
382 /* parameter check */
383 if(intf == RT_NULL)
384 {
385 rt_kprintf("the interface is not available\n");
386 return -RT_EIO;
387 }
388
389 RT_ASSERT(intf->device != RT_NULL);
390 RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_storage_request_sense\n"));
391
392 /* construct the command block wrapper */
393 rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
394 cmd.signature = CBW_SIGNATURE;
395 cmd.tag = CBW_TAG_VALUE;
396 cmd.xfer_len = 18;
397 cmd.dflags = CBWFLAGS_DIR_IN;
398 cmd.lun = 0;
399 cmd.cb_len = 6;
400 cmd.cb[0] = SCSI_REQUEST_SENSE;
401 cmd.cb[4] = 18;
402
403 return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
404 }
405
406 /**
407 * This function will execute SCSI_TEST_UNIT_READY command to get unit ready status.
408 *
409 * @param intf the interface instance.
410 *
411 * @return the error code, RT_EOK on successfully.
412 */
rt_usbh_storage_test_unit_ready(struct uhintf * intf)413 rt_err_t rt_usbh_storage_test_unit_ready(struct uhintf* intf)
414 {
415 struct ustorage_cbw cmd;
416 int timeout = USB_TIMEOUT_LONG;
417
418 /* parameter check */
419 if(intf == RT_NULL)
420 {
421 rt_kprintf("the interface is not available\n");
422 return -RT_EIO;
423 }
424
425 RT_ASSERT(intf->device != RT_NULL);
426 RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_storage_test_unit_ready\n"));
427
428 /* construct the command block wrapper */
429 rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
430 cmd.signature = CBW_SIGNATURE;
431 cmd.tag = CBW_TAG_VALUE;
432 cmd.xfer_len = 0;
433 cmd.dflags = CBWFLAGS_DIR_OUT;
434 cmd.lun = 0;
435 cmd.cb_len = 12;
436 cmd.cb[0] = SCSI_TEST_UNIT_READY;
437
438 return rt_usb_bulk_only_xfer(intf, &cmd, RT_NULL, timeout);
439 }
440
441 /**
442 * This function will execute SCSI_INQUIRY_CMD command to get inquiry data.
443 *
444 * @param intf the interface instance.
445 * @param buffer the data buffer to save inquiry data
446 *
447 * @return the error code, RT_EOK on successfully.
448 */
rt_usbh_storage_inquiry(struct uhintf * intf,rt_uint8_t * buffer)449 rt_err_t rt_usbh_storage_inquiry(struct uhintf* intf, rt_uint8_t* buffer)
450 {
451 struct ustorage_cbw cmd;
452 int timeout = USB_TIMEOUT_LONG;
453
454 /* parameter check */
455 if(intf == RT_NULL)
456 {
457 rt_kprintf("the interface is not available\n");
458 return -RT_EIO;
459 }
460
461 RT_ASSERT(intf->device != RT_NULL);
462 RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_storage_inquiry\n"));
463
464 /* construct the command block wrapper */
465 rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
466 cmd.signature = CBW_SIGNATURE;
467 cmd.tag = CBW_TAG_VALUE;
468 cmd.xfer_len = 36;
469 cmd.dflags = CBWFLAGS_DIR_IN;
470 cmd.lun = 0;
471 cmd.cb_len = 6;//12
472 cmd.cb[0] = SCSI_INQUIRY_CMD;
473 cmd.cb[4] = 36;
474
475 return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
476 }
477
478 /**
479 * This function will execute SCSI_READ_CAPACITY command to get capacity data.
480 *
481 * @param intf the interface instance.
482 * @param buffer the data buffer to save capacity data
483 *
484 * @return the error code, RT_EOK on successfully.
485 */
rt_usbh_storage_get_capacity(struct uhintf * intf,rt_uint8_t * buffer)486 rt_err_t rt_usbh_storage_get_capacity(struct uhintf* intf, rt_uint8_t* buffer)
487 {
488 struct ustorage_cbw cmd;
489 int timeout = USB_TIMEOUT_LONG;
490
491 /* parameter check */
492 if(intf == RT_NULL)
493 {
494 rt_kprintf("the interface is not available\n");
495 return -RT_EIO;
496 }
497
498 RT_ASSERT(intf->device != RT_NULL);
499 RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_storage_get_capacity\n"));
500
501 /* construct the command block wrapper */
502 rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
503 cmd.signature = CBW_SIGNATURE;
504 cmd.tag = CBW_TAG_VALUE;
505 cmd.xfer_len = 8;
506 cmd.dflags = CBWFLAGS_DIR_IN;
507 cmd.lun = 0;
508 cmd.cb_len = 12;
509 cmd.cb[0] = SCSI_READ_CAPACITY;
510
511 return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
512 }
513
514 /**
515 * This function will run mass storage class driver when usb device is detected
516 * and identified as a mass storage class device, it will continue to do the enumulate
517 * process.
518 *
519 * @param arg the argument.
520 *
521 * @return the error code, RT_EOK on successfully.
522 */
rt_usbh_storage_enable(void * arg)523 static rt_err_t rt_usbh_storage_enable(void* arg)
524 {
525 int i = 0;
526 rt_err_t ret;
527 ustor_t stor;
528 struct uhintf* intf = (struct uhintf*)arg;
529
530 /* parameter check */
531 if(intf == RT_NULL)
532 {
533 rt_kprintf("the interface is not available\n");
534 return -RT_EIO;
535 }
536
537 RT_DEBUG_LOG(RT_DEBUG_USB, ("subclass %d, protocal %d\n",
538 intf->intf_desc->bInterfaceSubClass,
539 intf->intf_desc->bInterfaceProtocol));
540
541 RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_storage_run\n"));
542
543 /* only support SCSI subclass and bulk only protocal */
544
545 stor = rt_malloc(sizeof(struct ustor));
546 RT_ASSERT(stor != RT_NULL);
547
548 /* initilize the data structure */
549 rt_memset(stor, 0, sizeof(struct ustor));
550 intf->user_data = (void*)stor;
551
552 for(i=0; i<intf->intf_desc->bNumEndpoints; i++)
553 {
554 uep_desc_t ep_desc;
555
556 /* get endpoint descriptor from interface descriptor */
557 rt_usbh_get_endpoint_descriptor(intf->intf_desc, i, &ep_desc);
558 if(ep_desc == RT_NULL)
559 {
560 rt_kprintf("rt_usb_get_endpoint_descriptor error\n");
561 return -RT_ERROR;
562 }
563
564 /* the endpoint type of mass storage class should be BULK */
565 if((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
566 continue;
567
568 /* allocate pipes according to the endpoint type */
569 if(ep_desc->bEndpointAddress & USB_DIR_IN)
570 {
571 /* alloc an in pipe for the storage instance */
572 stor->pipe_in = rt_usb_instance_find_pipe(intf->device,ep_desc->bEndpointAddress);
573 }
574 else
575 {
576 /* alloc an output pipe for the storage instance */
577 stor->pipe_out = rt_usb_instance_find_pipe(intf->device,ep_desc->bEndpointAddress);
578 }
579 }
580
581 /* check pipes infomation */
582 if(stor->pipe_in == RT_NULL || stor->pipe_out == RT_NULL)
583 {
584 rt_kprintf("pipe error, unsupported device\n");
585 return -RT_ERROR;
586 }
587
588 /* should implement as callback */
589 ret = rt_udisk_run(intf);
590 if(ret != RT_EOK) return ret;
591
592 return RT_EOK;
593 }
594
595 /**
596 * This function will be invoked when usb device plug out is detected and it would clean
597 * and release all mass storage class related resources.
598 *
599 * @param arg the argument.
600 *
601 * @return the error code, RT_EOK on successfully.
602 */
rt_usbh_storage_disable(void * arg)603 static rt_err_t rt_usbh_storage_disable(void* arg)
604 {
605 ustor_t stor;
606 struct uhintf* intf = (struct uhintf*)arg;
607
608 /* parameter check */
609 RT_ASSERT(intf != RT_NULL);
610 RT_ASSERT(intf->user_data != RT_NULL);
611 RT_ASSERT(intf->device != RT_NULL);
612
613 RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_storage_stop\n"));
614
615 /* get storage instance from interface instance */
616 stor = (ustor_t)intf->user_data;
617
618 rt_udisk_stop(intf);
619
620
621 /* free storage instance */
622 if(stor != RT_NULL) rt_free(stor);
623 return RT_EOK;
624 }
625
626 /**
627 * This function will register mass storage class driver to the usb class driver manager.
628 * and it should be invoked in the usb system initialization.
629 *
630 * @return the error code, RT_EOK on successfully.
631 */
rt_usbh_class_driver_storage(void)632 ucd_t rt_usbh_class_driver_storage(void)
633 {
634 storage_driver.class_code = USB_CLASS_MASS_STORAGE;
635
636 storage_driver.enable = rt_usbh_storage_enable;
637 storage_driver.disable = rt_usbh_storage_disable;
638
639 return &storage_driver;
640 }
641
642 #endif
643
644