1 /* ----------------------------------------------------------------------------
2 * Copyright (c) Huawei Technologies Co., Ltd. 2017-2019. All rights reserved.
3 * Description: LiteOS USB Driver Audio Stream
4 * Author: huangjieliang
5 * Create: 2017-12-12
6 * Redistribution and use in source and binary forms, with or without modification,
7 * are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
14 * to endorse or promote products derived from this software without specific prior written
15 * permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 * --------------------------------------------------------------------------- */
28 /* ----------------------------------------------------------------------------
29 * Notice of Export Control Law
30 * ===============================================
31 * Huawei LiteOS may be subject to applicable export control laws and regulations, which might
32 * include those applicable to Huawei LiteOS of U.S. and the country in which you are located.
33 * Import, export and usage of Huawei LiteOS in any manner by you shall be in compliance with such
34 * applicable export control laws and regulations.
35 * --------------------------------------------------------------------------- */
36
37 #include "gadget/usbd_audio.h"
38 #include "gadget/f_uac.h"
39 #include "implementation/global_implementation.h"
40
41 #ifdef __cplusplus
42 #if __cplusplus
43 extern "C" {
44 #endif /* __cplusplus */
45 #endif /* __cplusplus */
46
get_uac(void)47 static struct uac_softc *get_uac(void)
48 {
49 devclass_t dc;
50 device_t dev;
51 struct composite_softc *cdev;
52 struct composite_devobj_s *devobj;
53 struct usbdevclass_driver_s *drvr;
54 struct uac_driver_s *driver;
55
56 dc = devclass_find("composite");
57 if (dc == NULL)
58 {
59 PRINT_ERR("%s is failed\n", __FUNCTION__);
60 return NULL;
61 }
62 dev = devclass_get_device(dc, 0);
63 if (dev == NULL)
64 {
65 PRINT_ERR("%s, get dev failed\n", __FUNCTION__);
66 return NULL;
67 }
68 cdev = (struct composite_softc *)device_get_softc(dev);
69 if (cdev == NULL)
70 {
71 PRINT_ERR("%s, get softc failed\n", __FUNCTION__);
72 return NULL;
73 }
74
75 devobj = usbclass_devobj_get(&cdev->dev, DEV_UAC);
76 if (devobj == NULL)
77 {
78 return NULL;
79 }
80
81 drvr = devobj->dev;
82 if (drvr == NULL)
83 {
84 PRINT_ERR("%s, get driver failed\n", __FUNCTION__);
85 return NULL;
86 }
87 driver = (struct uac_driver_s *)drvr;
88
89 return container_of(driver, struct uac_softc, drvr);
90 }
91
fuac_host_connected(struct uac_dev_s * fuac)92 static int fuac_host_connected(struct uac_dev_s *fuac)
93 {
94 if (fuac == NULL)
95 {
96 return 0;
97 }
98
99 return fuac->connected;
100 }
101
uac_wait_hot_sub(void)102 static int uac_wait_hot_sub(void)
103 {
104 int ret;
105 struct uac_softc *fuac;
106 struct uac_dev_s *dev;
107
108 mtx_lock(&usb_mtx);
109 fuac = get_uac();
110 if (fuac == NULL)
111 {
112 mtx_unlock(&usb_mtx);
113 return UAC_ERROR_PTR;
114 }
115 dev = &fuac->dev;
116 ret = fuac_host_connected(dev) ;
117 mtx_unlock(&usb_mtx);
118
119 return ret;
120 }
121
uac_wait_host(int wait_option)122 int uac_wait_host(int wait_option)
123 {
124 int ret;
125
126 switch (wait_option)
127 {
128 case UAC_WAIT_HOST_NOP:
129 ret = uac_wait_hot_sub();
130 if (ret == 0) /* Device is not connected. */
131 {
132 ret = UAC_ERROR_NOMATCH;
133 }
134 else if (ret == 1) /* Device is connected. */
135 {
136 ret = UAC_OK;
137 }
138 break;
139
140 case UAC_WAIT_HOST_FOREVER:
141 while (!(ret = uac_wait_hot_sub()))
142 {
143 (void)LOS_TaskDelay(10);
144 }
145
146 if (ret != UAC_ERROR_PTR)
147 {
148 ret = UAC_OK;
149 }
150 break;
151
152 default:
153 return UAC_ERROR_VALUE;
154 }
155
156 return ret;
157 }
158
uac_queue_node_alloc(unsigned len)159 struct uac_queue_node *uac_queue_node_alloc(unsigned len)
160 {
161 struct uac_queue_node *queue_node;
162
163 queue_node = zalloc(sizeof(struct uac_queue_node));
164 if (queue_node == NULL)
165 {
166 PRINT_ERR("%s, malloc uac queue node failed\n", __FUNCTION__);
167 return NULL;
168 }
169
170 queue_node->buf_len = len;
171 queue_node->buf_used = 0;
172 queue_node->buf = malloc(len);
173 if (queue_node->buf == NULL)
174 {
175 free(queue_node);
176 PRINT_ERR("%s, malloc uac queue node buf failed\n", __FUNCTION__);
177 return NULL;
178 }
179
180 return queue_node;
181 }
182
uac_queue_node_free(struct uac_queue_node * node)183 void uac_queue_node_free(struct uac_queue_node *node)
184 {
185 free(node->buf);
186 node->buf = NULL;
187 free(node);
188 }
189
uac_send_data_sub(struct uac_dev_s * sc)190 void uac_send_data_sub(struct uac_dev_s *sc)
191 {
192 struct uac_dev_s *fuac = sc;
193 struct uac_queue_node *node = fuac->cur_node;
194 struct usbdev_req_s *req = &fuac->inputreq;
195
196 atomic_set(&fuac->busy_flag, 1);
197
198 if (node->buf_len > g_uac_iso_data_size)
199 {
200 req->len = g_uac_iso_data_size;
201 }
202 else
203 {
204 req->len = node->buf_len;
205 }
206 req->buf = node->buf + node->buf_used;
207
208 node->buf_len -= req->len;
209 node->buf_used += req->len;
210 (void)EP_SUBMIT(fuac->in_ep, req);
211 }
212
uac_queue_free(struct uac_dev_s * sc)213 void uac_queue_free(struct uac_dev_s *sc)
214 {
215 struct uac_queue_node *node;
216 struct uac_dev_s *fuac_sc = sc;
217
218 if (fuac_sc->cur_node != NULL)
219 {
220 uac_queue_node_free(fuac_sc->cur_node);
221 fuac_sc->cur_node = NULL;
222 }
223
224 while (!list_empty(&fuac_sc->uac_queue))
225 {
226 node = list_first_entry(&fuac_sc->uac_queue, struct uac_queue_node, irqqueue);
227 list_del_init(&node->irqqueue);
228 uac_queue_node_free(node);
229 }
230 INIT_LIST_HEAD(&fuac_sc->uac_queue);
231
232 fuac_sc->uac_queue_len = 0;
233 }
234
fuac_send_message(const void * buf,int len)235 int fuac_send_message(const void *buf, int len)
236 {
237 struct uac_softc *fuac;
238 struct uac_dev_s *dev;
239 struct uac_queue_node *node;
240 struct uac_queue_node *node_tx;
241 uint32_t flags;
242 int ret = 0;
243
244 if (buf == NULL || len < 0)
245 {
246 return UAC_ERROR_PTR;
247 }
248
249 node = uac_queue_node_alloc(len);
250 if (node == NULL)
251 {
252 return UAC_ERROR_MEMORY;
253 }
254 (void)memcpy_s(node->buf, len, buf, len);
255
256 mtx_lock(&usb_mtx);
257 fuac = get_uac();
258 if (fuac == NULL)
259 {
260 uac_queue_node_free(node);
261 PRINT_ERR("%s, get uac failed\n", __FUNCTION__);
262 ret = UAC_ERROR_PTR;
263 goto error;
264 }
265 dev = &fuac->dev;
266 spin_lock_irqsave(&dev->lock, flags);
267 if (!dev->connected)
268 {
269 uac_queue_node_free(node);
270 goto done;
271 }
272
273 if (dev->uac_queue_len > 8)
274 {
275 uac_queue_free(dev);
276 }
277
278 list_add_tail(&node->irqqueue, &dev->uac_queue);
279 dev->uac_queue_len++;
280
281 if (atomic_read(&dev->busy_flag))
282 {
283 goto done;
284 }
285
286 (void)EP_DISABLE(dev->in_ep);
287 (void)EP_CONFIGURE(dev->in_ep, (const usb_endpoint_descriptor_t *)&g_fuac_as_in_ep_desc, 0);
288
289 if (!list_empty(&dev->uac_queue))
290 {
291 node_tx = list_first_entry(&dev->uac_queue, struct uac_queue_node, irqqueue);
292 list_del_init(&node_tx->irqqueue);
293 dev->uac_queue_len--;
294 dev->cur_node = node_tx;
295 uac_send_data_sub(dev);
296 }
297
298 done:
299 spin_unlock_irqrestore(&dev->lock, flags);
300
301 error:
302 mtx_unlock(&usb_mtx);
303 return ret;
304 }
305
306 #ifdef __cplusplus
307 #if __cplusplus
308 }
309 #endif /* __cplusplus */
310 #endif /* __cplusplus */