1 /*
2 * Copyright (c) 2022, sakumisu
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include "usbh_core.h"
7 #include "usbh_audio.h"
8
9 #undef USB_DBG_TAG
10 #define USB_DBG_TAG "usbh_audio"
11 #include "usb_log.h"
12
13 #define DEV_FORMAT "/dev/audio%d"
14
15 /* general descriptor field offsets */
16 #define DESC_bLength 0 /** Length offset */
17 #define DESC_bDescriptorType 1 /** Descriptor type offset */
18 #define DESC_bDescriptorSubType 2 /** Descriptor subtype offset */
19
20 /* interface descriptor field offsets */
21 #define INTF_DESC_bInterfaceNumber 2 /** Interface number offset */
22 #define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
23
24 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_audio_buf[USB_ALIGN_UP(128, CONFIG_USB_ALIGN_SIZE)];
25
26 static struct usbh_audio g_audio_class[CONFIG_USBHOST_MAX_AUDIO_CLASS];
27 static uint32_t g_devinuse = 0;
28
usbh_audio_class_alloc(void)29 static struct usbh_audio *usbh_audio_class_alloc(void)
30 {
31 uint8_t devno;
32
33 for (devno = 0; devno < CONFIG_USBHOST_MAX_AUDIO_CLASS; devno++) {
34 if ((g_devinuse & (1U << devno)) == 0) {
35 g_devinuse |= (1U << devno);
36 memset(&g_audio_class[devno], 0, sizeof(struct usbh_audio));
37 g_audio_class[devno].minor = devno;
38 return &g_audio_class[devno];
39 }
40 }
41 return NULL;
42 }
43
usbh_audio_class_free(struct usbh_audio * audio_class)44 static void usbh_audio_class_free(struct usbh_audio *audio_class)
45 {
46 uint8_t devno = audio_class->minor;
47
48 if (devno < 32) {
49 g_devinuse &= ~(1U << devno);
50 }
51 memset(audio_class, 0, sizeof(struct usbh_audio));
52 }
53
usbh_audio_open(struct usbh_audio * audio_class,const char * name,uint32_t samp_freq,uint8_t bitresolution)54 int usbh_audio_open(struct usbh_audio *audio_class, const char *name, uint32_t samp_freq, uint8_t bitresolution)
55 {
56 struct usb_setup_packet *setup;
57 struct usb_endpoint_descriptor *ep_desc;
58 uint8_t mult;
59 uint16_t mps;
60 int ret;
61 uint8_t intf = 0xff;
62 uint8_t altsetting = 1;
63
64 if (!audio_class || !audio_class->hport) {
65 return -USB_ERR_INVAL;
66 }
67 setup = audio_class->hport->setup;
68
69 if (audio_class->is_opened) {
70 return 0;
71 }
72
73 for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
74 if (strcmp(name, audio_class->as_msg_table[i].stream_name) == 0) {
75 intf = audio_class->as_msg_table[i].stream_intf;
76 for (uint8_t j = 1; j < audio_class->as_msg_table[i].num_of_altsetting; j++) {
77 if (audio_class->as_msg_table[i].as_format[j].bBitResolution == bitresolution) {
78 for (uint8_t k = 0; k < audio_class->as_msg_table[i].as_format[j].bSamFreqType; k++) {
79 uint32_t freq = 0;
80
81 memcpy(&freq, &audio_class->as_msg_table[i].as_format[j].tSamFreq[3 * k], 3);
82 if (freq == samp_freq) {
83 altsetting = j;
84 goto freq_found;
85 }
86 }
87 }
88 }
89 }
90 }
91 return -USB_ERR_NODEV;
92
93 freq_found:
94
95 setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
96 setup->bRequest = USB_REQUEST_SET_INTERFACE;
97 setup->wValue = altsetting;
98 setup->wIndex = intf;
99 setup->wLength = 0;
100
101 ret = usbh_control_transfer(audio_class->hport, setup, NULL);
102 if (ret < 0) {
103 return ret;
104 }
105
106 ep_desc = &audio_class->hport->config.intf[intf].altsetting[altsetting].ep[0].ep_desc;
107
108 if (audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].ep_attr & AUDIO_EP_CONTROL_SAMPLING_FEQ) {
109 setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_ENDPOINT;
110 setup->bRequest = AUDIO_REQUEST_SET_CUR;
111 setup->wValue = (AUDIO_EP_CONTROL_SAMPLING_FEQ << 8) | 0x00;
112 setup->wIndex = ep_desc->bEndpointAddress;
113 setup->wLength = 3;
114
115 memcpy(g_audio_buf, &samp_freq, 3);
116 ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
117 if (ret < 0) {
118 return ret;
119 }
120 }
121
122 mult = (ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK) >> USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT;
123 mps = ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_MASK;
124 if (ep_desc->bEndpointAddress & 0x80) {
125 audio_class->isoin_mps = mps * (mult + 1);
126 USBH_EP_INIT(audio_class->isoin, ep_desc);
127 } else {
128 audio_class->isoout_mps = mps * (mult + 1);
129 USBH_EP_INIT(audio_class->isoout, ep_desc);
130 }
131
132 USB_LOG_INFO("Open audio stream :%s, altsetting: %u\r\n", name, altsetting);
133 audio_class->is_opened = true;
134 return ret;
135 }
136
usbh_audio_close(struct usbh_audio * audio_class,const char * name)137 int usbh_audio_close(struct usbh_audio *audio_class, const char *name)
138 {
139 struct usb_setup_packet *setup;
140 struct usb_endpoint_descriptor *ep_desc;
141 int ret;
142 uint8_t intf = 0xff;
143 uint8_t altsetting = 1;
144
145 if (!audio_class || !audio_class->hport) {
146 return -USB_ERR_INVAL;
147 }
148 setup = audio_class->hport->setup;
149
150 for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
151 if (strcmp(name, audio_class->as_msg_table[i].stream_name) == 0) {
152 intf = audio_class->as_msg_table[i].stream_intf;
153 }
154 }
155
156 if (intf == 0xff) {
157 return -USB_ERR_NODEV;
158 }
159
160 setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
161 setup->bRequest = USB_REQUEST_SET_INTERFACE;
162 setup->wValue = 0;
163 setup->wIndex = intf;
164 setup->wLength = 0;
165
166 ret = usbh_control_transfer(audio_class->hport, setup, NULL);
167 if (ret < 0) {
168 return ret;
169 }
170 USB_LOG_INFO("Close audio stream :%s\r\n", name);
171 audio_class->is_opened = false;
172
173 ep_desc = &audio_class->hport->config.intf[intf].altsetting[altsetting].ep[0].ep_desc;
174 if (ep_desc->bEndpointAddress & 0x80) {
175 if (audio_class->isoin) {
176 audio_class->isoin = NULL;
177 }
178 } else {
179 if (audio_class->isoout) {
180 audio_class->isoout = NULL;
181 }
182 }
183
184 return ret;
185 }
186
usbh_audio_set_volume(struct usbh_audio * audio_class,const char * name,uint8_t ch,int volume_db)187 int usbh_audio_set_volume(struct usbh_audio *audio_class, const char *name, uint8_t ch, int volume_db)
188 {
189 struct usb_setup_packet *setup;
190 int ret;
191 uint8_t feature_id = 0xff;
192 uint8_t intf;
193 uint16_t volume_hex;
194 int volume_min_db;
195 int volume_max_db;
196
197 if (!audio_class || !audio_class->hport) {
198 return -USB_ERR_INVAL;
199 }
200
201 if ((volume_db > 127) || (volume_db < -127)) {
202 return -USB_ERR_INVAL;
203 }
204
205 setup = audio_class->hport->setup;
206
207 for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
208 if (strcmp(name, audio_class->as_msg_table[i].stream_name) == 0) {
209 feature_id = audio_class->as_msg_table[i].feature_terminal_id;
210 intf = audio_class->as_msg_table[i].stream_intf;
211 }
212 }
213
214 if (feature_id == 0xff) {
215 return -USB_ERR_NODEV;
216 }
217
218 setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
219 setup->bRequest = AUDIO_REQUEST_GET_CUR;
220 setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
221 setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
222 setup->wLength = 2;
223
224 ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
225 if (ret < 0) {
226 return ret;
227 }
228
229 memcpy(&audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_cur, g_audio_buf, 2);
230
231 setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
232 setup->bRequest = AUDIO_REQUEST_GET_MIN;
233 setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
234 setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
235 setup->wLength = 2;
236
237 ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
238 if (ret < 0) {
239 return ret;
240 }
241
242 memcpy(&audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_min, g_audio_buf, 2);
243
244 setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
245 setup->bRequest = AUDIO_REQUEST_GET_MAX;
246 setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
247 setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
248 setup->wLength = 2;
249
250 ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
251 if (ret < 0) {
252 return ret;
253 }
254 memcpy(&audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_max, g_audio_buf, 2);
255
256 setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
257 setup->bRequest = AUDIO_REQUEST_GET_RES;
258 setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
259 setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
260 setup->wLength = 2;
261
262 ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
263 if (ret < 0) {
264 return ret;
265 }
266 memcpy(&audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_res, g_audio_buf, 2);
267
268 setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
269 setup->bRequest = AUDIO_REQUEST_SET_CUR;
270 setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
271 setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
272 setup->wLength = 2;
273
274 if (audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_min < 0x8000) {
275 volume_min_db = audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_min / 256;
276 } else {
277 volume_min_db = (audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_min - 0x10000) / 256;
278 }
279
280 if (audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_max < 0x8000) {
281 volume_max_db = audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_max / 256;
282 } else {
283 volume_max_db = (audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_max - 0x10000) / 256;
284 }
285
286 USB_LOG_INFO("Get ch:%u dB range: %ddB ~ %ddB\r\n", ch, volume_min_db, volume_max_db);
287
288 if (volume_db >= 0) {
289 volume_hex = volume_db * 256;
290 if (volume_hex > audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_max) {
291 return -USB_ERR_RANGE;
292 }
293 } else {
294 volume_hex = volume_db * 256 + 0x10000;
295 if (volume_hex < audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_min) {
296 return -USB_ERR_RANGE;
297 }
298 }
299
300 memcpy(g_audio_buf, &volume_hex, 2);
301 ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
302 if (ret < 0) {
303 return ret;
304 }
305 audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_cur = volume_hex;
306 return ret;
307 }
308
usbh_audio_set_mute(struct usbh_audio * audio_class,const char * name,uint8_t ch,bool mute)309 int usbh_audio_set_mute(struct usbh_audio *audio_class, const char *name, uint8_t ch, bool mute)
310 {
311 struct usb_setup_packet *setup;
312 int ret;
313 uint8_t feature_id = 0xff;
314 uint8_t intf = 0xff;
315
316 if (!audio_class || !audio_class->hport) {
317 return -USB_ERR_INVAL;
318 }
319 setup = audio_class->hport->setup;
320
321 for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
322 if (strcmp(name, audio_class->as_msg_table[i].stream_name) == 0) {
323 feature_id = audio_class->as_msg_table[i].feature_terminal_id;
324 intf = audio_class->as_msg_table[i].stream_intf;
325 }
326 }
327
328 if (feature_id == 0xff) {
329 return -USB_ERR_NODEV;
330 }
331
332 setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
333 setup->bRequest = AUDIO_REQUEST_SET_CUR;
334 setup->wValue = (AUDIO_FU_CONTROL_MUTE << 8) | ch;
335 setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
336 setup->wLength = 1;
337
338 memcpy(g_audio_buf, &mute, 1);
339 ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
340 if (ret < 0) {
341 return ret;
342 }
343 audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].mute = mute;
344 return ret;
345 }
346
usbh_audio_list_module(struct usbh_audio * audio_class)347 void usbh_audio_list_module(struct usbh_audio *audio_class)
348 {
349 USB_LOG_INFO("============= Audio module information ===================\r\n");
350 USB_LOG_RAW("bcdADC :%04x\r\n", audio_class->bcdADC);
351 USB_LOG_RAW("Num of audio stream :%u\r\n", audio_class->stream_intf_num);
352
353 for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
354 USB_LOG_RAW("\tstream name :%s\r\n", audio_class->as_msg_table[i].stream_name);
355 USB_LOG_RAW("\tstream intf :%u\r\n", audio_class->as_msg_table[i].stream_intf);
356 USB_LOG_RAW("\tNum of altsetting :%u\r\n", audio_class->as_msg_table[i].num_of_altsetting);
357
358 for (uint8_t j = 0; j < audio_class->as_msg_table[i].num_of_altsetting; j++) {
359 if (j == 0) {
360 USB_LOG_RAW("\t\tIngore altsetting 0\r\n");
361 continue;
362 }
363 USB_LOG_RAW("\t\tAltsetting :%u\r\n", j);
364 USB_LOG_RAW("\t\t\tbNrChannels :%u\r\n", audio_class->as_msg_table[i].as_format[j].bNrChannels);
365 USB_LOG_RAW("\t\t\tbBitResolution :%u\r\n", audio_class->as_msg_table[i].as_format[j].bBitResolution);
366 USB_LOG_RAW("\t\t\tbSamFreqType :%u\r\n", audio_class->as_msg_table[i].as_format[j].bSamFreqType);
367
368 for (uint8_t k = 0; k < audio_class->as_msg_table[i].as_format[j].bSamFreqType; k++) {
369 uint32_t freq = 0;
370
371 memcpy(&freq, &audio_class->as_msg_table[i].as_format[j].tSamFreq[3 * k], 3);
372 USB_LOG_RAW("\t\t\t\tSampleFreq :%u\r\n", freq);
373 }
374 }
375 }
376
377 USB_LOG_INFO("============= Audio module information ===================\r\n");
378 }
379
usbh_audio_ctrl_connect(struct usbh_hubport * hport,uint8_t intf)380 static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
381 {
382 int ret;
383 uint8_t cur_iface = 0;
384 uint8_t cur_iface_count = 0;
385 uint8_t cur_alt_setting = 0;
386 uint8_t input_offset = 0;
387 uint8_t output_offset = 0;
388 uint8_t feature_unit_offset = 0;
389 uint8_t *p;
390 struct usbh_audio_ac_msg ac_msg_table[CONFIG_USBHOST_AUDIO_MAX_STREAMS];
391
392 struct usbh_audio *audio_class = usbh_audio_class_alloc();
393 if (audio_class == NULL) {
394 USB_LOG_ERR("Fail to alloc audio_class\r\n");
395 return -USB_ERR_NOMEM;
396 }
397
398 audio_class->hport = hport;
399 audio_class->ctrl_intf = intf;
400 hport->config.intf[intf].priv = audio_class;
401
402 p = hport->raw_config_desc;
403 while (p[DESC_bLength]) {
404 switch (p[DESC_bDescriptorType]) {
405 case USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION:
406 cur_iface_count = p[3];
407 break;
408 case USB_DESCRIPTOR_TYPE_INTERFACE:
409 cur_iface = p[INTF_DESC_bInterfaceNumber];
410 cur_alt_setting = p[INTF_DESC_bAlternateSetting];
411 break;
412 case USB_DESCRIPTOR_TYPE_ENDPOINT:
413 break;
414 case AUDIO_INTERFACE_DESCRIPTOR_TYPE:
415 if (cur_iface == audio_class->ctrl_intf) {
416 switch (p[DESC_bDescriptorSubType]) {
417 case AUDIO_CONTROL_HEADER: {
418 struct audio_cs_if_ac_header_descriptor *desc = (struct audio_cs_if_ac_header_descriptor *)p;
419 audio_class->bcdADC = desc->bcdADC;
420 audio_class->bInCollection = desc->bInCollection;
421 } break;
422 case AUDIO_CONTROL_INPUT_TERMINAL: {
423 struct audio_cs_if_ac_input_terminal_descriptor *desc = (struct audio_cs_if_ac_input_terminal_descriptor *)p;
424
425 memcpy(&ac_msg_table[input_offset].ac_input, desc, sizeof(struct audio_cs_if_ac_input_terminal_descriptor));
426 input_offset++;
427 } break;
428 case AUDIO_CONTROL_OUTPUT_TERMINAL: {
429 struct audio_cs_if_ac_output_terminal_descriptor *desc = (struct audio_cs_if_ac_output_terminal_descriptor *)p;
430
431 memcpy(&ac_msg_table[output_offset].ac_output, desc, sizeof(struct audio_cs_if_ac_output_terminal_descriptor));
432 output_offset++;
433 } break;
434 case AUDIO_CONTROL_FEATURE_UNIT: {
435 struct audio_cs_if_ac_feature_unit_descriptor *desc = (struct audio_cs_if_ac_feature_unit_descriptor *)p;
436
437 memcpy(&ac_msg_table[feature_unit_offset].ac_feature_unit, desc, desc->bLength);
438 feature_unit_offset++;
439 } break;
440 default:
441 USB_LOG_ERR("Do not support %02x subtype\r\n", p[DESC_bDescriptorSubType]);
442 return -USB_ERR_NOTSUPP;
443 }
444 } else if ((cur_iface > audio_class->ctrl_intf) && (cur_iface < (audio_class->ctrl_intf + cur_iface_count))) {
445 switch (p[DESC_bDescriptorSubType]) {
446 case AUDIO_STREAMING_GENERAL: {
447 struct audio_cs_if_as_general_descriptor *desc = (struct audio_cs_if_as_general_descriptor *)p;
448
449 /* all altsetting have the same general */
450 audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].stream_intf = cur_iface;
451 memcpy(&audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].as_general, desc, sizeof(struct audio_cs_if_as_general_descriptor));
452 } break;
453 case AUDIO_STREAMING_FORMAT_TYPE: {
454 struct audio_cs_if_as_format_type_descriptor *desc = (struct audio_cs_if_as_format_type_descriptor *)p;
455 audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].num_of_altsetting = (cur_alt_setting + 1);
456 memcpy(&audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].as_format[cur_alt_setting], desc, desc->bLength);
457 } break;
458 default:
459 break;
460 }
461 }
462 break;
463 case AUDIO_ENDPOINT_DESCRIPTOR_TYPE:
464 if ((cur_iface > audio_class->ctrl_intf) && (cur_iface < (audio_class->ctrl_intf + cur_iface_count))) {
465 if (p[DESC_bDescriptorSubType] == AUDIO_ENDPOINT_GENERAL) {
466 struct audio_cs_ep_ep_general_descriptor *desc = (struct audio_cs_ep_ep_general_descriptor *)p;
467 audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].ep_attr = desc->bmAttributes;
468 }
469 }
470 break;
471 default:
472 break;
473 }
474 /* skip to next descriptor */
475 p += p[DESC_bLength];
476 }
477
478 if ((input_offset != output_offset) && (input_offset != feature_unit_offset)) {
479 USB_LOG_ERR("Audio control descriptor is invalid\r\n");
480 return -USB_ERR_INVAL;
481 }
482
483 if (cur_iface_count == 0xff) {
484 USB_LOG_ERR("Audio descriptor must have iad descriptor\r\n");
485 return -USB_ERR_INVAL;
486 }
487
488 audio_class->stream_intf_num = input_offset;
489
490 for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
491 /* Search 0x0101 in input or output desc */
492 for (uint8_t streamidx = 0; streamidx < audio_class->stream_intf_num; streamidx++) {
493 if (audio_class->as_msg_table[i].as_general.bTerminalLink == ac_msg_table[streamidx].ac_input.bTerminalID) {
494 /* INPUT --> FEATURE UNIT --> OUTPUT */
495 audio_class->as_msg_table[i].input_terminal_id = ac_msg_table[streamidx].ac_input.bTerminalID;
496
497 /* Search input terminal id in feature desc */
498 for (uint8_t featureidx = 0; featureidx < audio_class->stream_intf_num; featureidx++) {
499 if (ac_msg_table[streamidx].ac_input.bTerminalID == ac_msg_table[featureidx].ac_feature_unit.bSourceID) {
500 audio_class->as_msg_table[i].feature_terminal_id = ac_msg_table[featureidx].ac_feature_unit.bUnitID;
501
502 /* Search feature unit id in output desc */
503 for (uint8_t outputid = 0; outputid < audio_class->stream_intf_num; outputid++) {
504 if (ac_msg_table[featureidx].ac_feature_unit.bUnitID == ac_msg_table[outputid].ac_output.bSourceID) {
505 audio_class->as_msg_table[i].output_terminal_id = ac_msg_table[outputid].ac_output.bTerminalID;
506
507 switch (ac_msg_table[outputid].ac_output.wTerminalType) {
508 case AUDIO_OUTTERM_SPEAKER:
509 audio_class->as_msg_table[i].stream_name = "speaker";
510 break;
511 case AUDIO_OUTTERM_HEADPHONES:
512 audio_class->as_msg_table[i].stream_name = "headphoens";
513 break;
514 case AUDIO_OUTTERM_HEADDISPLAY:
515 audio_class->as_msg_table[i].stream_name = "headdisplay";
516 break;
517 default:
518 audio_class->as_msg_table[i].stream_name = "unknown";
519 break;
520 }
521 break;
522 }
523 }
524 break;
525 }
526 }
527 } else if (audio_class->as_msg_table[i].as_general.bTerminalLink == ac_msg_table[streamidx].ac_output.bTerminalID) {
528 /* OUTPUT --> FEATURE UNIT --> INPUT */
529 audio_class->as_msg_table[i].output_terminal_id = ac_msg_table[streamidx].ac_output.bTerminalID;
530
531 /* Search output terminal id in feature desc */
532 for (uint8_t featureidx = 0; featureidx < audio_class->stream_intf_num; featureidx++) {
533 if (ac_msg_table[streamidx].ac_output.bSourceID == ac_msg_table[featureidx].ac_feature_unit.bUnitID) {
534 audio_class->as_msg_table[i].feature_terminal_id = ac_msg_table[featureidx].ac_feature_unit.bUnitID;
535
536 /* Search feature unit id in input desc */
537 for (uint8_t inputid = 0; inputid < audio_class->stream_intf_num; inputid++) {
538 if (ac_msg_table[featureidx].ac_feature_unit.bSourceID == ac_msg_table[inputid].ac_input.bTerminalID) {
539 audio_class->as_msg_table[i].input_terminal_id = ac_msg_table[inputid].ac_input.bTerminalID;
540
541 switch (ac_msg_table[inputid].ac_input.wTerminalType) {
542 case AUDIO_INTERM_MIC:
543 audio_class->as_msg_table[i].stream_name = "mic";
544 break;
545 default:
546 audio_class->as_msg_table[i].stream_name = "unknown";
547 break;
548 }
549 break;
550 }
551 }
552 break;
553 }
554 }
555 }
556 }
557 }
558
559 for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
560 if (audio_class->as_msg_table[i].stream_name == NULL) {
561 USB_LOG_ERR("Audio stream search fail\r\n");
562 return -USB_ERR_NODEV;
563 }
564 }
565
566 for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
567 ret = usbh_audio_close(audio_class, audio_class->as_msg_table[i].stream_name);
568 if (ret < 0) {
569 USB_LOG_ERR("Fail to close audio stream :%s\r\n", audio_class->as_msg_table[i].stream_name);
570 return ret;
571 }
572 }
573
574 usbh_audio_list_module(audio_class);
575
576 snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, audio_class->minor);
577 USB_LOG_INFO("Register Audio Class:%s\r\n", hport->config.intf[intf].devname);
578
579 usbh_audio_run(audio_class);
580 return 0;
581 }
582
usbh_audio_ctrl_disconnect(struct usbh_hubport * hport,uint8_t intf)583 static int usbh_audio_ctrl_disconnect(struct usbh_hubport *hport, uint8_t intf)
584 {
585 int ret = 0;
586
587 struct usbh_audio *audio_class = (struct usbh_audio *)hport->config.intf[intf].priv;
588
589 if (audio_class) {
590 if (audio_class->isoin) {
591 }
592
593 if (audio_class->isoout) {
594 }
595
596 if (hport->config.intf[intf].devname[0] != '\0') {
597 usb_osal_thread_schedule_other();
598 USB_LOG_INFO("Unregister Audio Class:%s\r\n", hport->config.intf[intf].devname);
599 usbh_audio_stop(audio_class);
600 }
601
602 usbh_audio_class_free(audio_class);
603 }
604
605 return ret;
606 }
607
usbh_audio_data_connect(struct usbh_hubport * hport,uint8_t intf)608 static int usbh_audio_data_connect(struct usbh_hubport *hport, uint8_t intf)
609 {
610 (void)hport;
611 (void)intf;
612 return 0;
613 }
614
usbh_audio_data_disconnect(struct usbh_hubport * hport,uint8_t intf)615 static int usbh_audio_data_disconnect(struct usbh_hubport *hport, uint8_t intf)
616 {
617 (void)hport;
618 (void)intf;
619 return 0;
620 }
621
usbh_audio_run(struct usbh_audio * audio_class)622 __WEAK void usbh_audio_run(struct usbh_audio *audio_class)
623 {
624 (void)audio_class;
625 }
626
usbh_audio_stop(struct usbh_audio * audio_class)627 __WEAK void usbh_audio_stop(struct usbh_audio *audio_class)
628 {
629 (void)audio_class;
630 }
631
632 const struct usbh_class_driver audio_ctrl_class_driver = {
633 .driver_name = "audio_ctrl",
634 .connect = usbh_audio_ctrl_connect,
635 .disconnect = usbh_audio_ctrl_disconnect
636 };
637
638 const struct usbh_class_driver audio_streaming_class_driver = {
639 .driver_name = "audio_streaming",
640 .connect = usbh_audio_data_connect,
641 .disconnect = usbh_audio_data_disconnect
642 };
643
644 CLASS_INFO_DEFINE const struct usbh_class_info audio_ctrl_intf_class_info = {
645 .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS,
646 .bInterfaceClass = USB_DEVICE_CLASS_AUDIO,
647 .bInterfaceSubClass = AUDIO_SUBCLASS_AUDIOCONTROL,
648 .bInterfaceProtocol = 0x00,
649 .id_table = NULL,
650 .class_driver = &audio_ctrl_class_driver
651 };
652
653 CLASS_INFO_DEFINE const struct usbh_class_info audio_streaming_intf_class_info = {
654 .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS,
655 .bInterfaceClass = USB_DEVICE_CLASS_AUDIO,
656 .bInterfaceSubClass = AUDIO_SUBCLASS_AUDIOSTREAMING,
657 .bInterfaceProtocol = 0x00,
658 .id_table = NULL,
659 .class_driver = &audio_streaming_class_driver
660 };
661