1 /*
2 * Copyright (c) 2022, sakumisu
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include "usbd_core.h"
7 #include "usbd_audio.h"
8
9 struct audio_entity_param {
10 uint32_t wCur;
11 uint32_t wMin;
12 uint32_t wMax;
13 uint32_t wRes;
14 };
15
16 struct usbd_audio_priv {
17 struct audio_entity_info *table;
18 uint8_t num;
19 uint16_t uac_version;
20 } g_usbd_audio[CONFIG_USBDEV_MAX_BUS];
21
audio_class_endpoint_request_handler(uint8_t busid,struct usb_setup_packet * setup,uint8_t ** data,uint32_t * len)22 static int audio_class_endpoint_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
23 {
24 uint8_t control_selector;
25 uint32_t sampling_freq = 0;
26 uint8_t ep;
27
28 control_selector = HI_BYTE(setup->wValue);
29 ep = LO_BYTE(setup->wIndex);
30
31 switch (control_selector) {
32 case AUDIO_EP_CONTROL_SAMPLING_FEQ:
33 switch (setup->bRequest) {
34 case AUDIO_REQUEST_SET_CUR:
35 memcpy((uint8_t *)&sampling_freq, *data, *len);
36 USB_LOG_DBG("Set ep:0x%02x %d Hz\r\n", ep, (int)sampling_freq);
37 usbd_audio_set_sampling_freq(busid, ep, sampling_freq);
38 break;
39 case AUDIO_REQUEST_GET_CUR:
40 case AUDIO_REQUEST_GET_MIN:
41 case AUDIO_REQUEST_GET_MAX:
42 case AUDIO_REQUEST_GET_RES:
43 sampling_freq = usbd_audio_get_sampling_freq(busid, ep);
44 memcpy(*data, &sampling_freq, 3);
45 USB_LOG_DBG("Get ep:0x%02x %d Hz\r\n", ep, (int)sampling_freq);
46 *len = 3;
47 break;
48 }
49
50 break;
51 default:
52 USB_LOG_WRN("Unhandled Audio Class control selector 0x%02x\r\n", control_selector);
53 return -1;
54 }
55 return 0;
56 }
57
audio_class_interface_request_handler(uint8_t busid,struct usb_setup_packet * setup,uint8_t ** data,uint32_t * len)58 static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
59 {
60 USB_LOG_DBG("Audio Class request: "
61 "bRequest 0x%02x\r\n",
62 setup->bRequest);
63
64 uint8_t entity_id;
65 uint8_t ep = 0;
66 uint8_t subtype = 0x01;
67 uint8_t control_selector;
68 uint8_t ch;
69 uint8_t mute;
70 uint16_t volume;
71 int volume_db = 0;
72 uint32_t sampling_freq = 0;
73
74 const char *mute_string[2] = { "off", "on" };
75
76 entity_id = HI_BYTE(setup->wIndex);
77 control_selector = HI_BYTE(setup->wValue);
78 ch = LO_BYTE(setup->wValue);
79
80 ARG_UNUSED(mute_string);
81
82 for (uint8_t i = 0; i < g_usbd_audio[busid].num; i++) {
83 if (g_usbd_audio[busid].table[i].bEntityId == entity_id) {
84 subtype = g_usbd_audio[busid].table[i].bDescriptorSubtype;
85 ep = g_usbd_audio[busid].table[i].ep;
86 break;
87 }
88 }
89
90 if (subtype == 0x01) {
91 USB_LOG_ERR("Do not find subtype for 0x%02x\r\n", entity_id);
92 return -1;
93 }
94
95 USB_LOG_DBG("Audio entity_id:%02x, subtype:%02x, cs:%02x\r\n", entity_id, subtype, control_selector);
96
97 switch (subtype) {
98 case AUDIO_CONTROL_FEATURE_UNIT:
99 switch (control_selector) {
100 case AUDIO_FU_CONTROL_MUTE:
101 if (g_usbd_audio[busid].uac_version < 0x0200) {
102 switch (setup->bRequest) {
103 case AUDIO_REQUEST_SET_CUR:
104 mute = (*data)[0];
105 usbd_audio_set_mute(busid, ep, ch, mute);
106 break;
107 case AUDIO_REQUEST_GET_CUR:
108 (*data)[0] = usbd_audio_get_mute(busid, ep, ch);
109 *len = 1;
110 break;
111 default:
112 USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
113 return -1;
114 }
115 } else {
116 switch (setup->bRequest) {
117 case AUDIO_REQUEST_CUR:
118 if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
119 (*data)[0] = usbd_audio_get_mute(busid, ep, ch);
120 *len = 1;
121 } else {
122 mute = (*data)[0];
123 usbd_audio_set_mute(busid, ep, ch, mute);
124 }
125 break;
126 default:
127 //USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
128 return -1;
129 }
130 }
131 break;
132 case AUDIO_FU_CONTROL_VOLUME:
133 if (g_usbd_audio[busid].uac_version < 0x0200) {
134 switch (setup->bRequest) {
135 case AUDIO_REQUEST_SET_CUR:
136 memcpy(&volume, *data, *len);
137 if (volume < 0x8000) {
138 volume_db = volume / 256;
139 } else {
140 volume_db = (volume - 0x10000) / 256;
141 }
142 USB_LOG_DBG("Set ep:0x%02x ch:%d vol_hex:0x%04x, vol_db:%d dB\r\n", ep, ch, volume, volume_db);
143 usbd_audio_set_volume(busid, ep, ch, volume_db);
144 break;
145 case AUDIO_REQUEST_GET_CUR:
146 volume_db = usbd_audio_get_volume(busid, ep, ch);
147 if (volume_db >= 0) {
148 volume = volume_db * 256;
149 } else {
150 volume = volume_db * 256 + 0x10000;
151 }
152 USB_LOG_DBG("Get ep:0x%02x ch:%d vol_hex:0x%04x, vol_db:%d dB\r\n", ep, ch, volume, volume_db);
153 memcpy(*data, &volume, 2);
154 *len = 2;
155 break;
156 case AUDIO_REQUEST_GET_MIN:
157 (*data)[0] = 0x00; /* -100 dB */
158 (*data)[1] = 0x9c;
159 *len = 2;
160 break;
161 case AUDIO_REQUEST_GET_MAX:
162 (*data)[0] = 0x00; /* 0 dB */
163 (*data)[1] = 0x00;
164 *len = 2;
165 break;
166 case AUDIO_REQUEST_GET_RES:
167 (*data)[0] = 0x00; /* 1 dB */
168 (*data)[1] = 0x01;
169 *len = 2;
170 break;
171 default:
172 USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
173 return -1;
174 }
175 } else {
176 switch (setup->bRequest) {
177 case AUDIO_REQUEST_CUR:
178 if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
179 volume_db = usbd_audio_get_volume(busid, ep, ch);
180 if (volume_db >= 0) {
181 volume = volume_db * 256;
182 } else {
183 volume = volume_db * 256 + 0x10000;
184 }
185 USB_LOG_DBG("Get ep:0x%02x ch:%d vol_hex:0x%04x, vol_db:%d dB\r\n", ep, ch, volume, volume_db);
186 memcpy(*data, &volume, 2);
187 *len = 2;
188 } else {
189 memcpy(&volume, *data, *len);
190 if (volume < 0x8000) {
191 volume_db = volume / 256;
192 } else {
193 volume_db = (volume - 0x10000) / 256;
194 }
195 USB_LOG_DBG("Set ep:0x%02x ch:%d vol_hex:0x%04x, vol_db:%d dB\r\n", ep, ch, volume, volume_db);
196 usbd_audio_set_volume(busid, ep, ch, volume_db);
197 }
198 break;
199 case AUDIO_REQUEST_RANGE:
200 if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
201 *((uint16_t *)(*data + 0)) = 1;
202 *((uint16_t *)(*data + 2)) = 0x9c00; /* MIN -100 dB */
203 *((uint16_t *)(*data + 4)) = 0x0000; /* MAX 0 dB */
204 *((uint16_t *)(*data + 6)) = 0x100; /* RES 1 dB */
205 *len = 8;
206 } else {
207 }
208 break;
209 default:
210 //USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
211 return -1;
212 }
213 }
214 break;
215
216 default:
217 USB_LOG_WRN("Unhandled Audio Class cs 0x%02x \r\n", control_selector);
218 return -1;
219 }
220 break;
221 case AUDIO_CONTROL_CLOCK_SOURCE:
222 switch (control_selector) {
223 case AUDIO_CS_CONTROL_SAM_FREQ:
224 switch (setup->bRequest) {
225 case AUDIO_REQUEST_CUR:
226 if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
227 sampling_freq = usbd_audio_get_sampling_freq(busid, ep);
228 memcpy(*data, &sampling_freq, 4);
229 USB_LOG_DBG("Get ep:0x%02x %d Hz\r\n", ep, (int)sampling_freq);
230 *len = 4;
231 } else {
232 memcpy(&sampling_freq, *data, setup->wLength);
233 USB_LOG_DBG("Set ep:0x%02x %d Hz\r\n", ep, (int)sampling_freq);
234 usbd_audio_set_sampling_freq(busid, ep, sampling_freq);
235 }
236 break;
237 case AUDIO_REQUEST_RANGE:
238 if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
239 uint8_t *sampling_freq_table = NULL;
240 uint16_t num;
241
242 usbd_audio_get_sampling_freq_table(busid, ep, &sampling_freq_table);
243 num = (uint16_t)((uint16_t)(sampling_freq_table[1] << 8) | ((uint16_t)sampling_freq_table[0]));
244 memcpy(*data, sampling_freq_table, (12 * num + 2));
245 *len = (12 * num + 2);
246 } else {
247 }
248 break;
249 default:
250 //USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
251 return -1;
252 }
253 break;
254 case AUDIO_CS_CONTROL_CLOCK_VALID:
255 if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
256 (*data)[0] = 1;
257 *len = 1;
258 } else {
259 return -1;
260 }
261 break;
262
263 default:
264 //USB_LOG_WRN("Unhandled Audio Class cs 0x%02x \r\n", control_selector);
265 return -1;
266 }
267 break;
268
269 default:
270 break;
271 }
272 return 0;
273 }
274
audio_notify_handler(uint8_t busid,uint8_t event,void * arg)275 static void audio_notify_handler(uint8_t busid, uint8_t event, void *arg)
276 {
277 switch (event) {
278 case USBD_EVENT_RESET:
279
280 break;
281
282 case USBD_EVENT_SET_INTERFACE: {
283 struct usb_interface_descriptor *intf = (struct usb_interface_descriptor *)arg;
284 if (intf->bAlternateSetting) {
285 usbd_audio_open(busid, intf->bInterfaceNumber);
286 } else {
287 usbd_audio_close(busid, intf->bInterfaceNumber);
288 }
289 }
290
291 break;
292
293 default:
294 break;
295 }
296 }
297
usbd_audio_init_intf(uint8_t busid,struct usbd_interface * intf,uint16_t uac_version,struct audio_entity_info * table,uint8_t num)298 struct usbd_interface *usbd_audio_init_intf(uint8_t busid,
299 struct usbd_interface *intf,
300 uint16_t uac_version,
301 struct audio_entity_info *table,
302 uint8_t num)
303 {
304 if (uac_version < 0x0200) {
305 intf->class_interface_handler = audio_class_interface_request_handler;
306 intf->class_endpoint_handler = audio_class_endpoint_request_handler;
307 intf->vendor_handler = NULL;
308 intf->notify_handler = audio_notify_handler;
309 } else {
310 intf->class_interface_handler = audio_class_interface_request_handler;
311 intf->class_endpoint_handler = NULL;
312 intf->vendor_handler = NULL;
313 intf->notify_handler = audio_notify_handler;
314 }
315
316 g_usbd_audio[busid].uac_version = uac_version;
317 g_usbd_audio[busid].table = table;
318 g_usbd_audio[busid].num = num;
319
320 return intf;
321 }
322
usbd_audio_set_volume(uint8_t busid,uint8_t ep,uint8_t ch,int volume_db)323 __WEAK void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, int volume_db)
324 {
325 (void)busid;
326 (void)ep;
327 (void)ch;
328 (void)volume_db;
329 }
330
usbd_audio_get_volume(uint8_t busid,uint8_t ep,uint8_t ch)331 __WEAK int usbd_audio_get_volume(uint8_t busid, uint8_t ep, uint8_t ch)
332 {
333 (void)busid;
334 (void)ep;
335 (void)ch;
336
337 return 0;
338 }
339
usbd_audio_set_mute(uint8_t busid,uint8_t ep,uint8_t ch,bool mute)340 __WEAK void usbd_audio_set_mute(uint8_t busid, uint8_t ep, uint8_t ch, bool mute)
341 {
342 (void)busid;
343 (void)ep;
344 (void)ch;
345 (void)mute;
346 }
347
usbd_audio_get_mute(uint8_t busid,uint8_t ep,uint8_t ch)348 __WEAK bool usbd_audio_get_mute(uint8_t busid, uint8_t ep, uint8_t ch)
349 {
350 (void)busid;
351 (void)ep;
352 (void)ch;
353
354 return 0;
355 }
356
usbd_audio_set_sampling_freq(uint8_t busid,uint8_t ep,uint32_t sampling_freq)357 __WEAK void usbd_audio_set_sampling_freq(uint8_t busid, uint8_t ep, uint32_t sampling_freq)
358 {
359 (void)busid;
360 (void)ep;
361 (void)sampling_freq;
362 }
363
usbd_audio_get_sampling_freq(uint8_t busid,uint8_t ep)364 __WEAK uint32_t usbd_audio_get_sampling_freq(uint8_t busid, uint8_t ep)
365 {
366 (void)busid;
367 (void)ep;
368
369 return 0;
370 }
371
usbd_audio_get_sampling_freq_table(uint8_t busid,uint8_t ep,uint8_t ** sampling_freq_table)372 __WEAK void usbd_audio_get_sampling_freq_table(uint8_t busid, uint8_t ep, uint8_t **sampling_freq_table)
373 {
374 (void)busid;
375 (void)ep;
376 (void)sampling_freq_table;
377 }
378
usbd_audio_open(uint8_t busid,uint8_t intf)379 __WEAK void usbd_audio_open(uint8_t busid, uint8_t intf)
380 {
381 (void)busid;
382 (void)intf;
383 }
384
usbd_audio_close(uint8_t busid,uint8_t intf)385 __WEAK void usbd_audio_close(uint8_t busid, uint8_t intf)
386 {
387 (void)busid;
388 (void)intf;
389 }