1 /*
2  * Copyright (c) 2022 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include <rthw.h>
9 #include <rtdevice.h>
10 #include <rtdbg.h>
11 #include "tusb.h"
12 
13 /* Definition of logic unit number for each drive */
14 #define LUN_USB     (0U)    /* lun 0 of usb drive */
15 
16 static rt_ssize_t hpm_usb_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
17 static rt_ssize_t hpm_usb_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
18 rt_err_t  hpm_usb_control(rt_device_t dev, int cmd, void *args);
19 
20 rt_uint8_t usb_dev_addr;
21 
22 static struct rt_device hpm_usb = {
23     .read = hpm_usb_read,
24     .write = hpm_usb_write,
25     .control = hpm_usb_control,
26 };
27 
usb_disk_wait_for_complete(uint8_t usb_addr)28 static bool usb_disk_wait_for_complete(uint8_t usb_addr)
29 {
30     #if CFG_TUSB_OS != OPT_OS_NONE
31     int32_t retry_cnt = 200;
32     #else
33     int32_t retry_cnt = 5000000;
34     #endif
35 
36     while (!tuh_msc_idle(usb_addr) && retry_cnt--)
37     {
38         #if CFG_TUSB_OS != OPT_OS_NONE
39         osal_task_delay(5);
40         #else
41         tuh_task();
42         #endif
43     }
44 
45     return retry_cnt > 0 ? true : false;
46 }
47 
hpm_usb_set_addr(uint8_t dev_addr)48 void hpm_usb_set_addr(uint8_t dev_addr)
49 {
50     usb_dev_addr = dev_addr;
51 }
52 
hpm_usb_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)53 static rt_ssize_t hpm_usb_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
54 {
55     rt_bool_t result;
56 
57     result = tuh_msc_read10(usb_dev_addr, LUN_USB, buffer, pos, size, NULL);
58 
59     if (result) {
60         result =  usb_disk_wait_for_complete(usb_dev_addr);
61     }
62 
63     return result ? size : 0;
64 }
65 
hpm_usb_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)66 static rt_ssize_t hpm_usb_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
67 {
68     bool result;
69 
70     result = tuh_msc_write10(usb_dev_addr, LUN_USB, buffer, pos, size, NULL);
71 
72     if (result) {
73         result =  usb_disk_wait_for_complete(usb_dev_addr);
74     }
75 
76     return result ? size : 0;
77 }
78 
hpm_usb_control(rt_device_t dev,int cmd,void * args)79 rt_err_t hpm_usb_control(rt_device_t dev, int cmd, void *args)
80 {
81     rt_err_t ret = RT_EOK;
82 
83     switch (cmd)
84     {
85     case RT_DEVICE_CTRL_BLK_GETGEOME:
86         struct rt_device_blk_geometry *geometry = (struct rt_device_blk_geometry *)args;
87         geometry->sector_count = tuh_msc_get_block_count(usb_dev_addr, LUN_USB);
88         geometry->bytes_per_sector = tuh_msc_get_block_size(usb_dev_addr, LUN_USB);
89        break;
90     case RT_DEVICE_CTRL_BLK_SYNC:
91         break;
92     case RT_DEVICE_CTRL_BLK_ERASE:
93         break;
94 
95     default:
96         ret = RT_EINVAL;
97         break;
98     }
99 
100     return RT_EOK;
101 }
102 
rt_hw_usb_init(void)103 int rt_hw_usb_init(void)
104 {
105     rt_err_t err = RT_EOK;
106 
107     hpm_usb.type = RT_Device_Class_Block;
108 
109     err = rt_device_register(&hpm_usb, "usb0", RT_DEVICE_FLAG_RDWR);
110 
111     if (err != RT_EOK) {
112         LOG_E("rt device %s failed, status=%d\n", "usb", err);
113         return err;
114     }
115 
116     return err;
117 }
118 
119 INIT_BOARD_EXPORT(rt_hw_usb_init);
120