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