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