blob: 74c99b1f120421145b0164427fb6c80869eafd72 [file] [log] [blame]
H. Peter Anvinb8704722010-09-10 14:47:56 -07001/*
2 * QEMU USB audio device
3 *
4 * written by:
5 * H. Peter Anvin <hpa@linux.intel.com>
6 * Gerd Hoffmann <kraxel@redhat.com>
7 *
8 * lousely based on usb net device code which is:
9 *
10 * Copyright (c) 2006 Thomas Sailer
11 * Copyright (c) 2008 Andrzej Zaborowski
12 *
13 * Permission is hereby granted, free of charge, to any person obtaining a copy
14 * of this software and associated documentation files (the "Software"), to deal
15 * in the Software without restriction, including without limitation the rights
16 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 * copies of the Software, and to permit persons to whom the Software is
18 * furnished to do so, subject to the following conditions:
19 *
20 * The above copyright notice and this permission notice shall be included in
21 * all copies or substantial portions of the Software.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 * THE SOFTWARE.
30 */
31
Peter Maydelle532b2e2016-01-26 18:17:12 +000032#include "qemu/osdep.h"
Markus Armbruster0b8fa322019-05-23 16:35:07 +020033#include "qemu/module.h"
Markus Armbrustera27bd6c2019-08-12 07:23:51 +020034#include "hw/qdev-properties.h"
Gerd Hoffmannf1ae32a2012-03-07 14:55:18 +010035#include "hw/usb.h"
Markus Armbrusterd6454272019-08-12 07:23:45 +020036#include "migration/vmstate.h"
Michael S. Tsirkin463581a2018-05-03 22:50:48 +030037#include "desc.h"
H. Peter Anvinb8704722010-09-10 14:47:56 -070038#include "audio/audio.h"
39
40#define USBAUDIO_VENDOR_NUM 0x46f4 /* CRC16() of "QEMU" */
41#define USBAUDIO_PRODUCT_NUM 0x0002
42
43#define DEV_CONFIG_VALUE 1 /* The one and only */
44
45/* Descriptor subtypes for AC interfaces */
46#define DST_AC_HEADER 1
47#define DST_AC_INPUT_TERMINAL 2
48#define DST_AC_OUTPUT_TERMINAL 3
49#define DST_AC_FEATURE_UNIT 6
50/* Descriptor subtypes for AS interfaces */
51#define DST_AS_GENERAL 1
52#define DST_AS_FORMAT_TYPE 2
53/* Descriptor subtypes for endpoints */
54#define DST_EP_GENERAL 1
55
56enum usb_audio_strings {
57 STRING_NULL,
58 STRING_MANUFACTURER,
59 STRING_PRODUCT,
60 STRING_SERIALNUMBER,
61 STRING_CONFIG,
62 STRING_USBAUDIO_CONTROL,
63 STRING_INPUT_TERMINAL,
64 STRING_FEATURE_UNIT,
65 STRING_OUTPUT_TERMINAL,
66 STRING_NULL_STREAM,
67 STRING_REAL_STREAM,
68};
69
70static const USBDescStrings usb_audio_stringtable = {
71 [STRING_MANUFACTURER] = "QEMU",
72 [STRING_PRODUCT] = "QEMU USB Audio",
73 [STRING_SERIALNUMBER] = "1",
74 [STRING_CONFIG] = "Audio Configuration",
75 [STRING_USBAUDIO_CONTROL] = "Audio Device",
76 [STRING_INPUT_TERMINAL] = "Audio Output Pipe",
77 [STRING_FEATURE_UNIT] = "Audio Output Volume Control",
78 [STRING_OUTPUT_TERMINAL] = "Audio Output Terminal",
79 [STRING_NULL_STREAM] = "Audio Output - Disabled",
80 [STRING_REAL_STREAM] = "Audio Output - 48 kHz Stereo",
81};
82
83#define U16(x) ((x) & 0xff), (((x) >> 8) & 0xff)
84#define U24(x) U16(x), (((x) >> 16) & 0xff)
85#define U32(x) U24(x), (((x) >> 24) & 0xff)
86
87/*
88 * A Basic Audio Device uses these specific values
89 */
90#define USBAUDIO_PACKET_SIZE 192
91#define USBAUDIO_SAMPLE_RATE 48000
92#define USBAUDIO_PACKET_INTERVAL 1
93
94static const USBDescIface desc_iface[] = {
95 {
96 .bInterfaceNumber = 0,
97 .bNumEndpoints = 0,
98 .bInterfaceClass = USB_CLASS_AUDIO,
99 .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL,
100 .bInterfaceProtocol = 0x04,
101 .iInterface = STRING_USBAUDIO_CONTROL,
102 .ndesc = 4,
103 .descs = (USBDescOther[]) {
104 {
105 /* Headphone Class-Specific AC Interface Header Descriptor */
106 .data = (uint8_t[]) {
107 0x09, /* u8 bLength */
108 USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
109 DST_AC_HEADER, /* u8 bDescriptorSubtype */
110 U16(0x0100), /* u16 bcdADC */
111 U16(0x2b), /* u16 wTotalLength */
112 0x01, /* u8 bInCollection */
113 0x01, /* u8 baInterfaceNr */
114 }
115 },{
116 /* Generic Stereo Input Terminal ID1 Descriptor */
117 .data = (uint8_t[]) {
118 0x0c, /* u8 bLength */
119 USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
120 DST_AC_INPUT_TERMINAL, /* u8 bDescriptorSubtype */
121 0x01, /* u8 bTerminalID */
122 U16(0x0101), /* u16 wTerminalType */
123 0x00, /* u8 bAssocTerminal */
124 0x02, /* u16 bNrChannels */
125 U16(0x0003), /* u16 wChannelConfig */
126 0x00, /* u8 iChannelNames */
127 STRING_INPUT_TERMINAL, /* u8 iTerminal */
128 }
129 },{
130 /* Generic Stereo Feature Unit ID2 Descriptor */
131 .data = (uint8_t[]) {
132 0x0d, /* u8 bLength */
133 USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
134 DST_AC_FEATURE_UNIT, /* u8 bDescriptorSubtype */
135 0x02, /* u8 bUnitID */
136 0x01, /* u8 bSourceID */
137 0x02, /* u8 bControlSize */
138 U16(0x0001), /* u16 bmaControls(0) */
139 U16(0x0002), /* u16 bmaControls(1) */
140 U16(0x0002), /* u16 bmaControls(2) */
141 STRING_FEATURE_UNIT, /* u8 iFeature */
142 }
143 },{
144 /* Headphone Ouptut Terminal ID3 Descriptor */
145 .data = (uint8_t[]) {
146 0x09, /* u8 bLength */
147 USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
148 DST_AC_OUTPUT_TERMINAL, /* u8 bDescriptorSubtype */
149 0x03, /* u8 bUnitID */
150 U16(0x0301), /* u16 wTerminalType (SPK) */
151 0x00, /* u8 bAssocTerminal */
152 0x02, /* u8 bSourceID */
153 STRING_OUTPUT_TERMINAL, /* u8 iTerminal */
154 }
155 }
156 },
157 },{
158 .bInterfaceNumber = 1,
159 .bAlternateSetting = 0,
160 .bNumEndpoints = 0,
161 .bInterfaceClass = USB_CLASS_AUDIO,
162 .bInterfaceSubClass = USB_SUBCLASS_AUDIO_STREAMING,
163 .iInterface = STRING_NULL_STREAM,
164 },{
165 .bInterfaceNumber = 1,
166 .bAlternateSetting = 1,
167 .bNumEndpoints = 1,
168 .bInterfaceClass = USB_CLASS_AUDIO,
169 .bInterfaceSubClass = USB_SUBCLASS_AUDIO_STREAMING,
170 .iInterface = STRING_REAL_STREAM,
171 .ndesc = 2,
172 .descs = (USBDescOther[]) {
173 {
174 /* Headphone Class-specific AS General Interface Descriptor */
175 .data = (uint8_t[]) {
176 0x07, /* u8 bLength */
177 USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
178 DST_AS_GENERAL, /* u8 bDescriptorSubtype */
179 0x01, /* u8 bTerminalLink */
180 0x00, /* u8 bDelay */
181 0x01, 0x00, /* u16 wFormatTag */
182 }
183 },{
184 /* Headphone Type I Format Type Descriptor */
185 .data = (uint8_t[]) {
186 0x0b, /* u8 bLength */
187 USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
188 DST_AS_FORMAT_TYPE, /* u8 bDescriptorSubtype */
189 0x01, /* u8 bFormatType */
190 0x02, /* u8 bNrChannels */
191 0x02, /* u8 bSubFrameSize */
192 0x10, /* u8 bBitResolution */
193 0x01, /* u8 bSamFreqType */
194 U24(USBAUDIO_SAMPLE_RATE), /* u24 tSamFreq */
195 }
196 }
197 },
198 .eps = (USBDescEndpoint[]) {
199 {
200 .bEndpointAddress = USB_DIR_OUT | 0x01,
201 .bmAttributes = 0x0d,
202 .wMaxPacketSize = USBAUDIO_PACKET_SIZE,
203 .bInterval = 1,
204 .is_audio = 1,
205 /* Stereo Headphone Class-specific
206 AS Audio Data Endpoint Descriptor */
207 .extra = (uint8_t[]) {
208 0x07, /* u8 bLength */
209 USB_DT_CS_ENDPOINT, /* u8 bDescriptorType */
210 DST_EP_GENERAL, /* u8 bDescriptorSubtype */
211 0x00, /* u8 bmAttributes */
212 0x00, /* u8 bLockDelayUnits */
213 U16(0x0000), /* u16 wLockDelay */
214 },
215 },
216 }
217 }
218};
219
220static const USBDescDevice desc_device = {
Gerd Hoffmann2bbd0862012-08-28 16:43:34 +0200221 .bcdUSB = 0x0100,
H. Peter Anvinb8704722010-09-10 14:47:56 -0700222 .bMaxPacketSize0 = 64,
223 .bNumConfigurations = 1,
224 .confs = (USBDescConfig[]) {
225 {
226 .bNumInterfaces = 2,
227 .bConfigurationValue = DEV_CONFIG_VALUE,
228 .iConfiguration = STRING_CONFIG,
Pantelis Koukousoulasbd939762013-12-16 09:42:49 +0200229 .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
H. Peter Anvinb8704722010-09-10 14:47:56 -0700230 .bMaxPower = 0x32,
231 .nif = ARRAY_SIZE(desc_iface),
232 .ifs = desc_iface,
233 },
234 },
235};
236
237static const USBDesc desc_audio = {
238 .id = {
239 .idVendor = USBAUDIO_VENDOR_NUM,
240 .idProduct = USBAUDIO_PRODUCT_NUM,
241 .bcdDevice = 0,
242 .iManufacturer = STRING_MANUFACTURER,
243 .iProduct = STRING_PRODUCT,
244 .iSerialNumber = STRING_SERIALNUMBER,
245 },
246 .full = &desc_device,
247 .str = usb_audio_stringtable,
248};
249
250/*
251 * A USB audio device supports an arbitrary number of alternate
252 * interface settings for each interface. Each corresponds to a block
253 * diagram of parameterized blocks. This can thus refer to things like
254 * number of channels, data rates, or in fact completely different
255 * block diagrams. Alternative setting 0 is always the null block diagram,
256 * which is used by a disabled device.
257 */
258enum usb_audio_altset {
259 ALTSET_OFF = 0x00, /* No endpoint */
260 ALTSET_ON = 0x01, /* Single endpoint */
261};
262
263/*
264 * Class-specific control requests
265 */
266#define CR_SET_CUR 0x01
267#define CR_GET_CUR 0x81
268#define CR_SET_MIN 0x02
269#define CR_GET_MIN 0x82
270#define CR_SET_MAX 0x03
271#define CR_GET_MAX 0x83
272#define CR_SET_RES 0x04
273#define CR_GET_RES 0x84
274#define CR_SET_MEM 0x05
275#define CR_GET_MEM 0x85
276#define CR_GET_STAT 0xff
277
278/*
279 * Feature Unit Control Selectors
280 */
281#define MUTE_CONTROL 0x01
282#define VOLUME_CONTROL 0x02
283#define BASS_CONTROL 0x03
284#define MID_CONTROL 0x04
285#define TREBLE_CONTROL 0x05
286#define GRAPHIC_EQUALIZER_CONTROL 0x06
287#define AUTOMATIC_GAIN_CONTROL 0x07
288#define DELAY_CONTROL 0x08
289#define BASS_BOOST_CONTROL 0x09
290#define LOUDNESS_CONTROL 0x0a
291
292/*
293 * buffering
294 */
295
296struct streambuf {
297 uint8_t *data;
298 uint32_t size;
299 uint32_t prod;
300 uint32_t cons;
301};
302
303static void streambuf_init(struct streambuf *buf, uint32_t size)
304{
305 g_free(buf->data);
306 buf->size = size - (size % USBAUDIO_PACKET_SIZE);
307 buf->data = g_malloc(buf->size);
308 buf->prod = 0;
309 buf->cons = 0;
310}
311
312static void streambuf_fini(struct streambuf *buf)
313{
314 g_free(buf->data);
315 buf->data = NULL;
316}
317
318static int streambuf_put(struct streambuf *buf, USBPacket *p)
319{
320 uint32_t free = buf->size - (buf->prod - buf->cons);
321
Kővágó, Zoltán2c6a7402019-10-13 21:58:04 +0200322 if (free < USBAUDIO_PACKET_SIZE) {
H. Peter Anvinb8704722010-09-10 14:47:56 -0700323 return 0;
324 }
Gerd Hoffmanna7fde1c2018-12-11 08:26:49 +0100325 if (p->iov.size != USBAUDIO_PACKET_SIZE) {
326 return 0;
327 }
Kővágó, Zoltán2c6a7402019-10-13 21:58:04 +0200328
H. Peter Anvinb8704722010-09-10 14:47:56 -0700329 usb_packet_copy(p, buf->data + (buf->prod % buf->size),
330 USBAUDIO_PACKET_SIZE);
331 buf->prod += USBAUDIO_PACKET_SIZE;
332 return USBAUDIO_PACKET_SIZE;
333}
334
Kővágó, Zoltán2c6a7402019-10-13 21:58:04 +0200335static uint8_t *streambuf_get(struct streambuf *buf, size_t *len)
H. Peter Anvinb8704722010-09-10 14:47:56 -0700336{
337 uint32_t used = buf->prod - buf->cons;
338 uint8_t *data;
339
340 if (!used) {
Kővágó, Zoltán2c6a7402019-10-13 21:58:04 +0200341 *len = 0;
H. Peter Anvinb8704722010-09-10 14:47:56 -0700342 return NULL;
343 }
H. Peter Anvinb8704722010-09-10 14:47:56 -0700344 data = buf->data + (buf->cons % buf->size);
Kővágó, Zoltán2c6a7402019-10-13 21:58:04 +0200345 *len = MIN(buf->prod - buf->cons,
346 buf->size - (buf->cons % buf->size));
H. Peter Anvinb8704722010-09-10 14:47:56 -0700347 return data;
348}
349
350typedef struct USBAudioState {
351 /* qemu interfaces */
352 USBDevice dev;
353 QEMUSoundCard card;
354
355 /* state */
356 struct {
357 enum usb_audio_altset altset;
358 struct audsettings as;
359 SWVoiceOut *voice;
360 bool mute;
361 uint8_t vol[2];
362 struct streambuf buf;
363 } out;
364
365 /* properties */
366 uint32_t debug;
367 uint32_t buffer;
368} USBAudioState;
369
Gonglei0389a0b2015-05-06 20:55:24 +0800370#define TYPE_USB_AUDIO "usb-audio"
371#define USB_AUDIO(obj) OBJECT_CHECK(USBAudioState, (obj), TYPE_USB_AUDIO)
372
H. Peter Anvinb8704722010-09-10 14:47:56 -0700373static void output_callback(void *opaque, int avail)
374{
375 USBAudioState *s = opaque;
376 uint8_t *data;
377
Kővágó, Zoltán2c6a7402019-10-13 21:58:04 +0200378 while (avail) {
379 size_t written, len;
380
381 data = streambuf_get(&s->out.buf, &len);
Gongleid0657b22014-08-11 21:00:52 +0800382 if (!data) {
H. Peter Anvinb8704722010-09-10 14:47:56 -0700383 return;
384 }
Kővágó, Zoltán2c6a7402019-10-13 21:58:04 +0200385
386 written = AUD_write(s->out.voice, data, len);
387 avail -= written;
388 s->out.buf.cons += written;
389
390 if (written < len) {
391 return;
392 }
H. Peter Anvinb8704722010-09-10 14:47:56 -0700393 }
394}
395
396static int usb_audio_set_output_altset(USBAudioState *s, int altset)
397{
398 switch (altset) {
399 case ALTSET_OFF:
400 streambuf_init(&s->out.buf, s->buffer);
401 AUD_set_active_out(s->out.voice, false);
402 break;
403 case ALTSET_ON:
404 AUD_set_active_out(s->out.voice, true);
405 break;
406 default:
407 return -1;
408 }
409
410 if (s->debug) {
411 fprintf(stderr, "usb-audio: set interface %d\n", altset);
412 }
413 s->out.altset = altset;
414 return 0;
415}
416
417/*
418 * Note: we arbitrarily map the volume control range onto -inf..+8 dB
419 */
420#define ATTRIB_ID(cs, attrib, idif) \
421 (((cs) << 24) | ((attrib) << 16) | (idif))
422
423static int usb_audio_get_control(USBAudioState *s, uint8_t attrib,
424 uint16_t cscn, uint16_t idif,
425 int length, uint8_t *data)
426{
427 uint8_t cs = cscn >> 8;
428 uint8_t cn = cscn - 1; /* -1 for the non-present master control */
429 uint32_t aid = ATTRIB_ID(cs, attrib, idif);
430 int ret = USB_RET_STALL;
431
432 switch (aid) {
433 case ATTRIB_ID(MUTE_CONTROL, CR_GET_CUR, 0x0200):
434 data[0] = s->out.mute;
435 ret = 1;
436 break;
437 case ATTRIB_ID(VOLUME_CONTROL, CR_GET_CUR, 0x0200):
438 if (cn < 2) {
439 uint16_t vol = (s->out.vol[cn] * 0x8800 + 127) / 255 + 0x8000;
440 data[0] = vol;
441 data[1] = vol >> 8;
442 ret = 2;
443 }
444 break;
445 case ATTRIB_ID(VOLUME_CONTROL, CR_GET_MIN, 0x0200):
446 if (cn < 2) {
447 data[0] = 0x01;
448 data[1] = 0x80;
449 ret = 2;
450 }
451 break;
452 case ATTRIB_ID(VOLUME_CONTROL, CR_GET_MAX, 0x0200):
453 if (cn < 2) {
454 data[0] = 0x00;
455 data[1] = 0x08;
456 ret = 2;
457 }
458 break;
459 case ATTRIB_ID(VOLUME_CONTROL, CR_GET_RES, 0x0200):
460 if (cn < 2) {
461 data[0] = 0x88;
462 data[1] = 0x00;
463 ret = 2;
464 }
465 break;
466 }
467
468 return ret;
469}
470static int usb_audio_set_control(USBAudioState *s, uint8_t attrib,
471 uint16_t cscn, uint16_t idif,
472 int length, uint8_t *data)
473{
474 uint8_t cs = cscn >> 8;
475 uint8_t cn = cscn - 1; /* -1 for the non-present master control */
476 uint32_t aid = ATTRIB_ID(cs, attrib, idif);
477 int ret = USB_RET_STALL;
478 bool set_vol = false;
479
480 switch (aid) {
481 case ATTRIB_ID(MUTE_CONTROL, CR_SET_CUR, 0x0200):
482 s->out.mute = data[0] & 1;
483 set_vol = true;
484 ret = 0;
485 break;
486 case ATTRIB_ID(VOLUME_CONTROL, CR_SET_CUR, 0x0200):
487 if (cn < 2) {
488 uint16_t vol = data[0] + (data[1] << 8);
489
490 if (s->debug) {
491 fprintf(stderr, "usb-audio: vol %04x\n", (uint16_t)vol);
492 }
493
494 vol -= 0x8000;
495 vol = (vol * 255 + 0x4400) / 0x8800;
496 if (vol > 255) {
497 vol = 255;
498 }
499
500 s->out.vol[cn] = vol;
501 set_vol = true;
502 ret = 0;
503 }
504 break;
505 }
506
507 if (set_vol) {
508 if (s->debug) {
509 fprintf(stderr, "usb-audio: mute %d, lvol %3d, rvol %3d\n",
510 s->out.mute, s->out.vol[0], s->out.vol[1]);
511 }
512 AUD_set_volume_out(s->out.voice, s->out.mute,
513 s->out.vol[0], s->out.vol[1]);
514 }
515
516 return ret;
517}
518
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100519static void usb_audio_handle_control(USBDevice *dev, USBPacket *p,
H. Peter Anvinb8704722010-09-10 14:47:56 -0700520 int request, int value, int index,
521 int length, uint8_t *data)
522{
Gonglei0389a0b2015-05-06 20:55:24 +0800523 USBAudioState *s = USB_AUDIO(dev);
H. Peter Anvinb8704722010-09-10 14:47:56 -0700524 int ret = 0;
525
526 if (s->debug) {
527 fprintf(stderr, "usb-audio: control transaction: "
528 "request 0x%04x value 0x%04x index 0x%04x length 0x%04x\n",
529 request, value, index, length);
530 }
531
532 ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
533 if (ret >= 0) {
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100534 return;
H. Peter Anvinb8704722010-09-10 14:47:56 -0700535 }
536
537 switch (request) {
538 case ClassInterfaceRequest | CR_GET_CUR:
539 case ClassInterfaceRequest | CR_GET_MIN:
540 case ClassInterfaceRequest | CR_GET_MAX:
541 case ClassInterfaceRequest | CR_GET_RES:
542 ret = usb_audio_get_control(s, request & 0xff, value, index,
543 length, data);
544 if (ret < 0) {
545 if (s->debug) {
546 fprintf(stderr, "usb-audio: fail: get control\n");
547 }
548 goto fail;
549 }
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100550 p->actual_length = ret;
H. Peter Anvinb8704722010-09-10 14:47:56 -0700551 break;
552
553 case ClassInterfaceOutRequest | CR_SET_CUR:
554 case ClassInterfaceOutRequest | CR_SET_MIN:
555 case ClassInterfaceOutRequest | CR_SET_MAX:
556 case ClassInterfaceOutRequest | CR_SET_RES:
557 ret = usb_audio_set_control(s, request & 0xff, value, index,
558 length, data);
559 if (ret < 0) {
560 if (s->debug) {
561 fprintf(stderr, "usb-audio: fail: set control\n");
562 }
563 goto fail;
564 }
565 break;
566
567 default:
568fail:
569 if (s->debug) {
570 fprintf(stderr, "usb-audio: failed control transaction: "
571 "request 0x%04x value 0x%04x index 0x%04x length 0x%04x\n",
572 request, value, index, length);
573 }
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100574 p->status = USB_RET_STALL;
H. Peter Anvinb8704722010-09-10 14:47:56 -0700575 break;
576 }
H. Peter Anvinb8704722010-09-10 14:47:56 -0700577}
578
579static void usb_audio_set_interface(USBDevice *dev, int iface,
580 int old, int value)
581{
Gonglei0389a0b2015-05-06 20:55:24 +0800582 USBAudioState *s = USB_AUDIO(dev);
H. Peter Anvinb8704722010-09-10 14:47:56 -0700583
584 if (iface == 1) {
585 usb_audio_set_output_altset(s, value);
586 }
587}
588
589static void usb_audio_handle_reset(USBDevice *dev)
590{
Gonglei0389a0b2015-05-06 20:55:24 +0800591 USBAudioState *s = USB_AUDIO(dev);
H. Peter Anvinb8704722010-09-10 14:47:56 -0700592
593 if (s->debug) {
594 fprintf(stderr, "usb-audio: reset\n");
595 }
596 usb_audio_set_output_altset(s, ALTSET_OFF);
597}
598
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100599static void usb_audio_handle_dataout(USBAudioState *s, USBPacket *p)
H. Peter Anvinb8704722010-09-10 14:47:56 -0700600{
H. Peter Anvinb8704722010-09-10 14:47:56 -0700601 if (s->out.altset == ALTSET_OFF) {
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100602 p->status = USB_RET_STALL;
603 return;
H. Peter Anvinb8704722010-09-10 14:47:56 -0700604 }
605
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100606 streambuf_put(&s->out.buf, p);
607 if (p->actual_length < p->iov.size && s->debug > 1) {
H. Peter Anvinb8704722010-09-10 14:47:56 -0700608 fprintf(stderr, "usb-audio: output overrun (%zd bytes)\n",
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100609 p->iov.size - p->actual_length);
H. Peter Anvinb8704722010-09-10 14:47:56 -0700610 }
H. Peter Anvinb8704722010-09-10 14:47:56 -0700611}
612
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100613static void usb_audio_handle_data(USBDevice *dev, USBPacket *p)
H. Peter Anvinb8704722010-09-10 14:47:56 -0700614{
615 USBAudioState *s = (USBAudioState *) dev;
H. Peter Anvinb8704722010-09-10 14:47:56 -0700616
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100617 if (p->pid == USB_TOKEN_OUT && p->ep->nr == 1) {
618 usb_audio_handle_dataout(s, p);
619 return;
H. Peter Anvinb8704722010-09-10 14:47:56 -0700620 }
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100621
622 p->status = USB_RET_STALL;
623 if (s->debug) {
H. Peter Anvinb8704722010-09-10 14:47:56 -0700624 fprintf(stderr, "usb-audio: failed data transaction: "
625 "pid 0x%x ep 0x%x len 0x%zx\n",
Gerd Hoffmann079d0b72012-01-12 13:23:01 +0100626 p->pid, p->ep->nr, p->iov.size);
H. Peter Anvinb8704722010-09-10 14:47:56 -0700627 }
H. Peter Anvinb8704722010-09-10 14:47:56 -0700628}
629
Marc-André Lureauc4fe9702017-02-21 18:14:45 +0400630static void usb_audio_unrealize(USBDevice *dev, Error **errp)
H. Peter Anvinb8704722010-09-10 14:47:56 -0700631{
Gonglei0389a0b2015-05-06 20:55:24 +0800632 USBAudioState *s = USB_AUDIO(dev);
H. Peter Anvinb8704722010-09-10 14:47:56 -0700633
634 if (s->debug) {
635 fprintf(stderr, "usb-audio: destroy\n");
636 }
637
638 usb_audio_set_output_altset(s, ALTSET_OFF);
639 AUD_close_out(&s->card, s->out.voice);
640 AUD_remove_card(&s->card);
641
642 streambuf_fini(&s->out.buf);
643}
644
Gonglei5450eea2014-09-19 14:48:38 +0800645static void usb_audio_realize(USBDevice *dev, Error **errp)
H. Peter Anvinb8704722010-09-10 14:47:56 -0700646{
Gonglei0389a0b2015-05-06 20:55:24 +0800647 USBAudioState *s = USB_AUDIO(dev);
H. Peter Anvinb8704722010-09-10 14:47:56 -0700648
Gerd Hoffmann9d55d1a2012-04-20 12:33:30 +0200649 usb_desc_create_serial(dev);
H. Peter Anvinb8704722010-09-10 14:47:56 -0700650 usb_desc_init(dev);
651 s->dev.opaque = s;
Gonglei0389a0b2015-05-06 20:55:24 +0800652 AUD_register_card(TYPE_USB_AUDIO, &s->card);
H. Peter Anvinb8704722010-09-10 14:47:56 -0700653
654 s->out.altset = ALTSET_OFF;
655 s->out.mute = false;
656 s->out.vol[0] = 240; /* 0 dB */
657 s->out.vol[1] = 240; /* 0 dB */
658 s->out.as.freq = USBAUDIO_SAMPLE_RATE;
659 s->out.as.nchannels = 2;
Kővágó, Zoltán85bc5852019-03-08 23:34:13 +0100660 s->out.as.fmt = AUDIO_FORMAT_S16;
H. Peter Anvinb8704722010-09-10 14:47:56 -0700661 s->out.as.endianness = 0;
662 streambuf_init(&s->out.buf, s->buffer);
663
Gonglei0389a0b2015-05-06 20:55:24 +0800664 s->out.voice = AUD_open_out(&s->card, s->out.voice, TYPE_USB_AUDIO,
H. Peter Anvinb8704722010-09-10 14:47:56 -0700665 s, output_callback, &s->out.as);
666 AUD_set_volume_out(s->out.voice, s->out.mute, s->out.vol[0], s->out.vol[1]);
667 AUD_set_active_out(s->out.voice, 0);
H. Peter Anvinb8704722010-09-10 14:47:56 -0700668}
669
670static const VMStateDescription vmstate_usb_audio = {
Gonglei0389a0b2015-05-06 20:55:24 +0800671 .name = TYPE_USB_AUDIO,
H. Peter Anvinb8704722010-09-10 14:47:56 -0700672 .unmigratable = 1,
673};
674
Anthony Liguori39bffca2011-12-07 21:34:16 -0600675static Property usb_audio_properties[] = {
Kővágó, Zoltán88e47b92019-08-19 01:06:49 +0200676 DEFINE_AUDIO_PROPERTIES(USBAudioState, card),
Anthony Liguori39bffca2011-12-07 21:34:16 -0600677 DEFINE_PROP_UINT32("debug", USBAudioState, debug, 0),
678 DEFINE_PROP_UINT32("buffer", USBAudioState, buffer,
Gerd Hoffmann37bc43f2015-10-06 15:31:56 +0200679 32 * USBAUDIO_PACKET_SIZE),
Anthony Liguori39bffca2011-12-07 21:34:16 -0600680 DEFINE_PROP_END_OF_LIST(),
681};
682
Anthony Liguori62aed762011-12-15 14:53:10 -0600683static void usb_audio_class_init(ObjectClass *klass, void *data)
684{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600685 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori62aed762011-12-15 14:53:10 -0600686 USBDeviceClass *k = USB_DEVICE_CLASS(klass);
687
Anthony Liguori39bffca2011-12-07 21:34:16 -0600688 dc->vmsd = &vmstate_usb_audio;
689 dc->props = usb_audio_properties;
Marcel Apfelbaum125ee0e2013-07-29 17:17:45 +0300690 set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
Anthony Liguori62aed762011-12-15 14:53:10 -0600691 k->product_desc = "QEMU USB Audio Interface";
692 k->usb_desc = &desc_audio;
Gonglei5450eea2014-09-19 14:48:38 +0800693 k->realize = usb_audio_realize;
Anthony Liguori62aed762011-12-15 14:53:10 -0600694 k->handle_reset = usb_audio_handle_reset;
695 k->handle_control = usb_audio_handle_control;
696 k->handle_data = usb_audio_handle_data;
Marc-André Lureauc4fe9702017-02-21 18:14:45 +0400697 k->unrealize = usb_audio_unrealize;
Anthony Liguori62aed762011-12-15 14:53:10 -0600698 k->set_interface = usb_audio_set_interface;
699}
700
Andreas Färber8c43a6f2013-01-10 16:19:07 +0100701static const TypeInfo usb_audio_info = {
Gonglei0389a0b2015-05-06 20:55:24 +0800702 .name = TYPE_USB_AUDIO,
Anthony Liguori39bffca2011-12-07 21:34:16 -0600703 .parent = TYPE_USB_DEVICE,
704 .instance_size = sizeof(USBAudioState),
705 .class_init = usb_audio_class_init,
H. Peter Anvinb8704722010-09-10 14:47:56 -0700706};
707
Andreas Färber83f7d432012-02-09 15:20:55 +0100708static void usb_audio_register_types(void)
H. Peter Anvinb8704722010-09-10 14:47:56 -0700709{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600710 type_register_static(&usb_audio_info);
Gonglei0389a0b2015-05-06 20:55:24 +0800711 usb_legacy_register(TYPE_USB_AUDIO, "audio", NULL);
H. Peter Anvinb8704722010-09-10 14:47:56 -0700712}
713
Andreas Färber83f7d432012-02-09 15:20:55 +0100714type_init(usb_audio_register_types)