M480 BSP  V3.05.001
The Board Support Package for M480 Series
uac_driver.c
Go to the documentation of this file.
1 /**************************************************************************/
11 #include <stdio.h>
12 #include <string.h>
13 
14 #include "NuMicro.h"
15 
16 #include "usb.h"
17 #include "usbh_lib.h"
18 #include "usbh_uac.h"
19 #include "uac.h"
20 
21 
34 
36 static UAC_DEV_T g_uac_dev[CONFIG_UAC_MAX_DEV];
37 
38 static UAC_DEV_T *g_uac_list = NULL;
39 
40 
41 static UAC_DEV_T *alloc_uac_device(void)
42 {
43  int i;
44 
45  for (i = 0; i < CONFIG_UAC_MAX_DEV; i++)
46  {
47  if (g_uac_dev[i].udev == NULL)
48  {
49  memset((char *)&g_uac_dev[i], 0, sizeof(UAC_DEV_T));
50  return &g_uac_dev[i];
51  }
52  }
53  return NULL;
54 }
55 
56 static void free_uac_device(UAC_DEV_T *uac)
57 {
58  uac->udev = NULL;
59 }
60 
61 UAC_DEV_T *find_uac_device(UDEV_T *udev)
62 {
63  int i;
64 
65  if (udev == NULL)
66  return NULL;
67 
68  for (i = 0; i < CONFIG_UAC_MAX_DEV; i++)
69  {
70  if (g_uac_dev[i].udev == udev)
71  {
72  return &g_uac_dev[i];
73  }
74  }
75  return NULL;
76 }
77 
78 
79 static int uac_probe(IFACE_T *iface)
80 {
81  UDEV_T *udev = iface->udev;
82  ALT_IFACE_T *aif = iface->aif;
83  DESC_IF_T *ifd;
84  UAC_DEV_T *uac, *p;
85  uint8_t bAlternateSetting;
86  int ret;
87 
88  ifd = aif->ifd;
89 
90  /* Is this interface Audio class? */
91  if (ifd->bInterfaceClass != USB_CLASS_AUDIO)
92  return USBH_ERR_NOT_MATCHED;
93 
94  if ((ifd->bInterfaceSubClass != SUBCLS_AUDIOCONTROL) &&
95  (ifd->bInterfaceSubClass != SUBCLS_AUDIOSTREAMING))
96  {
97  UAC_ERRMSG("Audio class interface, but sub-class %x not supported!\n", ifd->bInterfaceSubClass);
98  return USBH_ERR_NOT_MATCHED;
99  }
100 
101  UAC_DBGMSG("\nuac_probe - device (vid=0x%x, pid=0x%x), interface %d, type: %s\n",
102  udev->descriptor.idVendor, udev->descriptor.idProduct, iface->if_num, (ifd->bInterfaceSubClass == SUBCLS_AUDIOCONTROL) ? "CONTROL" : "STREAM");
103 
104  uac = find_uac_device(udev);
105  if (uac == NULL)
106  {
107  /* UAC device should has not been created in the previous probe of the other interface */
108  /* return 0 to make USB core adding this interface to device working interface list. */
109  uac = alloc_uac_device();
110  if (uac == NULL)
111  return UAC_RET_OUT_OF_MEMORY;
112 
113  uac->udev = udev;
114  uac->state = UAC_STATE_CONNECTING;
115 
116  /* Add newly found Audio Class device to end of Audio Class device list.
117  */
118  if (g_uac_list == NULL)
119  {
120  g_uac_list = uac;
121  }
122  else
123  {
124  for (p = g_uac_list; p->next != NULL; p = p->next)
125  ;
126  p->next = uac;
127  }
128  }
129 
130  iface->context = (void *)uac;
131 
132  if (ifd->bInterfaceSubClass == SUBCLS_AUDIOSTREAMING)
133  {
134  if ((usbh_uac_find_max_alt(iface, EP_ADDR_DIR_IN, EP_ATTR_TT_ISO, &bAlternateSetting) == 0) ||
135  (usbh_uac_find_max_alt(iface, EP_ADDR_DIR_OUT, EP_ATTR_TT_ISO, &bAlternateSetting) == 0))
136  {
137  ret = usbh_set_interface(iface, bAlternateSetting);
138  if (ret < 0)
139  {
140  UAC_ERRMSG("Failed to set interface %d, %d! (%d)\n", iface->if_num, bAlternateSetting, ret);
141  return UAC_RET_IO_ERR;
142  }
143  }
144  else
145  {
146  UAC_ERRMSG("Cannot find audio stream endpoints!\n");
147  return UAC_RET_DEV_NOT_FOUND;
148  }
149 
150  ret = uac_parse_streaming_interface(uac, iface, bAlternateSetting);
151  if (ret < 0)
152  return ret;
153  }
154  else if (ifd->bInterfaceSubClass == SUBCLS_AUDIOCONTROL)
155  {
156  ret = uac_parse_control_interface(uac, iface);
157  if (ret < 0)
158  return ret;
159  }
160 
161  UAC_DBGMSG("UAC device 0x%x ==>\n", (int)uac);
162  UAC_DBGMSG(" CONTROL IFACE: 0x%x\n", (int)uac->acif.iface);
163  UAC_DBGMSG(" STREAM IN IFACE: 0x%x\n", (int)uac->asif_in.iface);
164  UAC_DBGMSG(" STREAM OUT IFACE: 0x%x\n", (int)uac->asif_out.iface);
165 
166  return ret;
167 }
168 
169 static void uac_disconnect(IFACE_T *iface)
170 {
171  UAC_DEV_T *uac, *p;
172  //ALT_IFACE_T *aif = iface->aif;
173  int i;
174 
175  uac = (UAC_DEV_T *)iface->context;
176 
177  uac->state = UAC_STATE_DISCONNECTING;
178 
179  UAC_DBGMSG("uac_disconnect - device (vid=0x%x, pid=0x%x), interface %d removed.\n",
180  uac->udev->descriptor.idVendor, uac->udev->descriptor.idProduct, iface->if_num);
181 
182  /*
183  * remove it from UAC device list
184  */
185  for (i = 0; i < CONFIG_UAC_MAX_DEV; i++)
186  {
187  if (g_uac_dev[i].udev == iface->udev)
188  {
189  uac = &g_uac_dev[i];
190 
191  if (uac->acif.iface == iface)
192  {
193  uac->acif.iface = NULL;
194  }
195  else if (uac->asif_in.iface == iface)
196  {
198  uac->asif_in.iface = NULL;
199  }
200  else if (uac->asif_out.iface == iface)
201  {
203  uac->asif_out.iface = NULL;
204  }
205 
206  if ((uac->acif.iface != NULL) || (uac->asif_in.iface != NULL) || (uac->asif_out.iface != NULL))
207  continue;
208 
209  /*
210  * All interface of UAC device are all disconnected. Remove it from UAC device list.
211  */
212 
213  if (uac == g_uac_list)
214  {
215  g_uac_list = g_uac_list->next;
216  }
217  else
218  {
219  for (p = g_uac_list; p != NULL; p = p->next)
220  {
221  if (p->next == uac)
222  {
223  p->next = uac->next;
224  break;
225  }
226  }
227  }
228  UAC_DBGMSG("uac_disconnect - device (vid=0x%x, pid=0x%x), UAC device removed.\n",
229  uac->udev->descriptor.idVendor, uac->udev->descriptor.idProduct);
230  free_uac_device(uac);
231  }
232  }
233 }
234 
235 UDEV_DRV_T uac_driver =
236 {
237  uac_probe,
238  uac_disconnect,
239  NULL, /* suspend */
240  NULL, /* resume */
241 };
242 
243 
245 
250 void usbh_uac_init(void)
251 {
252  memset((char *)&g_uac_dev[0], 0, sizeof(g_uac_dev));
253  g_uac_list = NULL;
254  usbh_register_driver(&uac_driver);
255 }
256 
257 
267 {
268  return g_uac_list;
269 }
270 
271  /* end of group USBH_EXPORTED_FUNCTIONS */
273  /* end of group USBH_Library */
275  /* end of group LIBRARY */
277 
278 /*** (C) COPYRIGHT 2016 Nuvoton Technology Corp. ***/
279 
struct uac_dev_t * usbh_uac_get_device_list(void)
Get a list of currently connected USB Audio Class devices.
Definition: uac_driver.c:266
UAC_STATE_E state
Definition: usbh_uac.h:118
USB Host UAC class driver header file.
#define UAC_RET_DEV_NOT_FOUND
Definition: usbh_lib.h:97
#define UAC_RET_IO_ERR
Definition: usbh_lib.h:99
int usbh_uac_stop_audio_in(struct uac_dev_t *audev)
Stop UAC device audio in data stream.
Definition: uac_core.c:703
NuMicro peripheral access layer header file.
IFACE_T * iface
Definition: usbh_uac.h:82
M480 MCU USB Host Audio Class header file.
USB Host library exported header file.
AS_IF_T asif_in
Definition: usbh_uac.h:113
#define UAC_RET_OUT_OF_MEMORY
Definition: usbh_lib.h:102
HIDDEN_SYMBOLS void usbh_uac_init(void)
Initialize USB Audio Class driver.
Definition: uac_driver.c:250
AS_IF_T asif_out
Definition: usbh_uac.h:114
int usbh_uac_stop_audio_out(struct uac_dev_t *audev)
Stop UAC device audio out data stream.
Definition: uac_core.c:946
#define CONFIG_UAC_MAX_DEV
Definition: usbh_uac.h:31
UDEV_T * udev
Definition: usbh_uac.h:111
IFACE_T * iface
Definition: usbh_uac.h:94
USB Host library header file.
struct uac_dev_t * next
Definition: usbh_uac.h:119
#define NULL
NULL pointer.
Definition: M480.h:604
#define USBH_ERR_NOT_MATCHED
Definition: usbh_lib.h:36
AC_IF_T acif
Definition: usbh_uac.h:112