• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
21 
audio_class_endpoint_request_handler(struct usb_setup_packet * setup,uint8_t ** data,uint32_t * len)22 static int audio_class_endpoint_request_handler(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(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(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(struct usb_setup_packet * setup,uint8_t ** data,uint32_t * len)58 static int audio_class_interface_request_handler(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;
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.num; i++) {
83         if (g_usbd_audio.table[i].bEntityId == entity_id) {
84             subtype = g_usbd_audio.table[i].bDescriptorSubtype;
85             ep = g_usbd_audio.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.uac_version < 0x0200) {
102                         switch (setup->bRequest) {
103                             case AUDIO_REQUEST_SET_CUR:
104                                 mute = (*data)[0];
105                                 usbd_audio_set_mute(ep, ch, mute);
106                                 break;
107                             case AUDIO_REQUEST_GET_CUR:
108                                 (*data)[0] = usbd_audio_get_mute(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(ep, ch);
120                                     *len = 1;
121                                 } else {
122                                     mute = (*data)[0];
123                                     usbd_audio_set_mute(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.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 if (volume > 0x8000) {
140                                     volume_db = (0xffff - volume + 1) / -256;
141                                 }
142                                 volume_db += 128; /* 0 ~ 255 */
143                                 USB_LOG_DBG("Set ep:0x%02x ch:%d volume:0x%04x\r\n", ep, ch, volume);
144                                 usbd_audio_set_volume(ep, ch, volume_db);
145                                 break;
146                             case AUDIO_REQUEST_GET_CUR:
147                                 volume_db = usbd_audio_get_volume(ep, ch);
148                                 volume_db -= 128;
149                                 if (volume_db >= 0) {
150                                     volume = volume_db * 256;
151                                 } else {
152                                     volume = volume_db * 256 + 0xffff + 1;
153                                 }
154                                 memcpy(*data, &volume, 2);
155                                 *len = 2;
156                                 break;
157                             case AUDIO_REQUEST_GET_MIN:
158                                 (*data)[0] = 0x00; /* -2560/256 dB */
159                                 (*data)[1] = 0xdb;
160                                 *len = 2;
161                                 break;
162                             case AUDIO_REQUEST_GET_MAX:
163                                 (*data)[0] = 0x00; /* 0 dB */
164                                 (*data)[1] = 0x00;
165                                 *len = 2;
166                                 break;
167                             case AUDIO_REQUEST_GET_RES:
168                                 (*data)[0] = 0x00; /* -256/256 dB */
169                                 (*data)[1] = 0x01;
170                                 *len = 2;
171                                 break;
172                             default:
173                                 USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
174                                 return -1;
175                         }
176                     } else {
177                         switch (setup->bRequest) {
178                             case AUDIO_REQUEST_CUR:
179                                 if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
180                                     volume_db = usbd_audio_get_volume(ep, ch);
181                                     volume = volume_db;
182                                     memcpy(*data, &volume, 2);
183                                     *len = 2;
184                                 } else {
185                                     memcpy(&volume, *data, *len);
186                                     volume_db = volume;
187                                     USB_LOG_DBG("Set ep:0x%02x ch:%d volume:0x%02x\r\n", ep, ch, volume);
188                                     usbd_audio_set_volume(ep, ch, volume_db);
189                                 }
190                                 break;
191                             case AUDIO_REQUEST_RANGE:
192                                 if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
193                                     *((uint16_t *)(*data + 0)) = 1;
194                                     *((uint16_t *)(*data + 2)) = 0;
195                                     *((uint16_t *)(*data + 4)) = 100;
196                                     *((uint16_t *)(*data + 6)) = 1;
197                                     *len = 8;
198                                 } else {
199                                 }
200                                 break;
201                             default:
202                                 //USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
203                                 return -1;
204                         }
205                     }
206                     break;
207 
208                 default:
209                     USB_LOG_WRN("Unhandled Audio Class cs 0x%02x \r\n", control_selector);
210                     return -1;
211             }
212             break;
213         case AUDIO_CONTROL_CLOCK_SOURCE:
214             switch (control_selector) {
215                 case AUDIO_CS_CONTROL_SAM_FREQ:
216                     switch (setup->bRequest) {
217                         case AUDIO_REQUEST_CUR:
218                             if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
219                                 sampling_freq = usbd_audio_get_sampling_freq(ep);
220                                 memcpy(*data, &sampling_freq, 4);
221                                 USB_LOG_DBG("Get ep:0x%02x %d Hz\r\n", ep, (int)sampling_freq);
222                                 *len = 4;
223                             } else {
224                                 memcpy(&sampling_freq, *data, setup->wLength);
225                                 USB_LOG_DBG("Set ep:0x%02x %d Hz\r\n", ep, (int)sampling_freq);
226                                 usbd_audio_set_sampling_freq(ep, sampling_freq);
227                             }
228                             break;
229                         case AUDIO_REQUEST_RANGE:
230                             if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
231                                 uint8_t *sampling_freq_table = NULL;
232                                 uint16_t num;
233 
234                                 usbd_audio_get_sampling_freq_table(ep, &sampling_freq_table);
235                                 num = (uint16_t)((uint16_t)(sampling_freq_table[1] << 8) | ((uint16_t)sampling_freq_table[0]));
236                                 memcpy(*data, sampling_freq_table, (12 * num + 2));
237                                 *len = (12 * num + 2);
238                             } else {
239                             }
240                             break;
241                         default:
242                             //USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
243                             return -1;
244                     }
245                     break;
246                 case AUDIO_CS_CONTROL_CLOCK_VALID:
247                     if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
248                         (*data)[0] = 1;
249                         *len = 1;
250                     } else {
251                         return -1;
252                     }
253                     break;
254 
255                 default:
256                     //USB_LOG_WRN("Unhandled Audio Class cs 0x%02x \r\n", control_selector);
257                     return -1;
258             }
259             break;
260 
261         default:
262             break;
263     }
264     return 0;
265 }
266 
audio_notify_handler(uint8_t event,void * arg)267 static void audio_notify_handler(uint8_t event, void *arg)
268 {
269     switch (event) {
270         case USBD_EVENT_RESET:
271 
272             break;
273 
274         case USBD_EVENT_SET_INTERFACE: {
275             struct usb_interface_descriptor *intf = (struct usb_interface_descriptor *)arg;
276             if (intf->bAlternateSetting) {
277                 usbd_audio_open(intf->bInterfaceNumber);
278             } else {
279                 usbd_audio_close(intf->bInterfaceNumber);
280             }
281         }
282 
283         break;
284 
285         default:
286             break;
287     }
288 }
289 
usbd_audio_init_intf(struct usbd_interface * intf,uint16_t uac_version,struct audio_entity_info * table,uint8_t num)290 struct usbd_interface *usbd_audio_init_intf(struct usbd_interface *intf,
291                                             uint16_t uac_version,
292                                             struct audio_entity_info *table,
293                                             uint8_t num)
294 {
295     if (uac_version < 0x0200) {
296         intf->class_interface_handler = audio_class_interface_request_handler;
297         intf->class_endpoint_handler = audio_class_endpoint_request_handler;
298         intf->vendor_handler = NULL;
299         intf->notify_handler = audio_notify_handler;
300     } else {
301         intf->class_interface_handler = audio_class_interface_request_handler;
302         intf->class_endpoint_handler = NULL;
303         intf->vendor_handler = NULL;
304         intf->notify_handler = audio_notify_handler;
305     }
306 
307     g_usbd_audio.uac_version = uac_version;
308     g_usbd_audio.table = table;
309     g_usbd_audio.num = num;
310 
311     return intf;
312 }
313 
usbd_audio_set_volume(uint8_t ep,uint8_t ch,int volume)314 __WEAK void usbd_audio_set_volume(uint8_t ep, uint8_t ch, int volume)
315 {
316 }
317 
usbd_audio_get_volume(uint8_t ep,uint8_t ch)318 __WEAK int usbd_audio_get_volume(uint8_t ep, uint8_t ch)
319 {
320     return 0;
321 }
322 
usbd_audio_set_mute(uint8_t ep,uint8_t ch,bool mute)323 __WEAK void usbd_audio_set_mute(uint8_t ep, uint8_t ch, bool mute)
324 {
325 }
326 
usbd_audio_get_mute(uint8_t ep,uint8_t ch)327 __WEAK bool usbd_audio_get_mute(uint8_t ep, uint8_t ch)
328 {
329     return 0;
330 }
331 
usbd_audio_set_sampling_freq(uint8_t ep,uint32_t sampling_freq)332 __WEAK void usbd_audio_set_sampling_freq(uint8_t ep, uint32_t sampling_freq)
333 {
334 }
335 
usbd_audio_get_sampling_freq(uint8_t ep)336 __WEAK uint32_t usbd_audio_get_sampling_freq(uint8_t ep)
337 {
338     return 0;
339 }
340 
usbd_audio_get_sampling_freq_table(uint8_t ep,uint8_t ** sampling_freq_table)341 __WEAK void usbd_audio_get_sampling_freq_table(uint8_t ep, uint8_t **sampling_freq_table)
342 {
343 }
344