1 /*
2  * Copyright (c) 2024, sakumisu
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include "usbd_core.h"
7 #include "usbd_msc.h"
8 
9 #define MSC_IN_EP  0x81
10 #define MSC_OUT_EP 0x02
11 
12 #define USBD_VID           0xFFFF
13 #define USBD_PID           0xFFFF
14 #define USBD_MAX_POWER     100
15 #define USBD_LANGID_STRING 1033
16 
17 #define USB_CONFIG_SIZE (9 + MSC_DESCRIPTOR_LEN)
18 
19 #ifdef CONFIG_USB_HS
20 #define MSC_MAX_MPS 512
21 #else
22 #define MSC_MAX_MPS 64
23 #endif
24 
25 #ifdef CONFIG_USBDEV_ADVANCE_DESC
26 static const uint8_t device_descriptor[] = {
27     USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01)
28 };
29 
30 static const uint8_t config_descriptor[] = {
31     USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
32     MSC_DESCRIPTOR_INIT(0x00, MSC_OUT_EP, MSC_IN_EP, MSC_MAX_MPS, 0x02)
33 };
34 
35 static const uint8_t device_quality_descriptor[] = {
36     ///////////////////////////////////////
37     /// device qualifier descriptor
38     ///////////////////////////////////////
39     0x0a,
40     USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
41     0x00,
42     0x02,
43     0x00,
44     0x00,
45     0x00,
46     0x40,
47     0x00,
48     0x00,
49 };
50 
51 static const char *string_descriptors[] = {
52     (const char[]){ 0x09, 0x04 }, /* Langid */
53     "CherryUSB",                  /* Manufacturer */
54     "CherryUSB MSC DEMO",         /* Product */
55     "2022123456",                 /* Serial Number */
56 };
57 
device_descriptor_callback(uint8_t speed)58 static const uint8_t *device_descriptor_callback(uint8_t speed)
59 {
60     return device_descriptor;
61 }
62 
config_descriptor_callback(uint8_t speed)63 static const uint8_t *config_descriptor_callback(uint8_t speed)
64 {
65     return config_descriptor;
66 }
67 
device_quality_descriptor_callback(uint8_t speed)68 static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
69 {
70     return device_quality_descriptor;
71 }
72 
string_descriptor_callback(uint8_t speed,uint8_t index)73 static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
74 {
75     if (index > 3) {
76         return NULL;
77     }
78     return string_descriptors[index];
79 }
80 
81 const struct usb_descriptor msc_ram_descriptor = {
82     .device_descriptor_callback = device_descriptor_callback,
83     .config_descriptor_callback = config_descriptor_callback,
84     .device_quality_descriptor_callback = device_quality_descriptor_callback,
85     .string_descriptor_callback = string_descriptor_callback
86 };
87 #else
88 const uint8_t msc_ram_descriptor[] = {
89     USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01),
90     USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
91     MSC_DESCRIPTOR_INIT(0x00, MSC_OUT_EP, MSC_IN_EP, MSC_MAX_MPS, 0x02),
92     ///////////////////////////////////////
93     /// string0 descriptor
94     ///////////////////////////////////////
95     USB_LANGID_INIT(USBD_LANGID_STRING),
96     ///////////////////////////////////////
97     /// string1 descriptor
98     ///////////////////////////////////////
99     0x14,                       /* bLength */
100     USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
101     'C', 0x00,                  /* wcChar0 */
102     'h', 0x00,                  /* wcChar1 */
103     'e', 0x00,                  /* wcChar2 */
104     'r', 0x00,                  /* wcChar3 */
105     'r', 0x00,                  /* wcChar4 */
106     'y', 0x00,                  /* wcChar5 */
107     'U', 0x00,                  /* wcChar6 */
108     'S', 0x00,                  /* wcChar7 */
109     'B', 0x00,                  /* wcChar8 */
110     ///////////////////////////////////////
111     /// string2 descriptor
112     ///////////////////////////////////////
113     0x26,                       /* bLength */
114     USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
115     'C', 0x00,                  /* wcChar0 */
116     'h', 0x00,                  /* wcChar1 */
117     'e', 0x00,                  /* wcChar2 */
118     'r', 0x00,                  /* wcChar3 */
119     'r', 0x00,                  /* wcChar4 */
120     'y', 0x00,                  /* wcChar5 */
121     'U', 0x00,                  /* wcChar6 */
122     'S', 0x00,                  /* wcChar7 */
123     'B', 0x00,                  /* wcChar8 */
124     ' ', 0x00,                  /* wcChar9 */
125     'M', 0x00,                  /* wcChar10 */
126     'S', 0x00,                  /* wcChar11 */
127     'C', 0x00,                  /* wcChar12 */
128     ' ', 0x00,                  /* wcChar13 */
129     'D', 0x00,                  /* wcChar14 */
130     'E', 0x00,                  /* wcChar15 */
131     'M', 0x00,                  /* wcChar16 */
132     'O', 0x00,                  /* wcChar17 */
133     ///////////////////////////////////////
134     /// string3 descriptor
135     ///////////////////////////////////////
136     0x16,                       /* bLength */
137     USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
138     '2', 0x00,                  /* wcChar0 */
139     '0', 0x00,                  /* wcChar1 */
140     '2', 0x00,                  /* wcChar2 */
141     '2', 0x00,                  /* wcChar3 */
142     '1', 0x00,                  /* wcChar4 */
143     '2', 0x00,                  /* wcChar5 */
144     '3', 0x00,                  /* wcChar6 */
145     '4', 0x00,                  /* wcChar7 */
146     '5', 0x00,                  /* wcChar8 */
147     '6', 0x00,                  /* wcChar9 */
148 #ifdef CONFIG_USB_HS
149     ///////////////////////////////////////
150     /// device qualifier descriptor
151     ///////////////////////////////////////
152     0x0a,
153     USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
154     0x00,
155     0x02,
156     0x00,
157     0x00,
158     0x00,
159     0x40,
160     0x00,
161     0x00,
162 #endif
163     0x00
164 };
165 #endif
166 
usbd_event_handler(uint8_t busid,uint8_t event)167 static void usbd_event_handler(uint8_t busid, uint8_t event)
168 {
169     switch (event) {
170         case USBD_EVENT_RESET:
171             break;
172         case USBD_EVENT_CONNECTED:
173             break;
174         case USBD_EVENT_DISCONNECTED:
175             break;
176         case USBD_EVENT_RESUME:
177             break;
178         case USBD_EVENT_SUSPEND:
179             break;
180         case USBD_EVENT_CONFIGURED:
181             break;
182         case USBD_EVENT_SET_REMOTE_WAKEUP:
183             break;
184         case USBD_EVENT_CLR_REMOTE_WAKEUP:
185             break;
186 
187         default:
188             break;
189     }
190 }
191 
192 #if !defined(RT_CHERRYUSB_DEVICE_TEMPLATE_MSC_BLKDEV) && !defined(PKG_CHERRYUSB_DEVICE_TEMPLATE_MSC_BLKDEV)
193 #define BLOCK_SIZE  512
194 #define BLOCK_COUNT 10
195 
196 typedef struct
197 {
198     uint8_t BlockSpace[BLOCK_SIZE];
199 } BLOCK_TYPE;
200 
201 BLOCK_TYPE mass_block[BLOCK_COUNT];
202 
usbd_msc_get_cap(uint8_t busid,uint8_t lun,uint32_t * block_num,uint32_t * block_size)203 void usbd_msc_get_cap(uint8_t busid, uint8_t lun, uint32_t *block_num, uint32_t *block_size)
204 {
205     *block_num = 1000; //Pretend having so many buffer,not has actually.
206     *block_size = BLOCK_SIZE;
207 }
usbd_msc_sector_read(uint8_t busid,uint8_t lun,uint32_t sector,uint8_t * buffer,uint32_t length)208 int usbd_msc_sector_read(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
209 {
210     if (sector < BLOCK_COUNT)
211         memcpy(buffer, mass_block[sector].BlockSpace, length);
212     return 0;
213 }
214 
usbd_msc_sector_write(uint8_t busid,uint8_t lun,uint32_t sector,uint8_t * buffer,uint32_t length)215 int usbd_msc_sector_write(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
216 {
217     if (sector < BLOCK_COUNT)
218         memcpy(mass_block[sector].BlockSpace, buffer, length);
219     return 0;
220 }
221 #else
222 #include <rtthread.h>
223 #include <rtdevice.h>
224 
225 #ifndef CONFIG_USBDEV_MSC_THREAD
226 #error "Please enable CONFIG_USBDEV_MSC_THREAD, move msc read & write from isr to thread"
227 #endif
228 
229 #ifndef CONFIG_USBDEV_MSC_BLOCK_DEV_NAME
230 #define CONFIG_USBDEV_MSC_BLOCK_DEV_NAME "sd0"
231 #endif
232 
233 static rt_device_t blk_dev = RT_NULL;
234 struct rt_device_blk_geometry geometry = { 0 };
235 
usbd_msc_get_cap(uint8_t busid,uint8_t lun,uint32_t * block_num,uint32_t * block_size)236 void usbd_msc_get_cap(uint8_t busid, uint8_t lun, uint32_t *block_num, uint32_t *block_size)
237 {
238     rt_device_control(blk_dev, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry);
239 
240     *block_num = geometry.sector_count;
241     *block_size = geometry.bytes_per_sector;
242 }
243 
usbd_msc_sector_read(uint8_t busid,uint8_t lun,uint32_t sector,uint8_t * buffer,uint32_t length)244 int usbd_msc_sector_read(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
245 {
246     rt_device_read(blk_dev, sector, buffer, length / geometry.bytes_per_sector);
247     return 0;
248 }
249 
usbd_msc_sector_write(uint8_t busid,uint8_t lun,uint32_t sector,uint8_t * buffer,uint32_t length)250 int usbd_msc_sector_write(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
251 {
252     rt_device_write(blk_dev, sector, buffer, length / geometry.bytes_per_sector);
253     return 0;
254 }
255 #endif
256 
257 static struct usbd_interface intf0;
258 
msc_ram_init(uint8_t busid,uintptr_t reg_base)259 void msc_ram_init(uint8_t busid, uintptr_t reg_base)
260 {
261 #if defined(RT_CHERRYUSB_DEVICE_TEMPLATE_MSC_BLKDEV) || defined(PKG_CHERRYUSB_DEVICE_TEMPLATE_MSC_BLKDEV)
262     rt_err_t res;
263 
264     blk_dev = rt_device_find(CONFIG_USBDEV_MSC_BLOCK_DEV_NAME);
265     RT_ASSERT(blk_dev);
266 
267     res = rt_device_open(blk_dev, RT_DEVICE_OFLAG_RDWR);
268     RT_ASSERT(res == RT_EOK);
269 #endif
270 #ifdef CONFIG_USBDEV_ADVANCE_DESC
271     usbd_desc_register(busid, &msc_ram_descriptor);
272 #else
273     usbd_desc_register(busid, msc_ram_descriptor);
274 #endif
275     usbd_add_interface(busid, usbd_msc_init_intf(busid, &intf0, MSC_OUT_EP, MSC_IN_EP));
276 
277     usbd_initialize(busid, reg_base, usbd_event_handler);
278 }
279 
280 #if defined(CONFIG_USBDEV_MSC_POLLING)
msc_ram_polling(uint8_t busid)281 void msc_ram_polling(uint8_t busid)
282 {
283     usbd_msc_polling(busid);
284 }
285 #endif