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