1 /*
2  * Copyright (c) 2024 Titouan Christophe
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT zephyr_midi2_device
8 
9 #include <zephyr/drivers/usb/udc.h>
10 #include <zephyr/sys/byteorder.h>
11 #include <zephyr/sys/ring_buffer.h>
12 #include <zephyr/usb/class/usbd_midi2.h>
13 #include <zephyr/usb/usbd.h>
14 
15 #include "usbd_uac2_macros.h"
16 
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(usbd_midi2, CONFIG_USBD_MIDI2_LOG_LEVEL);
19 
20 #define MIDI1_ALTERNATE 0x00
21 #define MIDI2_ALTERNATE 0x01
22 
23 UDC_BUF_POOL_DEFINE(usbd_midi_buf_pool, DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) * 2, 512U,
24 		    sizeof(struct udc_buf_info), NULL);
25 
26 #define MIDI_QUEUE_SIZE 64
27 
28 /* midi20 A.1 MS Class-Specific Interface Descriptor Types */
29 #define CS_GR_TRM_BLOCK	0x26
30 /* midi20 A.1 MS Class-Specific Interface Descriptor Subtypes */
31 #define MS_HEADER	0x01
32 
33 /* midi20 A.2 MS Class-Specific Endpoint Descriptor Subtypes */
34 #define MS_GENERAL	0x01
35 #define MS_GENERAL_2_0	0x02
36 
37 /* midi20 A.3 MS Class-Specific Group Terminal Block Descriptor Subtypes */
38 #define GR_TRM_BLOCK_HEADER	0x01
39 #define GR_TRM_BLOCK		0x02
40 
41 /* midi20 A.6 Group Terminal Block Type */
42 #define GR_TRM_BIDIRECTIONAL	0x00
43 #define GR_TRM_INPUT_ONLY	0x01
44 #define GR_TRM_OUTPUT_ONLY	0x02
45 
46 /* midi20 A.7 Group Terminal Default MIDI Protocol */
47 #define USE_MIDI_CI			0x00
48 #define MIDI_1_0_UP_TO_64_BITS		0x01
49 #define MIDI_1_0_UP_TO_64_BITS_JRTS	0x02
50 #define MIDI_1_0_UP_TO_128_BITS		0x03
51 #define MIDI_1_0_UP_TO_128_BITS_JRTS	0x04
52 #define MIDI_2_0			0x11
53 #define MIDI_2_0_JRTS			0x12
54 
55 /* midi20: B.2.2 Class-specific AC Interface Descriptor */
56 struct usb_midi_cs_ac_header_descriptor {
57 	uint8_t bLength;
58 	uint8_t bDescriptorType;
59 	uint8_t bDescriptorSubtype;
60 	uint16_t bcdADC;
61 	uint16_t wTotalLength;
62 	uint8_t bInCollection;
63 	uint8_t baInterfaceNr1;
64 } __packed;
65 
66 /* midi20 5.2.2.1 Class-Specific MS Interface Header Descriptor */
67 struct usb_midi_header_descriptor {
68 	uint8_t bLength;
69 	uint8_t bDescriptorType;
70 	uint8_t bDescriptorSubtype;
71 	uint16_t bcdMSC;
72 	uint16_t wTotalLength;
73 } __packed;
74 
75 /* midi20 5.3.2 Class-Specific MIDI Streaming Data Endpoint Descriptor */
76 struct usb_midi_cs_endpoint_descriptor {
77 	uint8_t bLength;
78 	uint8_t bDescriptorType;
79 	uint8_t bDescriptorSubtype;
80 	uint8_t bNumGrpTrmBlock;
81 	uint8_t baAssoGrpTrmBlkID[16];
82 } __packed;
83 
84 /* midi20 5.4.1 Class Specific Group Terminal Block Header Descriptor */
85 struct usb_midi_grptrm_header_descriptor {
86 	uint8_t bLength;
87 	uint8_t bDescriptorType;
88 	uint8_t bDescriptorSubtype;
89 	uint16_t wTotalLength;
90 } __packed;
91 
92 /* midi20 5.4.2.1 Group Terminal Block Descriptor */
93 struct usb_midi_grptrm_block_descriptor {
94 	uint8_t bLength;
95 	uint8_t bDescriptorType;
96 	uint8_t bDescriptorSubtype;
97 	uint8_t bGrpTrmBlkID;
98 	uint8_t bGrpTrmBlkType;
99 	uint8_t nGroupTrm;
100 	uint8_t nNumGroupTrm;
101 	uint8_t iBlockItem;
102 	uint8_t bMIDIProtocol;
103 	uint16_t wMaxInputBandwidth;
104 	uint16_t wMaxOutputBandwidth;
105 } __packed;
106 
107 struct usbd_midi_descriptors {
108 	struct usb_association_descriptor iad;
109 
110 	/* Standard AudioControl (AC) Interface Descriptor */
111 	struct usb_if_descriptor if0_std;
112 	struct usb_midi_cs_ac_header_descriptor if0_cs;
113 
114 	/* Empty MidiStreaming 1.0 on altsetting 0 */
115 	struct usb_if_descriptor if1_0_std;
116 	struct usb_midi_header_descriptor if1_0_ms_header;
117 	struct usb_ep_descriptor if1_0_out_ep_fs;
118 	struct usb_ep_descriptor if1_0_out_ep_hs;
119 	struct usb_midi_cs_endpoint_descriptor if1_0_cs_out_ep;
120 	struct usb_ep_descriptor if1_0_in_ep_fs;
121 	struct usb_ep_descriptor if1_0_in_ep_hs;
122 	struct usb_midi_cs_endpoint_descriptor if1_0_cs_in_ep;
123 
124 	/* MidiStreaming 2.0 on altsetting 1 */
125 	struct usb_if_descriptor if1_1_std;
126 	struct usb_midi_header_descriptor if1_1_ms_header;
127 	struct usb_ep_descriptor if1_1_out_ep_fs;
128 	struct usb_ep_descriptor if1_1_out_ep_hs;
129 	struct usb_midi_cs_endpoint_descriptor if1_1_cs_out_ep;
130 	struct usb_ep_descriptor if1_1_in_ep_fs;
131 	struct usb_ep_descriptor if1_1_in_ep_hs;
132 	struct usb_midi_cs_endpoint_descriptor if1_1_cs_in_ep;
133 
134 	/* MidiStreaming 2.0 Class-Specific Group Terminal Block Descriptors
135 	 * Retrievable by a Separate Get Request
136 	 */
137 	struct usb_midi_grptrm_header_descriptor grptrm_header;
138 	struct usb_midi_grptrm_block_descriptor grptrm_blocks[16];
139 };
140 
141 /* Device driver configuration */
142 struct usbd_midi_config {
143 	struct usbd_midi_descriptors *desc;
144 	struct usb_desc_header const **fs_descs;
145 	struct usb_desc_header const **hs_descs;
146 };
147 
148 /* Device driver data */
149 struct usbd_midi_data {
150 	struct usbd_class_data *class_data;
151 	struct k_work rx_work;
152 	struct k_work tx_work;
153 	uint8_t tx_queue_buf[MIDI_QUEUE_SIZE];
154 	struct ring_buf tx_queue;
155 	uint8_t altsetting;
156 	struct usbd_midi_ops ops;
157 };
158 
usbd_midi2_recv(const struct device * dev,struct net_buf * const buf)159 static void usbd_midi2_recv(const struct device *dev, struct net_buf *const buf)
160 {
161 	struct usbd_midi_data *data = dev->data;
162 	struct midi_ump ump;
163 
164 	LOG_HEXDUMP_DBG(buf->data, buf->len, "MIDI2 - Rx DATA");
165 	while (buf->len >= 4) {
166 		ump.data[0] = net_buf_pull_le32(buf);
167 		for (size_t i = 1; i < UMP_NUM_WORDS(ump); i++) {
168 			if (buf->len < 4) {
169 				LOG_ERR("Incomplete UMP");
170 				return;
171 			}
172 			ump.data[i] = net_buf_pull_le32(buf);
173 		}
174 
175 		if (data->ops.rx_packet_cb) {
176 			data->ops.rx_packet_cb(dev, ump);
177 		}
178 	}
179 
180 	if (buf->len) {
181 		LOG_HEXDUMP_WRN(buf->data, buf->len, "Trailing data in Rx buffer");
182 	}
183 }
184 
usbd_midi_class_request(struct usbd_class_data * const class_data,struct net_buf * const buf,const int err)185 static int usbd_midi_class_request(struct usbd_class_data *const class_data,
186 				   struct net_buf *const buf, const int err)
187 {
188 	struct usbd_context *uds_ctx = usbd_class_get_ctx(class_data);
189 	const struct device *dev = usbd_class_get_private(class_data);
190 	struct usbd_midi_data *data = dev->data;
191 	struct udc_buf_info *info = udc_get_buf_info(buf);
192 
193 	LOG_DBG("MIDI2 request for %s ep=%02X len=%d err=%d",
194 		dev->name, info->ep, buf->len, err);
195 
196 	if (err && err != -ECONNABORTED) {
197 		LOG_ERR("Transfer error %d", err);
198 	}
199 	if (USB_EP_DIR_IS_OUT(info->ep)) {
200 		usbd_midi2_recv(dev, buf);
201 		k_work_submit(&data->rx_work);
202 	} else {
203 		LOG_HEXDUMP_DBG(buf->data, buf->len, "Tx DATA complete");
204 		if (ring_buf_size_get(&data->tx_queue)) {
205 			k_work_submit(&data->tx_work);
206 		}
207 	}
208 
209 	return usbd_ep_buf_free(uds_ctx, buf);
210 }
211 
usbd_midi_class_update(struct usbd_class_data * const class_data,const uint8_t iface,const uint8_t alternate)212 static void usbd_midi_class_update(struct usbd_class_data *const class_data,
213 				   const uint8_t iface, const uint8_t alternate)
214 {
215 	const struct device *dev = usbd_class_get_private(class_data);
216 	bool ready = false;
217 	struct usbd_midi_data *data = dev->data;
218 
219 	LOG_DBG("update for %s: if=%u, alt=%u", dev->name, iface, alternate);
220 
221 	switch (alternate) {
222 	case MIDI1_ALTERNATE:
223 		data->altsetting = MIDI1_ALTERNATE;
224 		LOG_WRN("%s set USB-MIDI1.0 altsetting (not implemented !)", dev->name);
225 		break;
226 	case MIDI2_ALTERNATE:
227 		data->altsetting = MIDI2_ALTERNATE;
228 		ready = true;
229 		LOG_INF("%s set USB-MIDI2.0 altsetting", dev->name);
230 		break;
231 	}
232 
233 	if (data->ops.ready_cb) {
234 		data->ops.ready_cb(dev, ready);
235 	}
236 }
237 
usbd_midi_class_enable(struct usbd_class_data * const class_data)238 static void usbd_midi_class_enable(struct usbd_class_data *const class_data)
239 {
240 	const struct device *dev = usbd_class_get_private(class_data);
241 	struct usbd_midi_data *data = dev->data;
242 
243 	if (data->altsetting == MIDI2_ALTERNATE && data->ops.ready_cb) {
244 		data->ops.ready_cb(dev, true);
245 	}
246 
247 	LOG_DBG("Enable %s", dev->name);
248 	k_work_submit(&data->rx_work);
249 }
250 
usbd_midi_class_disable(struct usbd_class_data * const class_data)251 static void usbd_midi_class_disable(struct usbd_class_data *const class_data)
252 {
253 	const struct device *dev = usbd_class_get_private(class_data);
254 	struct usbd_midi_data *data = dev->data;
255 
256 	if (data->ops.ready_cb) {
257 		data->ops.ready_cb(dev, false);
258 	}
259 
260 	LOG_DBG("Disable %s", dev->name);
261 	k_work_cancel(&data->rx_work);
262 }
263 
usbd_midi_class_suspended(struct usbd_class_data * const class_data)264 static void usbd_midi_class_suspended(struct usbd_class_data *const class_data)
265 {
266 	const struct device *dev = usbd_class_get_private(class_data);
267 	struct usbd_midi_data *data = dev->data;
268 
269 	if (data->ops.ready_cb) {
270 		data->ops.ready_cb(dev, false);
271 	}
272 
273 	LOG_DBG("Suspend %s", dev->name);
274 	k_work_cancel(&data->rx_work);
275 }
276 
usbd_midi_class_resumed(struct usbd_class_data * const class_data)277 static void usbd_midi_class_resumed(struct usbd_class_data *const class_data)
278 {
279 	const struct device *dev = usbd_class_get_private(class_data);
280 	struct usbd_midi_data *data = dev->data;
281 
282 	if (data->altsetting == MIDI2_ALTERNATE && data->ops.ready_cb) {
283 		data->ops.ready_cb(dev, true);
284 	}
285 
286 	LOG_DBG("Resume %s", dev->name);
287 	k_work_submit(&data->rx_work);
288 }
289 
usbd_midi_class_cth(struct usbd_class_data * const class_data,const struct usb_setup_packet * const setup,struct net_buf * const buf)290 static int usbd_midi_class_cth(struct usbd_class_data *const class_data,
291 			       const struct usb_setup_packet *const setup,
292 			       struct net_buf *const buf)
293 {
294 	const struct device *dev = usbd_class_get_private(class_data);
295 	const struct usbd_midi_config *config = dev->config;
296 	struct usbd_midi_data *data = dev->data;
297 
298 	size_t head_len = config->desc->grptrm_header.bLength;
299 	size_t total_len = sys_le16_to_cpu(config->desc->grptrm_header.wTotalLength);
300 
301 	LOG_DBG("Control to host for %s", dev->name);
302 	LOG_DBG("  bmRequestType=%02X bRequest=%02X wValue=%04X wIndex=%04X wLength=%04X",
303 		setup->bmRequestType, setup->bRequest, setup->wValue, setup->wIndex,
304 		setup->wLength);
305 
306 	/* Only support Group Terminal blocks retrieved with
307 	 * midi20 6. Class Specific Command: Group Terminal Blocks Descriptors Request
308 	 */
309 	if (data->altsetting != MIDI2_ALTERNATE ||
310 	    setup->bRequest != USB_SREQ_GET_DESCRIPTOR ||
311 	    setup->wValue != ((CS_GR_TRM_BLOCK << 8) | MIDI2_ALTERNATE)) {
312 		errno = -ENOTSUP;
313 		return 0;
314 	}
315 
316 	/* Group terminal block header */
317 	net_buf_add_mem(buf, (void *) &config->desc->grptrm_header,
318 			MIN(head_len, setup->wLength));
319 
320 	/* Group terminal blocks */
321 	if (setup->wLength > head_len && total_len > head_len) {
322 		net_buf_add_mem(buf, (void *) &config->desc->grptrm_blocks,
323 				MIN(total_len, setup->wLength) - head_len);
324 	}
325 	LOG_HEXDUMP_DBG(buf->data, buf->len, "Control to host");
326 
327 	return 0;
328 }
329 
usbd_midi_class_init(struct usbd_class_data * const class_data)330 static int usbd_midi_class_init(struct usbd_class_data *const class_data)
331 {
332 	const struct device *dev = usbd_class_get_private(class_data);
333 
334 	LOG_DBG("Init %s device class", dev->name);
335 
336 	return 0;
337 }
338 
usbd_midi_class_get_desc(struct usbd_class_data * const class_data,const enum usbd_speed speed)339 static void *usbd_midi_class_get_desc(struct usbd_class_data *const class_data,
340 				      const enum usbd_speed speed)
341 {
342 	const struct device *dev = usbd_class_get_private(class_data);
343 	const struct usbd_midi_config *config = dev->config;
344 
345 	LOG_DBG("Get descriptors for %s", dev->name);
346 
347 	return (speed == USBD_SPEED_HS) ? config->hs_descs : config->fs_descs;
348 }
349 
350 
351 static struct usbd_class_api usbd_midi_class_api = {
352 	.request = usbd_midi_class_request,
353 	.update = usbd_midi_class_update,
354 	.enable = usbd_midi_class_enable,
355 	.disable = usbd_midi_class_disable,
356 	.suspended = usbd_midi_class_suspended,
357 	.resumed = usbd_midi_class_resumed,
358 	.control_to_host = usbd_midi_class_cth,
359 	.init = usbd_midi_class_init,
360 	.get_desc = usbd_midi_class_get_desc,
361 };
362 
usbd_midi_buf_alloc(uint8_t ep)363 static struct net_buf *usbd_midi_buf_alloc(uint8_t ep)
364 {
365 	struct udc_buf_info *info;
366 	struct net_buf *buf;
367 
368 	buf = net_buf_alloc(&usbd_midi_buf_pool, K_NO_WAIT);
369 	if (!buf) {
370 		return NULL;
371 	}
372 
373 	info = udc_get_buf_info(buf);
374 	info->ep = ep;
375 
376 	return buf;
377 }
378 
usbd_midi_get_bulk_in(struct usbd_class_data * const class_data)379 static uint8_t usbd_midi_get_bulk_in(struct usbd_class_data *const class_data)
380 {
381 	struct usbd_context *uds_ctx = usbd_class_get_ctx(class_data);
382 	const struct device *dev = usbd_class_get_private(class_data);
383 	const struct usbd_midi_config *cfg = dev->config;
384 
385 	if (usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) {
386 		return cfg->desc->if1_1_in_ep_hs.bEndpointAddress;
387 	}
388 
389 	return cfg->desc->if1_1_in_ep_fs.bEndpointAddress;
390 }
391 
usbd_midi_get_bulk_out(struct usbd_class_data * const class_data)392 static uint8_t usbd_midi_get_bulk_out(struct usbd_class_data *const class_data)
393 {
394 	struct usbd_context *uds_ctx = usbd_class_get_ctx(class_data);
395 	const struct device *dev = usbd_class_get_private(class_data);
396 	const struct usbd_midi_config *cfg = dev->config;
397 
398 	if (usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) {
399 		return cfg->desc->if1_1_out_ep_hs.bEndpointAddress;
400 	}
401 
402 	return cfg->desc->if1_1_out_ep_fs.bEndpointAddress;
403 }
404 
usbd_midi_rx_work(struct k_work * work)405 static void usbd_midi_rx_work(struct k_work *work)
406 {
407 	struct usbd_midi_data *data = CONTAINER_OF(work, struct usbd_midi_data, rx_work);
408 	struct net_buf *buf;
409 	int ret;
410 
411 	buf = usbd_midi_buf_alloc(usbd_midi_get_bulk_out(data->class_data));
412 	if (buf == NULL) {
413 		LOG_WRN("Unable to allocate Rx net_buf");
414 		return;
415 	}
416 
417 	LOG_DBG("Enqueue Rx...");
418 	ret = usbd_ep_enqueue(data->class_data, buf);
419 	if (ret) {
420 		LOG_ERR("Failed to enqueue Rx net_buf -> %d", ret);
421 		net_buf_unref(buf);
422 	}
423 }
424 
usbd_midi_tx_work(struct k_work * work)425 static void usbd_midi_tx_work(struct k_work *work)
426 {
427 	struct usbd_midi_data *data = CONTAINER_OF(work, struct usbd_midi_data, tx_work);
428 	struct net_buf *buf;
429 	int ret;
430 
431 	buf = usbd_midi_buf_alloc(usbd_midi_get_bulk_in(data->class_data));
432 	if (buf == NULL) {
433 		LOG_ERR("Unable to allocate Tx net_buf");
434 		return;
435 	}
436 
437 	net_buf_add(buf, ring_buf_get(&data->tx_queue, buf->data, buf->size));
438 	LOG_HEXDUMP_DBG(buf->data, buf->len, "MIDI2 - Tx DATA");
439 
440 	ret = usbd_ep_enqueue(data->class_data, buf);
441 	if (ret) {
442 		LOG_ERR("Failed to enqueue Tx net_buf -> %d", ret);
443 		net_buf_unref(buf);
444 	}
445 }
446 
usbd_midi_preinit(const struct device * dev)447 static int usbd_midi_preinit(const struct device *dev)
448 {
449 	struct usbd_midi_data *data = dev->data;
450 
451 	LOG_DBG("Init device %s", dev->name);
452 	ring_buf_init(&data->tx_queue, MIDI_QUEUE_SIZE, data->tx_queue_buf);
453 	k_work_init(&data->rx_work, usbd_midi_rx_work);
454 	k_work_init(&data->tx_work, usbd_midi_tx_work);
455 
456 	return 0;
457 }
458 
usbd_midi_send(const struct device * dev,const struct midi_ump ump)459 int usbd_midi_send(const struct device *dev, const struct midi_ump ump)
460 {
461 	struct usbd_midi_data *data = dev->data;
462 	size_t words = UMP_NUM_WORDS(ump);
463 	size_t buflen = 4 * words;
464 	uint32_t word;
465 
466 	LOG_DBG("Send MT=%X group=%X", UMP_MT(ump), UMP_GROUP(ump));
467 	if (data->altsetting != MIDI2_ALTERNATE) {
468 		LOG_WRN("MIDI2.0 is not enabled");
469 		return -EIO;
470 	}
471 
472 	if (buflen > ring_buf_space_get(&data->tx_queue)) {
473 		LOG_WRN("Not enough space in tx queue");
474 		return -ENOBUFS;
475 	}
476 
477 	for (size_t i = 0; i < words; i++) {
478 		word = sys_cpu_to_le32(ump.data[i]);
479 		ring_buf_put(&data->tx_queue, (const uint8_t *)&word, 4);
480 	}
481 	k_work_submit(&data->tx_work);
482 
483 	return 0;
484 }
485 
usbd_midi_set_ops(const struct device * dev,const struct usbd_midi_ops * ops)486 void usbd_midi_set_ops(const struct device *dev, const struct usbd_midi_ops *ops)
487 {
488 	struct usbd_midi_data *data = dev->data;
489 
490 	if (ops == NULL) {
491 		memset(&data->ops, 0, sizeof(struct usbd_midi_ops));
492 	} else {
493 		memcpy(&data->ops, ops, sizeof(struct usbd_midi_ops));
494 	}
495 
496 	LOG_DBG("Set ops for %s to %p", dev->name, ops);
497 }
498 
499 /* Group Terminal Block unique identification number, type and protocol
500  * see midi20 5.4.2 Group Terminal Block Descriptor
501  */
502 #define GRPTRM_BLOCK_ID(node) UTIL_INC(DT_NODE_CHILD_IDX(node))
503 #define GRPTRM_BLOCK_TYPE(node)                                                   \
504 	COND_CODE_1(DT_ENUM_HAS_VALUE(node, terminal_type, input_only),           \
505 		(GR_TRM_INPUT_ONLY),                                              \
506 		(COND_CODE_1(DT_ENUM_HAS_VALUE(node, terminal_type, output_only), \
507 			(GR_TRM_OUTPUT_ONLY),                                     \
508 			(GR_TRM_BIDIRECTIONAL)                                    \
509 		))                                                                \
510 	)
511 #define GRPTRM_PROTOCOL(node)                                                                     \
512 	COND_CODE_1(DT_ENUM_HAS_VALUE(node, protocol, midi2),                                     \
513 		(MIDI_2_0),                                                                       \
514 		(COND_CODE_1(DT_ENUM_HAS_VALUE(node, protocol, midi1_up_to_64b),                  \
515 				(MIDI_1_0_UP_TO_64_BITS),                                         \
516 				(COND_CODE_1(DT_ENUM_HAS_VALUE(node, protocol, midi1_up_to_128b), \
517 					(MIDI_1_0_UP_TO_128_BITS),                                \
518 					(USE_MIDI_CI)                                             \
519 				))                                                                \
520 			))                                                                        \
521 		)
522 
523 /* Group Terminal Block unique identification number with a trailing comma
524  * if that block is bidirectional or of given terminal type; otherwise empty
525  */
526 #define GRPTRM_BLOCK_ID_SEP_IF(node, ttype)                                    \
527 	IF_ENABLED(                                                            \
528 		UTIL_OR(DT_ENUM_HAS_VALUE(node, terminal_type, bidirectional), \
529 			DT_ENUM_HAS_VALUE(node, terminal_type, ttype)),        \
530 		(GRPTRM_BLOCK_ID(node),))
531 
532 /* All unique identification numbers of output+bidir group terminal blocks */
533 #define GRPTRM_OUTPUT_BLOCK_IDS(n) \
534 	DT_INST_FOREACH_CHILD_VARGS(n, GRPTRM_BLOCK_ID_SEP_IF, output_only)
535 
536 /* All unique identification numbers of input+bidir group terminal blocks */
537 #define GRPTRM_INPUT_BLOCK_IDS(n) \
538 	DT_INST_FOREACH_CHILD_VARGS(n, GRPTRM_BLOCK_ID_SEP_IF, input_only)
539 
540 #define N_INPUTS(n)  sizeof((uint8_t[]){GRPTRM_INPUT_BLOCK_IDS(n)})
541 #define N_OUTPUTS(n) sizeof((uint8_t[]){GRPTRM_OUTPUT_BLOCK_IDS(n)})
542 
543 #define USBD_MIDI_VALIDATE_GRPTRM_BLOCK(node)                              \
544 	BUILD_ASSERT(DT_REG_ADDR(node) < 16,                               \
545 		     "Group Terminal Block address must be within 0..15"); \
546 	BUILD_ASSERT(DT_REG_ADDR(node) + DT_REG_SIZE(node) <= 16,          \
547 		     "Too many Group Terminals in this Block");
548 
549 #define USBD_MIDI_VALIDATE_INSTANCE(n) \
550 	DT_INST_FOREACH_CHILD(n, USBD_MIDI_VALIDATE_GRPTRM_BLOCK)
551 
552 #define USBD_MIDI2_INIT_GRPTRM_BLOCK_DESCRIPTOR(node)                       \
553 	{                                                                   \
554 		.bLength = sizeof(struct usb_midi_grptrm_block_descriptor), \
555 		.bDescriptorType = CS_GR_TRM_BLOCK,                         \
556 		.bDescriptorSubtype = GR_TRM_BLOCK,                         \
557 		.bGrpTrmBlkID = GRPTRM_BLOCK_ID(node),                      \
558 		.bGrpTrmBlkType = GRPTRM_BLOCK_TYPE(node),                  \
559 		.nGroupTrm = DT_REG_ADDR(node),                             \
560 		.nNumGroupTrm = DT_REG_SIZE(node),                          \
561 		.iBlockItem = 0,                                            \
562 		.bMIDIProtocol = GRPTRM_PROTOCOL(node),                     \
563 		.wMaxInputBandwidth = 0x0000,                               \
564 		.wMaxOutputBandwidth = 0x0000,                              \
565 	}
566 
567 #define USBD_MIDI2_GRPTRM_TOTAL_LEN(n)                    \
568 	sizeof(struct usb_midi_grptrm_header_descriptor)  \
569 	+ DT_INST_CHILD_NUM_STATUS_OKAY(n)                \
570 	* sizeof(struct usb_midi_grptrm_block_descriptor)
571 
572 #define USBD_MIDI_DEFINE_DESCRIPTORS(n)                                                  \
573 	static struct usbd_midi_descriptors usbd_midi_desc_##n = {                       \
574 		.iad = {                                                                 \
575 			.bLength = sizeof(struct usb_association_descriptor),            \
576 			.bDescriptorType = USB_DESC_INTERFACE_ASSOC,                     \
577 			.bFirstInterface = 0,                                            \
578 			.bInterfaceCount = 2,                                            \
579 			.bFunctionClass = AUDIO,                                         \
580 			.bFunctionSubClass = MIDISTREAMING,                              \
581 		},                                                                       \
582 		.if0_std = {                                                             \
583 			.bLength = sizeof(struct usb_if_descriptor),                     \
584 			.bDescriptorType = USB_DESC_INTERFACE,                           \
585 			.bInterfaceNumber = 0,                                           \
586 			.bAlternateSetting = 0,                                          \
587 			.bNumEndpoints = 0,                                              \
588 			.bInterfaceClass = AUDIO,                                        \
589 			.bInterfaceSubClass = AUDIOCONTROL,                              \
590 		},                                                                       \
591 		.if0_cs = {                                                              \
592 			.bLength = sizeof(struct usb_midi_cs_ac_header_descriptor),      \
593 			.bDescriptorType = USB_DESC_CS_INTERFACE,                        \
594 			.bDescriptorSubtype = MS_HEADER,                                 \
595 			.bcdADC = sys_cpu_to_le16(0x0100),                               \
596 			.wTotalLength = sizeof(struct usb_midi_cs_ac_header_descriptor), \
597 			.bInCollection = 1,                                              \
598 			.baInterfaceNr1 = 1,                                             \
599 		},                                                                       \
600 		.if1_0_std = {                                                           \
601 			.bLength = sizeof(struct usb_if_descriptor),                     \
602 			.bDescriptorType = USB_DESC_INTERFACE,                           \
603 			.bInterfaceNumber = 1,                                           \
604 			.bAlternateSetting = MIDI1_ALTERNATE,                            \
605 			.bNumEndpoints = 2,                                              \
606 			.bInterfaceClass = AUDIO,                                        \
607 			.bInterfaceSubClass = MIDISTREAMING,                             \
608 		},                                                                       \
609 		.if1_0_ms_header = {                                                     \
610 			.bLength = sizeof(struct usb_midi_header_descriptor),            \
611 			.bDescriptorType = USB_DESC_CS_INTERFACE,                        \
612 			.bDescriptorSubtype = MS_HEADER,                                 \
613 			.bcdMSC = sys_cpu_to_le16(0x0100),                               \
614 			.wTotalLength = sys_cpu_to_le16(                                 \
615 				sizeof(struct usb_midi_header_descriptor)                \
616 				+ 2 * (sizeof(struct usb_ep_descriptor) + 4)             \
617 			),                                                               \
618 		},                                                                       \
619 		.if1_0_out_ep_fs = {                                                     \
620 			.bLength = sizeof(struct usb_ep_descriptor),                     \
621 			.bDescriptorType = USB_DESC_ENDPOINT,                            \
622 			.bEndpointAddress = n + FIRST_OUT_EP_ADDR,                       \
623 			.bmAttributes = USB_EP_TYPE_BULK,                                \
624 			.wMaxPacketSize = sys_cpu_to_le16(64U),                          \
625 		},                                                                       \
626 		.if1_0_out_ep_hs = {                                                     \
627 			.bLength = sizeof(struct usb_ep_descriptor),                     \
628 			.bDescriptorType = USB_DESC_ENDPOINT,                            \
629 			.bEndpointAddress = n + FIRST_OUT_EP_ADDR,                       \
630 			.bmAttributes = USB_EP_TYPE_BULK,                                \
631 			.wMaxPacketSize = sys_cpu_to_le16(512U),                         \
632 		},                                                                       \
633 		.if1_0_cs_out_ep = {                                                     \
634 			.bLength = 4,                                                    \
635 			.bDescriptorType = USB_DESC_CS_ENDPOINT,                         \
636 			.bDescriptorSubtype = MS_GENERAL,                                \
637 			.bNumGrpTrmBlock = 0,                                            \
638 		},                                                                       \
639 		.if1_0_in_ep_fs = {                                                      \
640 			.bLength = sizeof(struct usb_ep_descriptor),                     \
641 			.bDescriptorType = USB_DESC_ENDPOINT,                            \
642 			.bEndpointAddress = n + FIRST_IN_EP_ADDR,                        \
643 			.bmAttributes = USB_EP_TYPE_BULK,                                \
644 			.wMaxPacketSize = sys_cpu_to_le16(64U),                          \
645 		},                                                                       \
646 		.if1_0_in_ep_hs = {                                                      \
647 			.bLength = sizeof(struct usb_ep_descriptor),                     \
648 			.bDescriptorType = USB_DESC_ENDPOINT,                            \
649 			.bEndpointAddress = n + FIRST_IN_EP_ADDR,                        \
650 			.bmAttributes = USB_EP_TYPE_BULK,                                \
651 			.wMaxPacketSize = sys_cpu_to_le16(512U),                         \
652 		},                                                                       \
653 		.if1_0_cs_in_ep = {                                                      \
654 			.bLength = 4 + N_INPUTS(n),                                      \
655 			.bDescriptorType = USB_DESC_CS_ENDPOINT,                         \
656 			.bDescriptorSubtype = MS_GENERAL,                                \
657 			.bNumGrpTrmBlock = 0,                                            \
658 		},                                                                       \
659 		.if1_1_std = {                                                           \
660 			.bLength = sizeof(struct usb_if_descriptor),                     \
661 			.bDescriptorType = USB_DESC_INTERFACE,                           \
662 			.bInterfaceNumber = 1,                                           \
663 			.bAlternateSetting = MIDI2_ALTERNATE,                            \
664 			.bNumEndpoints = 2,                                              \
665 			.bInterfaceClass = AUDIO,                                        \
666 			.bInterfaceSubClass = MIDISTREAMING,                             \
667 		},                                                                       \
668 		.if1_1_ms_header = {                                                     \
669 			.bLength = sizeof(struct usb_midi_header_descriptor),            \
670 			.bDescriptorType = USB_DESC_CS_INTERFACE,                        \
671 			.bDescriptorSubtype = MS_HEADER,                                 \
672 			.bcdMSC = sys_cpu_to_le16(0x0200),                               \
673 			.wTotalLength = sys_cpu_to_le16(                                 \
674 				sizeof(struct usb_midi_header_descriptor)),              \
675 		},                                                                       \
676 		.if1_1_out_ep_fs = {                                                     \
677 			.bLength = sizeof(struct usb_ep_descriptor),                     \
678 			.bDescriptorType = USB_DESC_ENDPOINT,                            \
679 			.bEndpointAddress = n + FIRST_OUT_EP_ADDR,                       \
680 			.bmAttributes = USB_EP_TYPE_BULK,                                \
681 			.wMaxPacketSize = sys_cpu_to_le16(64U),                          \
682 		},                                                                       \
683 		.if1_1_out_ep_hs = {                                                     \
684 			.bLength = sizeof(struct usb_ep_descriptor),                     \
685 			.bDescriptorType = USB_DESC_ENDPOINT,                            \
686 			.bEndpointAddress = n + FIRST_OUT_EP_ADDR,                       \
687 			.bmAttributes = USB_EP_TYPE_BULK,                                \
688 			.wMaxPacketSize = sys_cpu_to_le16(512U),                         \
689 		},                                                                       \
690 		.if1_1_cs_out_ep = {                                                     \
691 			.bLength = 4 + N_OUTPUTS(n),                                     \
692 			.bDescriptorType = USB_DESC_CS_ENDPOINT,                         \
693 			.bDescriptorSubtype = MS_GENERAL_2_0,                            \
694 			.bNumGrpTrmBlock = N_OUTPUTS(n),                                 \
695 			.baAssoGrpTrmBlkID = {GRPTRM_OUTPUT_BLOCK_IDS(n)},               \
696 		},                                                                       \
697 		.if1_1_in_ep_fs = {                                                      \
698 			.bLength = sizeof(struct usb_ep_descriptor),                     \
699 			.bDescriptorType = USB_DESC_ENDPOINT,                            \
700 			.bEndpointAddress = n + FIRST_IN_EP_ADDR,                        \
701 			.bmAttributes = USB_EP_TYPE_BULK,                                \
702 			.wMaxPacketSize = sys_cpu_to_le16(64U),                          \
703 		},                                                                       \
704 		.if1_1_in_ep_hs = {                                                      \
705 			.bLength = sizeof(struct usb_ep_descriptor),                     \
706 			.bDescriptorType = USB_DESC_ENDPOINT,                            \
707 			.bEndpointAddress = n + FIRST_IN_EP_ADDR,                        \
708 			.bmAttributes = USB_EP_TYPE_BULK,                                \
709 			.wMaxPacketSize = sys_cpu_to_le16(512U),                         \
710 		},                                                                       \
711 		.if1_1_cs_in_ep = {                                                      \
712 			.bLength = 4 + N_INPUTS(n),                                      \
713 			.bDescriptorType = USB_DESC_CS_ENDPOINT,                         \
714 			.bDescriptorSubtype = MS_GENERAL_2_0,                            \
715 			.bNumGrpTrmBlock = N_INPUTS(n),                                  \
716 			.baAssoGrpTrmBlkID = {GRPTRM_INPUT_BLOCK_IDS(n)},                \
717 		},                                                                       \
718 		.grptrm_header = {                                                       \
719 			.bLength = sizeof(struct usb_midi_grptrm_header_descriptor),     \
720 			.bDescriptorType = CS_GR_TRM_BLOCK,                              \
721 			.bDescriptorSubtype = GR_TRM_BLOCK_HEADER,                       \
722 			.wTotalLength = sys_cpu_to_le16(                                 \
723 				USBD_MIDI2_GRPTRM_TOTAL_LEN(n)                           \
724 			),                                                               \
725 		},                                                                       \
726 		.grptrm_blocks = {                                                       \
727 			DT_INST_FOREACH_CHILD_SEP(                                       \
728 				n, USBD_MIDI2_INIT_GRPTRM_BLOCK_DESCRIPTOR, (,)          \
729 			)                                                                \
730 		},                                                                       \
731 	};                                                                               \
732 	static const struct usb_desc_header *usbd_midi_desc_array_fs_##n[] = {           \
733 		(struct usb_desc_header *)&usbd_midi_desc_##n.iad,                       \
734 		(struct usb_desc_header *)&usbd_midi_desc_##n.if0_std,                   \
735 		(struct usb_desc_header *)&usbd_midi_desc_##n.if0_cs,                    \
736 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_0_std,                 \
737 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_0_ms_header,           \
738 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_0_out_ep_fs,           \
739 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_0_cs_out_ep,           \
740 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_0_in_ep_fs,            \
741 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_0_cs_in_ep,            \
742 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_1_std,                 \
743 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_1_ms_header,           \
744 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_1_out_ep_fs,           \
745 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_1_cs_out_ep,           \
746 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_1_in_ep_fs,            \
747 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_1_cs_in_ep,            \
748 		NULL,                                                                    \
749 	};                                                                               \
750 	static const struct usb_desc_header *usbd_midi_desc_array_hs_##n[] = {           \
751 		(struct usb_desc_header *)&usbd_midi_desc_##n.iad,                       \
752 		(struct usb_desc_header *)&usbd_midi_desc_##n.if0_std,                   \
753 		(struct usb_desc_header *)&usbd_midi_desc_##n.if0_cs,                    \
754 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_0_std,                 \
755 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_0_ms_header,           \
756 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_0_out_ep_hs,           \
757 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_0_cs_out_ep,           \
758 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_0_in_ep_hs,            \
759 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_0_cs_in_ep,            \
760 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_1_std,                 \
761 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_1_ms_header,           \
762 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_1_out_ep_hs,           \
763 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_1_cs_out_ep,           \
764 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_1_in_ep_hs,            \
765 		(struct usb_desc_header *)&usbd_midi_desc_##n.if1_1_cs_in_ep,            \
766 		NULL,                                                                    \
767 	};
768 
769 #define USBD_MIDI_DEFINE_DEVICE(n)                                           \
770 	USBD_MIDI_VALIDATE_INSTANCE(n)                                       \
771 	USBD_MIDI_DEFINE_DESCRIPTORS(n);                                     \
772 	USBD_DEFINE_CLASS(midi_##n, &usbd_midi_class_api,                    \
773 			  (void *)DEVICE_DT_GET(DT_DRV_INST(n)), NULL);      \
774 	static const struct usbd_midi_config usbd_midi_config_##n = {        \
775 		.desc = &usbd_midi_desc_##n,                                 \
776 		.fs_descs = usbd_midi_desc_array_fs_##n,                     \
777 		.hs_descs = usbd_midi_desc_array_hs_##n,                     \
778 	};                                                                   \
779 	static struct usbd_midi_data usbd_midi_data_##n = {                  \
780 		.class_data = &midi_##n,                                     \
781 		.altsetting = MIDI1_ALTERNATE,                               \
782 	};                                                                   \
783 	DEVICE_DT_INST_DEFINE(n, usbd_midi_preinit, NULL,                    \
784 			      &usbd_midi_data_##n, &usbd_midi_config_##n,    \
785 			      POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, NULL);
786 
787 DT_INST_FOREACH_STATUS_OKAY(USBD_MIDI_DEFINE_DEVICE)
788