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