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