xref: /nrf52832-nimble/rt-thread/components/drivers/usb/usbhost/class/mass.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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