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