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