1 /* $FreeBSD: head/sys/dev/usb/template/usb_template_audio.c 246125 2013-01-30 16:05:54Z hselasky $ */ 2 /*- 3 * Copyright (c) 2010 Hans Petter Selasky. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 /* 28 * This file contains the USB template for an USB Audio Device. 29 */ 30 31 #ifdef USB_GLOBAL_INCLUDE_FILE 32 #include USB_GLOBAL_INCLUDE_FILE 33 #else 34 #include <sys/stdint.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/condvar.h> 44 #include <sys/sysctl.h> 45 #include <sys/unistd.h> 46 #include <sys/callout.h> 47 #include <sys/malloc.h> 48 #include <sys/caps.h> 49 50 #include <bus/u4b/usb.h> 51 #include <bus/u4b/usbdi.h> 52 #include <bus/u4b/usb_core.h> 53 #include <bus/u4b/usb_cdc.h> 54 55 #include <bus/u4b/template/usb_template.h> 56 #endif /* USB_GLOBAL_INCLUDE_FILE */ 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_AUDIO_PRODUCT \ 68 "A\0u\0d\0i\0o\0 \0T\0e\0s\0t\0 \0D\0e\0v\0i\0c\0e" 69 70 #define STRING_AUDIO_MIXER \ 71 "M\0i\0x\0e\0r\0 \0i\0n\0t\0e\0r\0f\0a\0c\0e" 72 73 #define STRING_AUDIO_RECORD \ 74 "R\0e\0c\0o\0r\0d\0 \0i\0n\0t\0e\0r\0f\0a\0c\0e" 75 76 #define STRING_AUDIO_PLAYBACK \ 77 "P\0l\0a\0y\0b\0a\0c\0k\0 \0i\0n\0t\0e\0r\0f\0a\0c\0e" 78 79 80 /* make the real string descriptors */ 81 82 USB_MAKE_STRING_DESC(STRING_AUDIO_MIXER, string_audio_mixer); 83 USB_MAKE_STRING_DESC(STRING_AUDIO_RECORD, string_audio_record); 84 USB_MAKE_STRING_DESC(STRING_AUDIO_PLAYBACK, string_audio_playback); 85 USB_MAKE_STRING_DESC(STRING_AUDIO_PRODUCT, string_audio_product); 86 87 /* prototypes */ 88 89 /* 90 * Audio Mixer description structures 91 * 92 * Some of the audio descriptors were dumped 93 * from a Creative Labs USB audio device. 94 */ 95 96 static const uint8_t audio_raw_desc_0[] = { 97 0x0a, 0x24, 0x01, 0x00, 0x01, 0xa9, 0x00, 0x02, 98 0x01, 0x02 99 }; 100 101 static const uint8_t audio_raw_desc_1[] = { 102 0x0c, 0x24, 0x02, 0x01, 0x01, 0x01, 0x00, 0x02, 103 0x03, 0x00, 0x00, 0x00 104 }; 105 106 static const uint8_t audio_raw_desc_2[] = { 107 0x0c, 0x24, 0x02, 0x02, 0x01, 0x02, 0x00, 0x02, 108 0x03, 0x00, 0x00, 0x00 109 }; 110 111 static const uint8_t audio_raw_desc_3[] = { 112 0x0c, 0x24, 0x02, 0x03, 0x03, 0x06, 0x00, 0x02, 113 0x03, 0x00, 0x00, 0x00 114 }; 115 116 static const uint8_t audio_raw_desc_4[] = { 117 0x0c, 0x24, 0x02, 0x04, 0x05, 0x06, 0x00, 0x02, 118 0x03, 0x00, 0x00, 0x00 119 }; 120 121 static const uint8_t audio_raw_desc_5[] = { 122 0x09, 0x24, 0x03, 0x05, 0x05, 0x06, 0x00, 0x01, 123 0x00 124 }; 125 126 static const uint8_t audio_raw_desc_6[] = { 127 0x09, 0x24, 0x03, 0x06, 0x01, 0x03, 0x00, 0x09, 128 0x00 129 }; 130 131 static const uint8_t audio_raw_desc_7[] = { 132 0x09, 0x24, 0x03, 0x07, 0x01, 0x01, 0x00, 0x08, 133 0x00 134 }; 135 136 static const uint8_t audio_raw_desc_8[] = { 137 0x09, 0x24, 0x05, 0x08, 0x03, 0x0a, 0x0b, 0x0c, 138 0x00 139 }; 140 141 static const uint8_t audio_raw_desc_9[] = { 142 0x0a, 0x24, 0x06, 0x09, 0x0f, 0x01, 0x01, 0x02, 143 0x02, 0x00 144 }; 145 146 static const uint8_t audio_raw_desc_10[] = { 147 0x0a, 0x24, 0x06, 0x0a, 0x02, 0x01, 0x43, 0x00, 148 0x00, 0x00 149 }; 150 151 static const uint8_t audio_raw_desc_11[] = { 152 0x0a, 0x24, 0x06, 0x0b, 0x03, 0x01, 0x01, 0x02, 153 0x02, 0x00 154 }; 155 156 static const uint8_t audio_raw_desc_12[] = { 157 0x0a, 0x24, 0x06, 0x0c, 0x04, 0x01, 0x01, 0x00, 158 0x00, 0x00 159 }; 160 161 static const uint8_t audio_raw_desc_13[] = { 162 0x0a, 0x24, 0x06, 0x0d, 0x02, 0x01, 0x03, 0x00, 163 0x00, 0x00 164 }; 165 166 static const uint8_t audio_raw_desc_14[] = { 167 0x0a, 0x24, 0x06, 0x0e, 0x03, 0x01, 0x01, 0x02, 168 0x02, 0x00 169 }; 170 171 static const uint8_t audio_raw_desc_15[] = { 172 0x0f, 0x24, 0x04, 0x0f, 0x03, 0x01, 0x0d, 0x0e, 173 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 174 }; 175 176 static const void *audio_raw_iface_0_desc[] = { 177 audio_raw_desc_0, 178 audio_raw_desc_1, 179 audio_raw_desc_2, 180 audio_raw_desc_3, 181 audio_raw_desc_4, 182 audio_raw_desc_5, 183 audio_raw_desc_6, 184 audio_raw_desc_7, 185 audio_raw_desc_8, 186 audio_raw_desc_9, 187 audio_raw_desc_10, 188 audio_raw_desc_11, 189 audio_raw_desc_12, 190 audio_raw_desc_13, 191 audio_raw_desc_14, 192 audio_raw_desc_15, 193 NULL, 194 }; 195 196 static const struct usb_temp_interface_desc audio_iface_0 = { 197 .ppEndpoints = NULL, /* no endpoints */ 198 .ppRawDesc = audio_raw_iface_0_desc, 199 .bInterfaceClass = 1, 200 .bInterfaceSubClass = 1, 201 .bInterfaceProtocol = 0, 202 .iInterface = INDEX_AUDIO_MIXER, 203 }; 204 205 static const uint8_t audio_raw_desc_20[] = { 206 0x07, 0x24, 0x01, 0x01, 0x03, 0x01, 0x00 207 208 }; 209 210 static const uint8_t audio_raw_desc_21[] = { 211 0x0b, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x01, 212 /* 48kHz */ 213 0x80, 0xbb, 0x00 214 }; 215 216 static const uint8_t audio_raw_desc_22[] = { 217 0x07, 0x25, 0x01, 0x00, 0x01, 0x04, 0x00 218 }; 219 220 static const void *audio_raw_iface_1_desc[] = { 221 audio_raw_desc_20, 222 audio_raw_desc_21, 223 NULL, 224 }; 225 226 static const void *audio_raw_ep_1_desc[] = { 227 audio_raw_desc_22, 228 NULL, 229 }; 230 231 static const struct usb_temp_packet_size audio_isoc_mps = { 232 .mps[USB_SPEED_FULL] = 0xC8, 233 .mps[USB_SPEED_HIGH] = 0xC8, 234 }; 235 236 static const struct usb_temp_interval audio_isoc_interval = { 237 .bInterval[USB_SPEED_FULL] = 1, /* 1:1 */ 238 .bInterval[USB_SPEED_HIGH] = 4, /* 1:8 */ 239 }; 240 241 static const struct usb_temp_endpoint_desc audio_isoc_out_ep = { 242 .ppRawDesc = audio_raw_ep_1_desc, 243 .pPacketSize = &audio_isoc_mps, 244 .pIntervals = &audio_isoc_interval, 245 .bEndpointAddress = UE_DIR_OUT, 246 .bmAttributes = UE_ISOCHRONOUS | UE_ISO_ADAPT, 247 }; 248 249 static const struct usb_temp_endpoint_desc *audio_iface_1_ep[] = { 250 &audio_isoc_out_ep, 251 NULL, 252 }; 253 254 static const struct usb_temp_interface_desc audio_iface_1_alt_0 = { 255 .ppEndpoints = NULL, /* no endpoints */ 256 .ppRawDesc = NULL, /* no raw descriptors */ 257 .bInterfaceClass = 1, 258 .bInterfaceSubClass = 2, 259 .bInterfaceProtocol = 0, 260 .iInterface = INDEX_AUDIO_PLAYBACK, 261 }; 262 263 static const struct usb_temp_interface_desc audio_iface_1_alt_1 = { 264 .ppEndpoints = audio_iface_1_ep, 265 .ppRawDesc = audio_raw_iface_1_desc, 266 .bInterfaceClass = 1, 267 .bInterfaceSubClass = 2, 268 .bInterfaceProtocol = 0, 269 .iInterface = INDEX_AUDIO_PLAYBACK, 270 .isAltInterface = 1, /* this is an alternate setting */ 271 }; 272 273 static const uint8_t audio_raw_desc_30[] = { 274 0x07, 0x24, 0x01, 0x07, 0x01, 0x01, 0x00 275 276 }; 277 278 static const uint8_t audio_raw_desc_31[] = { 279 0x0b, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x01, 280 /* 48kHz */ 281 0x80, 0xbb, 0x00 282 }; 283 284 static const uint8_t audio_raw_desc_32[] = { 285 0x07, 0x25, 0x01, 0x01, 0x00, 0x00, 0x00 286 }; 287 288 static const void *audio_raw_iface_2_desc[] = { 289 audio_raw_desc_30, 290 audio_raw_desc_31, 291 NULL, 292 }; 293 294 static const void *audio_raw_ep_2_desc[] = { 295 audio_raw_desc_32, 296 NULL, 297 }; 298 299 static const struct usb_temp_endpoint_desc audio_isoc_in_ep = { 300 .ppRawDesc = audio_raw_ep_2_desc, 301 .pPacketSize = &audio_isoc_mps, 302 .pIntervals = &audio_isoc_interval, 303 .bEndpointAddress = UE_DIR_IN, 304 .bmAttributes = UE_ISOCHRONOUS | UE_ISO_ADAPT, 305 }; 306 307 static const struct usb_temp_endpoint_desc *audio_iface_2_ep[] = { 308 &audio_isoc_in_ep, 309 NULL, 310 }; 311 312 static const struct usb_temp_interface_desc audio_iface_2_alt_0 = { 313 .ppEndpoints = NULL, /* no endpoints */ 314 .ppRawDesc = NULL, /* no raw descriptors */ 315 .bInterfaceClass = 1, 316 .bInterfaceSubClass = 2, 317 .bInterfaceProtocol = 0, 318 .iInterface = INDEX_AUDIO_RECORD, 319 }; 320 321 static const struct usb_temp_interface_desc audio_iface_2_alt_1 = { 322 .ppEndpoints = audio_iface_2_ep, 323 .ppRawDesc = audio_raw_iface_2_desc, 324 .bInterfaceClass = 1, 325 .bInterfaceSubClass = 2, 326 .bInterfaceProtocol = 0, 327 .iInterface = INDEX_AUDIO_RECORD, 328 .isAltInterface = 1, /* this is an alternate setting */ 329 }; 330 331 static const struct usb_temp_interface_desc *audio_interfaces[] = { 332 &audio_iface_0, 333 &audio_iface_1_alt_0, 334 &audio_iface_1_alt_1, 335 &audio_iface_2_alt_0, 336 &audio_iface_2_alt_1, 337 NULL, 338 }; 339 340 static const struct usb_temp_config_desc audio_config_desc = { 341 .ppIfaceDesc = audio_interfaces, 342 .bmAttributes = UC_BUS_POWERED, 343 .bMaxPower = 25, /* 50 mA */ 344 .iConfiguration = INDEX_AUDIO_PRODUCT, 345 }; 346 347 static const struct usb_temp_config_desc *audio_configs[] = { 348 &audio_config_desc, 349 NULL, 350 }; 351 352 static usb_temp_get_string_desc_t audio_get_string_desc; 353 354 const struct usb_temp_device_desc usb_template_audio = { 355 .getStringDesc = &audio_get_string_desc, 356 .ppConfigDesc = audio_configs, 357 .idVendor = USB_TEMPLATE_VENDOR, 358 .idProduct = 0x000A, 359 .bcdDevice = 0x0100, 360 .bDeviceClass = UDCLASS_COMM, 361 .bDeviceSubClass = 0, 362 .bDeviceProtocol = 0, 363 .iManufacturer = 0, 364 .iProduct = INDEX_AUDIO_PRODUCT, 365 .iSerialNumber = 0, 366 }; 367 368 /*------------------------------------------------------------------------* 369 * audio_get_string_desc 370 * 371 * Return values: 372 * NULL: Failure. No such string. 373 * Else: Success. Pointer to string descriptor is returned. 374 *------------------------------------------------------------------------*/ 375 static const void * 376 audio_get_string_desc(uint16_t lang_id, uint8_t string_index) 377 { 378 static const void *ptr[INDEX_AUDIO_MAX] = { 379 [INDEX_AUDIO_LANG] = &usb_string_lang_en, 380 [INDEX_AUDIO_MIXER] = &string_audio_mixer, 381 [INDEX_AUDIO_RECORD] = &string_audio_record, 382 [INDEX_AUDIO_PLAYBACK] = &string_audio_playback, 383 [INDEX_AUDIO_PRODUCT] = &string_audio_product, 384 }; 385 386 if (string_index == 0) { 387 return (&usb_string_lang_en); 388 } 389 if (lang_id != 0x0409) { 390 return (NULL); 391 } 392 if (string_index < INDEX_AUDIO_MAX) { 393 return (ptr[string_index]); 394 } 395 return (NULL); 396 } 397