• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define DEV_FORMAT "/dev/audio%d"
10 
11 /* general descriptor field offsets */
12 #define DESC_bLength            0 /** Length offset */
13 #define DESC_bDescriptorType    1 /** Descriptor type offset */
14 #define DESC_bDescriptorSubType 2 /** Descriptor subtype offset */
15 
16 /* interface descriptor field offsets */
17 #define INTF_DESC_bInterfaceNumber  2 /** Interface number offset */
18 #define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
19 
20 #ifndef CONFIG_USBHOST_MAX_AUDIO_CLASS
21 #define CONFIG_USBHOST_MAX_AUDIO_CLASS 4
22 #endif
23 
24 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_audio_buf[128];
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     int devno;
32 
33     for (devno = 0; devno < CONFIG_USBHOST_MAX_AUDIO_CLASS; devno++) {
34         if ((g_devinuse & (1 << devno)) == 0) {
35             g_devinuse |= (1 << 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     int devno = audio_class->minor;
47 
48     if (devno >= 0 && devno < 32) {
49         g_devinuse &= ~(1 << 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)54 int usbh_audio_open(struct usbh_audio *audio_class, const char *name, uint32_t samp_freq)
55 {
56     struct usb_setup_packet *setup = audio_class->hport->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->is_opened) {
65         return -EMFILE;
66     }
67 
68     for (uint8_t i = 0; i < audio_class->module_num; i++) {
69         if (strcmp(name, audio_class->module[i].name) == 0) {
70             for (uint8_t j = 0; j < audio_class->num_of_intf_altsettings; j++) {
71                 for (uint8_t k = 0; k < audio_class->module[i].altsetting[j].sampfreq_num; k++) {
72                     if (audio_class->module[i].altsetting[j].sampfreq[k] == samp_freq) {
73                         intf = audio_class->module[i].data_intf;
74                         altsetting = j;
75                         goto freq_found;
76                     }
77                 }
78             }
79         }
80     }
81 
82     return -ENODEV;
83 
84 freq_found:
85 
86     setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
87     setup->bRequest = USB_REQUEST_SET_INTERFACE;
88     setup->wValue = altsetting;
89     setup->wIndex = intf;
90     setup->wLength = 0;
91 
92     ret = usbh_control_transfer(audio_class->hport->ep0, setup, NULL);
93     if (ret < 0) {
94         return ret;
95     }
96 
97     ep_desc = &audio_class->hport->config.intf[intf].altsetting[altsetting].ep[0].ep_desc;
98 
99     setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_ENDPOINT;
100     setup->bRequest = AUDIO_REQUEST_SET_CUR;
101     setup->wValue = (AUDIO_EP_CONTROL_SAMPLING_FEQ << 8) | 0x00;
102     setup->wIndex = ep_desc->bEndpointAddress;
103     setup->wLength = 3;
104 
105     memcpy(g_audio_buf, &samp_freq, 3);
106     ret = usbh_control_transfer(audio_class->hport->ep0, setup, g_audio_buf);
107     if (ret < 0) {
108         return ret;
109     }
110 
111     mult = (ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK) >> USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT;
112     mps = ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_MASK;
113     if (ep_desc->bEndpointAddress & 0x80) {
114         audio_class->isoin_mps = mps * (mult + 1);
115         usbh_hport_activate_epx(&audio_class->isoin, audio_class->hport, ep_desc);
116     } else {
117         audio_class->isoout_mps = mps * (mult + 1);
118         usbh_hport_activate_epx(&audio_class->isoout, audio_class->hport, ep_desc);
119     }
120 
121     USB_LOG_INFO("Open audio module :%s, altsetting: %u\r\n", name, altsetting);
122     audio_class->is_opened = true;
123     return ret;
124 }
125 
usbh_audio_close(struct usbh_audio * audio_class,const char * name)126 int usbh_audio_close(struct usbh_audio *audio_class, const char *name)
127 {
128     struct usb_setup_packet *setup = audio_class->hport->setup;
129     struct usb_endpoint_descriptor *ep_desc;
130     int ret;
131     uint8_t intf = 0xff;
132     uint8_t altsetting = 1;
133 
134     for (size_t i = 0; i < audio_class->module_num; i++) {
135         if (strcmp(name, audio_class->module[i].name) == 0) {
136             intf = audio_class->module[i].data_intf;
137         }
138     }
139 
140     if (intf == 0xff) {
141         return -ENODEV;
142     }
143 
144     USB_LOG_INFO("Close audio module :%s\r\n", name);
145     audio_class->is_opened = false;
146 
147     ep_desc = &audio_class->hport->config.intf[intf].altsetting[altsetting].ep[0].ep_desc;
148     if (ep_desc->bEndpointAddress & 0x80) {
149         if (audio_class->isoin) {
150             usbh_pipe_free(audio_class->isoin);
151             audio_class->isoin = NULL;
152         }
153     } else {
154         if (audio_class->isoout) {
155             usbh_pipe_free(audio_class->isoout);
156             audio_class->isoout = NULL;
157         }
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->ep0, setup, NULL);
167 
168     return ret;
169 }
170 
usbh_audio_set_volume(struct usbh_audio * audio_class,const char * name,uint8_t ch,uint8_t volume)171 int usbh_audio_set_volume(struct usbh_audio *audio_class, const char *name, uint8_t ch, uint8_t volume)
172 {
173     struct usb_setup_packet *setup = audio_class->hport->setup;
174     int ret;
175     uint8_t intf = 0xff;
176     uint8_t feature_id = 0xff;
177     uint16_t volume_hex;
178 
179     for (size_t i = 0; i < audio_class->module_num; i++) {
180         if (strcmp(name, audio_class->module[i].name) == 0) {
181             intf = audio_class->ctrl_intf;
182             feature_id = audio_class->module[i].feature_unit_id;
183         }
184     }
185 
186     if (intf == 0xff) {
187         return -ENODEV;
188     }
189 
190     setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
191     setup->bRequest = AUDIO_REQUEST_SET_CUR;
192     setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
193     setup->wIndex = (feature_id << 8) | intf;
194     setup->wLength = 2;
195 
196     volume_hex = -0xDB00 / 100 * volume + 0xdb00;
197 
198     memcpy(g_audio_buf, &volume_hex, 2);
199     ret = usbh_control_transfer(audio_class->hport->ep0, setup, NULL);
200 
201     return ret;
202 }
203 
usbh_audio_set_mute(struct usbh_audio * audio_class,const char * name,uint8_t ch,bool mute)204 int usbh_audio_set_mute(struct usbh_audio *audio_class, const char *name, uint8_t ch, bool mute)
205 {
206     struct usb_setup_packet *setup = audio_class->hport->setup;
207     int ret;
208     uint8_t intf = 0xff;
209     uint8_t feature_id = 0xff;
210 
211     for (size_t i = 0; i < audio_class->module_num; i++) {
212         if (strcmp(name, audio_class->module[i].name) == 0) {
213             intf = audio_class->ctrl_intf;
214             feature_id = audio_class->module[i].feature_unit_id;
215         }
216     }
217 
218     if (intf == 0xff) {
219         return -ENODEV;
220     }
221 
222     setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
223     setup->bRequest = AUDIO_REQUEST_SET_CUR;
224     setup->wValue = (AUDIO_FU_CONTROL_MUTE << 8) | ch;
225     setup->wIndex = (feature_id << 8) | intf;
226     setup->wLength = 1;
227 
228     memcpy(g_audio_buf, &mute, 1);
229     ret = usbh_control_transfer(audio_class->hport->ep0, setup, g_audio_buf);
230 
231     return ret;
232 }
233 
usbh_audio_list_module(struct usbh_audio * audio_class)234 void usbh_audio_list_module(struct usbh_audio *audio_class)
235 {
236     USB_LOG_INFO("============= Audio module information ===================\r\n");
237     USB_LOG_INFO("bcdADC :%04x\r\n", audio_class->bcdADC);
238     USB_LOG_INFO("Num of modules :%u\r\n", audio_class->module_num);
239     USB_LOG_INFO("Num of altsettings:%u\r\n", audio_class->num_of_intf_altsettings);
240 
241     for (uint8_t i = 0; i < audio_class->module_num; i++) {
242         USB_LOG_INFO("  module name :%s\r\n", audio_class->module[i].name);
243         USB_LOG_INFO("  module feature unit id :%d\r\n", audio_class->module[i].feature_unit_id);
244 
245         for (uint8_t j = 0; j < audio_class->num_of_intf_altsettings; j++) {
246             if (j == 0) {
247                 USB_LOG_INFO("      Ingore altsetting 0\r\n");
248                 continue;
249             }
250             USB_LOG_INFO("      Altsetting %u\r\n", j);
251             USB_LOG_INFO("          module channels :%u\r\n", audio_class->module[i].altsetting[j].channels);
252             //USB_LOG_INFO("        module format_type :%u\r\n",audio_class->module[i].altsetting[j].format_type);
253             USB_LOG_INFO("          module bitresolution :%u\r\n", audio_class->module[i].altsetting[j].bitresolution);
254             USB_LOG_INFO("          module sampfreq num :%u\r\n", audio_class->module[i].altsetting[j].sampfreq_num);
255 
256             for (uint8_t k = 0; k < audio_class->module[i].altsetting[j].sampfreq_num; k++) {
257                 USB_LOG_INFO("              module sampfreq :%d hz\r\n", audio_class->module[i].altsetting[j].sampfreq[k]);
258             }
259         }
260     }
261 
262     USB_LOG_INFO("============= Audio module information ===================\r\n");
263 }
264 
usbh_audio_ctrl_connect(struct usbh_hubport * hport,uint8_t intf)265 static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
266 {
267     int ret;
268     uint8_t cur_iface = 0xff;
269     uint8_t cur_iface_count = 0xff;
270     uint8_t cur_alt_setting = 0xff;
271     uint8_t input_offset = 0;
272     uint8_t output_offset = 0;
273     uint8_t feature_unit_offset = 0;
274     uint8_t format_offset = 0;
275     uint8_t *p;
276 
277     struct usbh_audio *audio_class = usbh_audio_class_alloc();
278     if (audio_class == NULL) {
279         USB_LOG_ERR("Fail to alloc audio_class\r\n");
280         return -ENOMEM;
281     }
282 
283     audio_class->hport = hport;
284     audio_class->ctrl_intf = intf;
285     audio_class->num_of_intf_altsettings = hport->config.intf[intf + 1].altsetting_num;
286 
287     hport->config.intf[intf].priv = audio_class;
288 
289     p = hport->raw_config_desc;
290     while (p[DESC_bLength]) {
291         switch (p[DESC_bDescriptorType]) {
292             case USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION:
293                 cur_iface_count = p[3];
294                 break;
295             case USB_DESCRIPTOR_TYPE_INTERFACE:
296                 cur_iface = p[INTF_DESC_bInterfaceNumber];
297                 cur_alt_setting = p[INTF_DESC_bAlternateSetting];
298                 break;
299             case USB_DESCRIPTOR_TYPE_ENDPOINT:
300                 break;
301             case AUDIO_INTERFACE_DESCRIPTOR_TYPE:
302                 if (cur_iface == audio_class->ctrl_intf) {
303                     switch (p[DESC_bDescriptorSubType]) {
304                         case AUDIO_CONTROL_HEADER: {
305                             struct audio_cs_if_ac_header_descriptor *desc = (struct audio_cs_if_ac_header_descriptor *)p;
306                             audio_class->bcdADC = desc->bcdADC;
307                             audio_class->bInCollection = desc->bInCollection;
308                         } break;
309                         case AUDIO_CONTROL_INPUT_TERMINAL: {
310                             struct audio_cs_if_ac_input_terminal_descriptor *desc = (struct audio_cs_if_ac_input_terminal_descriptor *)p;
311 
312                             audio_class->module[input_offset].input_terminal_id = desc->bTerminalID;
313                             audio_class->module[input_offset].input_terminal_type = desc->wTerminalType;
314                             audio_class->module[input_offset].input_channel_config = desc->wChannelConfig;
315 
316                             if (desc->wTerminalType == AUDIO_TERMINAL_STREAMING) {
317                                 audio_class->module[input_offset].terminal_link_id = desc->bTerminalID;
318                             }
319                             if (desc->wTerminalType == AUDIO_INTERM_MIC) {
320                                 audio_class->module[input_offset].name = "mic";
321                             }
322                             input_offset++;
323                         } break;
324                             break;
325                         case AUDIO_CONTROL_OUTPUT_TERMINAL: {
326                             struct audio_cs_if_ac_output_terminal_descriptor *desc = (struct audio_cs_if_ac_output_terminal_descriptor *)p;
327                             audio_class->module[output_offset].output_terminal_id = desc->bTerminalID;
328                             audio_class->module[output_offset].output_terminal_type = desc->wTerminalType;
329                             if (desc->wTerminalType == AUDIO_TERMINAL_STREAMING) {
330                                 audio_class->module[output_offset].terminal_link_id = desc->bTerminalID;
331                             }
332                             if (desc->wTerminalType == AUDIO_OUTTERM_SPEAKER) {
333                                 audio_class->module[output_offset].name = "speaker";
334                             }
335                             output_offset++;
336                         } break;
337                         case AUDIO_CONTROL_FEATURE_UNIT: {
338                             struct audio_cs_if_ac_feature_unit_descriptor *desc = (struct audio_cs_if_ac_feature_unit_descriptor *)p;
339                             audio_class->module[feature_unit_offset].feature_unit_id = desc->bUnitID;
340                             audio_class->module[feature_unit_offset].feature_unit_controlsize = desc->bControlSize;
341 
342                             for (uint8_t j = 0; j < desc->bControlSize; j++) {
343                                 audio_class->module[feature_unit_offset].feature_unit_controls[j] = p[6 + j];
344                             }
345                             feature_unit_offset++;
346                         } break;
347                         case AUDIO_CONTROL_PROCESSING_UNIT:
348 
349                             break;
350                         default:
351                             break;
352                     }
353                 } else if ((cur_iface < (audio_class->ctrl_intf + cur_iface_count)) && (cur_iface > audio_class->ctrl_intf)) {
354                     switch (p[DESC_bDescriptorSubType]) {
355                         case AUDIO_STREAMING_GENERAL:
356 
357                             break;
358                         case AUDIO_STREAMING_FORMAT_TYPE: {
359                             struct audio_cs_if_as_format_type_descriptor *desc = (struct audio_cs_if_as_format_type_descriptor *)p;
360 
361                             audio_class->module[format_offset].data_intf = cur_iface;
362                             audio_class->module[format_offset].altsetting[cur_alt_setting].channels = desc->bNrChannels;
363                             audio_class->module[format_offset].altsetting[cur_alt_setting].format_type = desc->bFormatType;
364                             audio_class->module[format_offset].altsetting[cur_alt_setting].bitresolution = desc->bBitResolution;
365                             audio_class->module[format_offset].altsetting[cur_alt_setting].sampfreq_num = desc->bSamFreqType;
366 
367                             for (uint8_t j = 0; j < desc->bSamFreqType; j++) {
368                                 audio_class->module[format_offset].altsetting[cur_alt_setting].sampfreq[j] = (uint32_t)(p[10 + j] << 16) |
369                                                                                                              (uint32_t)(p[9 + j] << 8) |
370                                                                                                              (uint32_t)(p[8 + j] << 0);
371                             }
372                             if (cur_alt_setting == (hport->config.intf[intf + 1].altsetting_num - 1)) {
373                                 format_offset++;
374                             }
375                         } break;
376                         default:
377                             break;
378                     }
379                 }
380                 break;
381             default:
382                 break;
383         }
384         /* skip to next descriptor */
385         p += p[DESC_bLength];
386     }
387 
388     if ((input_offset != output_offset) && (input_offset != feature_unit_offset) && (input_offset != format_offset)) {
389         return -EINVAL;
390     }
391 
392     audio_class->module_num = input_offset;
393 
394     for (size_t i = 0; i < audio_class->module_num; i++) {
395         ret = usbh_audio_close(audio_class, audio_class->module[i].name);
396         if (ret < 0) {
397             USB_LOG_ERR("Fail to close audio module :%s\r\n", audio_class->module[i].name);
398             return ret;
399         }
400     }
401 
402     usbh_audio_list_module(audio_class);
403 
404     snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, audio_class->minor);
405     USB_LOG_INFO("Register Audio Class:%s\r\n", hport->config.intf[intf].devname);
406 
407     usbh_audio_run(audio_class);
408     return 0;
409 }
410 
usbh_audio_ctrl_disconnect(struct usbh_hubport * hport,uint8_t intf)411 static int usbh_audio_ctrl_disconnect(struct usbh_hubport *hport, uint8_t intf)
412 {
413     int ret = 0;
414 
415     struct usbh_audio *audio_class = (struct usbh_audio *)hport->config.intf[intf].priv;
416 
417     if (audio_class) {
418         if (audio_class->isoin) {
419             usbh_pipe_free(audio_class->isoin);
420         }
421 
422         if (audio_class->isoout) {
423             usbh_pipe_free(audio_class->isoout);
424         }
425 
426         if (hport->config.intf[intf].devname[0] != '\0') {
427             USB_LOG_INFO("Unregister Audio Class:%s\r\n", hport->config.intf[intf].devname);
428             usbh_audio_stop(audio_class);
429         }
430 
431         usbh_audio_class_free(audio_class);
432     }
433 
434     return ret;
435 }
436 
usbh_audio_data_connect(struct usbh_hubport * hport,uint8_t intf)437 static int usbh_audio_data_connect(struct usbh_hubport *hport, uint8_t intf)
438 {
439     return 0;
440 }
441 
usbh_audio_data_disconnect(struct usbh_hubport * hport,uint8_t intf)442 static int usbh_audio_data_disconnect(struct usbh_hubport *hport, uint8_t intf)
443 {
444     return 0;
445 }
446 
usbh_audio_run(struct usbh_audio * audio_class)447 __WEAK void usbh_audio_run(struct usbh_audio *audio_class)
448 {
449 }
450 
usbh_audio_stop(struct usbh_audio * audio_class)451 __WEAK void usbh_audio_stop(struct usbh_audio *audio_class)
452 {
453 }
454 
455 const struct usbh_class_driver audio_ctrl_class_driver = {
456     .driver_name = "audio_ctrl",
457     .connect = usbh_audio_ctrl_connect,
458     .disconnect = usbh_audio_ctrl_disconnect
459 };
460 
461 const struct usbh_class_driver audio_streaming_class_driver = {
462     .driver_name = "audio_streaming",
463     .connect = usbh_audio_data_connect,
464     .disconnect = usbh_audio_data_disconnect
465 };
466 
467 CLASS_INFO_DEFINE const struct usbh_class_info audio_ctrl_intf_class_info = {
468     .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS,
469     .class = USB_DEVICE_CLASS_AUDIO,
470     .subclass = AUDIO_SUBCLASS_AUDIOCONTROL,
471     .protocol = 0x00,
472     .vid = 0x00,
473     .pid = 0x00,
474     .class_driver = &audio_ctrl_class_driver
475 };
476 
477 CLASS_INFO_DEFINE const struct usbh_class_info audio_streaming_intf_class_info = {
478     .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS,
479     .class = USB_DEVICE_CLASS_AUDIO,
480     .subclass = AUDIO_SUBCLASS_AUDIOSTREAMING,
481     .protocol = 0x00,
482     .vid = 0x00,
483     .pid = 0x00,
484     .class_driver = &audio_streaming_class_driver
485 };
486