xref: /nrf52832-nimble/rt-thread/components/drivers/usb/usbhost/class/udisk.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 <dfs_fs.h>
13 #include <drivers/usb_host.h>
14 #include "mass.h"
15 
16 #ifdef RT_USBH_MSTORAGE
17 
18 #define UDISK_MAX_COUNT        8
19 static rt_uint8_t _udisk_idset = 0;
20 
21 static int udisk_get_id(void)
22 {
23     int i;
24 
25     for(i=0; i< UDISK_MAX_COUNT; i++)
26     {
27         if((_udisk_idset & (1 << i)) != 0) continue;
28         else break;
29     }
30 
31     /* it should not happen */
32     if(i == UDISK_MAX_COUNT) RT_ASSERT(0);
33 
34     _udisk_idset |= (1 << i);
35     return i;
36 }
37 
38 static void udisk_free_id(int id)
39 {
40     RT_ASSERT(id < UDISK_MAX_COUNT)
41 
42     _udisk_idset &= ~(1 << id);
43 }
44 
45 /**
46  * This function will initialize the udisk device
47  *
48  * @param dev the pointer of device driver structure
49  *
50  * @return RT_EOK
51  */
52 static rt_err_t rt_udisk_init(rt_device_t dev)
53 {
54     return RT_EOK;
55 }
56 
57 /**
58  * This function will read some data from a device.
59  *
60  * @param dev the pointer of device driver structure
61  * @param pos the position of reading
62  * @param buffer the data buffer to save read data
63  * @param size the size of buffer
64  *
65  * @return the actually read size on successful, otherwise negative returned.
66  */
67 static rt_size_t rt_udisk_read(rt_device_t dev, rt_off_t pos, void* buffer,
68     rt_size_t size)
69 {
70     rt_err_t ret;
71     struct uhintf* intf;
72     struct ustor_data* data;
73     int timeout = USB_TIMEOUT_LONG;
74 
75     /* check parameter */
76     RT_ASSERT(dev != RT_NULL);
77     RT_ASSERT(buffer != RT_NULL);
78 
79     if(size > 4096) timeout *= 2;
80 
81     data = (struct ustor_data*)dev->user_data;
82     intf = data->intf;
83 
84     ret = rt_usbh_storage_read10(intf, (rt_uint8_t*)buffer, pos, size, timeout);
85 
86     if (ret != RT_EOK)
87     {
88         rt_kprintf("usb mass_storage read failed\n");
89         return 0;
90     }
91 
92     return size;
93 }
94 
95 /**
96  * This function will write some data to a device.
97  *
98  * @param dev the pointer of device driver structure
99  * @param pos the position of written
100  * @param buffer the data buffer to be written to device
101  * @param size the size of buffer
102  *
103  * @return the actually written size on successful, otherwise negative returned.
104  */
105 static rt_size_t rt_udisk_write (rt_device_t dev, rt_off_t pos, const void* buffer,
106     rt_size_t size)
107 {
108     rt_err_t ret;
109     struct uhintf* intf;
110     struct ustor_data* data;
111     int timeout = USB_TIMEOUT_LONG;
112 
113     /* check parameter */
114     RT_ASSERT(dev != RT_NULL);
115     RT_ASSERT(buffer != RT_NULL);
116 
117     if(size * SECTOR_SIZE > 4096) timeout *= 2;
118 
119     data = (struct ustor_data*)dev->user_data;
120     intf = data->intf;
121 
122     ret = rt_usbh_storage_write10(intf, (rt_uint8_t*)buffer, pos, size, timeout);
123     if (ret != RT_EOK)
124     {
125         rt_kprintf("usb mass_storage write %d sector failed\n", size);
126         return 0;
127     }
128 
129     return size;
130 }
131 
132 /**
133  * This function will execute SCSI_INQUIRY_CMD command to get inquiry data.
134  *
135  * @param intf the interface instance.
136  * @param buffer the data buffer to save inquiry data
137  *
138  * @return the error code, RT_EOK on successfully.
139  */
140 static rt_err_t rt_udisk_control(rt_device_t dev, int cmd, void *args)
141 {
142     ustor_t stor;
143     struct ustor_data* data;
144 
145     /* check parameter */
146     RT_ASSERT(dev != RT_NULL);
147 
148     data = (struct ustor_data*)dev->user_data;
149     stor = (ustor_t)data->intf->user_data;
150 
151     if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
152     {
153         struct rt_device_blk_geometry *geometry;
154 
155         geometry = (struct rt_device_blk_geometry *)args;
156         if (geometry == RT_NULL) return -RT_ERROR;
157 
158         geometry->bytes_per_sector = SECTOR_SIZE;
159         geometry->block_size = stor->capicity[1];
160         geometry->sector_count = stor->capicity[0];
161     }
162 
163     return RT_EOK;
164 }
165 
166 #ifdef RT_USING_DEVICE_OPS
167 const static struct rt_device_ops udisk_device_ops =
168 {
169     rt_udisk_init,
170     RT_NULL,
171     RT_NULL,
172     rt_udisk_read,
173     rt_udisk_write,
174     rt_udisk_control
175 };
176 #endif
177 
178 /**
179  * This function will run udisk driver when usb disk is detected.
180  *
181  * @param intf the usb interface instance.
182  *
183  * @return the error code, RT_EOK on successfully.
184  */
185 rt_err_t rt_udisk_run(struct uhintf* intf)
186 {
187     int i = 0;
188     rt_err_t ret;
189     char dname[4];
190     char sname[8];
191     rt_uint8_t max_lun, *sector, sense[18], inquiry[36];
192     struct dfs_partition part[MAX_PARTITION_COUNT];
193     ustor_t stor;
194 
195     /* check parameter */
196     RT_ASSERT(intf != RT_NULL);
197 
198     /* set interface */
199 //    ret = rt_usbh_set_interface(intf->device, intf->intf_desc->bInterfaceNumber);
200 //    if(ret != RT_EOK)
201 //        rt_usbh_clear_feature(intf->device, 0, USB_FEATURE_ENDPOINT_HALT);
202     /* reset mass storage class device */
203     ret = rt_usbh_storage_reset(intf);
204     if(ret != RT_EOK) return ret;
205 
206     stor = (ustor_t)intf->user_data;
207 
208     /* get max logic unit number */
209     ret = rt_usbh_storage_get_max_lun(intf, &max_lun);
210     if(ret != RT_EOK)
211         rt_usbh_clear_feature(intf->device, 0, USB_FEATURE_ENDPOINT_HALT);
212 
213     /* reset pipe in endpoint */
214     if(stor->pipe_in->status == UPIPE_STATUS_STALL)
215     {
216         ret = rt_usbh_clear_feature(intf->device,
217         stor->pipe_in->ep.bEndpointAddress, USB_FEATURE_ENDPOINT_HALT);
218         if(ret != RT_EOK) return ret;
219     }
220 
221 
222     /* reset pipe out endpoint */
223     if(stor->pipe_out->status == UPIPE_STATUS_STALL)
224     {
225         ret = rt_usbh_clear_feature(intf->device,
226         stor->pipe_out->ep.bEndpointAddress, USB_FEATURE_ENDPOINT_HALT);
227         if(ret != RT_EOK) return ret;
228     }
229 
230     while((ret = rt_usbh_storage_inquiry(intf, inquiry)) != RT_EOK)
231     {
232         if(ret == -RT_EIO) return ret;
233 
234         rt_thread_delay(5);
235         if(i++ < 10) continue;
236         rt_kprintf("rt_usbh_storage_inquiry error\n");
237         return -RT_ERROR;
238     }
239 
240     i = 0;
241 
242     /* wait device ready */
243     while((ret = rt_usbh_storage_test_unit_ready(intf)) != RT_EOK)
244     {
245         if(ret == -RT_EIO) return ret;
246 
247         ret = rt_usbh_storage_request_sense(intf, sense);
248         if(ret == -RT_EIO) return ret;
249 
250         rt_thread_delay(10);
251         if(i++ < 10) continue;
252 
253         rt_kprintf("rt_usbh_storage_test_unit_ready error\n");
254         return -RT_ERROR;
255     }
256 
257     i = 0;
258     rt_memset(stor->capicity, 0, sizeof(stor->capicity));
259 
260     /* get storage capacity */
261     while((ret = rt_usbh_storage_get_capacity(intf,
262         (rt_uint8_t*)stor->capicity)) != RT_EOK)
263     {
264         if(ret == -RT_EIO) return ret;
265 
266         rt_thread_delay(50);
267         if(i++ < 10) continue;
268 
269         stor->capicity[0] = 2880;
270         stor->capicity[1] = 0x200;
271 
272         rt_kprintf("rt_usbh_storage_get_capacity error\n");
273         break;
274     }
275 
276     stor->capicity[0] = uswap_32(stor->capicity[0]);
277     stor->capicity[1] = uswap_32(stor->capicity[1]);
278     stor->capicity[0] += 1;
279 
280     RT_DEBUG_LOG(RT_DEBUG_USB, ("capicity %d, block size %d\n",
281         stor->capicity[0], stor->capicity[1]));
282 
283     /* get the first sector to read partition table */
284     sector = (rt_uint8_t*) rt_malloc (SECTOR_SIZE);
285     if (sector == RT_NULL)
286     {
287         rt_kprintf("allocate partition sector buffer failed\n");
288         return -RT_ERROR;
289     }
290 
291     rt_memset(sector, 0, SECTOR_SIZE);
292 
293     RT_DEBUG_LOG(RT_DEBUG_USB, ("read partition table\n"));
294 
295     /* get the partition table */
296     ret = rt_usbh_storage_read10(intf, sector, 0, 1, USB_TIMEOUT_LONG);
297     if(ret != RT_EOK)
298     {
299         rt_kprintf("read parition table error\n");
300 
301         rt_free(sector);
302         return -RT_ERROR;
303     }
304 
305     RT_DEBUG_LOG(RT_DEBUG_USB, ("finished reading partition\n"));
306 
307     for(i=0; i<MAX_PARTITION_COUNT; i++)
308     {
309         /* get the first partition */
310         ret = dfs_filesystem_get_partition(&part[i], sector, i);
311         if (ret == RT_EOK)
312         {
313             struct ustor_data* data = rt_malloc(sizeof(struct ustor_data));
314             rt_memset(data, 0, sizeof(struct ustor_data));
315             data->intf = intf;
316             data->udisk_id = udisk_get_id();
317             rt_snprintf(dname, 6, "ud%d-%d", data->udisk_id, i);
318             rt_snprintf(sname, 8, "sem_ud%d",  i);
319             data->part.lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO);
320 
321             /* register sdcard device */
322             stor->dev[i].type    = RT_Device_Class_Block;
323 #ifdef RT_USING_DEVICE_OPS
324             stor->dev[i].ops     = &udisk_device_ops;
325 #else
326             stor->dev[i].init    = rt_udisk_init;
327             stor->dev[i].read    = rt_udisk_read;
328             stor->dev[i].write   = rt_udisk_write;
329             stor->dev[i].control = rt_udisk_control;
330 #endif
331             stor->dev[i].user_data = (void*)data;
332 
333             rt_device_register(&stor->dev[i], dname, RT_DEVICE_FLAG_RDWR |
334                 RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);
335 
336             stor->dev_cnt++;
337             if (dfs_mount(stor->dev[i].parent.name, UDISK_MOUNTPOINT, "elm",
338                 0, 0) == 0)
339             {
340                 RT_DEBUG_LOG(RT_DEBUG_USB, ("udisk part %d mount successfully\n", i));
341             }
342             else
343             {
344                 RT_DEBUG_LOG(RT_DEBUG_USB, ("udisk part %d mount failed\n", i));
345             }
346         }
347         else
348         {
349             if(i == 0)
350             {
351                 struct ustor_data* data = rt_malloc(sizeof(struct ustor_data));
352                 rt_memset(data, 0, sizeof(struct ustor_data));
353                 data->udisk_id = udisk_get_id();
354 
355                 /* there is no partition table */
356                 data->part.offset = 0;
357                 data->part.size   = 0;
358                 data->intf = intf;
359                 data->part.lock = rt_sem_create("sem_ud", 1, RT_IPC_FLAG_FIFO);
360 
361                 rt_snprintf(dname, 7, "udisk%d", data->udisk_id);
362 
363                 /* register sdcard device */
364                 stor->dev[0].type    = RT_Device_Class_Block;
365 #ifdef RT_USING_DEVICE_OPS
366                 stor->dev[i].ops     = &udisk_device_ops;
367 #else
368                 stor->dev[0].init    = rt_udisk_init;
369                 stor->dev[0].read    = rt_udisk_read;
370                 stor->dev[0].write   = rt_udisk_write;
371                 stor->dev[0].control = rt_udisk_control;
372 #endif
373                 stor->dev[0].user_data = (void*)data;
374 
375                 rt_device_register(&stor->dev[0], dname,
376                     RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE
377                     | RT_DEVICE_FLAG_STANDALONE);
378 
379                 stor->dev_cnt++;
380                 if (dfs_mount(stor->dev[0].parent.name, UDISK_MOUNTPOINT,
381                     "elm", 0, 0) == 0)
382                 {
383                     rt_kprintf("Mount FAT on Udisk successful.\n");
384                 }
385                 else
386                 {
387                     rt_kprintf("Mount FAT on Udisk failed.\n");
388                 }
389             }
390 
391             break;
392         }
393     }
394 
395     rt_free(sector);
396 
397     return RT_EOK;
398 }
399 
400 /**
401  * This function will be invoked when usb disk plug out is detected and it would clean
402  * and release all udisk related resources.
403  *
404  * @param intf the usb interface instance.
405  *
406  * @return the error code, RT_EOK on successfully.
407  */
408 rt_err_t rt_udisk_stop(struct uhintf* intf)
409 {
410     int i;
411     ustor_t stor;
412     struct ustor_data* data;
413 
414     /* check parameter */
415     RT_ASSERT(intf != RT_NULL);
416     RT_ASSERT(intf->device != RT_NULL);
417 
418     stor = (ustor_t)intf->user_data;
419     RT_ASSERT(stor != RT_NULL);
420 
421     for(i=0; i<stor->dev_cnt; i++)
422     {
423         rt_device_t dev = &stor->dev[i];
424         data = (struct ustor_data*)dev->user_data;
425 
426         /* unmount filesystem */
427         dfs_unmount(UDISK_MOUNTPOINT);
428 
429         /* delete semaphore */
430         rt_sem_delete(data->part.lock);
431         udisk_free_id(data->udisk_id);
432         rt_free(data);
433 
434         /* unregister device */
435         rt_device_unregister(&stor->dev[i]);
436     }
437 
438     return RT_EOK;
439 }
440 
441 #endif
442 
443