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