xref: /freebsd/sys/dev/usb/template/usb_template_audio.c (revision 8e06491a4e5709cf821dc010f349062f7b34c2f4)
1d2b99310SHans Petter Selasky /* $FreeBSD$ */
2399e6543SHans Petter Selasky /*-
3718cf2ccSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4718cf2ccSPedro F. Giffuni  *
5*8e06491aSEdward Tomasz Napierala  * Copyright (c) 2010 Hans Petter Selasky
6*8e06491aSEdward Tomasz Napierala  * Copyright (c) 2018 The FreeBSD Foundation
7*8e06491aSEdward Tomasz Napierala  * All rights reserved.
8*8e06491aSEdward Tomasz Napierala  *
9*8e06491aSEdward Tomasz Napierala  * Portions of this software were developed by Edward Tomasz Napierala
10*8e06491aSEdward Tomasz Napierala  * under sponsorship from the FreeBSD Foundation.
11399e6543SHans Petter Selasky  *
12399e6543SHans Petter Selasky  * Redistribution and use in source and binary forms, with or without
13399e6543SHans Petter Selasky  * modification, are permitted provided that the following conditions
14399e6543SHans Petter Selasky  * are met:
15399e6543SHans Petter Selasky  * 1. Redistributions of source code must retain the above copyright
16399e6543SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer.
17399e6543SHans Petter Selasky  * 2. Redistributions in binary form must reproduce the above copyright
18399e6543SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer in the
19399e6543SHans Petter Selasky  *    documentation and/or other materials provided with the distribution.
20399e6543SHans Petter Selasky  *
21399e6543SHans Petter Selasky  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22399e6543SHans Petter Selasky  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23399e6543SHans Petter Selasky  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24399e6543SHans Petter Selasky  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25399e6543SHans Petter Selasky  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26399e6543SHans Petter Selasky  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27399e6543SHans Petter Selasky  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28399e6543SHans Petter Selasky  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29399e6543SHans Petter Selasky  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30399e6543SHans Petter Selasky  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31399e6543SHans Petter Selasky  * SUCH DAMAGE.
32399e6543SHans Petter Selasky  */
33399e6543SHans Petter Selasky 
34399e6543SHans Petter Selasky /*
35399e6543SHans Petter Selasky  * This file contains the USB template for an USB Audio Device.
36399e6543SHans Petter Selasky  */
37399e6543SHans Petter Selasky 
38d2b99310SHans Petter Selasky #ifdef USB_GLOBAL_INCLUDE_FILE
39d2b99310SHans Petter Selasky #include USB_GLOBAL_INCLUDE_FILE
40d2b99310SHans Petter Selasky #else
41399e6543SHans Petter Selasky #include <sys/stdint.h>
42399e6543SHans Petter Selasky #include <sys/stddef.h>
43399e6543SHans Petter Selasky #include <sys/param.h>
44399e6543SHans Petter Selasky #include <sys/queue.h>
45399e6543SHans Petter Selasky #include <sys/types.h>
46399e6543SHans Petter Selasky #include <sys/systm.h>
47399e6543SHans Petter Selasky #include <sys/kernel.h>
48399e6543SHans Petter Selasky #include <sys/bus.h>
49399e6543SHans Petter Selasky #include <sys/module.h>
50399e6543SHans Petter Selasky #include <sys/lock.h>
51399e6543SHans Petter Selasky #include <sys/mutex.h>
52399e6543SHans Petter Selasky #include <sys/condvar.h>
53399e6543SHans Petter Selasky #include <sys/sysctl.h>
54399e6543SHans Petter Selasky #include <sys/sx.h>
55399e6543SHans Petter Selasky #include <sys/unistd.h>
56399e6543SHans Petter Selasky #include <sys/callout.h>
57399e6543SHans Petter Selasky #include <sys/malloc.h>
58399e6543SHans Petter Selasky #include <sys/priv.h>
59399e6543SHans Petter Selasky 
60399e6543SHans Petter Selasky #include <dev/usb/usb.h>
61399e6543SHans Petter Selasky #include <dev/usb/usbdi.h>
6223ab0871SHans Petter Selasky #include <dev/usb/usb_core.h>
63399e6543SHans Petter Selasky #include <dev/usb/usb_cdc.h>
64*8e06491aSEdward Tomasz Napierala #include <dev/usb/usb_ioctl.h>
65*8e06491aSEdward Tomasz Napierala #include <dev/usb/usb_util.h>
66399e6543SHans Petter Selasky 
67399e6543SHans Petter Selasky #include <dev/usb/template/usb_template.h>
68d2b99310SHans Petter Selasky #endif			/* USB_GLOBAL_INCLUDE_FILE */
69399e6543SHans Petter Selasky 
70399e6543SHans Petter Selasky enum {
71*8e06491aSEdward Tomasz Napierala 	AUDIO_LANG_INDEX,
72*8e06491aSEdward Tomasz Napierala 	AUDIO_MIXER_INDEX,
73*8e06491aSEdward Tomasz Napierala 	AUDIO_RECORD_INDEX,
74*8e06491aSEdward Tomasz Napierala 	AUDIO_PLAYBACK_INDEX,
75*8e06491aSEdward Tomasz Napierala 	AUDIO_PRODUCT_INDEX,
76*8e06491aSEdward Tomasz Napierala 	AUDIO_MAX_INDEX,
77399e6543SHans Petter Selasky };
78399e6543SHans Petter Selasky 
79*8e06491aSEdward Tomasz Napierala #define	AUDIO_DEFAULT_PRODUCT		"Audio Test Device"
80*8e06491aSEdward Tomasz Napierala #define	AUDIO_DEFAULT_MIXER		"Mixer interface"
81*8e06491aSEdward Tomasz Napierala #define	AUDIO_DEFAULT_RECORD		"Record interface"
82*8e06491aSEdward Tomasz Napierala #define	AUDIO_DEFAULT_PLAYBACK		"Playback interface"
83399e6543SHans Petter Selasky 
84*8e06491aSEdward Tomasz Napierala static struct usb_string_descriptor	audio_mixer;
85*8e06491aSEdward Tomasz Napierala static struct usb_string_descriptor	audio_record;
86*8e06491aSEdward Tomasz Napierala static struct usb_string_descriptor	audio_playback;
87*8e06491aSEdward Tomasz Napierala static struct usb_string_descriptor	audio_product;
88399e6543SHans Petter Selasky 
89*8e06491aSEdward Tomasz Napierala static struct sysctl_ctx_list		audio_ctx_list;
90399e6543SHans Petter Selasky 
91399e6543SHans Petter Selasky /* prototypes */
92399e6543SHans Petter Selasky 
93df142785SHans Petter Selasky /*
94df142785SHans Petter Selasky  * Audio Mixer description structures
95df142785SHans Petter Selasky  *
96df142785SHans Petter Selasky  * Some of the audio descriptors were dumped
97df142785SHans Petter Selasky  * from a Creative Labs USB audio device.
98df142785SHans Petter Selasky  */
99399e6543SHans Petter Selasky 
100399e6543SHans Petter Selasky static const uint8_t audio_raw_desc_0[] = {
101399e6543SHans Petter Selasky 	0x0a, 0x24, 0x01, 0x00, 0x01, 0xa9, 0x00, 0x02,
102399e6543SHans Petter Selasky 	0x01, 0x02
103399e6543SHans Petter Selasky };
104399e6543SHans Petter Selasky 
105399e6543SHans Petter Selasky static const uint8_t audio_raw_desc_1[] = {
106399e6543SHans Petter Selasky 	0x0c, 0x24, 0x02, 0x01, 0x01, 0x01, 0x00, 0x02,
107399e6543SHans Petter Selasky 	0x03, 0x00, 0x00, 0x00
108399e6543SHans Petter Selasky };
109399e6543SHans Petter Selasky 
110399e6543SHans Petter Selasky static const uint8_t audio_raw_desc_2[] = {
111399e6543SHans Petter Selasky 	0x0c, 0x24, 0x02, 0x02, 0x01, 0x02, 0x00, 0x02,
112399e6543SHans Petter Selasky 	0x03, 0x00, 0x00, 0x00
113399e6543SHans Petter Selasky };
114399e6543SHans Petter Selasky 
115399e6543SHans Petter Selasky static const uint8_t audio_raw_desc_3[] = {
116399e6543SHans Petter Selasky 	0x0c, 0x24, 0x02, 0x03, 0x03, 0x06, 0x00, 0x02,
117399e6543SHans Petter Selasky 	0x03, 0x00, 0x00, 0x00
118399e6543SHans Petter Selasky };
119399e6543SHans Petter Selasky 
120399e6543SHans Petter Selasky static const uint8_t audio_raw_desc_4[] = {
121399e6543SHans Petter Selasky 	0x0c, 0x24, 0x02, 0x04, 0x05, 0x06, 0x00, 0x02,
122399e6543SHans Petter Selasky 	0x03, 0x00, 0x00, 0x00
123399e6543SHans Petter Selasky };
124399e6543SHans Petter Selasky 
125399e6543SHans Petter Selasky static const uint8_t audio_raw_desc_5[] = {
126399e6543SHans Petter Selasky 	0x09, 0x24, 0x03, 0x05, 0x05, 0x06, 0x00, 0x01,
127399e6543SHans Petter Selasky 	0x00
128399e6543SHans Petter Selasky };
129399e6543SHans Petter Selasky 
130399e6543SHans Petter Selasky static const uint8_t audio_raw_desc_6[] = {
131399e6543SHans Petter Selasky 	0x09, 0x24, 0x03, 0x06, 0x01, 0x03, 0x00, 0x09,
132399e6543SHans Petter Selasky 	0x00
133399e6543SHans Petter Selasky };
134399e6543SHans Petter Selasky 
135399e6543SHans Petter Selasky static const uint8_t audio_raw_desc_7[] = {
136399e6543SHans Petter Selasky 	0x09, 0x24, 0x03, 0x07, 0x01, 0x01, 0x00, 0x08,
137399e6543SHans Petter Selasky 	0x00
138399e6543SHans Petter Selasky };
139399e6543SHans Petter Selasky 
140399e6543SHans Petter Selasky static const uint8_t audio_raw_desc_8[] = {
141399e6543SHans Petter Selasky 	0x09, 0x24, 0x05, 0x08, 0x03, 0x0a, 0x0b, 0x0c,
142399e6543SHans Petter Selasky 	0x00
143399e6543SHans Petter Selasky };
144399e6543SHans Petter Selasky 
145399e6543SHans Petter Selasky static const uint8_t audio_raw_desc_9[] = {
146399e6543SHans Petter Selasky 	0x0a, 0x24, 0x06, 0x09, 0x0f, 0x01, 0x01, 0x02,
147399e6543SHans Petter Selasky 	0x02, 0x00
148399e6543SHans Petter Selasky };
149399e6543SHans Petter Selasky 
150399e6543SHans Petter Selasky static const uint8_t audio_raw_desc_10[] = {
151399e6543SHans Petter Selasky 	0x0a, 0x24, 0x06, 0x0a, 0x02, 0x01, 0x43, 0x00,
152399e6543SHans Petter Selasky 	0x00, 0x00
153399e6543SHans Petter Selasky };
154399e6543SHans Petter Selasky 
155399e6543SHans Petter Selasky static const uint8_t audio_raw_desc_11[] = {
156399e6543SHans Petter Selasky 	0x0a, 0x24, 0x06, 0x0b, 0x03, 0x01, 0x01, 0x02,
157399e6543SHans Petter Selasky 	0x02, 0x00
158399e6543SHans Petter Selasky };
159399e6543SHans Petter Selasky 
160399e6543SHans Petter Selasky static const uint8_t audio_raw_desc_12[] = {
161399e6543SHans Petter Selasky 	0x0a, 0x24, 0x06, 0x0c, 0x04, 0x01, 0x01, 0x00,
162399e6543SHans Petter Selasky 	0x00, 0x00
163399e6543SHans Petter Selasky };
164399e6543SHans Petter Selasky 
165399e6543SHans Petter Selasky static const uint8_t audio_raw_desc_13[] = {
166399e6543SHans Petter Selasky 	0x0a, 0x24, 0x06, 0x0d, 0x02, 0x01, 0x03, 0x00,
167399e6543SHans Petter Selasky 	0x00, 0x00
168399e6543SHans Petter Selasky };
169399e6543SHans Petter Selasky 
170399e6543SHans Petter Selasky static const uint8_t audio_raw_desc_14[] = {
171399e6543SHans Petter Selasky 	0x0a, 0x24, 0x06, 0x0e, 0x03, 0x01, 0x01, 0x02,
172399e6543SHans Petter Selasky 	0x02, 0x00
173399e6543SHans Petter Selasky };
174399e6543SHans Petter Selasky 
175399e6543SHans Petter Selasky static const uint8_t audio_raw_desc_15[] = {
176399e6543SHans Petter Selasky 	0x0f, 0x24, 0x04, 0x0f, 0x03, 0x01, 0x0d, 0x0e,
177399e6543SHans Petter Selasky 	0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00
178399e6543SHans Petter Selasky };
179399e6543SHans Petter Selasky 
180399e6543SHans Petter Selasky static const void *audio_raw_iface_0_desc[] = {
181399e6543SHans Petter Selasky 	audio_raw_desc_0,
182399e6543SHans Petter Selasky 	audio_raw_desc_1,
183399e6543SHans Petter Selasky 	audio_raw_desc_2,
184399e6543SHans Petter Selasky 	audio_raw_desc_3,
185399e6543SHans Petter Selasky 	audio_raw_desc_4,
186399e6543SHans Petter Selasky 	audio_raw_desc_5,
187399e6543SHans Petter Selasky 	audio_raw_desc_6,
188399e6543SHans Petter Selasky 	audio_raw_desc_7,
189399e6543SHans Petter Selasky 	audio_raw_desc_8,
190399e6543SHans Petter Selasky 	audio_raw_desc_9,
191399e6543SHans Petter Selasky 	audio_raw_desc_10,
192399e6543SHans Petter Selasky 	audio_raw_desc_11,
193399e6543SHans Petter Selasky 	audio_raw_desc_12,
194399e6543SHans Petter Selasky 	audio_raw_desc_13,
195399e6543SHans Petter Selasky 	audio_raw_desc_14,
196399e6543SHans Petter Selasky 	audio_raw_desc_15,
197399e6543SHans Petter Selasky 	NULL,
198399e6543SHans Petter Selasky };
199399e6543SHans Petter Selasky 
200399e6543SHans Petter Selasky static const struct usb_temp_interface_desc audio_iface_0 = {
201399e6543SHans Petter Selasky 	.ppEndpoints = NULL,		/* no endpoints */
202399e6543SHans Petter Selasky 	.ppRawDesc = audio_raw_iface_0_desc,
2034ffeccf1SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_AUDIO,
2044ffeccf1SEdward Tomasz Napierala 	.bInterfaceSubClass = UISUBCLASS_AUDIOCONTROL,
205399e6543SHans Petter Selasky 	.bInterfaceProtocol = 0,
206*8e06491aSEdward Tomasz Napierala 	.iInterface = AUDIO_MIXER_INDEX,
207399e6543SHans Petter Selasky };
208399e6543SHans Petter Selasky 
209399e6543SHans Petter Selasky static const uint8_t audio_raw_desc_20[] = {
210399e6543SHans Petter Selasky 	0x07, 0x24, 0x01, 0x01, 0x03, 0x01, 0x00
211399e6543SHans Petter Selasky 
212399e6543SHans Petter Selasky };
213399e6543SHans Petter Selasky 
214399e6543SHans Petter Selasky static const uint8_t audio_raw_desc_21[] = {
215399e6543SHans Petter Selasky 	0x0b, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x01,
216399e6543SHans Petter Selasky 	/* 48kHz */
217399e6543SHans Petter Selasky 	0x80, 0xbb, 0x00
218399e6543SHans Petter Selasky };
219399e6543SHans Petter Selasky 
220399e6543SHans Petter Selasky static const uint8_t audio_raw_desc_22[] = {
221399e6543SHans Petter Selasky 	0x07, 0x25, 0x01, 0x00, 0x01, 0x04, 0x00
222399e6543SHans Petter Selasky };
223399e6543SHans Petter Selasky 
224399e6543SHans Petter Selasky static const void *audio_raw_iface_1_desc[] = {
225399e6543SHans Petter Selasky 	audio_raw_desc_20,
226399e6543SHans Petter Selasky 	audio_raw_desc_21,
227399e6543SHans Petter Selasky 	NULL,
228399e6543SHans Petter Selasky };
229399e6543SHans Petter Selasky 
230399e6543SHans Petter Selasky static const void *audio_raw_ep_1_desc[] = {
231399e6543SHans Petter Selasky 	audio_raw_desc_22,
232399e6543SHans Petter Selasky 	NULL,
233399e6543SHans Petter Selasky };
234399e6543SHans Petter Selasky 
235399e6543SHans Petter Selasky static const struct usb_temp_packet_size audio_isoc_mps = {
236399e6543SHans Petter Selasky   .mps[USB_SPEED_FULL] = 0xC8,
237399e6543SHans Petter Selasky   .mps[USB_SPEED_HIGH] = 0xC8,
238399e6543SHans Petter Selasky };
239399e6543SHans Petter Selasky 
240399e6543SHans Petter Selasky static const struct usb_temp_interval audio_isoc_interval = {
241399e6543SHans Petter Selasky 	.bInterval[USB_SPEED_FULL] = 1,	/* 1:1 */
242399e6543SHans Petter Selasky 	.bInterval[USB_SPEED_HIGH] = 4,	/* 1:8 */
243399e6543SHans Petter Selasky };
244399e6543SHans Petter Selasky 
245399e6543SHans Petter Selasky static const struct usb_temp_endpoint_desc audio_isoc_out_ep = {
246399e6543SHans Petter Selasky 	.ppRawDesc = audio_raw_ep_1_desc,
247399e6543SHans Petter Selasky 	.pPacketSize = &audio_isoc_mps,
248399e6543SHans Petter Selasky 	.pIntervals = &audio_isoc_interval,
249399e6543SHans Petter Selasky 	.bEndpointAddress = UE_DIR_OUT,
250399e6543SHans Petter Selasky 	.bmAttributes = UE_ISOCHRONOUS | UE_ISO_ADAPT,
251399e6543SHans Petter Selasky };
252399e6543SHans Petter Selasky 
253399e6543SHans Petter Selasky static const struct usb_temp_endpoint_desc *audio_iface_1_ep[] = {
254399e6543SHans Petter Selasky 	&audio_isoc_out_ep,
255399e6543SHans Petter Selasky 	NULL,
256399e6543SHans Petter Selasky };
257399e6543SHans Petter Selasky 
258399e6543SHans Petter Selasky static const struct usb_temp_interface_desc audio_iface_1_alt_0 = {
259399e6543SHans Petter Selasky 	.ppEndpoints = NULL,		/* no endpoints */
260399e6543SHans Petter Selasky 	.ppRawDesc = NULL,		/* no raw descriptors */
2614ffeccf1SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_AUDIO,
2624ffeccf1SEdward Tomasz Napierala 	.bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
263399e6543SHans Petter Selasky 	.bInterfaceProtocol = 0,
264*8e06491aSEdward Tomasz Napierala 	.iInterface = AUDIO_PLAYBACK_INDEX,
265399e6543SHans Petter Selasky };
266399e6543SHans Petter Selasky 
267399e6543SHans Petter Selasky static const struct usb_temp_interface_desc audio_iface_1_alt_1 = {
268399e6543SHans Petter Selasky 	.ppEndpoints = audio_iface_1_ep,
269399e6543SHans Petter Selasky 	.ppRawDesc = audio_raw_iface_1_desc,
2704ffeccf1SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_AUDIO,
2714ffeccf1SEdward Tomasz Napierala 	.bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
272399e6543SHans Petter Selasky 	.bInterfaceProtocol = 0,
273*8e06491aSEdward Tomasz Napierala 	.iInterface = AUDIO_PLAYBACK_INDEX,
274399e6543SHans Petter Selasky 	.isAltInterface = 1,		/* this is an alternate setting */
275399e6543SHans Petter Selasky };
276399e6543SHans Petter Selasky 
277399e6543SHans Petter Selasky static const uint8_t audio_raw_desc_30[] = {
278399e6543SHans Petter Selasky 	0x07, 0x24, 0x01, 0x07, 0x01, 0x01, 0x00
279399e6543SHans Petter Selasky 
280399e6543SHans Petter Selasky };
281399e6543SHans Petter Selasky 
282399e6543SHans Petter Selasky static const uint8_t audio_raw_desc_31[] = {
283399e6543SHans Petter Selasky 	0x0b, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x01,
284399e6543SHans Petter Selasky 	/* 48kHz */
285399e6543SHans Petter Selasky 	0x80, 0xbb, 0x00
286399e6543SHans Petter Selasky };
287399e6543SHans Petter Selasky 
288399e6543SHans Petter Selasky static const uint8_t audio_raw_desc_32[] = {
289399e6543SHans Petter Selasky 	0x07, 0x25, 0x01, 0x01, 0x00, 0x00, 0x00
290399e6543SHans Petter Selasky };
291399e6543SHans Petter Selasky 
292399e6543SHans Petter Selasky static const void *audio_raw_iface_2_desc[] = {
293399e6543SHans Petter Selasky 	audio_raw_desc_30,
294399e6543SHans Petter Selasky 	audio_raw_desc_31,
295399e6543SHans Petter Selasky 	NULL,
296399e6543SHans Petter Selasky };
297399e6543SHans Petter Selasky 
298399e6543SHans Petter Selasky static const void *audio_raw_ep_2_desc[] = {
299399e6543SHans Petter Selasky 	audio_raw_desc_32,
300399e6543SHans Petter Selasky 	NULL,
301399e6543SHans Petter Selasky };
302399e6543SHans Petter Selasky 
303399e6543SHans Petter Selasky static const struct usb_temp_endpoint_desc audio_isoc_in_ep = {
304399e6543SHans Petter Selasky 	.ppRawDesc = audio_raw_ep_2_desc,
305399e6543SHans Petter Selasky 	.pPacketSize = &audio_isoc_mps,
306399e6543SHans Petter Selasky 	.pIntervals = &audio_isoc_interval,
307399e6543SHans Petter Selasky 	.bEndpointAddress = UE_DIR_IN,
308399e6543SHans Petter Selasky 	.bmAttributes = UE_ISOCHRONOUS | UE_ISO_ADAPT,
309399e6543SHans Petter Selasky };
310399e6543SHans Petter Selasky 
311399e6543SHans Petter Selasky static const struct usb_temp_endpoint_desc *audio_iface_2_ep[] = {
312399e6543SHans Petter Selasky 	&audio_isoc_in_ep,
313399e6543SHans Petter Selasky 	NULL,
314399e6543SHans Petter Selasky };
315399e6543SHans Petter Selasky 
316399e6543SHans Petter Selasky static const struct usb_temp_interface_desc audio_iface_2_alt_0 = {
317399e6543SHans Petter Selasky 	.ppEndpoints = NULL,		/* no endpoints */
318399e6543SHans Petter Selasky 	.ppRawDesc = NULL,		/* no raw descriptors */
3194ffeccf1SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_AUDIO,
3204ffeccf1SEdward Tomasz Napierala 	.bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
321399e6543SHans Petter Selasky 	.bInterfaceProtocol = 0,
322*8e06491aSEdward Tomasz Napierala 	.iInterface = AUDIO_RECORD_INDEX,
323399e6543SHans Petter Selasky };
324399e6543SHans Petter Selasky 
325399e6543SHans Petter Selasky static const struct usb_temp_interface_desc audio_iface_2_alt_1 = {
326399e6543SHans Petter Selasky 	.ppEndpoints = audio_iface_2_ep,
327399e6543SHans Petter Selasky 	.ppRawDesc = audio_raw_iface_2_desc,
3284ffeccf1SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_AUDIO,
3294ffeccf1SEdward Tomasz Napierala 	.bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
330399e6543SHans Petter Selasky 	.bInterfaceProtocol = 0,
331*8e06491aSEdward Tomasz Napierala 	.iInterface = AUDIO_RECORD_INDEX,
332399e6543SHans Petter Selasky 	.isAltInterface = 1,		/* this is an alternate setting */
333399e6543SHans Petter Selasky };
334399e6543SHans Petter Selasky 
335399e6543SHans Petter Selasky static const struct usb_temp_interface_desc *audio_interfaces[] = {
336399e6543SHans Petter Selasky 	&audio_iface_0,
337399e6543SHans Petter Selasky 	&audio_iface_1_alt_0,
338399e6543SHans Petter Selasky 	&audio_iface_1_alt_1,
339399e6543SHans Petter Selasky 	&audio_iface_2_alt_0,
340399e6543SHans Petter Selasky 	&audio_iface_2_alt_1,
341399e6543SHans Petter Selasky 	NULL,
342399e6543SHans Petter Selasky };
343399e6543SHans Petter Selasky 
344399e6543SHans Petter Selasky static const struct usb_temp_config_desc audio_config_desc = {
345399e6543SHans Petter Selasky 	.ppIfaceDesc = audio_interfaces,
346399e6543SHans Petter Selasky 	.bmAttributes = UC_BUS_POWERED,
347399e6543SHans Petter Selasky 	.bMaxPower = 25,		/* 50 mA */
348*8e06491aSEdward Tomasz Napierala 	.iConfiguration = AUDIO_PRODUCT_INDEX,
349399e6543SHans Petter Selasky };
350399e6543SHans Petter Selasky 
351399e6543SHans Petter Selasky static const struct usb_temp_config_desc *audio_configs[] = {
352399e6543SHans Petter Selasky 	&audio_config_desc,
353399e6543SHans Petter Selasky 	NULL,
354399e6543SHans Petter Selasky };
355399e6543SHans Petter Selasky 
356399e6543SHans Petter Selasky static usb_temp_get_string_desc_t audio_get_string_desc;
357399e6543SHans Petter Selasky 
358*8e06491aSEdward Tomasz Napierala struct usb_temp_device_desc usb_template_audio = {
359399e6543SHans Petter Selasky 	.getStringDesc = &audio_get_string_desc,
360399e6543SHans Petter Selasky 	.ppConfigDesc = audio_configs,
361399e6543SHans Petter Selasky 	.idVendor = USB_TEMPLATE_VENDOR,
362399e6543SHans Petter Selasky 	.idProduct = 0x000A,
363399e6543SHans Petter Selasky 	.bcdDevice = 0x0100,
364399e6543SHans Petter Selasky 	.bDeviceClass = UDCLASS_COMM,
365399e6543SHans Petter Selasky 	.bDeviceSubClass = 0,
366399e6543SHans Petter Selasky 	.bDeviceProtocol = 0,
367*8e06491aSEdward Tomasz Napierala 	.iProduct = AUDIO_PRODUCT_INDEX,
368399e6543SHans Petter Selasky };
369399e6543SHans Petter Selasky 
370399e6543SHans Petter Selasky /*------------------------------------------------------------------------*
371399e6543SHans Petter Selasky  *	audio_get_string_desc
372399e6543SHans Petter Selasky  *
373399e6543SHans Petter Selasky  * Return values:
374399e6543SHans Petter Selasky  * NULL: Failure. No such string.
375399e6543SHans Petter Selasky  * Else: Success. Pointer to string descriptor is returned.
376399e6543SHans Petter Selasky  *------------------------------------------------------------------------*/
377399e6543SHans Petter Selasky static const void *
378399e6543SHans Petter Selasky audio_get_string_desc(uint16_t lang_id, uint8_t string_index)
379399e6543SHans Petter Selasky {
380*8e06491aSEdward Tomasz Napierala 	static const void *ptr[AUDIO_MAX_INDEX] = {
381*8e06491aSEdward Tomasz Napierala 		[AUDIO_LANG_INDEX] = &usb_string_lang_en,
382*8e06491aSEdward Tomasz Napierala 		[AUDIO_MIXER_INDEX] = &audio_mixer,
383*8e06491aSEdward Tomasz Napierala 		[AUDIO_RECORD_INDEX] = &audio_record,
384*8e06491aSEdward Tomasz Napierala 		[AUDIO_PLAYBACK_INDEX] = &audio_playback,
385*8e06491aSEdward Tomasz Napierala 		[AUDIO_PRODUCT_INDEX] = &audio_product,
386399e6543SHans Petter Selasky 	};
387399e6543SHans Petter Selasky 
388399e6543SHans Petter Selasky 	if (string_index == 0) {
38923ab0871SHans Petter Selasky 		return (&usb_string_lang_en);
390399e6543SHans Petter Selasky 	}
391399e6543SHans Petter Selasky 	if (lang_id != 0x0409) {
392399e6543SHans Petter Selasky 		return (NULL);
393399e6543SHans Petter Selasky 	}
394*8e06491aSEdward Tomasz Napierala 	if (string_index < AUDIO_MAX_INDEX) {
395399e6543SHans Petter Selasky 		return (ptr[string_index]);
396399e6543SHans Petter Selasky 	}
397399e6543SHans Petter Selasky 	return (NULL);
398399e6543SHans Petter Selasky }
399*8e06491aSEdward Tomasz Napierala 
400*8e06491aSEdward Tomasz Napierala static void
401*8e06491aSEdward Tomasz Napierala audio_init(void *arg __unused)
402*8e06491aSEdward Tomasz Napierala {
403*8e06491aSEdward Tomasz Napierala 	struct sysctl_oid *parent;
404*8e06491aSEdward Tomasz Napierala 	char parent_name[3];
405*8e06491aSEdward Tomasz Napierala 
406*8e06491aSEdward Tomasz Napierala 	usb_make_str_desc(&audio_mixer, sizeof(audio_mixer),
407*8e06491aSEdward Tomasz Napierala 	    AUDIO_DEFAULT_MIXER);
408*8e06491aSEdward Tomasz Napierala 	usb_make_str_desc(&audio_record, sizeof(audio_record),
409*8e06491aSEdward Tomasz Napierala 	    AUDIO_DEFAULT_RECORD);
410*8e06491aSEdward Tomasz Napierala 	usb_make_str_desc(&audio_playback, sizeof(audio_playback),
411*8e06491aSEdward Tomasz Napierala 	    AUDIO_DEFAULT_PLAYBACK);
412*8e06491aSEdward Tomasz Napierala 	usb_make_str_desc(&audio_product, sizeof(audio_product),
413*8e06491aSEdward Tomasz Napierala 	    AUDIO_DEFAULT_PRODUCT);
414*8e06491aSEdward Tomasz Napierala 
415*8e06491aSEdward Tomasz Napierala 	snprintf(parent_name, sizeof(parent_name), "%d", USB_TEMP_AUDIO);
416*8e06491aSEdward Tomasz Napierala 	sysctl_ctx_init(&audio_ctx_list);
417*8e06491aSEdward Tomasz Napierala 
418*8e06491aSEdward Tomasz Napierala 	parent = SYSCTL_ADD_NODE(&audio_ctx_list,
419*8e06491aSEdward Tomasz Napierala 	    SYSCTL_STATIC_CHILDREN(_hw_usb_templates), OID_AUTO,
420*8e06491aSEdward Tomasz Napierala 	    parent_name, CTLFLAG_RW,
421*8e06491aSEdward Tomasz Napierala 	    0, "USB Audio Interface device side template");
422*8e06491aSEdward Tomasz Napierala 	SYSCTL_ADD_U16(&audio_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
423*8e06491aSEdward Tomasz Napierala 	    "vendor_id", CTLFLAG_RWTUN, &usb_template_audio.idVendor,
424*8e06491aSEdward Tomasz Napierala 	    1, "Vendor identifier");
425*8e06491aSEdward Tomasz Napierala 	SYSCTL_ADD_U16(&audio_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
426*8e06491aSEdward Tomasz Napierala 	    "product_id", CTLFLAG_RWTUN, &usb_template_audio.idProduct,
427*8e06491aSEdward Tomasz Napierala 	    1, "Product identifier");
428*8e06491aSEdward Tomasz Napierala #if 0
429*8e06491aSEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&audio_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
430*8e06491aSEdward Tomasz Napierala 	    "mixer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
431*8e06491aSEdward Tomasz Napierala 	    &audio_mixer, sizeof(audio_mixer), usb_temp_sysctl,
432*8e06491aSEdward Tomasz Napierala 	    "A", "Mixer interface string");
433*8e06491aSEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&audio_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
434*8e06491aSEdward Tomasz Napierala 	    "record", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
435*8e06491aSEdward Tomasz Napierala 	    &audio_record, sizeof(audio_record), usb_temp_sysctl,
436*8e06491aSEdward Tomasz Napierala 	    "A", "Record interface string");
437*8e06491aSEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&audio_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
438*8e06491aSEdward Tomasz Napierala 	    "playback", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
439*8e06491aSEdward Tomasz Napierala 	    &audio_playback, sizeof(audio_playback), usb_temp_sysctl,
440*8e06491aSEdward Tomasz Napierala 	    "A", "Playback interface string");
441*8e06491aSEdward Tomasz Napierala #endif
442*8e06491aSEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&audio_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
443*8e06491aSEdward Tomasz Napierala 	    "product", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
444*8e06491aSEdward Tomasz Napierala 	    &audio_product, sizeof(audio_product), usb_temp_sysctl,
445*8e06491aSEdward Tomasz Napierala 	    "A", "Product string");
446*8e06491aSEdward Tomasz Napierala }
447*8e06491aSEdward Tomasz Napierala 
448*8e06491aSEdward Tomasz Napierala static void
449*8e06491aSEdward Tomasz Napierala audio_uninit(void *arg __unused)
450*8e06491aSEdward Tomasz Napierala {
451*8e06491aSEdward Tomasz Napierala 
452*8e06491aSEdward Tomasz Napierala 	sysctl_ctx_free(&audio_ctx_list);
453*8e06491aSEdward Tomasz Napierala }
454*8e06491aSEdward Tomasz Napierala 
455*8e06491aSEdward Tomasz Napierala SYSINIT(audio_init, SI_SUB_LOCK, SI_ORDER_FIRST, audio_init, NULL);
456*8e06491aSEdward Tomasz Napierala SYSUNINIT(audio_init, SI_SUB_LOCK, SI_ORDER_FIRST, audio_uninit, NULL);
457