]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/usb/template/usb_template_audio.c
Fix sysctl description.
[FreeBSD/FreeBSD.git] / sys / dev / usb / template / usb_template_audio.c
1 /* $FreeBSD$ */
2 /*-
3  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4  *
5  * Copyright (c) 2010 Hans Petter Selasky
6  * Copyright (c) 2018 The FreeBSD Foundation
7  * All rights reserved.
8  *
9  * Portions of this software were developed by Edward Tomasz Napierala
10  * under sponsorship from the FreeBSD Foundation.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 /*
35  * This file contains the USB template for an USB Audio Device.
36  */
37
38 #ifdef USB_GLOBAL_INCLUDE_FILE
39 #include USB_GLOBAL_INCLUDE_FILE
40 #else
41 #include <sys/stdint.h>
42 #include <sys/stddef.h>
43 #include <sys/param.h>
44 #include <sys/queue.h>
45 #include <sys/types.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/bus.h>
49 #include <sys/module.h>
50 #include <sys/lock.h>
51 #include <sys/mutex.h>
52 #include <sys/condvar.h>
53 #include <sys/sysctl.h>
54 #include <sys/sx.h>
55 #include <sys/unistd.h>
56 #include <sys/callout.h>
57 #include <sys/malloc.h>
58 #include <sys/priv.h>
59
60 #include <dev/usb/usb.h>
61 #include <dev/usb/usbdi.h>
62 #include <dev/usb/usb_core.h>
63 #include <dev/usb/usb_cdc.h>
64 #include <dev/usb/usb_ioctl.h>
65 #include <dev/usb/usb_util.h>
66
67 #include <dev/usb/template/usb_template.h>
68 #endif                  /* USB_GLOBAL_INCLUDE_FILE */
69
70 enum {
71         AUDIO_LANG_INDEX,
72         AUDIO_MIXER_INDEX,
73         AUDIO_RECORD_INDEX,
74         AUDIO_PLAYBACK_INDEX,
75         AUDIO_MANUFACTURER_INDEX,
76         AUDIO_PRODUCT_INDEX,
77         AUDIO_SERIAL_NUMBER_INDEX,
78         AUDIO_MAX_INDEX,
79 };
80
81 #define AUDIO_DEFAULT_MIXER             "Mixer interface"
82 #define AUDIO_DEFAULT_RECORD            "Record interface"
83 #define AUDIO_DEFAULT_PLAYBACK          "Playback interface"
84 #define AUDIO_DEFAULT_MANUFACTURER      "FreeBSD foundation"
85 #define AUDIO_DEFAULT_PRODUCT           "Audio Test Device"
86 #define AUDIO_DEFAULT_SERIAL_NUMBER     "March 2008"
87
88 static struct usb_string_descriptor     audio_mixer;
89 static struct usb_string_descriptor     audio_record;
90 static struct usb_string_descriptor     audio_playback;
91 static struct usb_string_descriptor     audio_manufacturer;
92 static struct usb_string_descriptor     audio_product;
93 static struct usb_string_descriptor     audio_serial_number;
94
95 static struct sysctl_ctx_list           audio_ctx_list;
96
97 /* prototypes */
98
99 /*
100  * Audio Mixer description structures
101  *
102  * Some of the audio descriptors were dumped
103  * from a Creative Labs USB audio device.
104  */
105
106 static const uint8_t audio_raw_desc_0[] = {
107         0x0a, 0x24, 0x01, 0x00, 0x01, 0xa9, 0x00, 0x02,
108         0x01, 0x02
109 };
110
111 static const uint8_t audio_raw_desc_1[] = {
112         0x0c, 0x24, 0x02, 0x01, 0x01, 0x01, 0x00, 0x02,
113         0x03, 0x00, 0x00, 0x00
114 };
115
116 static const uint8_t audio_raw_desc_2[] = {
117         0x0c, 0x24, 0x02, 0x02, 0x01, 0x02, 0x00, 0x02,
118         0x03, 0x00, 0x00, 0x00
119 };
120
121 static const uint8_t audio_raw_desc_3[] = {
122         0x0c, 0x24, 0x02, 0x03, 0x03, 0x06, 0x00, 0x02,
123         0x03, 0x00, 0x00, 0x00
124 };
125
126 static const uint8_t audio_raw_desc_4[] = {
127         0x0c, 0x24, 0x02, 0x04, 0x05, 0x06, 0x00, 0x02,
128         0x03, 0x00, 0x00, 0x00
129 };
130
131 static const uint8_t audio_raw_desc_5[] = {
132         0x09, 0x24, 0x03, 0x05, 0x05, 0x06, 0x00, 0x01,
133         0x00
134 };
135
136 static const uint8_t audio_raw_desc_6[] = {
137         0x09, 0x24, 0x03, 0x06, 0x01, 0x03, 0x00, 0x09,
138         0x00
139 };
140
141 static const uint8_t audio_raw_desc_7[] = {
142         0x09, 0x24, 0x03, 0x07, 0x01, 0x01, 0x00, 0x08,
143         0x00
144 };
145
146 static const uint8_t audio_raw_desc_8[] = {
147         0x09, 0x24, 0x05, 0x08, 0x03, 0x0a, 0x0b, 0x0c,
148         0x00
149 };
150
151 static const uint8_t audio_raw_desc_9[] = {
152         0x0a, 0x24, 0x06, 0x09, 0x0f, 0x01, 0x01, 0x02,
153         0x02, 0x00
154 };
155
156 static const uint8_t audio_raw_desc_10[] = {
157         0x0a, 0x24, 0x06, 0x0a, 0x02, 0x01, 0x43, 0x00,
158         0x00, 0x00
159 };
160
161 static const uint8_t audio_raw_desc_11[] = {
162         0x0a, 0x24, 0x06, 0x0b, 0x03, 0x01, 0x01, 0x02,
163         0x02, 0x00
164 };
165
166 static const uint8_t audio_raw_desc_12[] = {
167         0x0a, 0x24, 0x06, 0x0c, 0x04, 0x01, 0x01, 0x00,
168         0x00, 0x00
169 };
170
171 static const uint8_t audio_raw_desc_13[] = {
172         0x0a, 0x24, 0x06, 0x0d, 0x02, 0x01, 0x03, 0x00,
173         0x00, 0x00
174 };
175
176 static const uint8_t audio_raw_desc_14[] = {
177         0x0a, 0x24, 0x06, 0x0e, 0x03, 0x01, 0x01, 0x02,
178         0x02, 0x00
179 };
180
181 static const uint8_t audio_raw_desc_15[] = {
182         0x0f, 0x24, 0x04, 0x0f, 0x03, 0x01, 0x0d, 0x0e,
183         0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00
184 };
185
186 static const void *audio_raw_iface_0_desc[] = {
187         audio_raw_desc_0,
188         audio_raw_desc_1,
189         audio_raw_desc_2,
190         audio_raw_desc_3,
191         audio_raw_desc_4,
192         audio_raw_desc_5,
193         audio_raw_desc_6,
194         audio_raw_desc_7,
195         audio_raw_desc_8,
196         audio_raw_desc_9,
197         audio_raw_desc_10,
198         audio_raw_desc_11,
199         audio_raw_desc_12,
200         audio_raw_desc_13,
201         audio_raw_desc_14,
202         audio_raw_desc_15,
203         NULL,
204 };
205
206 static const struct usb_temp_interface_desc audio_iface_0 = {
207         .ppEndpoints = NULL,            /* no endpoints */
208         .ppRawDesc = audio_raw_iface_0_desc,
209         .bInterfaceClass = UICLASS_AUDIO,
210         .bInterfaceSubClass = UISUBCLASS_AUDIOCONTROL,
211         .bInterfaceProtocol = 0,
212         .iInterface = AUDIO_MIXER_INDEX,
213 };
214
215 static const uint8_t audio_raw_desc_20[] = {
216         0x07, 0x24, 0x01, 0x01, 0x03, 0x01, 0x00
217
218 };
219
220 static const uint8_t audio_raw_desc_21[] = {
221         0x0b, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x01,
222         /* 48kHz */
223         0x80, 0xbb, 0x00
224 };
225
226 static const uint8_t audio_raw_desc_22[] = {
227         0x07, 0x25, 0x01, 0x00, 0x01, 0x04, 0x00
228 };
229
230 static const void *audio_raw_iface_1_desc[] = {
231         audio_raw_desc_20,
232         audio_raw_desc_21,
233         NULL,
234 };
235
236 static const void *audio_raw_ep_1_desc[] = {
237         audio_raw_desc_22,
238         NULL,
239 };
240
241 static const struct usb_temp_packet_size audio_isoc_mps = {
242   .mps[USB_SPEED_FULL] = 0xC8,
243   .mps[USB_SPEED_HIGH] = 0xC8,
244 };
245
246 static const struct usb_temp_interval audio_isoc_interval = {
247         .bInterval[USB_SPEED_FULL] = 1, /* 1:1 */
248         .bInterval[USB_SPEED_HIGH] = 4, /* 1:8 */
249 };
250
251 static const struct usb_temp_endpoint_desc audio_isoc_out_ep = {
252         .ppRawDesc = audio_raw_ep_1_desc,
253         .pPacketSize = &audio_isoc_mps,
254         .pIntervals = &audio_isoc_interval,
255         .bEndpointAddress = UE_DIR_OUT,
256         .bmAttributes = UE_ISOCHRONOUS | UE_ISO_ADAPT,
257 };
258
259 static const struct usb_temp_endpoint_desc *audio_iface_1_ep[] = {
260         &audio_isoc_out_ep,
261         NULL,
262 };
263
264 static const struct usb_temp_interface_desc audio_iface_1_alt_0 = {
265         .ppEndpoints = NULL,            /* no endpoints */
266         .ppRawDesc = NULL,              /* no raw descriptors */
267         .bInterfaceClass = UICLASS_AUDIO,
268         .bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
269         .bInterfaceProtocol = 0,
270         .iInterface = AUDIO_PLAYBACK_INDEX,
271 };
272
273 static const struct usb_temp_interface_desc audio_iface_1_alt_1 = {
274         .ppEndpoints = audio_iface_1_ep,
275         .ppRawDesc = audio_raw_iface_1_desc,
276         .bInterfaceClass = UICLASS_AUDIO,
277         .bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
278         .bInterfaceProtocol = 0,
279         .iInterface = AUDIO_PLAYBACK_INDEX,
280         .isAltInterface = 1,            /* this is an alternate setting */
281 };
282
283 static const uint8_t audio_raw_desc_30[] = {
284         0x07, 0x24, 0x01, 0x07, 0x01, 0x01, 0x00
285
286 };
287
288 static const uint8_t audio_raw_desc_31[] = {
289         0x0b, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x01,
290         /* 48kHz */
291         0x80, 0xbb, 0x00
292 };
293
294 static const uint8_t audio_raw_desc_32[] = {
295         0x07, 0x25, 0x01, 0x01, 0x00, 0x00, 0x00
296 };
297
298 static const void *audio_raw_iface_2_desc[] = {
299         audio_raw_desc_30,
300         audio_raw_desc_31,
301         NULL,
302 };
303
304 static const void *audio_raw_ep_2_desc[] = {
305         audio_raw_desc_32,
306         NULL,
307 };
308
309 static const struct usb_temp_endpoint_desc audio_isoc_in_ep = {
310         .ppRawDesc = audio_raw_ep_2_desc,
311         .pPacketSize = &audio_isoc_mps,
312         .pIntervals = &audio_isoc_interval,
313         .bEndpointAddress = UE_DIR_IN,
314         .bmAttributes = UE_ISOCHRONOUS | UE_ISO_ADAPT,
315 };
316
317 static const struct usb_temp_endpoint_desc *audio_iface_2_ep[] = {
318         &audio_isoc_in_ep,
319         NULL,
320 };
321
322 static const struct usb_temp_interface_desc audio_iface_2_alt_0 = {
323         .ppEndpoints = NULL,            /* no endpoints */
324         .ppRawDesc = NULL,              /* no raw descriptors */
325         .bInterfaceClass = UICLASS_AUDIO,
326         .bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
327         .bInterfaceProtocol = 0,
328         .iInterface = AUDIO_RECORD_INDEX,
329 };
330
331 static const struct usb_temp_interface_desc audio_iface_2_alt_1 = {
332         .ppEndpoints = audio_iface_2_ep,
333         .ppRawDesc = audio_raw_iface_2_desc,
334         .bInterfaceClass = UICLASS_AUDIO,
335         .bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
336         .bInterfaceProtocol = 0,
337         .iInterface = AUDIO_RECORD_INDEX,
338         .isAltInterface = 1,            /* this is an alternate setting */
339 };
340
341 static const struct usb_temp_interface_desc *audio_interfaces[] = {
342         &audio_iface_0,
343         &audio_iface_1_alt_0,
344         &audio_iface_1_alt_1,
345         &audio_iface_2_alt_0,
346         &audio_iface_2_alt_1,
347         NULL,
348 };
349
350 static const struct usb_temp_config_desc audio_config_desc = {
351         .ppIfaceDesc = audio_interfaces,
352         .bmAttributes = UC_BUS_POWERED,
353         .bMaxPower = 25,                /* 50 mA */
354         .iConfiguration = AUDIO_PRODUCT_INDEX,
355 };
356
357 static const struct usb_temp_config_desc *audio_configs[] = {
358         &audio_config_desc,
359         NULL,
360 };
361
362 static usb_temp_get_string_desc_t audio_get_string_desc;
363
364 struct usb_temp_device_desc usb_template_audio = {
365         .getStringDesc = &audio_get_string_desc,
366         .ppConfigDesc = audio_configs,
367         .idVendor = USB_TEMPLATE_VENDOR,
368         .idProduct = 0x000A,
369         .bcdDevice = 0x0100,
370         .bDeviceClass = UDCLASS_COMM,
371         .bDeviceSubClass = 0,
372         .bDeviceProtocol = 0,
373         .iManufacturer = AUDIO_MANUFACTURER_INDEX,
374         .iProduct = AUDIO_PRODUCT_INDEX,
375         .iSerialNumber = AUDIO_SERIAL_NUMBER_INDEX,
376 };
377
378 /*------------------------------------------------------------------------*
379  *      audio_get_string_desc
380  *
381  * Return values:
382  * NULL: Failure. No such string.
383  * Else: Success. Pointer to string descriptor is returned.
384  *------------------------------------------------------------------------*/
385 static const void *
386 audio_get_string_desc(uint16_t lang_id, uint8_t string_index)
387 {
388         static const void *ptr[AUDIO_MAX_INDEX] = {
389                 [AUDIO_LANG_INDEX] = &usb_string_lang_en,
390                 [AUDIO_MIXER_INDEX] = &audio_mixer,
391                 [AUDIO_RECORD_INDEX] = &audio_record,
392                 [AUDIO_PLAYBACK_INDEX] = &audio_playback,
393                 [AUDIO_MANUFACTURER_INDEX] = &audio_manufacturer,
394                 [AUDIO_PRODUCT_INDEX] = &audio_product,
395                 [AUDIO_SERIAL_NUMBER_INDEX] = &audio_serial_number,
396         };
397
398         if (string_index == 0) {
399                 return (&usb_string_lang_en);
400         }
401         if (lang_id != 0x0409) {
402                 return (NULL);
403         }
404         if (string_index < AUDIO_MAX_INDEX) {
405                 return (ptr[string_index]);
406         }
407         return (NULL);
408 }
409
410 static void
411 audio_init(void *arg __unused)
412 {
413         struct sysctl_oid *parent;
414         char parent_name[3];
415
416         usb_make_str_desc(&audio_mixer, sizeof(audio_mixer),
417             AUDIO_DEFAULT_MIXER);
418         usb_make_str_desc(&audio_record, sizeof(audio_record),
419             AUDIO_DEFAULT_RECORD);
420         usb_make_str_desc(&audio_playback, sizeof(audio_playback),
421             AUDIO_DEFAULT_PLAYBACK);
422         usb_make_str_desc(&audio_manufacturer, sizeof(audio_manufacturer),
423             AUDIO_DEFAULT_MANUFACTURER);
424         usb_make_str_desc(&audio_product, sizeof(audio_product),
425             AUDIO_DEFAULT_PRODUCT);
426         usb_make_str_desc(&audio_serial_number, sizeof(audio_serial_number),
427             AUDIO_DEFAULT_SERIAL_NUMBER);
428
429         snprintf(parent_name, sizeof(parent_name), "%d", USB_TEMP_AUDIO);
430         sysctl_ctx_init(&audio_ctx_list);
431
432         parent = SYSCTL_ADD_NODE(&audio_ctx_list,
433             SYSCTL_STATIC_CHILDREN(_hw_usb_templates), OID_AUTO,
434             parent_name, CTLFLAG_RW,
435             0, "USB Audio Interface device side template");
436         SYSCTL_ADD_U16(&audio_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
437             "vendor_id", CTLFLAG_RWTUN, &usb_template_audio.idVendor,
438             1, "Vendor identifier");
439         SYSCTL_ADD_U16(&audio_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
440             "product_id", CTLFLAG_RWTUN, &usb_template_audio.idProduct,
441             1, "Product identifier");
442 #if 0
443         SYSCTL_ADD_PROC(&audio_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
444             "mixer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
445             &audio_mixer, sizeof(audio_mixer), usb_temp_sysctl,
446             "A", "Mixer interface string");
447         SYSCTL_ADD_PROC(&audio_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
448             "record", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
449             &audio_record, sizeof(audio_record), usb_temp_sysctl,
450             "A", "Record interface string");
451         SYSCTL_ADD_PROC(&audio_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
452             "playback", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
453             &audio_playback, sizeof(audio_playback), usb_temp_sysctl,
454             "A", "Playback interface string");
455 #endif
456         SYSCTL_ADD_PROC(&audio_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
457             "manufacturer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
458             &audio_manufacturer, sizeof(audio_manufacturer), usb_temp_sysctl,
459             "A", "Manufacturer string");
460         SYSCTL_ADD_PROC(&audio_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
461             "product", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
462             &audio_product, sizeof(audio_product), usb_temp_sysctl,
463             "A", "Product string");
464         SYSCTL_ADD_PROC(&audio_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
465             "serial_number", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
466             &audio_serial_number, sizeof(audio_serial_number), usb_temp_sysctl,
467             "A", "Serial number string");
468 }
469
470 static void
471 audio_uninit(void *arg __unused)
472 {
473
474         sysctl_ctx_free(&audio_ctx_list);
475 }
476
477 SYSINIT(audio_init, SI_SUB_LOCK, SI_ORDER_FIRST, audio_init, NULL);
478 SYSUNINIT(audio_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, audio_uninit, NULL);