xref: /openbmc/qemu/hw/usb/dev-audio.c (revision bd93976a)
1f1ae32a1SGerd Hoffmann /*
2f1ae32a1SGerd Hoffmann  * QEMU USB audio device
3f1ae32a1SGerd Hoffmann  *
4f1ae32a1SGerd Hoffmann  * written by:
5f1ae32a1SGerd Hoffmann  *  H. Peter Anvin <hpa@linux.intel.com>
6f1ae32a1SGerd Hoffmann  *  Gerd Hoffmann <kraxel@redhat.com>
7f1ae32a1SGerd Hoffmann  *
8f1ae32a1SGerd Hoffmann  * lousely based on usb net device code which is:
9f1ae32a1SGerd Hoffmann  *
10f1ae32a1SGerd Hoffmann  * Copyright (c) 2006 Thomas Sailer
11f1ae32a1SGerd Hoffmann  * Copyright (c) 2008 Andrzej Zaborowski
12f1ae32a1SGerd Hoffmann  *
13f1ae32a1SGerd Hoffmann  * Permission is hereby granted, free of charge, to any person obtaining a copy
14f1ae32a1SGerd Hoffmann  * of this software and associated documentation files (the "Software"), to deal
15f1ae32a1SGerd Hoffmann  * in the Software without restriction, including without limitation the rights
16f1ae32a1SGerd Hoffmann  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17f1ae32a1SGerd Hoffmann  * copies of the Software, and to permit persons to whom the Software is
18f1ae32a1SGerd Hoffmann  * furnished to do so, subject to the following conditions:
19f1ae32a1SGerd Hoffmann  *
20f1ae32a1SGerd Hoffmann  * The above copyright notice and this permission notice shall be included in
21f1ae32a1SGerd Hoffmann  * all copies or substantial portions of the Software.
22f1ae32a1SGerd Hoffmann  *
23f1ae32a1SGerd Hoffmann  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24f1ae32a1SGerd Hoffmann  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25f1ae32a1SGerd Hoffmann  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26f1ae32a1SGerd Hoffmann  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27f1ae32a1SGerd Hoffmann  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28f1ae32a1SGerd Hoffmann  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29f1ae32a1SGerd Hoffmann  * THE SOFTWARE.
30f1ae32a1SGerd Hoffmann  */
31f1ae32a1SGerd Hoffmann 
32f1ae32a1SGerd Hoffmann #include "qemu-common.h"
33f1ae32a1SGerd Hoffmann #include "hw/usb.h"
34f1ae32a1SGerd Hoffmann #include "hw/usb/desc.h"
35f1ae32a1SGerd Hoffmann #include "hw/hw.h"
36f1ae32a1SGerd Hoffmann #include "audio/audio.h"
37f1ae32a1SGerd Hoffmann 
38f1ae32a1SGerd Hoffmann #define USBAUDIO_VENDOR_NUM     0x46f4 /* CRC16() of "QEMU" */
39f1ae32a1SGerd Hoffmann #define USBAUDIO_PRODUCT_NUM    0x0002
40f1ae32a1SGerd Hoffmann 
41f1ae32a1SGerd Hoffmann #define DEV_CONFIG_VALUE        1 /* The one and only */
42f1ae32a1SGerd Hoffmann 
43f1ae32a1SGerd Hoffmann /* Descriptor subtypes for AC interfaces */
44f1ae32a1SGerd Hoffmann #define DST_AC_HEADER           1
45f1ae32a1SGerd Hoffmann #define DST_AC_INPUT_TERMINAL   2
46f1ae32a1SGerd Hoffmann #define DST_AC_OUTPUT_TERMINAL  3
47f1ae32a1SGerd Hoffmann #define DST_AC_FEATURE_UNIT     6
48f1ae32a1SGerd Hoffmann /* Descriptor subtypes for AS interfaces */
49f1ae32a1SGerd Hoffmann #define DST_AS_GENERAL          1
50f1ae32a1SGerd Hoffmann #define DST_AS_FORMAT_TYPE      2
51f1ae32a1SGerd Hoffmann /* Descriptor subtypes for endpoints */
52f1ae32a1SGerd Hoffmann #define DST_EP_GENERAL          1
53f1ae32a1SGerd Hoffmann 
54f1ae32a1SGerd Hoffmann enum usb_audio_strings {
55f1ae32a1SGerd Hoffmann     STRING_NULL,
56f1ae32a1SGerd Hoffmann     STRING_MANUFACTURER,
57f1ae32a1SGerd Hoffmann     STRING_PRODUCT,
58f1ae32a1SGerd Hoffmann     STRING_SERIALNUMBER,
59f1ae32a1SGerd Hoffmann     STRING_CONFIG,
60f1ae32a1SGerd Hoffmann     STRING_USBAUDIO_CONTROL,
61f1ae32a1SGerd Hoffmann     STRING_INPUT_TERMINAL,
62f1ae32a1SGerd Hoffmann     STRING_FEATURE_UNIT,
63f1ae32a1SGerd Hoffmann     STRING_OUTPUT_TERMINAL,
64f1ae32a1SGerd Hoffmann     STRING_NULL_STREAM,
65f1ae32a1SGerd Hoffmann     STRING_REAL_STREAM,
66f1ae32a1SGerd Hoffmann };
67f1ae32a1SGerd Hoffmann 
68f1ae32a1SGerd Hoffmann static const USBDescStrings usb_audio_stringtable = {
69f1ae32a1SGerd Hoffmann     [STRING_MANUFACTURER]       = "QEMU",
70f1ae32a1SGerd Hoffmann     [STRING_PRODUCT]            = "QEMU USB Audio",
71f1ae32a1SGerd Hoffmann     [STRING_SERIALNUMBER]       = "1",
72f1ae32a1SGerd Hoffmann     [STRING_CONFIG]             = "Audio Configuration",
73f1ae32a1SGerd Hoffmann     [STRING_USBAUDIO_CONTROL]   = "Audio Device",
74f1ae32a1SGerd Hoffmann     [STRING_INPUT_TERMINAL]     = "Audio Output Pipe",
75f1ae32a1SGerd Hoffmann     [STRING_FEATURE_UNIT]       = "Audio Output Volume Control",
76f1ae32a1SGerd Hoffmann     [STRING_OUTPUT_TERMINAL]    = "Audio Output Terminal",
77f1ae32a1SGerd Hoffmann     [STRING_NULL_STREAM]        = "Audio Output - Disabled",
78f1ae32a1SGerd Hoffmann     [STRING_REAL_STREAM]        = "Audio Output - 48 kHz Stereo",
79f1ae32a1SGerd Hoffmann };
80f1ae32a1SGerd Hoffmann 
81f1ae32a1SGerd Hoffmann #define U16(x) ((x) & 0xff), (((x) >> 8) & 0xff)
82f1ae32a1SGerd Hoffmann #define U24(x) U16(x), (((x) >> 16) & 0xff)
83f1ae32a1SGerd Hoffmann #define U32(x) U24(x), (((x) >> 24) & 0xff)
84f1ae32a1SGerd Hoffmann 
85f1ae32a1SGerd Hoffmann /*
86f1ae32a1SGerd Hoffmann  * A Basic Audio Device uses these specific values
87f1ae32a1SGerd Hoffmann  */
88f1ae32a1SGerd Hoffmann #define USBAUDIO_PACKET_SIZE     192
89f1ae32a1SGerd Hoffmann #define USBAUDIO_SAMPLE_RATE     48000
90f1ae32a1SGerd Hoffmann #define USBAUDIO_PACKET_INTERVAL 1
91f1ae32a1SGerd Hoffmann 
92f1ae32a1SGerd Hoffmann static const USBDescIface desc_iface[] = {
93f1ae32a1SGerd Hoffmann     {
94f1ae32a1SGerd Hoffmann         .bInterfaceNumber              = 0,
95f1ae32a1SGerd Hoffmann         .bNumEndpoints                 = 0,
96f1ae32a1SGerd Hoffmann         .bInterfaceClass               = USB_CLASS_AUDIO,
97f1ae32a1SGerd Hoffmann         .bInterfaceSubClass            = USB_SUBCLASS_AUDIO_CONTROL,
98f1ae32a1SGerd Hoffmann         .bInterfaceProtocol            = 0x04,
99f1ae32a1SGerd Hoffmann         .iInterface                    = STRING_USBAUDIO_CONTROL,
100f1ae32a1SGerd Hoffmann         .ndesc                         = 4,
101f1ae32a1SGerd Hoffmann         .descs = (USBDescOther[]) {
102f1ae32a1SGerd Hoffmann             {
103f1ae32a1SGerd Hoffmann                 /* Headphone Class-Specific AC Interface Header Descriptor */
104f1ae32a1SGerd Hoffmann                 .data = (uint8_t[]) {
105f1ae32a1SGerd Hoffmann                     0x09,                       /*  u8  bLength */
106f1ae32a1SGerd Hoffmann                     USB_DT_CS_INTERFACE,        /*  u8  bDescriptorType */
107f1ae32a1SGerd Hoffmann                     DST_AC_HEADER,              /*  u8  bDescriptorSubtype */
108f1ae32a1SGerd Hoffmann                     U16(0x0100),                /* u16  bcdADC */
109f1ae32a1SGerd Hoffmann                     U16(0x2b),                  /* u16  wTotalLength */
110f1ae32a1SGerd Hoffmann                     0x01,                       /*  u8  bInCollection */
111f1ae32a1SGerd Hoffmann                     0x01,                       /*  u8  baInterfaceNr */
112f1ae32a1SGerd Hoffmann                 }
113f1ae32a1SGerd Hoffmann             },{
114f1ae32a1SGerd Hoffmann                 /* Generic Stereo Input Terminal ID1 Descriptor */
115f1ae32a1SGerd Hoffmann                 .data = (uint8_t[]) {
116f1ae32a1SGerd Hoffmann                     0x0c,                       /*  u8  bLength */
117f1ae32a1SGerd Hoffmann                     USB_DT_CS_INTERFACE,        /*  u8  bDescriptorType */
118f1ae32a1SGerd Hoffmann                     DST_AC_INPUT_TERMINAL,      /*  u8  bDescriptorSubtype */
119f1ae32a1SGerd Hoffmann                     0x01,                       /*  u8  bTerminalID */
120f1ae32a1SGerd Hoffmann                     U16(0x0101),                /* u16  wTerminalType */
121f1ae32a1SGerd Hoffmann                     0x00,                       /*  u8  bAssocTerminal */
122f1ae32a1SGerd Hoffmann                     0x02,                       /* u16  bNrChannels */
123f1ae32a1SGerd Hoffmann                     U16(0x0003),                /* u16  wChannelConfig */
124f1ae32a1SGerd Hoffmann                     0x00,                       /*  u8  iChannelNames */
125f1ae32a1SGerd Hoffmann                     STRING_INPUT_TERMINAL,      /*  u8  iTerminal */
126f1ae32a1SGerd Hoffmann                 }
127f1ae32a1SGerd Hoffmann             },{
128f1ae32a1SGerd Hoffmann                 /* Generic Stereo Feature Unit ID2 Descriptor */
129f1ae32a1SGerd Hoffmann                 .data = (uint8_t[]) {
130f1ae32a1SGerd Hoffmann                     0x0d,                       /*  u8  bLength */
131f1ae32a1SGerd Hoffmann                     USB_DT_CS_INTERFACE,        /*  u8  bDescriptorType */
132f1ae32a1SGerd Hoffmann                     DST_AC_FEATURE_UNIT,        /*  u8  bDescriptorSubtype */
133f1ae32a1SGerd Hoffmann                     0x02,                       /*  u8  bUnitID */
134f1ae32a1SGerd Hoffmann                     0x01,                       /*  u8  bSourceID */
135f1ae32a1SGerd Hoffmann                     0x02,                       /*  u8  bControlSize */
136f1ae32a1SGerd Hoffmann                     U16(0x0001),                /* u16  bmaControls(0) */
137f1ae32a1SGerd Hoffmann                     U16(0x0002),                /* u16  bmaControls(1) */
138f1ae32a1SGerd Hoffmann                     U16(0x0002),                /* u16  bmaControls(2) */
139f1ae32a1SGerd Hoffmann                     STRING_FEATURE_UNIT,        /*  u8  iFeature */
140f1ae32a1SGerd Hoffmann                 }
141f1ae32a1SGerd Hoffmann             },{
142f1ae32a1SGerd Hoffmann                 /* Headphone Ouptut Terminal ID3 Descriptor */
143f1ae32a1SGerd Hoffmann                 .data = (uint8_t[]) {
144f1ae32a1SGerd Hoffmann                     0x09,                       /*  u8  bLength */
145f1ae32a1SGerd Hoffmann                     USB_DT_CS_INTERFACE,        /*  u8  bDescriptorType */
146f1ae32a1SGerd Hoffmann                     DST_AC_OUTPUT_TERMINAL,     /*  u8  bDescriptorSubtype */
147f1ae32a1SGerd Hoffmann                     0x03,                       /*  u8  bUnitID */
148f1ae32a1SGerd Hoffmann                     U16(0x0301),                /* u16  wTerminalType (SPK) */
149f1ae32a1SGerd Hoffmann                     0x00,                       /*  u8  bAssocTerminal */
150f1ae32a1SGerd Hoffmann                     0x02,                       /*  u8  bSourceID */
151f1ae32a1SGerd Hoffmann                     STRING_OUTPUT_TERMINAL,     /*  u8  iTerminal */
152f1ae32a1SGerd Hoffmann                 }
153f1ae32a1SGerd Hoffmann             }
154f1ae32a1SGerd Hoffmann         },
155f1ae32a1SGerd Hoffmann     },{
156f1ae32a1SGerd Hoffmann         .bInterfaceNumber              = 1,
157f1ae32a1SGerd Hoffmann         .bAlternateSetting             = 0,
158f1ae32a1SGerd Hoffmann         .bNumEndpoints                 = 0,
159f1ae32a1SGerd Hoffmann         .bInterfaceClass               = USB_CLASS_AUDIO,
160f1ae32a1SGerd Hoffmann         .bInterfaceSubClass            = USB_SUBCLASS_AUDIO_STREAMING,
161f1ae32a1SGerd Hoffmann         .iInterface                    = STRING_NULL_STREAM,
162f1ae32a1SGerd Hoffmann     },{
163f1ae32a1SGerd Hoffmann         .bInterfaceNumber              = 1,
164f1ae32a1SGerd Hoffmann         .bAlternateSetting             = 1,
165f1ae32a1SGerd Hoffmann         .bNumEndpoints                 = 1,
166f1ae32a1SGerd Hoffmann         .bInterfaceClass               = USB_CLASS_AUDIO,
167f1ae32a1SGerd Hoffmann         .bInterfaceSubClass            = USB_SUBCLASS_AUDIO_STREAMING,
168f1ae32a1SGerd Hoffmann         .iInterface                    = STRING_REAL_STREAM,
169f1ae32a1SGerd Hoffmann         .ndesc                         = 2,
170f1ae32a1SGerd Hoffmann         .descs = (USBDescOther[]) {
171f1ae32a1SGerd Hoffmann             {
172f1ae32a1SGerd Hoffmann                 /* Headphone Class-specific AS General Interface Descriptor */
173f1ae32a1SGerd Hoffmann                 .data = (uint8_t[]) {
174f1ae32a1SGerd Hoffmann                     0x07,                       /*  u8  bLength */
175f1ae32a1SGerd Hoffmann                     USB_DT_CS_INTERFACE,        /*  u8  bDescriptorType */
176f1ae32a1SGerd Hoffmann                     DST_AS_GENERAL,             /*  u8  bDescriptorSubtype */
177f1ae32a1SGerd Hoffmann                     0x01,                       /*  u8  bTerminalLink */
178f1ae32a1SGerd Hoffmann                     0x00,                       /*  u8  bDelay */
179f1ae32a1SGerd Hoffmann                     0x01, 0x00,                 /* u16  wFormatTag */
180f1ae32a1SGerd Hoffmann                 }
181f1ae32a1SGerd Hoffmann             },{
182f1ae32a1SGerd Hoffmann                 /* Headphone Type I Format Type Descriptor */
183f1ae32a1SGerd Hoffmann                 .data = (uint8_t[]) {
184f1ae32a1SGerd Hoffmann                     0x0b,                       /*  u8  bLength */
185f1ae32a1SGerd Hoffmann                     USB_DT_CS_INTERFACE,        /*  u8  bDescriptorType */
186f1ae32a1SGerd Hoffmann                     DST_AS_FORMAT_TYPE,         /*  u8  bDescriptorSubtype */
187f1ae32a1SGerd Hoffmann                     0x01,                       /*  u8  bFormatType */
188f1ae32a1SGerd Hoffmann                     0x02,                       /*  u8  bNrChannels */
189f1ae32a1SGerd Hoffmann                     0x02,                       /*  u8  bSubFrameSize */
190f1ae32a1SGerd Hoffmann                     0x10,                       /*  u8  bBitResolution */
191f1ae32a1SGerd Hoffmann                     0x01,                       /*  u8  bSamFreqType */
192f1ae32a1SGerd Hoffmann                     U24(USBAUDIO_SAMPLE_RATE),  /* u24  tSamFreq */
193f1ae32a1SGerd Hoffmann                 }
194f1ae32a1SGerd Hoffmann             }
195f1ae32a1SGerd Hoffmann         },
196f1ae32a1SGerd Hoffmann         .eps = (USBDescEndpoint[]) {
197f1ae32a1SGerd Hoffmann             {
198f1ae32a1SGerd Hoffmann                 .bEndpointAddress      = USB_DIR_OUT | 0x01,
199f1ae32a1SGerd Hoffmann                 .bmAttributes          = 0x0d,
200f1ae32a1SGerd Hoffmann                 .wMaxPacketSize        = USBAUDIO_PACKET_SIZE,
201f1ae32a1SGerd Hoffmann                 .bInterval             = 1,
202f1ae32a1SGerd Hoffmann                 .is_audio              = 1,
203f1ae32a1SGerd Hoffmann                 /* Stereo Headphone Class-specific
204f1ae32a1SGerd Hoffmann                    AS Audio Data Endpoint Descriptor */
205f1ae32a1SGerd Hoffmann                 .extra = (uint8_t[]) {
206f1ae32a1SGerd Hoffmann                     0x07,                       /*  u8  bLength */
207f1ae32a1SGerd Hoffmann                     USB_DT_CS_ENDPOINT,         /*  u8  bDescriptorType */
208f1ae32a1SGerd Hoffmann                     DST_EP_GENERAL,             /*  u8  bDescriptorSubtype */
209f1ae32a1SGerd Hoffmann                     0x00,                       /*  u8  bmAttributes */
210f1ae32a1SGerd Hoffmann                     0x00,                       /*  u8  bLockDelayUnits */
211f1ae32a1SGerd Hoffmann                     U16(0x0000),                /* u16  wLockDelay */
212f1ae32a1SGerd Hoffmann                 },
213f1ae32a1SGerd Hoffmann             },
214f1ae32a1SGerd Hoffmann         }
215f1ae32a1SGerd Hoffmann     }
216f1ae32a1SGerd Hoffmann };
217f1ae32a1SGerd Hoffmann 
218f1ae32a1SGerd Hoffmann static const USBDescDevice desc_device = {
2192bbd086cSGerd Hoffmann     .bcdUSB                        = 0x0100,
220f1ae32a1SGerd Hoffmann     .bMaxPacketSize0               = 64,
221f1ae32a1SGerd Hoffmann     .bNumConfigurations            = 1,
222f1ae32a1SGerd Hoffmann     .confs = (USBDescConfig[]) {
223f1ae32a1SGerd Hoffmann         {
224f1ae32a1SGerd Hoffmann             .bNumInterfaces        = 2,
225f1ae32a1SGerd Hoffmann             .bConfigurationValue   = DEV_CONFIG_VALUE,
226f1ae32a1SGerd Hoffmann             .iConfiguration        = STRING_CONFIG,
227*bd93976aSPantelis Koukousoulas             .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
228f1ae32a1SGerd Hoffmann             .bMaxPower             = 0x32,
229f1ae32a1SGerd Hoffmann             .nif = ARRAY_SIZE(desc_iface),
230f1ae32a1SGerd Hoffmann             .ifs = desc_iface,
231f1ae32a1SGerd Hoffmann         },
232f1ae32a1SGerd Hoffmann     },
233f1ae32a1SGerd Hoffmann };
234f1ae32a1SGerd Hoffmann 
235f1ae32a1SGerd Hoffmann static const USBDesc desc_audio = {
236f1ae32a1SGerd Hoffmann     .id = {
237f1ae32a1SGerd Hoffmann         .idVendor          = USBAUDIO_VENDOR_NUM,
238f1ae32a1SGerd Hoffmann         .idProduct         = USBAUDIO_PRODUCT_NUM,
239f1ae32a1SGerd Hoffmann         .bcdDevice         = 0,
240f1ae32a1SGerd Hoffmann         .iManufacturer     = STRING_MANUFACTURER,
241f1ae32a1SGerd Hoffmann         .iProduct          = STRING_PRODUCT,
242f1ae32a1SGerd Hoffmann         .iSerialNumber     = STRING_SERIALNUMBER,
243f1ae32a1SGerd Hoffmann     },
244f1ae32a1SGerd Hoffmann     .full = &desc_device,
245f1ae32a1SGerd Hoffmann     .str  = usb_audio_stringtable,
246f1ae32a1SGerd Hoffmann };
247f1ae32a1SGerd Hoffmann 
248f1ae32a1SGerd Hoffmann /*
249f1ae32a1SGerd Hoffmann  * A USB audio device supports an arbitrary number of alternate
250f1ae32a1SGerd Hoffmann  * interface settings for each interface.  Each corresponds to a block
251f1ae32a1SGerd Hoffmann  * diagram of parameterized blocks.  This can thus refer to things like
252f1ae32a1SGerd Hoffmann  * number of channels, data rates, or in fact completely different
253f1ae32a1SGerd Hoffmann  * block diagrams.  Alternative setting 0 is always the null block diagram,
254f1ae32a1SGerd Hoffmann  * which is used by a disabled device.
255f1ae32a1SGerd Hoffmann  */
256f1ae32a1SGerd Hoffmann enum usb_audio_altset {
257f1ae32a1SGerd Hoffmann     ALTSET_OFF  = 0x00,         /* No endpoint */
258f1ae32a1SGerd Hoffmann     ALTSET_ON   = 0x01,         /* Single endpoint */
259f1ae32a1SGerd Hoffmann };
260f1ae32a1SGerd Hoffmann 
261f1ae32a1SGerd Hoffmann /*
262f1ae32a1SGerd Hoffmann  * Class-specific control requests
263f1ae32a1SGerd Hoffmann  */
264f1ae32a1SGerd Hoffmann #define CR_SET_CUR      0x01
265f1ae32a1SGerd Hoffmann #define CR_GET_CUR      0x81
266f1ae32a1SGerd Hoffmann #define CR_SET_MIN      0x02
267f1ae32a1SGerd Hoffmann #define CR_GET_MIN      0x82
268f1ae32a1SGerd Hoffmann #define CR_SET_MAX      0x03
269f1ae32a1SGerd Hoffmann #define CR_GET_MAX      0x83
270f1ae32a1SGerd Hoffmann #define CR_SET_RES      0x04
271f1ae32a1SGerd Hoffmann #define CR_GET_RES      0x84
272f1ae32a1SGerd Hoffmann #define CR_SET_MEM      0x05
273f1ae32a1SGerd Hoffmann #define CR_GET_MEM      0x85
274f1ae32a1SGerd Hoffmann #define CR_GET_STAT     0xff
275f1ae32a1SGerd Hoffmann 
276f1ae32a1SGerd Hoffmann /*
277f1ae32a1SGerd Hoffmann  * Feature Unit Control Selectors
278f1ae32a1SGerd Hoffmann  */
279f1ae32a1SGerd Hoffmann #define MUTE_CONTROL                    0x01
280f1ae32a1SGerd Hoffmann #define VOLUME_CONTROL                  0x02
281f1ae32a1SGerd Hoffmann #define BASS_CONTROL                    0x03
282f1ae32a1SGerd Hoffmann #define MID_CONTROL                     0x04
283f1ae32a1SGerd Hoffmann #define TREBLE_CONTROL                  0x05
284f1ae32a1SGerd Hoffmann #define GRAPHIC_EQUALIZER_CONTROL       0x06
285f1ae32a1SGerd Hoffmann #define AUTOMATIC_GAIN_CONTROL          0x07
286f1ae32a1SGerd Hoffmann #define DELAY_CONTROL                   0x08
287f1ae32a1SGerd Hoffmann #define BASS_BOOST_CONTROL              0x09
288f1ae32a1SGerd Hoffmann #define LOUDNESS_CONTROL                0x0a
289f1ae32a1SGerd Hoffmann 
290f1ae32a1SGerd Hoffmann /*
291f1ae32a1SGerd Hoffmann  * buffering
292f1ae32a1SGerd Hoffmann  */
293f1ae32a1SGerd Hoffmann 
294f1ae32a1SGerd Hoffmann struct streambuf {
295f1ae32a1SGerd Hoffmann     uint8_t *data;
296f1ae32a1SGerd Hoffmann     uint32_t size;
297f1ae32a1SGerd Hoffmann     uint32_t prod;
298f1ae32a1SGerd Hoffmann     uint32_t cons;
299f1ae32a1SGerd Hoffmann };
300f1ae32a1SGerd Hoffmann 
301f1ae32a1SGerd Hoffmann static void streambuf_init(struct streambuf *buf, uint32_t size)
302f1ae32a1SGerd Hoffmann {
303f1ae32a1SGerd Hoffmann     g_free(buf->data);
304f1ae32a1SGerd Hoffmann     buf->size = size - (size % USBAUDIO_PACKET_SIZE);
305f1ae32a1SGerd Hoffmann     buf->data = g_malloc(buf->size);
306f1ae32a1SGerd Hoffmann     buf->prod = 0;
307f1ae32a1SGerd Hoffmann     buf->cons = 0;
308f1ae32a1SGerd Hoffmann }
309f1ae32a1SGerd Hoffmann 
310f1ae32a1SGerd Hoffmann static void streambuf_fini(struct streambuf *buf)
311f1ae32a1SGerd Hoffmann {
312f1ae32a1SGerd Hoffmann     g_free(buf->data);
313f1ae32a1SGerd Hoffmann     buf->data = NULL;
314f1ae32a1SGerd Hoffmann }
315f1ae32a1SGerd Hoffmann 
316f1ae32a1SGerd Hoffmann static int streambuf_put(struct streambuf *buf, USBPacket *p)
317f1ae32a1SGerd Hoffmann {
318f1ae32a1SGerd Hoffmann     uint32_t free = buf->size - (buf->prod - buf->cons);
319f1ae32a1SGerd Hoffmann 
320f1ae32a1SGerd Hoffmann     if (!free) {
321f1ae32a1SGerd Hoffmann         return 0;
322f1ae32a1SGerd Hoffmann     }
323f1ae32a1SGerd Hoffmann     assert(free >= USBAUDIO_PACKET_SIZE);
324f1ae32a1SGerd Hoffmann     usb_packet_copy(p, buf->data + (buf->prod % buf->size),
325f1ae32a1SGerd Hoffmann                     USBAUDIO_PACKET_SIZE);
326f1ae32a1SGerd Hoffmann     buf->prod += USBAUDIO_PACKET_SIZE;
327f1ae32a1SGerd Hoffmann     return USBAUDIO_PACKET_SIZE;
328f1ae32a1SGerd Hoffmann }
329f1ae32a1SGerd Hoffmann 
330f1ae32a1SGerd Hoffmann static uint8_t *streambuf_get(struct streambuf *buf)
331f1ae32a1SGerd Hoffmann {
332f1ae32a1SGerd Hoffmann     uint32_t used = buf->prod - buf->cons;
333f1ae32a1SGerd Hoffmann     uint8_t *data;
334f1ae32a1SGerd Hoffmann 
335f1ae32a1SGerd Hoffmann     if (!used) {
336f1ae32a1SGerd Hoffmann         return NULL;
337f1ae32a1SGerd Hoffmann     }
338f1ae32a1SGerd Hoffmann     assert(used >= USBAUDIO_PACKET_SIZE);
339f1ae32a1SGerd Hoffmann     data = buf->data + (buf->cons % buf->size);
340f1ae32a1SGerd Hoffmann     buf->cons += USBAUDIO_PACKET_SIZE;
341f1ae32a1SGerd Hoffmann     return data;
342f1ae32a1SGerd Hoffmann }
343f1ae32a1SGerd Hoffmann 
344f1ae32a1SGerd Hoffmann typedef struct USBAudioState {
345f1ae32a1SGerd Hoffmann     /* qemu interfaces */
346f1ae32a1SGerd Hoffmann     USBDevice dev;
347f1ae32a1SGerd Hoffmann     QEMUSoundCard card;
348f1ae32a1SGerd Hoffmann 
349f1ae32a1SGerd Hoffmann     /* state */
350f1ae32a1SGerd Hoffmann     struct {
351f1ae32a1SGerd Hoffmann         enum usb_audio_altset altset;
352f1ae32a1SGerd Hoffmann         struct audsettings as;
353f1ae32a1SGerd Hoffmann         SWVoiceOut *voice;
354f1ae32a1SGerd Hoffmann         bool mute;
355f1ae32a1SGerd Hoffmann         uint8_t vol[2];
356f1ae32a1SGerd Hoffmann         struct streambuf buf;
357f1ae32a1SGerd Hoffmann     } out;
358f1ae32a1SGerd Hoffmann 
359f1ae32a1SGerd Hoffmann     /* properties */
360f1ae32a1SGerd Hoffmann     uint32_t debug;
361f1ae32a1SGerd Hoffmann     uint32_t buffer;
362f1ae32a1SGerd Hoffmann } USBAudioState;
363f1ae32a1SGerd Hoffmann 
364f1ae32a1SGerd Hoffmann static void output_callback(void *opaque, int avail)
365f1ae32a1SGerd Hoffmann {
366f1ae32a1SGerd Hoffmann     USBAudioState *s = opaque;
367f1ae32a1SGerd Hoffmann     uint8_t *data;
368f1ae32a1SGerd Hoffmann 
369f1ae32a1SGerd Hoffmann     for (;;) {
370f1ae32a1SGerd Hoffmann         if (avail < USBAUDIO_PACKET_SIZE) {
371f1ae32a1SGerd Hoffmann             return;
372f1ae32a1SGerd Hoffmann         }
373f1ae32a1SGerd Hoffmann         data = streambuf_get(&s->out.buf);
374f1ae32a1SGerd Hoffmann         if (NULL == data) {
375f1ae32a1SGerd Hoffmann             return;
376f1ae32a1SGerd Hoffmann         }
377f1ae32a1SGerd Hoffmann         AUD_write(s->out.voice, data, USBAUDIO_PACKET_SIZE);
378f1ae32a1SGerd Hoffmann         avail -= USBAUDIO_PACKET_SIZE;
379f1ae32a1SGerd Hoffmann     }
380f1ae32a1SGerd Hoffmann }
381f1ae32a1SGerd Hoffmann 
382f1ae32a1SGerd Hoffmann static int usb_audio_set_output_altset(USBAudioState *s, int altset)
383f1ae32a1SGerd Hoffmann {
384f1ae32a1SGerd Hoffmann     switch (altset) {
385f1ae32a1SGerd Hoffmann     case ALTSET_OFF:
386f1ae32a1SGerd Hoffmann         streambuf_init(&s->out.buf, s->buffer);
387f1ae32a1SGerd Hoffmann         AUD_set_active_out(s->out.voice, false);
388f1ae32a1SGerd Hoffmann         break;
389f1ae32a1SGerd Hoffmann     case ALTSET_ON:
390f1ae32a1SGerd Hoffmann         AUD_set_active_out(s->out.voice, true);
391f1ae32a1SGerd Hoffmann         break;
392f1ae32a1SGerd Hoffmann     default:
393f1ae32a1SGerd Hoffmann         return -1;
394f1ae32a1SGerd Hoffmann     }
395f1ae32a1SGerd Hoffmann 
396f1ae32a1SGerd Hoffmann     if (s->debug) {
397f1ae32a1SGerd Hoffmann         fprintf(stderr, "usb-audio: set interface %d\n", altset);
398f1ae32a1SGerd Hoffmann     }
399f1ae32a1SGerd Hoffmann     s->out.altset = altset;
400f1ae32a1SGerd Hoffmann     return 0;
401f1ae32a1SGerd Hoffmann }
402f1ae32a1SGerd Hoffmann 
403f1ae32a1SGerd Hoffmann /*
404f1ae32a1SGerd Hoffmann  * Note: we arbitrarily map the volume control range onto -inf..+8 dB
405f1ae32a1SGerd Hoffmann  */
406f1ae32a1SGerd Hoffmann #define ATTRIB_ID(cs, attrib, idif)     \
407f1ae32a1SGerd Hoffmann     (((cs) << 24) | ((attrib) << 16) | (idif))
408f1ae32a1SGerd Hoffmann 
409f1ae32a1SGerd Hoffmann static int usb_audio_get_control(USBAudioState *s, uint8_t attrib,
410f1ae32a1SGerd Hoffmann                                  uint16_t cscn, uint16_t idif,
411f1ae32a1SGerd Hoffmann                                  int length, uint8_t *data)
412f1ae32a1SGerd Hoffmann {
413f1ae32a1SGerd Hoffmann     uint8_t cs = cscn >> 8;
414f1ae32a1SGerd Hoffmann     uint8_t cn = cscn - 1;      /* -1 for the non-present master control */
415f1ae32a1SGerd Hoffmann     uint32_t aid = ATTRIB_ID(cs, attrib, idif);
416f1ae32a1SGerd Hoffmann     int ret = USB_RET_STALL;
417f1ae32a1SGerd Hoffmann 
418f1ae32a1SGerd Hoffmann     switch (aid) {
419f1ae32a1SGerd Hoffmann     case ATTRIB_ID(MUTE_CONTROL, CR_GET_CUR, 0x0200):
420f1ae32a1SGerd Hoffmann         data[0] = s->out.mute;
421f1ae32a1SGerd Hoffmann         ret = 1;
422f1ae32a1SGerd Hoffmann         break;
423f1ae32a1SGerd Hoffmann     case ATTRIB_ID(VOLUME_CONTROL, CR_GET_CUR, 0x0200):
424f1ae32a1SGerd Hoffmann         if (cn < 2) {
425f1ae32a1SGerd Hoffmann             uint16_t vol = (s->out.vol[cn] * 0x8800 + 127) / 255 + 0x8000;
426f1ae32a1SGerd Hoffmann             data[0] = vol;
427f1ae32a1SGerd Hoffmann             data[1] = vol >> 8;
428f1ae32a1SGerd Hoffmann             ret = 2;
429f1ae32a1SGerd Hoffmann         }
430f1ae32a1SGerd Hoffmann         break;
431f1ae32a1SGerd Hoffmann     case ATTRIB_ID(VOLUME_CONTROL, CR_GET_MIN, 0x0200):
432f1ae32a1SGerd Hoffmann         if (cn < 2) {
433f1ae32a1SGerd Hoffmann             data[0] = 0x01;
434f1ae32a1SGerd Hoffmann             data[1] = 0x80;
435f1ae32a1SGerd Hoffmann             ret = 2;
436f1ae32a1SGerd Hoffmann         }
437f1ae32a1SGerd Hoffmann         break;
438f1ae32a1SGerd Hoffmann     case ATTRIB_ID(VOLUME_CONTROL, CR_GET_MAX, 0x0200):
439f1ae32a1SGerd Hoffmann         if (cn < 2) {
440f1ae32a1SGerd Hoffmann             data[0] = 0x00;
441f1ae32a1SGerd Hoffmann             data[1] = 0x08;
442f1ae32a1SGerd Hoffmann             ret = 2;
443f1ae32a1SGerd Hoffmann         }
444f1ae32a1SGerd Hoffmann         break;
445f1ae32a1SGerd Hoffmann     case ATTRIB_ID(VOLUME_CONTROL, CR_GET_RES, 0x0200):
446f1ae32a1SGerd Hoffmann         if (cn < 2) {
447f1ae32a1SGerd Hoffmann             data[0] = 0x88;
448f1ae32a1SGerd Hoffmann             data[1] = 0x00;
449f1ae32a1SGerd Hoffmann             ret = 2;
450f1ae32a1SGerd Hoffmann         }
451f1ae32a1SGerd Hoffmann         break;
452f1ae32a1SGerd Hoffmann     }
453f1ae32a1SGerd Hoffmann 
454f1ae32a1SGerd Hoffmann     return ret;
455f1ae32a1SGerd Hoffmann }
456f1ae32a1SGerd Hoffmann static int usb_audio_set_control(USBAudioState *s, uint8_t attrib,
457f1ae32a1SGerd Hoffmann                                  uint16_t cscn, uint16_t idif,
458f1ae32a1SGerd Hoffmann                                  int length, uint8_t *data)
459f1ae32a1SGerd Hoffmann {
460f1ae32a1SGerd Hoffmann     uint8_t cs = cscn >> 8;
461f1ae32a1SGerd Hoffmann     uint8_t cn = cscn - 1;      /* -1 for the non-present master control */
462f1ae32a1SGerd Hoffmann     uint32_t aid = ATTRIB_ID(cs, attrib, idif);
463f1ae32a1SGerd Hoffmann     int ret = USB_RET_STALL;
464f1ae32a1SGerd Hoffmann     bool set_vol = false;
465f1ae32a1SGerd Hoffmann 
466f1ae32a1SGerd Hoffmann     switch (aid) {
467f1ae32a1SGerd Hoffmann     case ATTRIB_ID(MUTE_CONTROL, CR_SET_CUR, 0x0200):
468f1ae32a1SGerd Hoffmann         s->out.mute = data[0] & 1;
469f1ae32a1SGerd Hoffmann         set_vol = true;
470f1ae32a1SGerd Hoffmann         ret = 0;
471f1ae32a1SGerd Hoffmann         break;
472f1ae32a1SGerd Hoffmann     case ATTRIB_ID(VOLUME_CONTROL, CR_SET_CUR, 0x0200):
473f1ae32a1SGerd Hoffmann         if (cn < 2) {
474f1ae32a1SGerd Hoffmann             uint16_t vol = data[0] + (data[1] << 8);
475f1ae32a1SGerd Hoffmann 
476f1ae32a1SGerd Hoffmann             if (s->debug) {
477f1ae32a1SGerd Hoffmann                 fprintf(stderr, "usb-audio: vol %04x\n", (uint16_t)vol);
478f1ae32a1SGerd Hoffmann             }
479f1ae32a1SGerd Hoffmann 
480f1ae32a1SGerd Hoffmann             vol -= 0x8000;
481f1ae32a1SGerd Hoffmann             vol = (vol * 255 + 0x4400) / 0x8800;
482f1ae32a1SGerd Hoffmann             if (vol > 255) {
483f1ae32a1SGerd Hoffmann                 vol = 255;
484f1ae32a1SGerd Hoffmann             }
485f1ae32a1SGerd Hoffmann 
486f1ae32a1SGerd Hoffmann             s->out.vol[cn] = vol;
487f1ae32a1SGerd Hoffmann             set_vol = true;
488f1ae32a1SGerd Hoffmann             ret = 0;
489f1ae32a1SGerd Hoffmann         }
490f1ae32a1SGerd Hoffmann         break;
491f1ae32a1SGerd Hoffmann     }
492f1ae32a1SGerd Hoffmann 
493f1ae32a1SGerd Hoffmann     if (set_vol) {
494f1ae32a1SGerd Hoffmann         if (s->debug) {
495f1ae32a1SGerd Hoffmann             fprintf(stderr, "usb-audio: mute %d, lvol %3d, rvol %3d\n",
496f1ae32a1SGerd Hoffmann                     s->out.mute, s->out.vol[0], s->out.vol[1]);
497f1ae32a1SGerd Hoffmann         }
498f1ae32a1SGerd Hoffmann         AUD_set_volume_out(s->out.voice, s->out.mute,
499f1ae32a1SGerd Hoffmann                            s->out.vol[0], s->out.vol[1]);
500f1ae32a1SGerd Hoffmann     }
501f1ae32a1SGerd Hoffmann 
502f1ae32a1SGerd Hoffmann     return ret;
503f1ae32a1SGerd Hoffmann }
504f1ae32a1SGerd Hoffmann 
5059a77a0f5SHans de Goede static void usb_audio_handle_control(USBDevice *dev, USBPacket *p,
506f1ae32a1SGerd Hoffmann                                     int request, int value, int index,
507f1ae32a1SGerd Hoffmann                                     int length, uint8_t *data)
508f1ae32a1SGerd Hoffmann {
509f1ae32a1SGerd Hoffmann     USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev);
510f1ae32a1SGerd Hoffmann     int ret = 0;
511f1ae32a1SGerd Hoffmann 
512f1ae32a1SGerd Hoffmann     if (s->debug) {
513f1ae32a1SGerd Hoffmann         fprintf(stderr, "usb-audio: control transaction: "
514f1ae32a1SGerd Hoffmann                 "request 0x%04x value 0x%04x index 0x%04x length 0x%04x\n",
515f1ae32a1SGerd Hoffmann                 request, value, index, length);
516f1ae32a1SGerd Hoffmann     }
517f1ae32a1SGerd Hoffmann 
518f1ae32a1SGerd Hoffmann     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
519f1ae32a1SGerd Hoffmann     if (ret >= 0) {
5209a77a0f5SHans de Goede         return;
521f1ae32a1SGerd Hoffmann     }
522f1ae32a1SGerd Hoffmann 
523f1ae32a1SGerd Hoffmann     switch (request) {
524f1ae32a1SGerd Hoffmann     case ClassInterfaceRequest | CR_GET_CUR:
525f1ae32a1SGerd Hoffmann     case ClassInterfaceRequest | CR_GET_MIN:
526f1ae32a1SGerd Hoffmann     case ClassInterfaceRequest | CR_GET_MAX:
527f1ae32a1SGerd Hoffmann     case ClassInterfaceRequest | CR_GET_RES:
528f1ae32a1SGerd Hoffmann         ret = usb_audio_get_control(s, request & 0xff, value, index,
529f1ae32a1SGerd Hoffmann                                     length, data);
530f1ae32a1SGerd Hoffmann         if (ret < 0) {
531f1ae32a1SGerd Hoffmann             if (s->debug) {
532f1ae32a1SGerd Hoffmann                 fprintf(stderr, "usb-audio: fail: get control\n");
533f1ae32a1SGerd Hoffmann             }
534f1ae32a1SGerd Hoffmann             goto fail;
535f1ae32a1SGerd Hoffmann         }
5369a77a0f5SHans de Goede         p->actual_length = ret;
537f1ae32a1SGerd Hoffmann         break;
538f1ae32a1SGerd Hoffmann 
539f1ae32a1SGerd Hoffmann     case ClassInterfaceOutRequest | CR_SET_CUR:
540f1ae32a1SGerd Hoffmann     case ClassInterfaceOutRequest | CR_SET_MIN:
541f1ae32a1SGerd Hoffmann     case ClassInterfaceOutRequest | CR_SET_MAX:
542f1ae32a1SGerd Hoffmann     case ClassInterfaceOutRequest | CR_SET_RES:
543f1ae32a1SGerd Hoffmann         ret = usb_audio_set_control(s, request & 0xff, value, index,
544f1ae32a1SGerd Hoffmann                                     length, data);
545f1ae32a1SGerd Hoffmann         if (ret < 0) {
546f1ae32a1SGerd Hoffmann             if (s->debug) {
547f1ae32a1SGerd Hoffmann                 fprintf(stderr, "usb-audio: fail: set control\n");
548f1ae32a1SGerd Hoffmann             }
549f1ae32a1SGerd Hoffmann             goto fail;
550f1ae32a1SGerd Hoffmann         }
551f1ae32a1SGerd Hoffmann         break;
552f1ae32a1SGerd Hoffmann 
553f1ae32a1SGerd Hoffmann     default:
554f1ae32a1SGerd Hoffmann fail:
555f1ae32a1SGerd Hoffmann         if (s->debug) {
556f1ae32a1SGerd Hoffmann             fprintf(stderr, "usb-audio: failed control transaction: "
557f1ae32a1SGerd Hoffmann                     "request 0x%04x value 0x%04x index 0x%04x length 0x%04x\n",
558f1ae32a1SGerd Hoffmann                     request, value, index, length);
559f1ae32a1SGerd Hoffmann         }
5609a77a0f5SHans de Goede         p->status = USB_RET_STALL;
561f1ae32a1SGerd Hoffmann         break;
562f1ae32a1SGerd Hoffmann     }
563f1ae32a1SGerd Hoffmann }
564f1ae32a1SGerd Hoffmann 
565f1ae32a1SGerd Hoffmann static void usb_audio_set_interface(USBDevice *dev, int iface,
566f1ae32a1SGerd Hoffmann                                     int old, int value)
567f1ae32a1SGerd Hoffmann {
568f1ae32a1SGerd Hoffmann     USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev);
569f1ae32a1SGerd Hoffmann 
570f1ae32a1SGerd Hoffmann     if (iface == 1) {
571f1ae32a1SGerd Hoffmann         usb_audio_set_output_altset(s, value);
572f1ae32a1SGerd Hoffmann     }
573f1ae32a1SGerd Hoffmann }
574f1ae32a1SGerd Hoffmann 
575f1ae32a1SGerd Hoffmann static void usb_audio_handle_reset(USBDevice *dev)
576f1ae32a1SGerd Hoffmann {
577f1ae32a1SGerd Hoffmann     USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev);
578f1ae32a1SGerd Hoffmann 
579f1ae32a1SGerd Hoffmann     if (s->debug) {
580f1ae32a1SGerd Hoffmann         fprintf(stderr, "usb-audio: reset\n");
581f1ae32a1SGerd Hoffmann     }
582f1ae32a1SGerd Hoffmann     usb_audio_set_output_altset(s, ALTSET_OFF);
583f1ae32a1SGerd Hoffmann }
584f1ae32a1SGerd Hoffmann 
5859a77a0f5SHans de Goede static void usb_audio_handle_dataout(USBAudioState *s, USBPacket *p)
586f1ae32a1SGerd Hoffmann {
587f1ae32a1SGerd Hoffmann     if (s->out.altset == ALTSET_OFF) {
5889a77a0f5SHans de Goede         p->status = USB_RET_STALL;
5899a77a0f5SHans de Goede         return;
590f1ae32a1SGerd Hoffmann     }
591f1ae32a1SGerd Hoffmann 
5929a77a0f5SHans de Goede     streambuf_put(&s->out.buf, p);
5939a77a0f5SHans de Goede     if (p->actual_length < p->iov.size && s->debug > 1) {
594f1ae32a1SGerd Hoffmann         fprintf(stderr, "usb-audio: output overrun (%zd bytes)\n",
5959a77a0f5SHans de Goede                 p->iov.size - p->actual_length);
5969a77a0f5SHans de Goede     }
597f1ae32a1SGerd Hoffmann }
598f1ae32a1SGerd Hoffmann 
5999a77a0f5SHans de Goede static void usb_audio_handle_data(USBDevice *dev, USBPacket *p)
600f1ae32a1SGerd Hoffmann {
601f1ae32a1SGerd Hoffmann     USBAudioState *s = (USBAudioState *) dev;
602f1ae32a1SGerd Hoffmann 
6039a77a0f5SHans de Goede     if (p->pid == USB_TOKEN_OUT && p->ep->nr == 1) {
6049a77a0f5SHans de Goede         usb_audio_handle_dataout(s, p);
6059a77a0f5SHans de Goede         return;
606f1ae32a1SGerd Hoffmann     }
607f1ae32a1SGerd Hoffmann 
6089a77a0f5SHans de Goede     p->status = USB_RET_STALL;
6099a77a0f5SHans de Goede     if (s->debug) {
610f1ae32a1SGerd Hoffmann         fprintf(stderr, "usb-audio: failed data transaction: "
611f1ae32a1SGerd Hoffmann                         "pid 0x%x ep 0x%x len 0x%zx\n",
612f1ae32a1SGerd Hoffmann                         p->pid, p->ep->nr, p->iov.size);
613f1ae32a1SGerd Hoffmann     }
614f1ae32a1SGerd Hoffmann }
615f1ae32a1SGerd Hoffmann 
616f1ae32a1SGerd Hoffmann static void usb_audio_handle_destroy(USBDevice *dev)
617f1ae32a1SGerd Hoffmann {
618f1ae32a1SGerd Hoffmann     USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev);
619f1ae32a1SGerd Hoffmann 
620f1ae32a1SGerd Hoffmann     if (s->debug) {
621f1ae32a1SGerd Hoffmann         fprintf(stderr, "usb-audio: destroy\n");
622f1ae32a1SGerd Hoffmann     }
623f1ae32a1SGerd Hoffmann 
624f1ae32a1SGerd Hoffmann     usb_audio_set_output_altset(s, ALTSET_OFF);
625f1ae32a1SGerd Hoffmann     AUD_close_out(&s->card, s->out.voice);
626f1ae32a1SGerd Hoffmann     AUD_remove_card(&s->card);
627f1ae32a1SGerd Hoffmann 
628f1ae32a1SGerd Hoffmann     streambuf_fini(&s->out.buf);
629f1ae32a1SGerd Hoffmann }
630f1ae32a1SGerd Hoffmann 
631f1ae32a1SGerd Hoffmann static int usb_audio_initfn(USBDevice *dev)
632f1ae32a1SGerd Hoffmann {
633f1ae32a1SGerd Hoffmann     USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev);
634f1ae32a1SGerd Hoffmann 
6359d55d1adSGerd Hoffmann     usb_desc_create_serial(dev);
636f1ae32a1SGerd Hoffmann     usb_desc_init(dev);
637f1ae32a1SGerd Hoffmann     s->dev.opaque = s;
638f1ae32a1SGerd Hoffmann     AUD_register_card("usb-audio", &s->card);
639f1ae32a1SGerd Hoffmann 
640f1ae32a1SGerd Hoffmann     s->out.altset        = ALTSET_OFF;
641f1ae32a1SGerd Hoffmann     s->out.mute          = false;
642f1ae32a1SGerd Hoffmann     s->out.vol[0]        = 240; /* 0 dB */
643f1ae32a1SGerd Hoffmann     s->out.vol[1]        = 240; /* 0 dB */
644f1ae32a1SGerd Hoffmann     s->out.as.freq       = USBAUDIO_SAMPLE_RATE;
645f1ae32a1SGerd Hoffmann     s->out.as.nchannels  = 2;
646f1ae32a1SGerd Hoffmann     s->out.as.fmt        = AUD_FMT_S16;
647f1ae32a1SGerd Hoffmann     s->out.as.endianness = 0;
648f1ae32a1SGerd Hoffmann     streambuf_init(&s->out.buf, s->buffer);
649f1ae32a1SGerd Hoffmann 
650f1ae32a1SGerd Hoffmann     s->out.voice = AUD_open_out(&s->card, s->out.voice, "usb-audio",
651f1ae32a1SGerd Hoffmann                                 s, output_callback, &s->out.as);
652f1ae32a1SGerd Hoffmann     AUD_set_volume_out(s->out.voice, s->out.mute, s->out.vol[0], s->out.vol[1]);
653f1ae32a1SGerd Hoffmann     AUD_set_active_out(s->out.voice, 0);
654f1ae32a1SGerd Hoffmann     return 0;
655f1ae32a1SGerd Hoffmann }
656f1ae32a1SGerd Hoffmann 
657f1ae32a1SGerd Hoffmann static const VMStateDescription vmstate_usb_audio = {
658f1ae32a1SGerd Hoffmann     .name = "usb-audio",
659f1ae32a1SGerd Hoffmann     .unmigratable = 1,
660f1ae32a1SGerd Hoffmann };
661f1ae32a1SGerd Hoffmann 
662f1ae32a1SGerd Hoffmann static Property usb_audio_properties[] = {
663f1ae32a1SGerd Hoffmann     DEFINE_PROP_UINT32("debug", USBAudioState, debug, 0),
664f1ae32a1SGerd Hoffmann     DEFINE_PROP_UINT32("buffer", USBAudioState, buffer,
665f1ae32a1SGerd Hoffmann                        8 * USBAUDIO_PACKET_SIZE),
666f1ae32a1SGerd Hoffmann     DEFINE_PROP_END_OF_LIST(),
667f1ae32a1SGerd Hoffmann };
668f1ae32a1SGerd Hoffmann 
669f1ae32a1SGerd Hoffmann static void usb_audio_class_init(ObjectClass *klass, void *data)
670f1ae32a1SGerd Hoffmann {
671f1ae32a1SGerd Hoffmann     DeviceClass *dc = DEVICE_CLASS(klass);
672f1ae32a1SGerd Hoffmann     USBDeviceClass *k = USB_DEVICE_CLASS(klass);
673f1ae32a1SGerd Hoffmann 
674f1ae32a1SGerd Hoffmann     dc->vmsd          = &vmstate_usb_audio;
675f1ae32a1SGerd Hoffmann     dc->props         = usb_audio_properties;
676125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
677f1ae32a1SGerd Hoffmann     k->product_desc   = "QEMU USB Audio Interface";
678f1ae32a1SGerd Hoffmann     k->usb_desc       = &desc_audio;
679f1ae32a1SGerd Hoffmann     k->init           = usb_audio_initfn;
680f1ae32a1SGerd Hoffmann     k->handle_reset   = usb_audio_handle_reset;
681f1ae32a1SGerd Hoffmann     k->handle_control = usb_audio_handle_control;
682f1ae32a1SGerd Hoffmann     k->handle_data    = usb_audio_handle_data;
683f1ae32a1SGerd Hoffmann     k->handle_destroy = usb_audio_handle_destroy;
684f1ae32a1SGerd Hoffmann     k->set_interface  = usb_audio_set_interface;
685f1ae32a1SGerd Hoffmann }
686f1ae32a1SGerd Hoffmann 
6878c43a6f0SAndreas Färber static const TypeInfo usb_audio_info = {
688f1ae32a1SGerd Hoffmann     .name          = "usb-audio",
689f1ae32a1SGerd Hoffmann     .parent        = TYPE_USB_DEVICE,
690f1ae32a1SGerd Hoffmann     .instance_size = sizeof(USBAudioState),
691f1ae32a1SGerd Hoffmann     .class_init    = usb_audio_class_init,
692f1ae32a1SGerd Hoffmann };
693f1ae32a1SGerd Hoffmann 
694f1ae32a1SGerd Hoffmann static void usb_audio_register_types(void)
695f1ae32a1SGerd Hoffmann {
696f1ae32a1SGerd Hoffmann     type_register_static(&usb_audio_info);
697f1ae32a1SGerd Hoffmann     usb_legacy_register("usb-audio", "audio", NULL);
698f1ae32a1SGerd Hoffmann }
699f1ae32a1SGerd Hoffmann 
700f1ae32a1SGerd Hoffmann type_init(usb_audio_register_types)
701