1 /* $FreeBSD$ */ 2 /*- 3 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 #ifdef USB_GLOBAL_INCLUDE_FILE 34 #include USB_GLOBAL_INCLUDE_FILE 35 #else 36 #include <sys/stdint.h> 37 #include <sys/stddef.h> 38 #include <sys/param.h> 39 #include <sys/queue.h> 40 #include <sys/types.h> 41 #include <sys/systm.h> 42 #include <sys/kernel.h> 43 #include <sys/bus.h> 44 #include <sys/module.h> 45 #include <sys/lock.h> 46 #include <sys/mutex.h> 47 #include <sys/condvar.h> 48 #include <sys/sysctl.h> 49 #include <sys/sx.h> 50 #include <sys/unistd.h> 51 #include <sys/callout.h> 52 #include <sys/malloc.h> 53 #include <sys/priv.h> 54 55 #include <dev/usb/usb.h> 56 #include <dev/usb/usbdi.h> 57 #include <dev/usb/usb_core.h> 58 #include <dev/usb/usb_cdc.h> 59 60 #include <dev/usb/template/usb_template.h> 61 #endif /* USB_GLOBAL_INCLUDE_FILE */ 62 63 enum { 64 INDEX_AUDIO_LANG, 65 INDEX_AUDIO_MIXER, 66 INDEX_AUDIO_RECORD, 67 INDEX_AUDIO_PLAYBACK, 68 INDEX_AUDIO_PRODUCT, 69 INDEX_AUDIO_MAX, 70 }; 71 72 #define STRING_AUDIO_PRODUCT \ 73 "A\0u\0d\0i\0o\0 \0T\0e\0s\0t\0 \0D\0e\0v\0i\0c\0e" 74 75 #define STRING_AUDIO_MIXER \ 76 "M\0i\0x\0e\0r\0 \0i\0n\0t\0e\0r\0f\0a\0c\0e" 77 78 #define STRING_AUDIO_RECORD \ 79 "R\0e\0c\0o\0r\0d\0 \0i\0n\0t\0e\0r\0f\0a\0c\0e" 80 81 #define STRING_AUDIO_PLAYBACK \ 82 "P\0l\0a\0y\0b\0a\0c\0k\0 \0i\0n\0t\0e\0r\0f\0a\0c\0e" 83 84 85 /* make the real string descriptors */ 86 87 USB_MAKE_STRING_DESC(STRING_AUDIO_MIXER, string_audio_mixer); 88 USB_MAKE_STRING_DESC(STRING_AUDIO_RECORD, string_audio_record); 89 USB_MAKE_STRING_DESC(STRING_AUDIO_PLAYBACK, string_audio_playback); 90 USB_MAKE_STRING_DESC(STRING_AUDIO_PRODUCT, string_audio_product); 91 92 /* prototypes */ 93 94 /* 95 * Audio Mixer description structures 96 * 97 * Some of the audio descriptors were dumped 98 * from a Creative Labs USB audio device. 99 */ 100 101 static const uint8_t audio_raw_desc_0[] = { 102 0x0a, 0x24, 0x01, 0x00, 0x01, 0xa9, 0x00, 0x02, 103 0x01, 0x02 104 }; 105 106 static const uint8_t audio_raw_desc_1[] = { 107 0x0c, 0x24, 0x02, 0x01, 0x01, 0x01, 0x00, 0x02, 108 0x03, 0x00, 0x00, 0x00 109 }; 110 111 static const uint8_t audio_raw_desc_2[] = { 112 0x0c, 0x24, 0x02, 0x02, 0x01, 0x02, 0x00, 0x02, 113 0x03, 0x00, 0x00, 0x00 114 }; 115 116 static const uint8_t audio_raw_desc_3[] = { 117 0x0c, 0x24, 0x02, 0x03, 0x03, 0x06, 0x00, 0x02, 118 0x03, 0x00, 0x00, 0x00 119 }; 120 121 static const uint8_t audio_raw_desc_4[] = { 122 0x0c, 0x24, 0x02, 0x04, 0x05, 0x06, 0x00, 0x02, 123 0x03, 0x00, 0x00, 0x00 124 }; 125 126 static const uint8_t audio_raw_desc_5[] = { 127 0x09, 0x24, 0x03, 0x05, 0x05, 0x06, 0x00, 0x01, 128 0x00 129 }; 130 131 static const uint8_t audio_raw_desc_6[] = { 132 0x09, 0x24, 0x03, 0x06, 0x01, 0x03, 0x00, 0x09, 133 0x00 134 }; 135 136 static const uint8_t audio_raw_desc_7[] = { 137 0x09, 0x24, 0x03, 0x07, 0x01, 0x01, 0x00, 0x08, 138 0x00 139 }; 140 141 static const uint8_t audio_raw_desc_8[] = { 142 0x09, 0x24, 0x05, 0x08, 0x03, 0x0a, 0x0b, 0x0c, 143 0x00 144 }; 145 146 static const uint8_t audio_raw_desc_9[] = { 147 0x0a, 0x24, 0x06, 0x09, 0x0f, 0x01, 0x01, 0x02, 148 0x02, 0x00 149 }; 150 151 static const uint8_t audio_raw_desc_10[] = { 152 0x0a, 0x24, 0x06, 0x0a, 0x02, 0x01, 0x43, 0x00, 153 0x00, 0x00 154 }; 155 156 static const uint8_t audio_raw_desc_11[] = { 157 0x0a, 0x24, 0x06, 0x0b, 0x03, 0x01, 0x01, 0x02, 158 0x02, 0x00 159 }; 160 161 static const uint8_t audio_raw_desc_12[] = { 162 0x0a, 0x24, 0x06, 0x0c, 0x04, 0x01, 0x01, 0x00, 163 0x00, 0x00 164 }; 165 166 static const uint8_t audio_raw_desc_13[] = { 167 0x0a, 0x24, 0x06, 0x0d, 0x02, 0x01, 0x03, 0x00, 168 0x00, 0x00 169 }; 170 171 static const uint8_t audio_raw_desc_14[] = { 172 0x0a, 0x24, 0x06, 0x0e, 0x03, 0x01, 0x01, 0x02, 173 0x02, 0x00 174 }; 175 176 static const uint8_t audio_raw_desc_15[] = { 177 0x0f, 0x24, 0x04, 0x0f, 0x03, 0x01, 0x0d, 0x0e, 178 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 179 }; 180 181 static const void *audio_raw_iface_0_desc[] = { 182 audio_raw_desc_0, 183 audio_raw_desc_1, 184 audio_raw_desc_2, 185 audio_raw_desc_3, 186 audio_raw_desc_4, 187 audio_raw_desc_5, 188 audio_raw_desc_6, 189 audio_raw_desc_7, 190 audio_raw_desc_8, 191 audio_raw_desc_9, 192 audio_raw_desc_10, 193 audio_raw_desc_11, 194 audio_raw_desc_12, 195 audio_raw_desc_13, 196 audio_raw_desc_14, 197 audio_raw_desc_15, 198 NULL, 199 }; 200 201 static const struct usb_temp_interface_desc audio_iface_0 = { 202 .ppEndpoints = NULL, /* no endpoints */ 203 .ppRawDesc = audio_raw_iface_0_desc, 204 .bInterfaceClass = UICLASS_AUDIO, 205 .bInterfaceSubClass = UISUBCLASS_AUDIOCONTROL, 206 .bInterfaceProtocol = 0, 207 .iInterface = INDEX_AUDIO_MIXER, 208 }; 209 210 static const uint8_t audio_raw_desc_20[] = { 211 0x07, 0x24, 0x01, 0x01, 0x03, 0x01, 0x00 212 213 }; 214 215 static const uint8_t audio_raw_desc_21[] = { 216 0x0b, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x01, 217 /* 48kHz */ 218 0x80, 0xbb, 0x00 219 }; 220 221 static const uint8_t audio_raw_desc_22[] = { 222 0x07, 0x25, 0x01, 0x00, 0x01, 0x04, 0x00 223 }; 224 225 static const void *audio_raw_iface_1_desc[] = { 226 audio_raw_desc_20, 227 audio_raw_desc_21, 228 NULL, 229 }; 230 231 static const void *audio_raw_ep_1_desc[] = { 232 audio_raw_desc_22, 233 NULL, 234 }; 235 236 static const struct usb_temp_packet_size audio_isoc_mps = { 237 .mps[USB_SPEED_FULL] = 0xC8, 238 .mps[USB_SPEED_HIGH] = 0xC8, 239 }; 240 241 static const struct usb_temp_interval audio_isoc_interval = { 242 .bInterval[USB_SPEED_FULL] = 1, /* 1:1 */ 243 .bInterval[USB_SPEED_HIGH] = 4, /* 1:8 */ 244 }; 245 246 static const struct usb_temp_endpoint_desc audio_isoc_out_ep = { 247 .ppRawDesc = audio_raw_ep_1_desc, 248 .pPacketSize = &audio_isoc_mps, 249 .pIntervals = &audio_isoc_interval, 250 .bEndpointAddress = UE_DIR_OUT, 251 .bmAttributes = UE_ISOCHRONOUS | UE_ISO_ADAPT, 252 }; 253 254 static const struct usb_temp_endpoint_desc *audio_iface_1_ep[] = { 255 &audio_isoc_out_ep, 256 NULL, 257 }; 258 259 static const struct usb_temp_interface_desc audio_iface_1_alt_0 = { 260 .ppEndpoints = NULL, /* no endpoints */ 261 .ppRawDesc = NULL, /* no raw descriptors */ 262 .bInterfaceClass = UICLASS_AUDIO, 263 .bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM, 264 .bInterfaceProtocol = 0, 265 .iInterface = INDEX_AUDIO_PLAYBACK, 266 }; 267 268 static const struct usb_temp_interface_desc audio_iface_1_alt_1 = { 269 .ppEndpoints = audio_iface_1_ep, 270 .ppRawDesc = audio_raw_iface_1_desc, 271 .bInterfaceClass = UICLASS_AUDIO, 272 .bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM, 273 .bInterfaceProtocol = 0, 274 .iInterface = INDEX_AUDIO_PLAYBACK, 275 .isAltInterface = 1, /* this is an alternate setting */ 276 }; 277 278 static const uint8_t audio_raw_desc_30[] = { 279 0x07, 0x24, 0x01, 0x07, 0x01, 0x01, 0x00 280 281 }; 282 283 static const uint8_t audio_raw_desc_31[] = { 284 0x0b, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x01, 285 /* 48kHz */ 286 0x80, 0xbb, 0x00 287 }; 288 289 static const uint8_t audio_raw_desc_32[] = { 290 0x07, 0x25, 0x01, 0x01, 0x00, 0x00, 0x00 291 }; 292 293 static const void *audio_raw_iface_2_desc[] = { 294 audio_raw_desc_30, 295 audio_raw_desc_31, 296 NULL, 297 }; 298 299 static const void *audio_raw_ep_2_desc[] = { 300 audio_raw_desc_32, 301 NULL, 302 }; 303 304 static const struct usb_temp_endpoint_desc audio_isoc_in_ep = { 305 .ppRawDesc = audio_raw_ep_2_desc, 306 .pPacketSize = &audio_isoc_mps, 307 .pIntervals = &audio_isoc_interval, 308 .bEndpointAddress = UE_DIR_IN, 309 .bmAttributes = UE_ISOCHRONOUS | UE_ISO_ADAPT, 310 }; 311 312 static const struct usb_temp_endpoint_desc *audio_iface_2_ep[] = { 313 &audio_isoc_in_ep, 314 NULL, 315 }; 316 317 static const struct usb_temp_interface_desc audio_iface_2_alt_0 = { 318 .ppEndpoints = NULL, /* no endpoints */ 319 .ppRawDesc = NULL, /* no raw descriptors */ 320 .bInterfaceClass = UICLASS_AUDIO, 321 .bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM, 322 .bInterfaceProtocol = 0, 323 .iInterface = INDEX_AUDIO_RECORD, 324 }; 325 326 static const struct usb_temp_interface_desc audio_iface_2_alt_1 = { 327 .ppEndpoints = audio_iface_2_ep, 328 .ppRawDesc = audio_raw_iface_2_desc, 329 .bInterfaceClass = UICLASS_AUDIO, 330 .bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM, 331 .bInterfaceProtocol = 0, 332 .iInterface = INDEX_AUDIO_RECORD, 333 .isAltInterface = 1, /* this is an alternate setting */ 334 }; 335 336 static const struct usb_temp_interface_desc *audio_interfaces[] = { 337 &audio_iface_0, 338 &audio_iface_1_alt_0, 339 &audio_iface_1_alt_1, 340 &audio_iface_2_alt_0, 341 &audio_iface_2_alt_1, 342 NULL, 343 }; 344 345 static const struct usb_temp_config_desc audio_config_desc = { 346 .ppIfaceDesc = audio_interfaces, 347 .bmAttributes = UC_BUS_POWERED, 348 .bMaxPower = 25, /* 50 mA */ 349 .iConfiguration = INDEX_AUDIO_PRODUCT, 350 }; 351 352 static const struct usb_temp_config_desc *audio_configs[] = { 353 &audio_config_desc, 354 NULL, 355 }; 356 357 static usb_temp_get_string_desc_t audio_get_string_desc; 358 359 const struct usb_temp_device_desc usb_template_audio = { 360 .getStringDesc = &audio_get_string_desc, 361 .ppConfigDesc = audio_configs, 362 .idVendor = USB_TEMPLATE_VENDOR, 363 .idProduct = 0x000A, 364 .bcdDevice = 0x0100, 365 .bDeviceClass = UDCLASS_COMM, 366 .bDeviceSubClass = 0, 367 .bDeviceProtocol = 0, 368 .iManufacturer = 0, 369 .iProduct = INDEX_AUDIO_PRODUCT, 370 .iSerialNumber = 0, 371 }; 372 373 /*------------------------------------------------------------------------* 374 * audio_get_string_desc 375 * 376 * Return values: 377 * NULL: Failure. No such string. 378 * Else: Success. Pointer to string descriptor is returned. 379 *------------------------------------------------------------------------*/ 380 static const void * 381 audio_get_string_desc(uint16_t lang_id, uint8_t string_index) 382 { 383 static const void *ptr[INDEX_AUDIO_MAX] = { 384 [INDEX_AUDIO_LANG] = &usb_string_lang_en, 385 [INDEX_AUDIO_MIXER] = &string_audio_mixer, 386 [INDEX_AUDIO_RECORD] = &string_audio_record, 387 [INDEX_AUDIO_PLAYBACK] = &string_audio_playback, 388 [INDEX_AUDIO_PRODUCT] = &string_audio_product, 389 }; 390 391 if (string_index == 0) { 392 return (&usb_string_lang_en); 393 } 394 if (lang_id != 0x0409) { 395 return (NULL); 396 } 397 if (string_index < INDEX_AUDIO_MAX) { 398 return (ptr[string_index]); 399 } 400 return (NULL); 401 } 402