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 }