NUC472_NUC442_BSP V3.03.004
The Board Support Package for NUC472/NUC442
uac_parser.c
Go to the documentation of this file.
1/**************************************************************************/
13#include <stdio.h>
14#include <string.h>
15
16#include "NUC472_442.h"
17#include "usbh_core.h"
18
19#include "usbh_uac.h"
20#include "uac.h"
21
23
24
25static AC_FU_T * funit[MAX_FEATURE_UNIT]; /* array recording position of FEATURE UNITs */
26static int fu_cnt; /* number of FEATURE UNITs */
27
28
29static int uac_parse_cs_interface(UAC_DEV_T *audev, USB_IF_DESC_T *ifp, uint8_t *buffer, int size)
30{
31 UAC_INFO_T *uac_info = (UAC_INFO_T *)audev->priv;
32 AC_IF_HDR_T *hdr;
33 AS_GEN_T *as_gen;
34 AC_IT_T *ac_itd;
35 AC_OT_T *ac_otd;
36#ifdef USBAS_DEBUG
37 AC_FU_T *ac_fu;
38 AC_PU_T *ac_pu;
39 AC_MXR_T *ac_mxr;
40 AC_SU_T *ac_su;
41#endif
42
43 hdr = (AC_IF_HDR_T *)buffer;
44
45 if (ifp->bInterfaceSubClass == SUBCLS_AUDIOCONTROL)
46 {
47 switch (hdr->bDescriptorSubtype)
48 {
49 case AC_DESCRIPTOR_UNDEFINED:
50 USBAS_DBGMSG("AC: AC_DESCRIPTOR_UNDEFINED\n");
51 break;
52
53 case HEADER:
54 USBAS_DBGMSG("AC: HEADER\n");
55 break;
56
57 case INPUT_TERMINAL:
58 USBAS_DBGMSG("AC: INPUT_TERMINAL\n");
59 ac_itd = (AC_IT_T *)buffer;
60 if (ac_itd->wTerminalType == UAC_TT_USB_STREAMING)
61 {
62 USBAS_DBGMSG("SPEAKER USB streaming terminal found, ID=0x%x\n", ac_itd->bTerminalID);
63 uac_info->it_usbs = ac_itd;
64 }
65 else if ((ac_itd->wTerminalType & 0x200) == 0x200)
66 {
67 USBAS_DBGMSG("MICROPHONE input terminal found, ID=0x%x\n", ac_itd->bTerminalID);
68 uac_info->it_microphone = ac_itd;
69 }
70 else
71 {
72 USBAS_DBGMSG("Unsupported INPUT TERMINAL, ignore it!\n");
73 }
74 USBAS_DBGMSG(" bTerminalID: 0%x\n", ac_itd->bTerminalID);
75 USBAS_DBGMSG(" wTerminalType: 0%x\n", ac_itd->wTerminalType);
76 USBAS_DBGMSG(" bAssocTerminal: 0%x\n", ac_itd->bAssocTerminal);
77 USBAS_DBGMSG(" bNrChannels: 0%x\n", ac_itd->bNrChannels);
78 USBAS_DBGMSG(" wChannelConfig: 0%x\n", ac_itd->wChannelConfig);
79 break;
80
81 case OUTPUT_TERMINAL:
82 USBAS_DBGMSG("AC: OUTPUT_TERMINAL\n");
83 ac_otd = (AC_OT_T *)buffer;
84 if (ac_otd->wTerminalType == UAC_TT_USB_STREAMING)
85 {
86 USBAS_DBGMSG("MICROPHONE USB streaming terminal found, ID=0x%x\n", ac_otd->bTerminalID);
87 uac_info->ot_usbs = ac_otd;
88 }
89 else if ((ac_otd->wTerminalType & 0x300) == 0x300)
90 {
91 USBAS_DBGMSG("SPEAKER output terminal found, ID=0x%x\n", ac_otd->bTerminalID);
92 uac_info->ot_speaker = ac_otd;
93 }
94 else
95 {
96 USBAS_DBGMSG("Unsupported OUTPUT TERMINAL, ignore it!\n");
97 }
98 USBAS_DBGMSG(" bTerminalID: 0%x\n", ac_otd->bTerminalID);
99 USBAS_DBGMSG(" wTerminalType: 0%x\n", ac_otd->wTerminalType);
100 USBAS_DBGMSG(" bAssocTerminal: 0%x\n", ac_otd->bAssocTerminal);
101 USBAS_DBGMSG(" bSourceID: 0%x\n", ac_otd->bSourceID);
102 break;
103
104 case MIXER_UNIT:
105 USBAS_DBGMSG("AC: MIXER_UNIT\n");
106#ifdef USBAS_DEBUG
107 ac_mxr = (AC_MXR_T *)buffer;
108 USBAS_DBGMSG(" bUnitID: 0%x\n", ac_mxr->bUnitID);
109 USBAS_DBGMSG(" bNrInPins: 0%x\n", ac_mxr->bNrInPins);
110#endif
111 break;
112
113 case SELECTOR_UNIT:
114 USBAS_DBGMSG("AC: SELECTOR_UNIT\n");
115#ifdef USBAS_DEBUG
116 ac_su = (AC_SU_T *)buffer;
117 USBAS_DBGMSG(" bUnitID: 0%x\n", ac_su->bUnitID);
118 USBAS_DBGMSG(" bNrInPins: 0%x\n", ac_su->bNrInPins);
119#endif
120 break;
121
122 case FEATURE_UNIT:
123 USBAS_DBGMSG("AC: FEATURE_UNIT\n");
124 if (fu_cnt < MAX_FEATURE_UNIT)
125 {
126 funit[fu_cnt] = (AC_FU_T *)buffer;
127 fu_cnt++;
128 }
129 else
130 {
131 USBAS_ERRMSG("Too many FEATURE UNITs, information may be lost!\n");
132 }
133#ifdef USBAS_DEBUG
134 ac_fu = (AC_FU_T *)buffer;
135 USBAS_DBGMSG(" bUnitID: 0%x\n", ac_fu->bUnitID);
136 USBAS_DBGMSG(" bSourceID: 0%x\n", ac_fu->bSourceID);
137 USBAS_DBGMSG(" bControlSize: 0%x\n", ac_fu->bControlSize);
138#endif
139 break;
140
141 case PROCESSING_UNIT:
142 USBAS_DBGMSG("AC: PROCESSING_UNIT\n");
143#ifdef USBAS_DEBUG
144 ac_pu = (AC_PU_T *)buffer;
145 USBAS_DBGMSG(" bUnitID: 0%x\n", ac_pu->bUnitID);
146 USBAS_DBGMSG(" wProcessType: 0%x\n", ac_pu->wProcessType);
147 USBAS_DBGMSG(" bNrInPins: 0%x\n", ac_pu->bNrInPins);
148#endif
149 break;
150
151 case EXTENSION_UNIT:
152 USBAS_DBGMSG("AC: EXTENSION_UNIT\n");
153 break;
154 }
155 }
156
157 if (ifp->bInterfaceSubClass == SUBCLS_AUDIOSTREAMING)
158 {
159 switch (hdr->bDescriptorSubtype)
160 {
161 case AS_DESCRIPTOR_UNDEFINED:
162 USBAS_DBGMSG("AS: AS_DESCRIPTOR_UNDEFINED\n");
163 break;
164
165 case AS_GENERAL:
166 USBAS_DBGMSG("AS: AS_GENERAL\n");
167 as_gen = (AS_GEN_T *)hdr;
168 uac_info->last_gen = as_gen;
169 USBAS_DBGMSG(" bTerminalLink: 0%x\n", as_gen->bTerminalLink);
170 USBAS_DBGMSG(" wFormatTag: 0%x\n", as_gen->wFormatTag);
171 break;
172
173 case FORMAT_TYPE:
174 uac_info->last_ft = (AC_FT1_T *)hdr;
175 USBAS_DBGMSG("AS: FORMAT_TYPE\n");
176 break;
177
178 case FORMAT_SPECIFIC:
179 USBAS_DBGMSG("AS: FORMAT_SPECIFIC\n");
180 break;
181 }
182 }
183
184 return hdr->bLength;
185}
186
187
188static int uac_parse_interface(UAC_DEV_T *audev, uint8_t *buffer, int size)
189{
190 UAC_INFO_T * uac_info = (UAC_INFO_T *)audev->priv;
191 USB_DESC_HDR_T * header=NULL;
192 static USB_IF_DESC_T *ifp;
193 USB_EP_DESC_T * ep;
194 int retval, parsed = 0;
195
196 while (size > 0)
197 {
198 while (size >= sizeof(USB_DESC_HDR_T))
199 {
200 header = (USB_DESC_HDR_T *)buffer;
201
202 if (header->bLength < 2)
203 {
204 USBAS_DBGMSG("Invalid descriptor length of %d\n", header->bLength);
205 return -1;
206 }
207
208 /* We interested in Audio Class-specific descriptor only. */
209 if ((header->bDescriptorType == USB_DT_INTERFACE) ||
210 (header->bDescriptorType == USB_DT_ENDPOINT) ||
211 (header->bDescriptorType == USB_DT_CONFIG) ||
212 (header->bDescriptorType == USB_DT_DEVICE) ||
213 (header->bDescriptorType == CS_INTERFACE) ||
214 (header->bDescriptorType == CS_ENDPOINT))
215 break;
216
217 USBAS_DBGMSG("IF skipping descriptor 0x%X\n", header->bDescriptorType);
218 buffer += header->bLength;
219 parsed += header->bLength;
220 size -= header->bLength;
221 }
222
223 if (header->bDescriptorType == USB_DT_INTERFACE)
224 {
225 ifp = (USB_IF_DESC_T *)buffer;
226
227 USBAS_DBGMSG("DT_INTERFACE\n");
228 USBAS_DBGMSG(" bInterfaceNumber: %d\n", ifp->bInterfaceNumber);
229
230 uac_info->last_ifd = ifp;
231
232 /* Skip over the interface */
233 buffer += ifp->bLength;
234 parsed += ifp->bLength;
235 size -= ifp->bLength;
236 }
237 else if (header->bDescriptorType == CS_INTERFACE)
238 {
239 retval = uac_parse_cs_interface(audev, uac_info->last_ifd, buffer, size);
240 if (retval < 0)
241 return retval;
242
243 buffer += retval;
244 parsed += retval;
245 size -= retval;
246 }
247 else if (header->bDescriptorType == CS_ENDPOINT)
248 {
249 USBAS_DBGMSG("CS_ENDPOINT\n");
250 buffer += header->bLength;
251 parsed += header->bLength;
252 size -= header->bLength;
253 }
254 else if (header->bDescriptorType == USB_DT_ENDPOINT)
255 {
256 ep = (USB_EP_DESC_T *)header;
257 USBAS_DBGMSG("USB_DT_ENDPOINT\n");
258 USBAS_DBGMSG(" bEndpointAddress: 0x%x, %s\n", ep->bEndpointAddress, (ep->bEndpointAddress & 0x80) ? "IN" : "OUT");
259 USBAS_DBGMSG(" wMaxPacketSize: %d\n", ep->wMaxPacketSize);
260 USBAS_DBGMSG(" bInterval: %d\n", ep->bInterval);
261
262 if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC)
263 {
264 if (ep->bEndpointAddress & 0x80) /* is IN endpoint? */
265 {
266 if (ep->wMaxPacketSize > AU_IN_MAX_PKTSZ)
267 {
268 USBAS_ERRMSG("IN endpoint packet size is larger than AU_IN_MAX_PKTSZ setting!\n");
270 }
271 uac_info->ifd_rec = uac_info->last_ifd;
272 uac_info->epd_rec = ep;
273 uac_info->gen_rec = uac_info->last_gen;
274 if ((uac_info->last_ft->bFormatType == FORMAT_TYPE_I) ||
275 (uac_info->last_ft->bFormatType == FORMAT_TYPE_III))
276 uac_info->ft_rec = uac_info->last_ft;
277 }
278 else
279 {
280 if (ep->wMaxPacketSize > AU_OUT_MAX_PKTSZ)
281 {
282 USBAS_ERRMSG("OUT endpoint packet size is larger than AU_OUT_MAX_PKTSZ setting!\n");
284 }
285 uac_info->ifd_play = uac_info->last_ifd;
286 uac_info->epd_play = ep;
287 uac_info->gen_play = uac_info->last_gen;
288 if ((uac_info->last_ft->bFormatType == FORMAT_TYPE_I) ||
289 (uac_info->last_ft->bFormatType == FORMAT_TYPE_III))
290 uac_info->ft_play = uac_info->last_ft;
291 }
292 }
293
294 buffer += header->bLength;
295 parsed += header->bLength;
296 size -= header->bLength;
297 }
298 else
299 {
300 USBAS_DBGMSG("Unexpected error occurred on parsing interface descriptor!\n");
301 break;
302 }
303
304 } /* end of while */
305 return parsed;
306}
307
308
309int uac_config_parser(UAC_DEV_T *audev)
310{
311 USB_DEV_T *udev = audev->udev;
312 UAC_INFO_T *uac_info = (UAC_INFO_T *)audev->priv;
313 USB_CONFIG_DESC_T *config;
314 USB_DESC_HDR_T *header;
315 uint8_t *buffer;
316 int i, length, size, result;
317
318 buffer = (uint8_t *)uac_info->cfg_desc;
319
320 config = (USB_CONFIG_DESC_T *)buffer;
321
322 USBAS_DBGMSG("\n\n");
323 USBAS_DBGMSG("+------------------------------+\n");
324 USBAS_DBGMSG("| UAC descriptor parser |\n");
325 USBAS_DBGMSG("+------------------------------+\n");
326
327 /*------------------------------------------------------------------*/
328 /* Get configuration descriptor from device... */
329 /*------------------------------------------------------------------*/
330
331 result = USBH_GetDescriptor(udev, USB_DT_CONFIG, 0, buffer, 8);
332 if (result < 8)
333 {
334 result = USB_ERR_INVAL;
335 return -1;
336 }
337
338 length = config->wTotalLength;
339 if (length > MAX_CFG_DESC_SIZE)
340 {
341 USBAS_ERRMSG("The Configuration descriptor of Audio Class device is too large.\n");
342 USBAS_ERRMSG("Please enlarge MAX_CFG_DESC_SIZE in usbh_uac.h to be larger than %d.\n", length);
343 return -1;
344 }
345
346 /* Now that we know the length, get the whole thing */
347 result = USBH_GetDescriptor(udev, USB_DT_CONFIG, 0, buffer, length);
348 if (result != length)
349 {
350 USBAS_DBGMSG("Failed to get configuration descriptor!\n");
351 return -1;
352 }
353
354 /*------------------------------------------------------------------*/
355 /* Parsing configuration descriptor... */
356 /*------------------------------------------------------------------*/
357
358 fu_cnt = 0;
359 buffer = (uint8_t *)uac_info->cfg_desc;
360 buffer += config->bLength;
361 size = config->wTotalLength - config->bLength;
362
363 for (i = 0; i < config->bNumInterfaces; i++)
364 {
365 /* Skip over the rest of the Class Specific or Vendor */
366 /* Specific descriptors */
367 while (size >= sizeof(USB_DESC_HDR_T))
368 {
369 header = (USB_DESC_HDR_T *)buffer;
370
371 if ((header->bLength > size) || (header->bLength < 2))
372 {
373 USBAS_DBGMSG("Error - invalid descriptor length of %d\n", header->bLength);
374 return -1;
375 }
376
377 /* If we find another descriptor which is at or below */
378 /* us in the descriptor heirarchy then we're done */
379 if ((header->bDescriptorType == USB_DT_ENDPOINT) ||
380 (header->bDescriptorType == USB_DT_INTERFACE) ||
381 (header->bDescriptorType == USB_DT_CONFIG) ||
382 (header->bDescriptorType == USB_DT_DEVICE) ||
383 (header->bDescriptorType == CS_INTERFACE) ||
384 (header->bDescriptorType == CS_ENDPOINT))
385 break;
386
387 USBAS_DBGMSG("CFG skipping descriptor 0x%X\n", header->bDescriptorType);
388
389 buffer += header->bLength;
390 size -= header->bLength;
391 } /* end of while */
392
393 result = uac_parse_interface(audev, buffer, size);
394 if (result < 0)
395 return -1;
396
397 buffer += result;
398 size -= result;
399 }
400
401 if ((uac_info->gen_play == NULL) && (uac_info->gen_rec == NULL))
402 {
403 USBAS_ERRMSG("Audio stream interface not found!\n");
404 return -1;
405 }
406
407 for (i = 0; i < fu_cnt; i++)
408 {
409 if (funit[i]->bSourceID == uac_info->it_microphone->bTerminalID)
410 {
411 uac_info->fu_rec = funit[i];
412 break;
413 }
414 }
415
416 for (i = 0; i < fu_cnt; i++)
417 {
418 if (funit[i]->bUnitID == uac_info->ot_speaker->bSourceID)
419 {
420 uac_info->fu_play = funit[i];
421 break;
422 }
423 }
424
425 if (uac_info->fu_play)
426 USBAS_DBGMSG("FEATURE UNIT for playback is 0x%x\n", uac_info->fu_play->bUnitID);
427
428 if (uac_info->fu_rec)
429 USBAS_DBGMSG("FEATURE UNIT for record is 0x%x\n", uac_info->fu_rec->bUnitID);
430
431 return 0;
432}
433
434
435int uac_check_fu_ctrl(UAC_INFO_T *uac_info, uint8_t target, int channel, int control)
436{
437 AC_FU_T *fu = NULL;
438 AC_FT1_T *ft = NULL;
439 uint8_t *bptr;
440 uint16_t bitmap;
441
442 if (channel == 0)
443 return 0; /* always fine for master channel */
444
445 if (target == UAC_SPEAKER)
446 {
447 fu = uac_info->fu_play;
448 ft = uac_info->ft_play;
449 }
450 else if (target == UAC_MICROPHONE)
451 {
452 fu = uac_info->fu_rec;
453 ft = uac_info->ft_rec;
454 }
455 else
456 return UAC_RET_INVALID;
457
458 if (!fu || !ft)
460
461 if (channel > ft->bNrChannels)
463
464 bptr = (uint8_t *)fu + 6 + fu->bControlSize * (channel - 1);
465
466 if (fu->bControlSize == 1)
467 bitmap = *bptr;
468 else
469 bitmap = *bptr | (*(bptr+1) << 8);
470
471 USBAS_DBGMSG("channel %d bmaControl is 0x%x\n", channel, bitmap);
472
473 if (bitmap & (1 << (control-1)))
474 return 0; // UAC device support this control.
475 else
477}
478
479
481
482/*** (C) COPYRIGHT 2014 Nuvoton Technology Corp. ***/
483
NUC472/NUC442 peripheral access layer header file. This file contains all the peripheral register's d...
#define UAC_MICROPHONE
Definition: usbh_uac.h:29
#define UAC_SPEAKER
Definition: usbh_uac.h:28
#define MAX_FEATURE_UNIT
Definition: usbh_uac.h:21
#define UAC_RET_INVALID
Definition: usbh_uac.h:38
#define UAC_RET_DEV_NOT_SUPPORTED
Definition: usbh_uac.h:41
#define AU_IN_MAX_PKTSZ
Definition: usbh_uac.h:24
#define UAC_RET_DRV_NOT_SUPPORTED
Definition: usbh_uac.h:40
#define MAX_CFG_DESC_SIZE
Definition: usbh_uac.h:20
#define AU_OUT_MAX_PKTSZ
Definition: usbh_uac.h:25
void * priv
Definition: usbh_uac.h:105
USB_DEV_T * udev
Definition: usbh_uac.h:101
#define USB_ERR_INVAL
Definition: usbh_err_code.h:24
int32_t USBH_GetDescriptor(USB_DEV_T *dev, uint8_t type, uint8_t index, void *buf, int size)
Get a descriptor from device.
Definition: usbh_core.c:822
USB_IF_DESC_T
Definition: usbh_core.h:335
USB_CONFIG_DESC_T
Definition: usbh_core.h:366
HIDDEN_SYMBOLS struct usb_device USB_DEV_T
USB_EP_DESC_T
Definition: usbh_core.h:300
#define NULL
NULL pointer.
Definition: NUC472_442.h:29018
USB Host core driver header file.