1 /* $FreeBSD: head/sys/dev/usb/template/usb_template_audio.c 246125 2013-01-30 16:05:54Z hselasky $ */
2 /*-
3  * Copyright (c) 2010 Hans Petter Selasky. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 /*
28  * This file contains the USB template for an USB Audio Device.
29  */
30 
31 #ifdef USB_GLOBAL_INCLUDE_FILE
32 #include USB_GLOBAL_INCLUDE_FILE
33 #else
34 #include <sys/stdint.h>
35 #include <sys/param.h>
36 #include <sys/queue.h>
37 #include <sys/types.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/bus.h>
41 #include <sys/module.h>
42 #include <sys/lock.h>
43 #include <sys/condvar.h>
44 #include <sys/sysctl.h>
45 #include <sys/unistd.h>
46 #include <sys/callout.h>
47 #include <sys/malloc.h>
48 #include <sys/caps.h>
49 
50 #include <bus/u4b/usb.h>
51 #include <bus/u4b/usbdi.h>
52 #include <bus/u4b/usb_core.h>
53 #include <bus/u4b/usb_cdc.h>
54 
55 #include <bus/u4b/template/usb_template.h>
56 #endif			/* USB_GLOBAL_INCLUDE_FILE */
57 
58 enum {
59 	INDEX_AUDIO_LANG,
60 	INDEX_AUDIO_MIXER,
61 	INDEX_AUDIO_RECORD,
62 	INDEX_AUDIO_PLAYBACK,
63 	INDEX_AUDIO_PRODUCT,
64 	INDEX_AUDIO_MAX,
65 };
66 
67 #define	STRING_AUDIO_PRODUCT \
68   "A\0u\0d\0i\0o\0 \0T\0e\0s\0t\0 \0D\0e\0v\0i\0c\0e"
69 
70 #define	STRING_AUDIO_MIXER \
71   "M\0i\0x\0e\0r\0 \0i\0n\0t\0e\0r\0f\0a\0c\0e"
72 
73 #define	STRING_AUDIO_RECORD \
74   "R\0e\0c\0o\0r\0d\0 \0i\0n\0t\0e\0r\0f\0a\0c\0e"
75 
76 #define	STRING_AUDIO_PLAYBACK \
77   "P\0l\0a\0y\0b\0a\0c\0k\0 \0i\0n\0t\0e\0r\0f\0a\0c\0e"
78 
79 
80 /* make the real string descriptors */
81 
82 USB_MAKE_STRING_DESC(STRING_AUDIO_MIXER, string_audio_mixer);
83 USB_MAKE_STRING_DESC(STRING_AUDIO_RECORD, string_audio_record);
84 USB_MAKE_STRING_DESC(STRING_AUDIO_PLAYBACK, string_audio_playback);
85 USB_MAKE_STRING_DESC(STRING_AUDIO_PRODUCT, string_audio_product);
86 
87 /* prototypes */
88 
89 /*
90  * Audio Mixer description structures
91  *
92  * Some of the audio descriptors were dumped
93  * from a Creative Labs USB audio device.
94  */
95 
96 static const uint8_t audio_raw_desc_0[] = {
97 	0x0a, 0x24, 0x01, 0x00, 0x01, 0xa9, 0x00, 0x02,
98 	0x01, 0x02
99 };
100 
101 static const uint8_t audio_raw_desc_1[] = {
102 	0x0c, 0x24, 0x02, 0x01, 0x01, 0x01, 0x00, 0x02,
103 	0x03, 0x00, 0x00, 0x00
104 };
105 
106 static const uint8_t audio_raw_desc_2[] = {
107 	0x0c, 0x24, 0x02, 0x02, 0x01, 0x02, 0x00, 0x02,
108 	0x03, 0x00, 0x00, 0x00
109 };
110 
111 static const uint8_t audio_raw_desc_3[] = {
112 	0x0c, 0x24, 0x02, 0x03, 0x03, 0x06, 0x00, 0x02,
113 	0x03, 0x00, 0x00, 0x00
114 };
115 
116 static const uint8_t audio_raw_desc_4[] = {
117 	0x0c, 0x24, 0x02, 0x04, 0x05, 0x06, 0x00, 0x02,
118 	0x03, 0x00, 0x00, 0x00
119 };
120 
121 static const uint8_t audio_raw_desc_5[] = {
122 	0x09, 0x24, 0x03, 0x05, 0x05, 0x06, 0x00, 0x01,
123 	0x00
124 };
125 
126 static const uint8_t audio_raw_desc_6[] = {
127 	0x09, 0x24, 0x03, 0x06, 0x01, 0x03, 0x00, 0x09,
128 	0x00
129 };
130 
131 static const uint8_t audio_raw_desc_7[] = {
132 	0x09, 0x24, 0x03, 0x07, 0x01, 0x01, 0x00, 0x08,
133 	0x00
134 };
135 
136 static const uint8_t audio_raw_desc_8[] = {
137 	0x09, 0x24, 0x05, 0x08, 0x03, 0x0a, 0x0b, 0x0c,
138 	0x00
139 };
140 
141 static const uint8_t audio_raw_desc_9[] = {
142 	0x0a, 0x24, 0x06, 0x09, 0x0f, 0x01, 0x01, 0x02,
143 	0x02, 0x00
144 };
145 
146 static const uint8_t audio_raw_desc_10[] = {
147 	0x0a, 0x24, 0x06, 0x0a, 0x02, 0x01, 0x43, 0x00,
148 	0x00, 0x00
149 };
150 
151 static const uint8_t audio_raw_desc_11[] = {
152 	0x0a, 0x24, 0x06, 0x0b, 0x03, 0x01, 0x01, 0x02,
153 	0x02, 0x00
154 };
155 
156 static const uint8_t audio_raw_desc_12[] = {
157 	0x0a, 0x24, 0x06, 0x0c, 0x04, 0x01, 0x01, 0x00,
158 	0x00, 0x00
159 };
160 
161 static const uint8_t audio_raw_desc_13[] = {
162 	0x0a, 0x24, 0x06, 0x0d, 0x02, 0x01, 0x03, 0x00,
163 	0x00, 0x00
164 };
165 
166 static const uint8_t audio_raw_desc_14[] = {
167 	0x0a, 0x24, 0x06, 0x0e, 0x03, 0x01, 0x01, 0x02,
168 	0x02, 0x00
169 };
170 
171 static const uint8_t audio_raw_desc_15[] = {
172 	0x0f, 0x24, 0x04, 0x0f, 0x03, 0x01, 0x0d, 0x0e,
173 	0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00
174 };
175 
176 static const void *audio_raw_iface_0_desc[] = {
177 	audio_raw_desc_0,
178 	audio_raw_desc_1,
179 	audio_raw_desc_2,
180 	audio_raw_desc_3,
181 	audio_raw_desc_4,
182 	audio_raw_desc_5,
183 	audio_raw_desc_6,
184 	audio_raw_desc_7,
185 	audio_raw_desc_8,
186 	audio_raw_desc_9,
187 	audio_raw_desc_10,
188 	audio_raw_desc_11,
189 	audio_raw_desc_12,
190 	audio_raw_desc_13,
191 	audio_raw_desc_14,
192 	audio_raw_desc_15,
193 	NULL,
194 };
195 
196 static const struct usb_temp_interface_desc audio_iface_0 = {
197 	.ppEndpoints = NULL,		/* no endpoints */
198 	.ppRawDesc = audio_raw_iface_0_desc,
199 	.bInterfaceClass = 1,
200 	.bInterfaceSubClass = 1,
201 	.bInterfaceProtocol = 0,
202 	.iInterface = INDEX_AUDIO_MIXER,
203 };
204 
205 static const uint8_t audio_raw_desc_20[] = {
206 	0x07, 0x24, 0x01, 0x01, 0x03, 0x01, 0x00
207 
208 };
209 
210 static const uint8_t audio_raw_desc_21[] = {
211 	0x0b, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x01,
212 	/* 48kHz */
213 	0x80, 0xbb, 0x00
214 };
215 
216 static const uint8_t audio_raw_desc_22[] = {
217 	0x07, 0x25, 0x01, 0x00, 0x01, 0x04, 0x00
218 };
219 
220 static const void *audio_raw_iface_1_desc[] = {
221 	audio_raw_desc_20,
222 	audio_raw_desc_21,
223 	NULL,
224 };
225 
226 static const void *audio_raw_ep_1_desc[] = {
227 	audio_raw_desc_22,
228 	NULL,
229 };
230 
231 static const struct usb_temp_packet_size audio_isoc_mps = {
232   .mps[USB_SPEED_FULL] = 0xC8,
233   .mps[USB_SPEED_HIGH] = 0xC8,
234 };
235 
236 static const struct usb_temp_interval audio_isoc_interval = {
237 	.bInterval[USB_SPEED_FULL] = 1,	/* 1:1 */
238 	.bInterval[USB_SPEED_HIGH] = 4,	/* 1:8 */
239 };
240 
241 static const struct usb_temp_endpoint_desc audio_isoc_out_ep = {
242 	.ppRawDesc = audio_raw_ep_1_desc,
243 	.pPacketSize = &audio_isoc_mps,
244 	.pIntervals = &audio_isoc_interval,
245 	.bEndpointAddress = UE_DIR_OUT,
246 	.bmAttributes = UE_ISOCHRONOUS | UE_ISO_ADAPT,
247 };
248 
249 static const struct usb_temp_endpoint_desc *audio_iface_1_ep[] = {
250 	&audio_isoc_out_ep,
251 	NULL,
252 };
253 
254 static const struct usb_temp_interface_desc audio_iface_1_alt_0 = {
255 	.ppEndpoints = NULL,		/* no endpoints */
256 	.ppRawDesc = NULL,		/* no raw descriptors */
257 	.bInterfaceClass = 1,
258 	.bInterfaceSubClass = 2,
259 	.bInterfaceProtocol = 0,
260 	.iInterface = INDEX_AUDIO_PLAYBACK,
261 };
262 
263 static const struct usb_temp_interface_desc audio_iface_1_alt_1 = {
264 	.ppEndpoints = audio_iface_1_ep,
265 	.ppRawDesc = audio_raw_iface_1_desc,
266 	.bInterfaceClass = 1,
267 	.bInterfaceSubClass = 2,
268 	.bInterfaceProtocol = 0,
269 	.iInterface = INDEX_AUDIO_PLAYBACK,
270 	.isAltInterface = 1,		/* this is an alternate setting */
271 };
272 
273 static const uint8_t audio_raw_desc_30[] = {
274 	0x07, 0x24, 0x01, 0x07, 0x01, 0x01, 0x00
275 
276 };
277 
278 static const uint8_t audio_raw_desc_31[] = {
279 	0x0b, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x01,
280 	/* 48kHz */
281 	0x80, 0xbb, 0x00
282 };
283 
284 static const uint8_t audio_raw_desc_32[] = {
285 	0x07, 0x25, 0x01, 0x01, 0x00, 0x00, 0x00
286 };
287 
288 static const void *audio_raw_iface_2_desc[] = {
289 	audio_raw_desc_30,
290 	audio_raw_desc_31,
291 	NULL,
292 };
293 
294 static const void *audio_raw_ep_2_desc[] = {
295 	audio_raw_desc_32,
296 	NULL,
297 };
298 
299 static const struct usb_temp_endpoint_desc audio_isoc_in_ep = {
300 	.ppRawDesc = audio_raw_ep_2_desc,
301 	.pPacketSize = &audio_isoc_mps,
302 	.pIntervals = &audio_isoc_interval,
303 	.bEndpointAddress = UE_DIR_IN,
304 	.bmAttributes = UE_ISOCHRONOUS | UE_ISO_ADAPT,
305 };
306 
307 static const struct usb_temp_endpoint_desc *audio_iface_2_ep[] = {
308 	&audio_isoc_in_ep,
309 	NULL,
310 };
311 
312 static const struct usb_temp_interface_desc audio_iface_2_alt_0 = {
313 	.ppEndpoints = NULL,		/* no endpoints */
314 	.ppRawDesc = NULL,		/* no raw descriptors */
315 	.bInterfaceClass = 1,
316 	.bInterfaceSubClass = 2,
317 	.bInterfaceProtocol = 0,
318 	.iInterface = INDEX_AUDIO_RECORD,
319 };
320 
321 static const struct usb_temp_interface_desc audio_iface_2_alt_1 = {
322 	.ppEndpoints = audio_iface_2_ep,
323 	.ppRawDesc = audio_raw_iface_2_desc,
324 	.bInterfaceClass = 1,
325 	.bInterfaceSubClass = 2,
326 	.bInterfaceProtocol = 0,
327 	.iInterface = INDEX_AUDIO_RECORD,
328 	.isAltInterface = 1,		/* this is an alternate setting */
329 };
330 
331 static const struct usb_temp_interface_desc *audio_interfaces[] = {
332 	&audio_iface_0,
333 	&audio_iface_1_alt_0,
334 	&audio_iface_1_alt_1,
335 	&audio_iface_2_alt_0,
336 	&audio_iface_2_alt_1,
337 	NULL,
338 };
339 
340 static const struct usb_temp_config_desc audio_config_desc = {
341 	.ppIfaceDesc = audio_interfaces,
342 	.bmAttributes = UC_BUS_POWERED,
343 	.bMaxPower = 25,		/* 50 mA */
344 	.iConfiguration = INDEX_AUDIO_PRODUCT,
345 };
346 
347 static const struct usb_temp_config_desc *audio_configs[] = {
348 	&audio_config_desc,
349 	NULL,
350 };
351 
352 static usb_temp_get_string_desc_t audio_get_string_desc;
353 
354 const struct usb_temp_device_desc usb_template_audio = {
355 	.getStringDesc = &audio_get_string_desc,
356 	.ppConfigDesc = audio_configs,
357 	.idVendor = USB_TEMPLATE_VENDOR,
358 	.idProduct = 0x000A,
359 	.bcdDevice = 0x0100,
360 	.bDeviceClass = UDCLASS_COMM,
361 	.bDeviceSubClass = 0,
362 	.bDeviceProtocol = 0,
363 	.iManufacturer = 0,
364 	.iProduct = INDEX_AUDIO_PRODUCT,
365 	.iSerialNumber = 0,
366 };
367 
368 /*------------------------------------------------------------------------*
369  *	audio_get_string_desc
370  *
371  * Return values:
372  * NULL: Failure. No such string.
373  * Else: Success. Pointer to string descriptor is returned.
374  *------------------------------------------------------------------------*/
375 static const void *
audio_get_string_desc(uint16_t lang_id,uint8_t string_index)376 audio_get_string_desc(uint16_t lang_id, uint8_t string_index)
377 {
378 	static const void *ptr[INDEX_AUDIO_MAX] = {
379 		[INDEX_AUDIO_LANG] = &usb_string_lang_en,
380 		[INDEX_AUDIO_MIXER] = &string_audio_mixer,
381 		[INDEX_AUDIO_RECORD] = &string_audio_record,
382 		[INDEX_AUDIO_PLAYBACK] = &string_audio_playback,
383 		[INDEX_AUDIO_PRODUCT] = &string_audio_product,
384 	};
385 
386 	if (string_index == 0) {
387 		return (&usb_string_lang_en);
388 	}
389 	if (lang_id != 0x0409) {
390 		return (NULL);
391 	}
392 	if (string_index < INDEX_AUDIO_MAX) {
393 		return (ptr[string_index]);
394 	}
395 	return (NULL);
396 }
397