1 /*
2  * Copyright (c) 2024, sakumisu
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include "usbd_core.h"
7 #include "usb_midi.h"
8 
9 #define MIDI_OUT_EP 0x02
10 #define MIDI_IN_EP  0x81
11 
12 #define USBD_VID           0x0d28
13 #define USBD_PID           0x0404
14 #define USBD_MAX_POWER     100
15 #define USBD_LANGID_STRING 1033
16 
17 #define USB_CONFIG_SIZE (9 + 9 + 9 + 9 + 7 + MIDI_SIZEOF_JACK_DESC + 9 + 5 + 9 + 5)
18 
19 #ifdef CONFIG_USB_HS
20 #define MIDI_EP_MPS 512
21 #else
22 #define MIDI_EP_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, 0x0100, 0x01)
28 };
29 
30 static const uint8_t config_descriptor[] = {
31     USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
32     // Standard AC Interface Descriptor
33     0x09,
34     0x04,
35     0x00,
36     0x00,
37     0x00,
38     0x01,
39     0x01,
40     0x00,
41     0x00,
42     // Class-specific AC Interface Descriptor
43     0x09,
44     0x24,
45     0x01,
46     0x00,
47     0x01,
48     0x09,
49     0x00,
50     0x01,
51     0x01,
52     // MIDIStreaming Interface Descriptors
53     0x09,
54     0x04,
55     0x01,
56     0x00,
57     0x02,
58     0x01,
59     0x03,
60     0x00,
61     0x00,
62     // Class-Specific MS Interface Header Descriptor
63     0x07,
64     0x24,
65     0x01,
66     0x00,
67     0x01,
68     WBVAL(65),
69 
70     // MIDI_IN_JACK_DESCRIPTOR_INIT(MIDI_JACK_TYPE_EMBEDDED, 0x01),
71     // MIDI_IN_JACK_DESCRIPTOR_INIT(MIDI_JACK_TYPE_EXTERNAL, 0x02),
72     // MIDI_OUT_JACK_DESCRIPTOR_INIT(MIDI_JACK_TYPE_EMBEDDED, 0x03, 0x02),
73     // MIDI_OUT_JACK_DESCRIPTOR_INIT(MIDI_JACK_TYPE_EXTERNAL, 0x04, 0x01),
74     MIDI_JACK_DESCRIPTOR_INIT(0x01),
75     // OUT endpoint descriptor
76     0x09, 0x05, MIDI_OUT_EP, 0x02, WBVAL(MIDI_EP_MPS), 0x00, 0x00, 0x00,
77     0x05, 0x25, 0x01, 0x01, 0x01,
78 
79     // IN endpoint descriptor
80     0x09, 0x05, MIDI_IN_EP, 0x02, WBVAL(MIDI_EP_MPS), 0x00, 0x00, 0x00,
81     0x05, 0x25, 0x01, 0x01, 0x03
82 };
83 
84 static const uint8_t device_quality_descriptor[] = {
85     ///////////////////////////////////////
86     /// device qualifier descriptor
87     ///////////////////////////////////////
88     0x0a,
89     USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
90     0x00,
91     0x02,
92     0x00,
93     0x00,
94     0x00,
95     0x40,
96     0x00,
97     0x00,
98 };
99 
100 static const char *string_descriptors[] = {
101     (const char[]){ 0x09, 0x04 }, /* Langid */
102     "CherryUSB",                  /* Manufacturer */
103     "CherryUSB MIDI DEMO",        /* Product */
104     "2022123456",                 /* Serial Number */
105 };
106 
device_descriptor_callback(uint8_t speed)107 static const uint8_t *device_descriptor_callback(uint8_t speed)
108 {
109     return device_descriptor;
110 }
111 
config_descriptor_callback(uint8_t speed)112 static const uint8_t *config_descriptor_callback(uint8_t speed)
113 {
114     return config_descriptor;
115 }
116 
device_quality_descriptor_callback(uint8_t speed)117 static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
118 {
119     return device_quality_descriptor;
120 }
121 
string_descriptor_callback(uint8_t speed,uint8_t index)122 static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
123 {
124     if (index > 3) {
125         return NULL;
126     }
127     return string_descriptors[index];
128 }
129 
130 const struct usb_descriptor midi_descriptor = {
131     .device_descriptor_callback = device_descriptor_callback,
132     .config_descriptor_callback = config_descriptor_callback,
133     .device_quality_descriptor_callback = device_quality_descriptor_callback,
134     .string_descriptor_callback = string_descriptor_callback
135 };
136 #else
137 const uint8_t midi_descriptor[] = {
138     USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0100, 0x01),
139     USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
140     // Standard AC Interface Descriptor
141     0x09,
142     0x04,
143     0x00,
144     0x00,
145     0x00,
146     0x01,
147     0x01,
148     0x00,
149     0x00,
150     // Class-specific AC Interface Descriptor
151     0x09,
152     0x24,
153     0x01,
154     0x00,
155     0x01,
156     0x09,
157     0x00,
158     0x01,
159     0x01,
160     // MIDIStreaming Interface Descriptors
161     0x09,
162     0x04,
163     0x01,
164     0x00,
165     0x02,
166     0x01,
167     0x03,
168     0x00,
169     0x00,
170     // Class-Specific MS Interface Header Descriptor
171     0x07,
172     0x24,
173     0x01,
174     0x00,
175     0x01,
176     WBVAL(65),
177 
178     // MIDI_IN_JACK_DESCRIPTOR_INIT(MIDI_JACK_TYPE_EMBEDDED, 0x01),
179     // MIDI_IN_JACK_DESCRIPTOR_INIT(MIDI_JACK_TYPE_EXTERNAL, 0x02),
180     // MIDI_OUT_JACK_DESCRIPTOR_INIT(MIDI_JACK_TYPE_EMBEDDED, 0x03, 0x02),
181     // MIDI_OUT_JACK_DESCRIPTOR_INIT(MIDI_JACK_TYPE_EXTERNAL, 0x04, 0x01),
182     MIDI_JACK_DESCRIPTOR_INIT(0x01),
183     // OUT endpoint descriptor
184     0x09, 0x05, MIDI_OUT_EP, 0x02, WBVAL(MIDI_EP_MPS), 0x00, 0x00, 0x00,
185     0x05, 0x25, 0x01, 0x01, 0x01,
186 
187     // IN endpoint descriptor
188     0x09, 0x05, MIDI_IN_EP, 0x02, WBVAL(MIDI_EP_MPS), 0x00, 0x00, 0x00,
189     0x05, 0x25, 0x01, 0x01, 0x03,
190 
191     ///////////////////////////////////////
192     /// string0 descriptor
193     ///////////////////////////////////////
194     USB_LANGID_INIT(USBD_LANGID_STRING),
195     ///////////////////////////////////////
196     /// string1 descriptor
197     ///////////////////////////////////////
198     0x14,                       /* bLength */
199     USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
200     'C', 0x00,                  /* wcChar0 */
201     'h', 0x00,                  /* wcChar1 */
202     'e', 0x00,                  /* wcChar2 */
203     'r', 0x00,                  /* wcChar3 */
204     'r', 0x00,                  /* wcChar4 */
205     'y', 0x00,                  /* wcChar5 */
206     'U', 0x00,                  /* wcChar6 */
207     'S', 0x00,                  /* wcChar7 */
208     'B', 0x00,                  /* wcChar8 */
209     ///////////////////////////////////////
210     /// string2 descriptor
211     ///////////////////////////////////////
212     0x28,                       /* bLength */
213     USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
214     'C', 0x00,                  /* wcChar0 */
215     'h', 0x00,                  /* wcChar1 */
216     'e', 0x00,                  /* wcChar2 */
217     'r', 0x00,                  /* wcChar3 */
218     'r', 0x00,                  /* wcChar4 */
219     'y', 0x00,                  /* wcChar5 */
220     'U', 0x00,                  /* wcChar6 */
221     'S', 0x00,                  /* wcChar7 */
222     'B', 0x00,                  /* wcChar8 */
223     ' ', 0x00,                  /* wcChar9 */
224     'M', 0x00,                  /* wcChar10 */
225     'I', 0x00,                  /* wcChar11 */
226     'D', 0x00,                  /* wcChar12 */
227     'I', 0x00,                  /* wcChar13 */
228     ' ', 0x00,                  /* wcChar14 */
229     'D', 0x00,                  /* wcChar15 */
230     'E', 0x00,                  /* wcChar16 */
231     'M', 0x00,                  /* wcChar17 */
232     'O', 0x00,                  /* wcChar18 */
233     ///////////////////////////////////////
234     /// string3 descriptor
235     ///////////////////////////////////////
236     0x16,                       /* bLength */
237     USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
238     '2', 0x00,                  /* wcChar0 */
239     '0', 0x00,                  /* wcChar1 */
240     '2', 0x00,                  /* wcChar2 */
241     '1', 0x00,                  /* wcChar3 */
242     '0', 0x00,                  /* wcChar4 */
243     '3', 0x00,                  /* wcChar5 */
244     '1', 0x00,                  /* wcChar6 */
245     '0', 0x00,                  /* wcChar7 */
246     '0', 0x00,                  /* wcChar8 */
247     '0', 0x00,                  /* wcChar9 */
248 #ifdef CONFIG_USB_HS
249     ///////////////////////////////////////
250     /// device qualifier descriptor
251     ///////////////////////////////////////
252     0x0a,
253     USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
254     0x00,
255     0x02,
256     0x00,
257     0x00,
258     0x00,
259     0x40,
260     0x00,
261     0x00,
262 #endif
263     0x00
264 };
265 #endif
266 
267 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[MIDI_EP_MPS];
268 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[MIDI_EP_MPS];
269 
usbd_event_handler(uint8_t busid,uint8_t event)270 static void usbd_event_handler(uint8_t busid, uint8_t event)
271 {
272     switch (event) {
273         case USBD_EVENT_RESET:
274             break;
275         case USBD_EVENT_CONNECTED:
276             break;
277         case USBD_EVENT_DISCONNECTED:
278             break;
279         case USBD_EVENT_RESUME:
280             break;
281         case USBD_EVENT_SUSPEND:
282             break;
283         case USBD_EVENT_CONFIGURED:
284             usbd_ep_start_read(busid, MIDI_OUT_EP, read_buffer, MIDI_EP_MPS);
285             break;
286         case USBD_EVENT_SET_REMOTE_WAKEUP:
287             break;
288         case USBD_EVENT_CLR_REMOTE_WAKEUP:
289             break;
290 
291         default:
292             break;
293     }
294 }
295 
usbd_midi_bulk_out(uint8_t busid,uint8_t ep,uint32_t nbytes)296 void usbd_midi_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
297 {
298     usbd_ep_start_read(busid, MIDI_OUT_EP, read_buffer, MIDI_EP_MPS);
299 }
300 
usbd_midi_bulk_in(uint8_t busid,uint8_t ep,uint32_t nbytes)301 void usbd_midi_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
302 {
303 }
304 
305 struct usbd_interface intf0;
306 struct usbd_interface intf1;
307 
308 struct usbd_endpoint midi_out_ep = {
309     .ep_addr = MIDI_OUT_EP,
310     .ep_cb = usbd_midi_bulk_out
311 };
312 
313 struct usbd_endpoint midi_in_ep = {
314     .ep_addr = MIDI_IN_EP,
315     .ep_cb = usbd_midi_bulk_in
316 };
317 
midi_init(uint8_t busid,uintptr_t reg_base)318 void midi_init(uint8_t busid, uintptr_t reg_base)
319 {
320 #ifdef CONFIG_USBDEV_ADVANCE_DESC
321     usbd_desc_register(busid, &midi_descriptor);
322 #else
323     usbd_desc_register(busid, midi_descriptor);
324 #endif
325     usbd_add_interface(busid, &intf0);
326     usbd_add_interface(busid, &intf1);
327     usbd_add_endpoint(busid, &midi_out_ep);
328     usbd_add_endpoint(busid, &midi_in_ep);
329 
330     usbd_initialize(busid, reg_base, usbd_event_handler);
331 }