xref: /dragonfly/sys/bus/u4b/template/usb_template_audio.c (revision 2b3f93ea6d1f70880f3e87f3c2cbe0dc0bfc9332)
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