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