1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2010 Hans Petter Selasky. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 /*
29 * USB audio specs: http://www.usb.org/developers/devclass_docs/audio10.pdf
30 * http://www.usb.org/developers/devclass_docs/frmts10.pdf
31 * http://www.usb.org/developers/devclass_docs/termt10.pdf
32 */
33
34 #include <sys/param.h>
35 #include <sys/stdint.h>
36 #include <sys/stddef.h>
37 #include <sys/queue.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/bus.h>
41 #include <sys/linker_set.h>
42 #include <sys/module.h>
43 #include <sys/lock.h>
44 #include <sys/mutex.h>
45 #include <sys/condvar.h>
46 #include <sys/sysctl.h>
47 #include <sys/sx.h>
48 #include <sys/unistd.h>
49 #include <sys/callout.h>
50 #include <sys/malloc.h>
51 #include <sys/priv.h>
52
53 #include <dev/usb/usb.h>
54 #include <dev/usb/usb_cdc.h>
55 #include <dev/usb/usbdi.h>
56 #include <dev/usb/usbdi_util.h>
57 #include <dev/usb/usbhid.h>
58 #include "usb_if.h"
59
60 #define USB_DEBUG_VAR g_audio_debug
61 #include <dev/usb/usb_debug.h>
62
63 #include <dev/usb/gadget/g_audio.h>
64
65 enum {
66 G_AUDIO_ISOC0_RD,
67 G_AUDIO_ISOC1_RD,
68 G_AUDIO_ISOC0_WR,
69 G_AUDIO_ISOC1_WR,
70 G_AUDIO_N_TRANSFER,
71 };
72
73 struct g_audio_softc {
74 struct mtx sc_mtx;
75 struct usb_callout sc_callout;
76 struct usb_callout sc_watchdog;
77 struct usb_xfer *sc_xfer[G_AUDIO_N_TRANSFER];
78
79 int sc_mode;
80 int sc_pattern_len;
81 int sc_throughput;
82 int sc_tx_interval;
83 int sc_state;
84 int sc_noise_rem;
85
86 int8_t sc_pattern[G_AUDIO_MAX_STRLEN];
87
88 uint16_t sc_data_len[2][G_AUDIO_FRAMES];
89
90 int16_t sc_data_buf[2][G_AUDIO_BUFSIZE / 2];
91
92 uint8_t sc_volume_setting[32];
93 uint8_t sc_volume_limit[32];
94 uint8_t sc_sample_rate[32];
95 };
96
97 static SYSCTL_NODE(_hw_usb, OID_AUTO, g_audio, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
98 "USB audio gadget");
99
100 #ifdef USB_DEBUG
101 static int g_audio_debug = 0;
102
103 SYSCTL_INT(_hw_usb_g_audio, OID_AUTO, debug, CTLFLAG_RWTUN,
104 &g_audio_debug, 0, "Debug level");
105 #endif
106
107 static int g_audio_mode = 0;
108
109 SYSCTL_INT(_hw_usb_g_audio, OID_AUTO, mode, CTLFLAG_RWTUN,
110 &g_audio_mode, 0, "Mode selection");
111
112 static int g_audio_pattern_interval = 1000;
113
114 SYSCTL_INT(_hw_usb_g_audio, OID_AUTO, pattern_interval, CTLFLAG_RWTUN,
115 &g_audio_pattern_interval, 0, "Pattern interval in milliseconds");
116
117 static char g_audio_pattern_data[G_AUDIO_MAX_STRLEN];
118
119 SYSCTL_STRING(_hw_usb_g_audio, OID_AUTO, pattern, CTLFLAG_RW,
120 &g_audio_pattern_data, sizeof(g_audio_pattern_data), "Data pattern");
121
122 static int g_audio_throughput;
123
124 SYSCTL_INT(_hw_usb_g_audio, OID_AUTO, throughput, CTLFLAG_RD,
125 &g_audio_throughput, sizeof(g_audio_throughput), "Throughput in bytes per second");
126
127 static device_probe_t g_audio_probe;
128 static device_attach_t g_audio_attach;
129 static device_detach_t g_audio_detach;
130 static usb_handle_request_t g_audio_handle_request;
131
132 static usb_callback_t g_audio_isoc_read_callback;
133 static usb_callback_t g_audio_isoc_write_callback;
134
135 static void g_audio_watchdog(void *arg);
136 static void g_audio_timeout(void *arg);
137
138 static device_method_t g_audio_methods[] = {
139 /* USB interface */
140 DEVMETHOD(usb_handle_request, g_audio_handle_request),
141
142 /* Device interface */
143 DEVMETHOD(device_probe, g_audio_probe),
144 DEVMETHOD(device_attach, g_audio_attach),
145 DEVMETHOD(device_detach, g_audio_detach),
146
147 DEVMETHOD_END
148 };
149
150 static driver_t g_audio_driver = {
151 .name = "g_audio",
152 .methods = g_audio_methods,
153 .size = sizeof(struct g_audio_softc),
154 };
155
156 DRIVER_MODULE(g_audio, uhub, g_audio_driver, 0, 0);
157 MODULE_DEPEND(g_audio, usb, 1, 1, 1);
158
159 static const struct usb_config g_audio_config[G_AUDIO_N_TRANSFER] = {
160 [G_AUDIO_ISOC0_RD] = {
161 .type = UE_ISOCHRONOUS,
162 .endpoint = UE_ADDR_ANY,
163 .direction = UE_DIR_RX,
164 .flags = {.ext_buffer = 1,.pipe_bof = 1,.short_xfer_ok = 1,},
165 .bufsize = G_AUDIO_BUFSIZE,
166 .callback = &g_audio_isoc_read_callback,
167 .frames = G_AUDIO_FRAMES,
168 .usb_mode = USB_MODE_DEVICE,
169 .if_index = 1,
170 },
171
172 [G_AUDIO_ISOC1_RD] = {
173 .type = UE_ISOCHRONOUS,
174 .endpoint = UE_ADDR_ANY,
175 .direction = UE_DIR_RX,
176 .flags = {.ext_buffer = 1,.pipe_bof = 1,.short_xfer_ok = 1,},
177 .bufsize = G_AUDIO_BUFSIZE,
178 .callback = &g_audio_isoc_read_callback,
179 .frames = G_AUDIO_FRAMES,
180 .usb_mode = USB_MODE_DEVICE,
181 .if_index = 1,
182 },
183
184 [G_AUDIO_ISOC0_WR] = {
185 .type = UE_ISOCHRONOUS,
186 .endpoint = UE_ADDR_ANY,
187 .direction = UE_DIR_TX,
188 .flags = {.ext_buffer = 1,.pipe_bof = 1,},
189 .bufsize = G_AUDIO_BUFSIZE,
190 .callback = &g_audio_isoc_write_callback,
191 .frames = G_AUDIO_FRAMES,
192 .usb_mode = USB_MODE_DEVICE,
193 .if_index = 2,
194 },
195
196 [G_AUDIO_ISOC1_WR] = {
197 .type = UE_ISOCHRONOUS,
198 .endpoint = UE_ADDR_ANY,
199 .direction = UE_DIR_TX,
200 .flags = {.ext_buffer = 1,.pipe_bof = 1,},
201 .bufsize = G_AUDIO_BUFSIZE,
202 .callback = &g_audio_isoc_write_callback,
203 .frames = G_AUDIO_FRAMES,
204 .usb_mode = USB_MODE_DEVICE,
205 .if_index = 2,
206 },
207 };
208
209 static void
g_audio_timeout_reset(struct g_audio_softc * sc)210 g_audio_timeout_reset(struct g_audio_softc *sc)
211 {
212 int i = g_audio_pattern_interval;
213
214 sc->sc_tx_interval = i;
215
216 if (i <= 0)
217 i = 1;
218 else if (i > 1023)
219 i = 1023;
220
221 i = USB_MS_TO_TICKS(i);
222
223 usb_callout_reset(&sc->sc_callout, i, &g_audio_timeout, sc);
224 }
225
226 static void
g_audio_timeout(void * arg)227 g_audio_timeout(void *arg)
228 {
229 struct g_audio_softc *sc = arg;
230
231 sc->sc_mode = g_audio_mode;
232
233 memcpy(sc->sc_pattern, g_audio_pattern_data, sizeof(sc->sc_pattern));
234
235 sc->sc_pattern[G_AUDIO_MAX_STRLEN - 1] = 0;
236
237 sc->sc_pattern_len = strlen(sc->sc_pattern);
238
239 if (sc->sc_mode != G_AUDIO_MODE_LOOP) {
240 usbd_transfer_start(sc->sc_xfer[G_AUDIO_ISOC0_WR]);
241 usbd_transfer_start(sc->sc_xfer[G_AUDIO_ISOC1_WR]);
242 }
243 g_audio_timeout_reset(sc);
244 }
245
246 static void
g_audio_watchdog_reset(struct g_audio_softc * sc)247 g_audio_watchdog_reset(struct g_audio_softc *sc)
248 {
249 usb_callout_reset(&sc->sc_watchdog, hz, &g_audio_watchdog, sc);
250 }
251
252 static void
g_audio_watchdog(void * arg)253 g_audio_watchdog(void *arg)
254 {
255 struct g_audio_softc *sc = arg;
256 int i;
257
258 i = sc->sc_throughput;
259
260 sc->sc_throughput = 0;
261
262 g_audio_throughput = i;
263
264 g_audio_watchdog_reset(sc);
265 }
266
267 static int
g_audio_probe(device_t dev)268 g_audio_probe(device_t dev)
269 {
270 struct usb_attach_arg *uaa = device_get_ivars(dev);
271
272 DPRINTFN(11, "\n");
273
274 if (uaa->usb_mode != USB_MODE_DEVICE)
275 return (ENXIO);
276
277 if ((uaa->info.bInterfaceClass == UICLASS_AUDIO) &&
278 (uaa->info.bInterfaceSubClass == UISUBCLASS_AUDIOCONTROL))
279 return (0);
280
281 return (ENXIO);
282 }
283
284 static int
g_audio_attach(device_t dev)285 g_audio_attach(device_t dev)
286 {
287 struct g_audio_softc *sc = device_get_softc(dev);
288 struct usb_attach_arg *uaa = device_get_ivars(dev);
289 int error;
290 int i;
291 uint8_t iface_index[3];
292
293 DPRINTFN(11, "\n");
294
295 device_set_usb_desc(dev);
296
297 mtx_init(&sc->sc_mtx, "g_audio", NULL, MTX_DEF);
298
299 usb_callout_init_mtx(&sc->sc_callout, &sc->sc_mtx, 0);
300 usb_callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 0);
301
302 sc->sc_mode = G_AUDIO_MODE_SILENT;
303
304 sc->sc_noise_rem = 1;
305
306 for (i = 0; i != G_AUDIO_FRAMES; i++) {
307 sc->sc_data_len[0][i] = G_AUDIO_BUFSIZE / G_AUDIO_FRAMES;
308 sc->sc_data_len[1][i] = G_AUDIO_BUFSIZE / G_AUDIO_FRAMES;
309 }
310
311 iface_index[0] = uaa->info.bIfaceIndex;
312 iface_index[1] = uaa->info.bIfaceIndex + 1;
313 iface_index[2] = uaa->info.bIfaceIndex + 2;
314
315 error = usbd_set_alt_interface_index(uaa->device, iface_index[1], 1);
316 if (error) {
317 DPRINTF("alt iface setting error=%s\n", usbd_errstr(error));
318 goto detach;
319 }
320 error = usbd_set_alt_interface_index(uaa->device, iface_index[2], 1);
321 if (error) {
322 DPRINTF("alt iface setting error=%s\n", usbd_errstr(error));
323 goto detach;
324 }
325 error = usbd_transfer_setup(uaa->device,
326 iface_index, sc->sc_xfer, g_audio_config,
327 G_AUDIO_N_TRANSFER, sc, &sc->sc_mtx);
328
329 if (error) {
330 DPRINTF("error=%s\n", usbd_errstr(error));
331 goto detach;
332 }
333 usbd_set_parent_iface(uaa->device, iface_index[1], iface_index[0]);
334 usbd_set_parent_iface(uaa->device, iface_index[2], iface_index[0]);
335
336 mtx_lock(&sc->sc_mtx);
337
338 usbd_transfer_start(sc->sc_xfer[G_AUDIO_ISOC0_RD]);
339 usbd_transfer_start(sc->sc_xfer[G_AUDIO_ISOC1_RD]);
340
341 usbd_transfer_start(sc->sc_xfer[G_AUDIO_ISOC0_WR]);
342 usbd_transfer_start(sc->sc_xfer[G_AUDIO_ISOC1_WR]);
343
344 g_audio_timeout_reset(sc);
345
346 g_audio_watchdog_reset(sc);
347
348 mtx_unlock(&sc->sc_mtx);
349
350 return (0); /* success */
351
352 detach:
353 g_audio_detach(dev);
354
355 return (ENXIO); /* error */
356 }
357
358 static int
g_audio_detach(device_t dev)359 g_audio_detach(device_t dev)
360 {
361 struct g_audio_softc *sc = device_get_softc(dev);
362
363 DPRINTF("\n");
364
365 mtx_lock(&sc->sc_mtx);
366 usb_callout_stop(&sc->sc_callout);
367 usb_callout_stop(&sc->sc_watchdog);
368 mtx_unlock(&sc->sc_mtx);
369
370 usbd_transfer_unsetup(sc->sc_xfer, G_AUDIO_N_TRANSFER);
371
372 usb_callout_drain(&sc->sc_callout);
373 usb_callout_drain(&sc->sc_watchdog);
374
375 mtx_destroy(&sc->sc_mtx);
376
377 return (0);
378 }
379
380 static int32_t
g_noise(struct g_audio_softc * sc)381 g_noise(struct g_audio_softc *sc)
382 {
383 uint32_t temp;
384 const uint32_t prime = 0xFFFF1D;
385
386 if (sc->sc_noise_rem & 1) {
387 sc->sc_noise_rem += prime;
388 }
389 sc->sc_noise_rem /= 2;
390
391 temp = sc->sc_noise_rem;
392
393 /* unsigned to signed conversion */
394
395 temp ^= 0x800000;
396 if (temp & 0x800000) {
397 temp |= (-0x800000);
398 }
399 return temp;
400 }
401
402 static void
g_audio_make_samples(struct g_audio_softc * sc,int16_t * ptr,int samples)403 g_audio_make_samples(struct g_audio_softc *sc, int16_t *ptr, int samples)
404 {
405 int i;
406 int j;
407
408 for (i = 0; i != samples; i++) {
409 j = g_noise(sc);
410
411 if ((sc->sc_state < 0) || (sc->sc_state >= sc->sc_pattern_len))
412 sc->sc_state = 0;
413
414 if (sc->sc_pattern_len != 0) {
415 j = (j * sc->sc_pattern[sc->sc_state]) >> 16;
416 sc->sc_state++;
417 }
418 *ptr++ = j / 256;
419 *ptr++ = j / 256;
420 }
421 }
422
423 static void
g_audio_isoc_write_callback(struct usb_xfer * xfer,usb_error_t error)424 g_audio_isoc_write_callback(struct usb_xfer *xfer, usb_error_t error)
425 {
426 struct g_audio_softc *sc = usbd_xfer_softc(xfer);
427 int actlen;
428 int aframes;
429 int nr = (xfer == sc->sc_xfer[G_AUDIO_ISOC0_WR]) ? 0 : 1;
430 int16_t *ptr;
431 int i;
432
433 usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
434
435 DPRINTF("st=%d aframes=%d actlen=%d bytes\n",
436 USB_GET_STATE(xfer), aframes, actlen);
437
438 switch (USB_GET_STATE(xfer)) {
439 case USB_ST_TRANSFERRED:
440
441 sc->sc_throughput += actlen;
442
443 if (sc->sc_mode == G_AUDIO_MODE_LOOP)
444 break; /* sync with RX */
445
446 case USB_ST_SETUP:
447 tr_setup:
448
449 ptr = sc->sc_data_buf[nr];
450
451 if (sc->sc_mode == G_AUDIO_MODE_PATTERN) {
452 for (i = 0; i != G_AUDIO_FRAMES; i++) {
453 usbd_xfer_set_frame_data(xfer, i, ptr, sc->sc_data_len[nr][i]);
454
455 g_audio_make_samples(sc, ptr, (G_AUDIO_BUFSIZE / G_AUDIO_FRAMES) / 2);
456
457 ptr += (G_AUDIO_BUFSIZE / G_AUDIO_FRAMES) / 2;
458 }
459 } else if (sc->sc_mode == G_AUDIO_MODE_LOOP) {
460 for (i = 0; i != G_AUDIO_FRAMES; i++) {
461 usbd_xfer_set_frame_data(xfer, i, ptr, sc->sc_data_len[nr][i] & ~3);
462
463 g_audio_make_samples(sc, ptr, sc->sc_data_len[nr][i] / 4);
464
465 ptr += (G_AUDIO_BUFSIZE / G_AUDIO_FRAMES) / 2;
466 }
467 }
468 break;
469
470 default: /* Error */
471 DPRINTF("error=%s\n", usbd_errstr(error));
472
473 if (error != USB_ERR_CANCELLED) {
474 /* try to clear stall first */
475 usbd_xfer_set_stall(xfer);
476 goto tr_setup;
477 }
478 break;
479 }
480 }
481
482 static void
g_audio_isoc_read_callback(struct usb_xfer * xfer,usb_error_t error)483 g_audio_isoc_read_callback(struct usb_xfer *xfer, usb_error_t error)
484 {
485 struct g_audio_softc *sc = usbd_xfer_softc(xfer);
486 int actlen;
487 int aframes;
488 int nr = (xfer == sc->sc_xfer[G_AUDIO_ISOC0_RD]) ? 0 : 1;
489 int16_t *ptr;
490 int i;
491
492 usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
493
494 DPRINTF("st=%d aframes=%d actlen=%d bytes\n",
495 USB_GET_STATE(xfer), aframes, actlen);
496
497 switch (USB_GET_STATE(xfer)) {
498 case USB_ST_TRANSFERRED:
499
500 sc->sc_throughput += actlen;
501
502 for (i = 0; i != G_AUDIO_FRAMES; i++) {
503 sc->sc_data_len[nr][i] = usbd_xfer_frame_len(xfer, i);
504 }
505
506 usbd_transfer_start(sc->sc_xfer[G_AUDIO_ISOC0_WR]);
507 usbd_transfer_start(sc->sc_xfer[G_AUDIO_ISOC1_WR]);
508
509 break;
510
511 case USB_ST_SETUP:
512 tr_setup:
513 ptr = sc->sc_data_buf[nr];
514
515 for (i = 0; i != G_AUDIO_FRAMES; i++) {
516 usbd_xfer_set_frame_data(xfer, i, ptr,
517 G_AUDIO_BUFSIZE / G_AUDIO_FRAMES);
518
519 ptr += (G_AUDIO_BUFSIZE / G_AUDIO_FRAMES) / 2;
520 }
521
522 usbd_transfer_submit(xfer);
523 break;
524
525 default: /* Error */
526 DPRINTF("error=%s\n", usbd_errstr(error));
527
528 if (error != USB_ERR_CANCELLED) {
529 /* try to clear stall first */
530 usbd_xfer_set_stall(xfer);
531 goto tr_setup;
532 }
533 break;
534 }
535 }
536
537 static int
g_audio_handle_request(device_t dev,const void * preq,void ** pptr,uint16_t * plen,uint16_t offset,uint8_t * pstate)538 g_audio_handle_request(device_t dev,
539 const void *preq, void **pptr, uint16_t *plen,
540 uint16_t offset, uint8_t *pstate)
541 {
542 struct g_audio_softc *sc = device_get_softc(dev);
543 const struct usb_device_request *req = preq;
544 uint8_t is_complete = *pstate;
545
546 if (!is_complete) {
547 if ((req->bmRequestType == UT_READ_CLASS_INTERFACE) &&
548 (req->bRequest == 0x82 /* get min */ )) {
549 if (offset == 0) {
550 USETW(sc->sc_volume_limit, 0);
551 *plen = 2;
552 *pptr = &sc->sc_volume_limit;
553 } else {
554 *plen = 0;
555 }
556 return (0);
557 } else if ((req->bmRequestType == UT_READ_CLASS_INTERFACE) &&
558 (req->bRequest == 0x83 /* get max */ )) {
559 if (offset == 0) {
560 USETW(sc->sc_volume_limit, 0x2000);
561 *plen = 2;
562 *pptr = &sc->sc_volume_limit;
563 } else {
564 *plen = 0;
565 }
566 return (0);
567 } else if ((req->bmRequestType == UT_READ_CLASS_INTERFACE) &&
568 (req->bRequest == 0x84 /* get residue */ )) {
569 if (offset == 0) {
570 USETW(sc->sc_volume_limit, 1);
571 *plen = 2;
572 *pptr = &sc->sc_volume_limit;
573 } else {
574 *plen = 0;
575 }
576 return (0);
577 } else if ((req->bmRequestType == UT_READ_CLASS_INTERFACE) &&
578 (req->bRequest == 0x81 /* get value */ )) {
579 if (offset == 0) {
580 USETW(sc->sc_volume_setting, 0x2000);
581 *plen = sizeof(sc->sc_volume_setting);
582 *pptr = &sc->sc_volume_setting;
583 } else {
584 *plen = 0;
585 }
586 return (0);
587 } else if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
588 (req->bRequest == 0x01 /* set value */ )) {
589 if (offset == 0) {
590 *plen = sizeof(sc->sc_volume_setting);
591 *pptr = &sc->sc_volume_setting;
592 } else {
593 *plen = 0;
594 }
595 return (0);
596 } else if ((req->bmRequestType == UT_WRITE_CLASS_ENDPOINT) &&
597 (req->bRequest == 0x01 /* set value */ )) {
598 if (offset == 0) {
599 *plen = sizeof(sc->sc_sample_rate);
600 *pptr = &sc->sc_sample_rate;
601 } else {
602 *plen = 0;
603 }
604 return (0);
605 }
606 }
607 return (ENXIO); /* use builtin handler */
608 }
609