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