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