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 58enum { 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 90USB_MAKE_STRING_DESC(STRING_LANG, string_lang); 91USB_MAKE_STRING_DESC(STRING_AUDIO_MIXER, string_audio_mixer); 92USB_MAKE_STRING_DESC(STRING_AUDIO_RECORD, string_audio_record); 93USB_MAKE_STRING_DESC(STRING_AUDIO_PLAYBACK, string_audio_playback); 94USB_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 105static const uint8_t audio_raw_desc_0[] = { 106 0x0a, 0x24, 0x01, 0x00, 0x01, 0xa9, 0x00, 0x02, 107 0x01, 0x02 108}; 109 110static const uint8_t audio_raw_desc_1[] = { 111 0x0c, 0x24, 0x02, 0x01, 0x01, 0x01, 0x00, 0x02, 112 0x03, 0x00, 0x00, 0x00 113}; 114 115static const uint8_t audio_raw_desc_2[] = { 116 0x0c, 0x24, 0x02, 0x02, 0x01, 0x02, 0x00, 0x02, 117 0x03, 0x00, 0x00, 0x00 118}; 119 120static const uint8_t audio_raw_desc_3[] = { 121 0x0c, 0x24, 0x02, 0x03, 0x03, 0x06, 0x00, 0x02, 122 0x03, 0x00, 0x00, 0x00 123}; 124 125static const uint8_t audio_raw_desc_4[] = { 126 0x0c, 0x24, 0x02, 0x04, 0x05, 0x06, 0x00, 0x02, 127 0x03, 0x00, 0x00, 0x00 128}; 129 130static const uint8_t audio_raw_desc_5[] = { 131 0x09, 0x24, 0x03, 0x05, 0x05, 0x06, 0x00, 0x01, 132 0x00 133}; 134 135static const uint8_t audio_raw_desc_6[] = { 136 0x09, 0x24, 0x03, 0x06, 0x01, 0x03, 0x00, 0x09, 137 0x00 138}; 139 140static const uint8_t audio_raw_desc_7[] = { 141 0x09, 0x24, 0x03, 0x07, 0x01, 0x01, 0x00, 0x08, 142 0x00 143}; 144 145static const uint8_t audio_raw_desc_8[] = { 146 0x09, 0x24, 0x05, 0x08, 0x03, 0x0a, 0x0b, 0x0c, 147 0x00 148}; 149 150static const uint8_t audio_raw_desc_9[] = { 151 0x0a, 0x24, 0x06, 0x09, 0x0f, 0x01, 0x01, 0x02, 152 0x02, 0x00 153}; 154 155static const uint8_t audio_raw_desc_10[] = { 156 0x0a, 0x24, 0x06, 0x0a, 0x02, 0x01, 0x43, 0x00, 157 0x00, 0x00 158}; 159 160static const uint8_t audio_raw_desc_11[] = { 161 0x0a, 0x24, 0x06, 0x0b, 0x03, 0x01, 0x01, 0x02, 162 0x02, 0x00 163}; 164 165static const uint8_t audio_raw_desc_12[] = { 166 0x0a, 0x24, 0x06, 0x0c, 0x04, 0x01, 0x01, 0x00, 167 0x00, 0x00 168}; 169 170static const uint8_t audio_raw_desc_13[] = { 171 0x0a, 0x24, 0x06, 0x0d, 0x02, 0x01, 0x03, 0x00, 172 0x00, 0x00 173}; 174 175static const uint8_t audio_raw_desc_14[] = { 176 0x0a, 0x24, 0x06, 0x0e, 0x03, 0x01, 0x01, 0x02, 177 0x02, 0x00 178}; 179 180static 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 185static 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 205static 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 214static const uint8_t audio_raw_desc_20[] = { 215 0x07, 0x24, 0x01, 0x01, 0x03, 0x01, 0x00 216 217}; 218 219static const uint8_t audio_raw_desc_21[] = { 220 0x0b, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x01, 221 /* 48kHz */ 222 0x80, 0xbb, 0x00 223}; 224 225static const uint8_t audio_raw_desc_22[] = { 226 0x07, 0x25, 0x01, 0x00, 0x01, 0x04, 0x00 227}; 228 229static const void *audio_raw_iface_1_desc[] = { 230 audio_raw_desc_20, 231 audio_raw_desc_21, 232 NULL, 233}; 234 235static const void *audio_raw_ep_1_desc[] = { 236 audio_raw_desc_22, 237 NULL, 238}; 239 240static const struct usb_temp_packet_size audio_isoc_mps = { 241 .mps[USB_SPEED_FULL] = 0xC8, 242 .mps[USB_SPEED_HIGH] = 0xC8, 243}; 244 245static 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 250static 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 258static const struct usb_temp_endpoint_desc *audio_iface_1_ep[] = { 259 &audio_isoc_out_ep, 260 NULL, 261}; 262 263static 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 272static 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 282static const uint8_t audio_raw_desc_30[] = { 283 0x07, 0x24, 0x01, 0x07, 0x01, 0x01, 0x00 284 285}; 286 287static const uint8_t audio_raw_desc_31[] = { 288 0x0b, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x01, 289 /* 48kHz */ 290 0x80, 0xbb, 0x00 291}; 292 293static const uint8_t audio_raw_desc_32[] = { 294 0x07, 0x25, 0x01, 0x01, 0x00, 0x00, 0x00 295}; 296 297static const void *audio_raw_iface_2_desc[] = { 298 audio_raw_desc_30, 299 audio_raw_desc_31, 300 NULL, 301}; 302 303static const void *audio_raw_ep_2_desc[] = { 304 audio_raw_desc_32, 305 NULL, 306}; 307 308static 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 316static const struct usb_temp_endpoint_desc *audio_iface_2_ep[] = { 317 &audio_isoc_in_ep, 318 NULL, 319}; 320 321static 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 330static 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 340static 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 349static 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 356static const struct usb_temp_config_desc *audio_configs[] = { 357 &audio_config_desc, 358 NULL, 359}; 360 361static usb_temp_get_string_desc_t audio_get_string_desc; 362 363const 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 *------------------------------------------------------------------------*/ 384static const void * 385audio_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} 406