1184610Salfred/* $NetBSD: uaudio.c,v 1.91 2004/11/05 17:46:14 kent Exp $ */ 2184610Salfred/* $FreeBSD$ */ 3184610Salfred 4184610Salfred/*- 5184610Salfred * Copyright (c) 1999 The NetBSD Foundation, Inc. 6184610Salfred * All rights reserved. 7184610Salfred * 8184610Salfred * This code is derived from software contributed to The NetBSD Foundation 9184610Salfred * by Lennart Augustsson (lennart@augustsson.net) at 10184610Salfred * Carlstedt Research & Technology. 11184610Salfred * 12184610Salfred * Redistribution and use in source and binary forms, with or without 13184610Salfred * modification, are permitted provided that the following conditions 14184610Salfred * are met: 15184610Salfred * 1. Redistributions of source code must retain the above copyright 16184610Salfred * notice, this list of conditions and the following disclaimer. 17184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 18184610Salfred * notice, this list of conditions and the following disclaimer in the 19184610Salfred * documentation and/or other materials provided with the distribution. 20184610Salfred * 21184610Salfred * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22184610Salfred * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23184610Salfred * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24184610Salfred * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25184610Salfred * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26184610Salfred * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27184610Salfred * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28184610Salfred * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29184610Salfred * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30184610Salfred * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31184610Salfred * POSSIBILITY OF SUCH DAMAGE. 32184610Salfred */ 33184610Salfred 34227843Smarius#include <sys/cdefs.h> 35227843Smarius__FBSDID("$FreeBSD$"); 36227843Smarius 37184610Salfred/* 38184610Salfred * USB audio specs: http://www.usb.org/developers/devclass_docs/audio10.pdf 39184610Salfred * http://www.usb.org/developers/devclass_docs/frmts10.pdf 40184610Salfred * http://www.usb.org/developers/devclass_docs/termt10.pdf 41184610Salfred */ 42184610Salfred 43184610Salfred/* 44184610Salfred * Also merged: 45184610Salfred * $NetBSD: uaudio.c,v 1.94 2005/01/15 15:19:53 kent Exp $ 46184610Salfred * $NetBSD: uaudio.c,v 1.95 2005/01/16 06:02:19 dsainty Exp $ 47184610Salfred * $NetBSD: uaudio.c,v 1.96 2005/01/16 12:46:00 kent Exp $ 48184610Salfred * $NetBSD: uaudio.c,v 1.97 2005/02/24 08:19:38 martin Exp $ 49184610Salfred */ 50184610Salfred 51194677Sthompsa#include <sys/stdint.h> 52194677Sthompsa#include <sys/stddef.h> 53194677Sthompsa#include <sys/param.h> 54194677Sthompsa#include <sys/queue.h> 55194677Sthompsa#include <sys/types.h> 56194677Sthompsa#include <sys/systm.h> 57194677Sthompsa#include <sys/kernel.h> 58194677Sthompsa#include <sys/bus.h> 59194677Sthompsa#include <sys/module.h> 60194677Sthompsa#include <sys/lock.h> 61194677Sthompsa#include <sys/mutex.h> 62194677Sthompsa#include <sys/condvar.h> 63194677Sthompsa#include <sys/sysctl.h> 64194677Sthompsa#include <sys/sx.h> 65194677Sthompsa#include <sys/unistd.h> 66194677Sthompsa#include <sys/callout.h> 67194677Sthompsa#include <sys/malloc.h> 68194677Sthompsa#include <sys/priv.h> 69194677Sthompsa 70188746Sthompsa#include "usbdevs.h" 71188942Sthompsa#include <dev/usb/usb.h> 72194677Sthompsa#include <dev/usb/usbdi.h> 73194677Sthompsa#include <dev/usb/usbdi_util.h> 74246421Shselasky#include <dev/usb/usbhid.h> 75242438Shselasky#include <dev/usb/usb_request.h> 76249796Shselasky#include <dev/usb/usb_process.h> 77184610Salfred 78184610Salfred#define USB_DEBUG_VAR uaudio_debug 79188942Sthompsa#include <dev/usb/usb_debug.h> 80184610Salfred 81188942Sthompsa#include <dev/usb/quirk/usb_quirk.h> 82184610Salfred 83184610Salfred#include <sys/reboot.h> /* for bootverbose */ 84184610Salfred 85193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS 86193640Sariff#include "opt_snd.h" 87193640Sariff#endif 88193640Sariff 89184610Salfred#include <dev/sound/pcm/sound.h> 90188957Sthompsa#include <dev/sound/usb/uaudioreg.h> 91188957Sthompsa#include <dev/sound/usb/uaudio.h> 92184610Salfred#include <dev/sound/chip.h> 93184610Salfred#include "feeder_if.h" 94184610Salfred 95200825Sthompsastatic int uaudio_default_rate = 0; /* use rate list */ 96186730Salfredstatic int uaudio_default_bits = 32; 97200825Sthompsastatic int uaudio_default_channels = 0; /* use default */ 98186730Salfred 99207077Sthompsa#ifdef USB_DEBUG 100184610Salfredstatic int uaudio_debug = 0; 101184610Salfred 102227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, uaudio, CTLFLAG_RW, 0, "USB uaudio"); 103200825Sthompsa 104192505SthompsaSYSCTL_INT(_hw_usb_uaudio, OID_AUTO, debug, CTLFLAG_RW, 105184610Salfred &uaudio_debug, 0, "uaudio debug level"); 106200825Sthompsa 107200825SthompsaTUNABLE_INT("hw.usb.uaudio.default_rate", &uaudio_default_rate); 108192505SthompsaSYSCTL_INT(_hw_usb_uaudio, OID_AUTO, default_rate, CTLFLAG_RW, 109186730Salfred &uaudio_default_rate, 0, "uaudio default sample rate"); 110200825Sthompsa 111200825SthompsaTUNABLE_INT("hw.usb.uaudio.default_bits", &uaudio_default_bits); 112192505SthompsaSYSCTL_INT(_hw_usb_uaudio, OID_AUTO, default_bits, CTLFLAG_RW, 113186730Salfred &uaudio_default_bits, 0, "uaudio default sample bits"); 114200825Sthompsa 115200825SthompsaTUNABLE_INT("hw.usb.uaudio.default_channels", &uaudio_default_channels); 116192505SthompsaSYSCTL_INT(_hw_usb_uaudio, OID_AUTO, default_channels, CTLFLAG_RW, 117186730Salfred &uaudio_default_channels, 0, "uaudio default sample channels"); 118184610Salfred#endif 119184610Salfred 120199060Sthompsa#define UAUDIO_NFRAMES 64 /* must be factor of 8 due HS-USB */ 121240609Shselasky#define UAUDIO_NCHANBUFS 2 /* number of outstanding request */ 122240609Shselasky#define UAUDIO_RECURSE_LIMIT 255 /* rounds */ 123184610Salfred 124184610Salfred#define MAKE_WORD(h,l) (((h) << 8) | (l)) 125184610Salfred#define BIT_TEST(bm,bno) (((bm)[(bno) / 8] >> (7 - ((bno) % 8))) & 1) 126193465Sthompsa#define UAUDIO_MAX_CHAN(x) (x) 127244567Shselasky#define MIX(sc) ((sc)->sc_mixer_node) 128184610Salfred 129240609Shselaskyunion uaudio_asid { 130240609Shselasky const struct usb_audio_streaming_interface_descriptor *v1; 131240609Shselasky const struct usb_audio20_streaming_interface_descriptor *v2; 132240609Shselasky}; 133240609Shselasky 134240609Shselaskyunion uaudio_asf1d { 135240609Shselasky const struct usb_audio_streaming_type1_descriptor *v1; 136240609Shselasky const struct usb_audio20_streaming_type1_descriptor *v2; 137240609Shselasky}; 138240609Shselasky 139240609Shselaskyunion uaudio_sed { 140240609Shselasky const struct usb_audio_streaming_endpoint_descriptor *v1; 141240609Shselasky const struct usb_audio20_streaming_endpoint_descriptor *v2; 142240609Shselasky}; 143240609Shselasky 144184610Salfredstruct uaudio_mixer_node { 145242438Shselasky const char *name; 146242438Shselasky 147184610Salfred int32_t minval; 148184610Salfred int32_t maxval; 149242438Shselasky#define MIX_MAX_CHAN 16 150184610Salfred int32_t wValue[MIX_MAX_CHAN]; /* using nchan */ 151184610Salfred uint32_t mul; 152184610Salfred uint32_t ctl; 153184610Salfred 154242438Shselasky int wData[MIX_MAX_CHAN]; /* using nchan */ 155184610Salfred uint16_t wIndex; 156184610Salfred 157184610Salfred uint8_t update[(MIX_MAX_CHAN + 7) / 8]; 158184610Salfred uint8_t nchan; 159184610Salfred uint8_t type; 160184610Salfred#define MIX_ON_OFF 1 161184610Salfred#define MIX_SIGNED_16 2 162184610Salfred#define MIX_UNSIGNED_16 3 163184610Salfred#define MIX_SIGNED_8 4 164184610Salfred#define MIX_SELECTOR 5 165184610Salfred#define MIX_UNKNOWN 6 166184610Salfred#define MIX_SIZE(n) ((((n) == MIX_SIGNED_16) || \ 167184610Salfred ((n) == MIX_UNSIGNED_16)) ? 2 : 1) 168184610Salfred#define MIX_UNSIGNED(n) ((n) == MIX_UNSIGNED_16) 169184610Salfred 170184610Salfred#define MAX_SELECTOR_INPUT_PIN 256 171184610Salfred uint8_t slctrtype[MAX_SELECTOR_INPUT_PIN]; 172184610Salfred uint8_t class; 173242453Shselasky uint8_t val_default; 174184610Salfred 175242438Shselasky uint8_t desc[64]; 176242438Shselasky 177184610Salfred struct uaudio_mixer_node *next; 178184610Salfred}; 179184610Salfred 180249796Shselaskystruct uaudio_configure_msg { 181249796Shselasky struct usb_proc_msg hdr; 182249796Shselasky struct uaudio_softc *sc; 183249796Shselasky}; 184249796Shselasky 185263642Shselasky#define CHAN_MAX_ALT 24 186249796Shselasky 187249796Shselaskystruct uaudio_chan_alt { 188249796Shselasky union uaudio_asf1d p_asf1d; 189249796Shselasky union uaudio_sed p_sed; 190249796Shselasky const usb_endpoint_descriptor_audio_t *p_ed1; 191249796Shselasky const struct uaudio_format *p_fmt; 192249796Shselasky const struct usb_config *usb_cfg; 193249796Shselasky uint32_t sample_rate; /* in Hz */ 194249796Shselasky uint16_t sample_size; 195249796Shselasky uint8_t iface_index; 196249796Shselasky uint8_t iface_alt_index; 197249796Shselasky uint8_t channels; 198249796Shselasky}; 199249796Shselasky 200184610Salfredstruct uaudio_chan { 201184610Salfred struct pcmchan_caps pcm_cap; /* capabilities */ 202249796Shselasky struct uaudio_chan_alt usb_alt[CHAN_MAX_ALT]; 203184610Salfred struct snd_dbuf *pcm_buf; 204184610Salfred struct mtx *pcm_mtx; /* lock protecting this structure */ 205184610Salfred struct uaudio_softc *priv_sc; 206184610Salfred struct pcm_channel *pcm_ch; 207242223Shselasky struct usb_xfer *xfer[UAUDIO_NCHANBUFS + 1]; 208184610Salfred 209184610Salfred uint8_t *buf; /* pointer to buffer */ 210184610Salfred uint8_t *start; /* upper layer buffer start */ 211184610Salfred uint8_t *end; /* upper layer buffer end */ 212184610Salfred uint8_t *cur; /* current position in upper layer 213184610Salfred * buffer */ 214184610Salfred 215199060Sthompsa uint32_t intr_frames; /* in units */ 216200825Sthompsa uint32_t frames_per_second; 217200825Sthompsa uint32_t sample_rem; 218200825Sthompsa uint32_t sample_curr; 219249796Shselasky uint32_t max_buf; 220200825Sthompsa 221184610Salfred uint32_t pcm_format[2]; 222184610Salfred 223200825Sthompsa uint16_t bytes_per_frame[2]; 224184610Salfred 225249796Shselasky uint8_t num_alt; 226249796Shselasky uint8_t cur_alt; 227249796Shselasky uint8_t set_alt; 228249796Shselasky uint8_t operation; 229249796Shselasky#define CHAN_OP_NONE 0 230249796Shselasky#define CHAN_OP_START 1 231249796Shselasky#define CHAN_OP_STOP 2 232249796Shselasky#define CHAN_OP_DRAIN 3 233200825Sthompsa 234242223Shselasky uint8_t last_sync_time; 235242223Shselasky uint8_t last_sync_state; 236242223Shselasky#define UAUDIO_SYNC_NONE 0 237242223Shselasky#define UAUDIO_SYNC_MORE 1 238242223Shselasky#define UAUDIO_SYNC_LESS 2 239184610Salfred}; 240184610Salfred 241272423Shselasky#define UMIDI_EMB_JACK_MAX 16 /* units */ 242224024Shselasky#define UMIDI_TX_FRAMES 256 /* units */ 243223727Shselasky#define UMIDI_TX_BUFFER (UMIDI_TX_FRAMES * 4) /* bytes */ 244184610Salfred 245218791Shselaskyenum { 246218791Shselasky UMIDI_TX_TRANSFER, 247218791Shselasky UMIDI_RX_TRANSFER, 248218791Shselasky UMIDI_N_TRANSFER, 249218791Shselasky}; 250218791Shselasky 251184610Salfredstruct umidi_sub_chan { 252192984Sthompsa struct usb_fifo_sc fifo; 253184610Salfred uint8_t *temp_cmd; 254184610Salfred uint8_t temp_0[4]; 255184610Salfred uint8_t temp_1[4]; 256184610Salfred uint8_t state; 257184610Salfred#define UMIDI_ST_UNKNOWN 0 /* scan for command */ 258184610Salfred#define UMIDI_ST_1PARAM 1 259184610Salfred#define UMIDI_ST_2PARAM_1 2 260184610Salfred#define UMIDI_ST_2PARAM_2 3 261184610Salfred#define UMIDI_ST_SYSEX_0 4 262184610Salfred#define UMIDI_ST_SYSEX_1 5 263184610Salfred#define UMIDI_ST_SYSEX_2 6 264184610Salfred 265184610Salfred uint8_t read_open:1; 266184610Salfred uint8_t write_open:1; 267184610Salfred uint8_t unused:6; 268184610Salfred}; 269184610Salfred 270184610Salfredstruct umidi_chan { 271184610Salfred 272272423Shselasky struct umidi_sub_chan sub[UMIDI_EMB_JACK_MAX]; 273184610Salfred struct mtx mtx; 274184610Salfred 275192984Sthompsa struct usb_xfer *xfer[UMIDI_N_TRANSFER]; 276184610Salfred 277184610Salfred uint8_t iface_index; 278184610Salfred uint8_t iface_alt_index; 279184610Salfred 280184610Salfred uint8_t read_open_refcount; 281184610Salfred uint8_t write_open_refcount; 282184610Salfred 283184610Salfred uint8_t curr_cable; 284272423Shselasky uint8_t max_emb_jack; 285184610Salfred uint8_t valid; 286223736Shselasky uint8_t single_command; 287184610Salfred}; 288184610Salfred 289240609Shselaskystruct uaudio_search_result { 290240609Shselasky uint8_t bit_input[(256 + 7) / 8]; 291240609Shselasky uint8_t bit_output[(256 + 7) / 8]; 292240609Shselasky uint8_t recurse_level; 293240609Shselasky uint8_t id_max; 294240609Shselasky uint8_t is_input; 295240609Shselasky}; 296240609Shselasky 297246421Shselaskyenum { 298246421Shselasky UAUDIO_HID_RX_TRANSFER, 299246421Shselasky UAUDIO_HID_N_TRANSFER, 300246421Shselasky}; 301246421Shselasky 302246421Shselaskystruct uaudio_hid { 303246421Shselasky struct usb_xfer *xfer[UAUDIO_HID_N_TRANSFER]; 304246421Shselasky struct hid_location volume_up_loc; 305246421Shselasky struct hid_location volume_down_loc; 306246454Shselasky struct hid_location mute_loc; 307246421Shselasky uint32_t flags; 308246421Shselasky#define UAUDIO_HID_VALID 0x0001 309246421Shselasky#define UAUDIO_HID_HAS_ID 0x0002 310246421Shselasky#define UAUDIO_HID_HAS_VOLUME_UP 0x0004 311246421Shselasky#define UAUDIO_HID_HAS_VOLUME_DOWN 0x0008 312246454Shselasky#define UAUDIO_HID_HAS_MUTE 0x0010 313246421Shselasky uint8_t iface_index; 314246421Shselasky uint8_t volume_up_id; 315246421Shselasky uint8_t volume_down_id; 316246454Shselasky uint8_t mute_id; 317246421Shselasky}; 318246421Shselasky 319184610Salfredstruct uaudio_softc { 320184610Salfred struct sbuf sc_sndstat; 321184610Salfred struct sndcard_func sc_sndcard_func; 322184610Salfred struct uaudio_chan sc_rec_chan; 323184610Salfred struct uaudio_chan sc_play_chan; 324184610Salfred struct umidi_chan sc_midi_chan; 325246421Shselasky struct uaudio_hid sc_hid; 326240609Shselasky struct uaudio_search_result sc_mixer_clocks; 327244567Shselasky struct uaudio_mixer_node sc_mixer_node; 328249796Shselasky struct uaudio_configure_msg sc_config_msg[2]; 329184610Salfred 330242438Shselasky struct mtx *sc_mixer_lock; 331246421Shselasky struct snd_mixer *sc_mixer_dev; 332192984Sthompsa struct usb_device *sc_udev; 333192984Sthompsa struct usb_xfer *sc_mixer_xfer[1]; 334184610Salfred struct uaudio_mixer_node *sc_mixer_root; 335184610Salfred struct uaudio_mixer_node *sc_mixer_curr; 336184610Salfred 337184610Salfred uint32_t sc_mix_info; 338184610Salfred uint32_t sc_recsrc_info; 339184610Salfred 340184610Salfred uint16_t sc_audio_rev; 341184610Salfred uint16_t sc_mixer_count; 342184610Salfred 343184610Salfred uint8_t sc_sndstat_valid; 344184610Salfred uint8_t sc_mixer_iface_index; 345184610Salfred uint8_t sc_mixer_iface_no; 346184610Salfred uint8_t sc_mixer_chan; 347184610Salfred uint8_t sc_pcm_registered:1; 348184610Salfred uint8_t sc_mixer_init:1; 349184610Salfred uint8_t sc_uq_audio_swap_lr:1; 350184610Salfred uint8_t sc_uq_au_inp_async:1; 351184610Salfred uint8_t sc_uq_au_no_xu:1; 352184610Salfred uint8_t sc_uq_bad_adc:1; 353218988Shselasky uint8_t sc_uq_au_vendor_class:1; 354184610Salfred}; 355184610Salfred 356184610Salfredstruct uaudio_terminal_node { 357184610Salfred union { 358192984Sthompsa const struct usb_descriptor *desc; 359240609Shselasky const struct usb_audio_input_terminal *it_v1; 360240609Shselasky const struct usb_audio_output_terminal *ot_v1; 361240609Shselasky const struct usb_audio_mixer_unit_0 *mu_v1; 362240609Shselasky const struct usb_audio_selector_unit *su_v1; 363240609Shselasky const struct usb_audio_feature_unit *fu_v1; 364240609Shselasky const struct usb_audio_processing_unit_0 *pu_v1; 365240609Shselasky const struct usb_audio_extension_unit_0 *eu_v1; 366240609Shselasky const struct usb_audio20_clock_source_unit *csrc_v2; 367240609Shselasky const struct usb_audio20_clock_selector_unit_0 *csel_v2; 368240609Shselasky const struct usb_audio20_clock_multiplier_unit *cmul_v2; 369240609Shselasky const struct usb_audio20_input_terminal *it_v2; 370240609Shselasky const struct usb_audio20_output_terminal *ot_v2; 371240609Shselasky const struct usb_audio20_mixer_unit_0 *mu_v2; 372240609Shselasky const struct usb_audio20_selector_unit *su_v2; 373240609Shselasky const struct usb_audio20_feature_unit *fu_v2; 374240609Shselasky const struct usb_audio20_sample_rate_unit *ru_v2; 375240609Shselasky const struct usb_audio20_processing_unit_0 *pu_v2; 376240609Shselasky const struct usb_audio20_extension_unit_0 *eu_v2; 377240609Shselasky const struct usb_audio20_effect_unit *ef_v2; 378184610Salfred } u; 379184610Salfred struct uaudio_search_result usr; 380184610Salfred struct uaudio_terminal_node *root; 381184610Salfred}; 382184610Salfred 383184610Salfredstruct uaudio_format { 384184610Salfred uint16_t wFormat; 385184610Salfred uint8_t bPrecision; 386184610Salfred uint32_t freebsd_fmt; 387184610Salfred const char *description; 388184610Salfred}; 389184610Salfred 390240609Shselaskystatic const struct uaudio_format uaudio10_formats[] = { 391184610Salfred 392184610Salfred {UA_FMT_PCM8, 8, AFMT_U8, "8-bit U-LE PCM"}, 393184610Salfred {UA_FMT_PCM8, 16, AFMT_U16_LE, "16-bit U-LE PCM"}, 394184610Salfred {UA_FMT_PCM8, 24, AFMT_U24_LE, "24-bit U-LE PCM"}, 395184610Salfred {UA_FMT_PCM8, 32, AFMT_U32_LE, "32-bit U-LE PCM"}, 396184610Salfred 397184610Salfred {UA_FMT_PCM, 8, AFMT_S8, "8-bit S-LE PCM"}, 398184610Salfred {UA_FMT_PCM, 16, AFMT_S16_LE, "16-bit S-LE PCM"}, 399184610Salfred {UA_FMT_PCM, 24, AFMT_S24_LE, "24-bit S-LE PCM"}, 400184610Salfred {UA_FMT_PCM, 32, AFMT_S32_LE, "32-bit S-LE PCM"}, 401184610Salfred 402184610Salfred {UA_FMT_ALAW, 8, AFMT_A_LAW, "8-bit A-Law"}, 403184610Salfred {UA_FMT_MULAW, 8, AFMT_MU_LAW, "8-bit mu-Law"}, 404184610Salfred 405184610Salfred {0, 0, 0, NULL} 406184610Salfred}; 407184610Salfred 408240609Shselaskystatic const struct uaudio_format uaudio20_formats[] = { 409240609Shselasky 410240609Shselasky {UA20_FMT_PCM, 8, AFMT_S8, "8-bit S-LE PCM"}, 411240609Shselasky {UA20_FMT_PCM, 16, AFMT_S16_LE, "16-bit S-LE PCM"}, 412240609Shselasky {UA20_FMT_PCM, 24, AFMT_S24_LE, "24-bit S-LE PCM"}, 413240609Shselasky {UA20_FMT_PCM, 32, AFMT_S32_LE, "32-bit S-LE PCM"}, 414240609Shselasky 415240609Shselasky {UA20_FMT_PCM8, 8, AFMT_U8, "8-bit U-LE PCM"}, 416240609Shselasky {UA20_FMT_PCM8, 16, AFMT_U16_LE, "16-bit U-LE PCM"}, 417240609Shselasky {UA20_FMT_PCM8, 24, AFMT_U24_LE, "24-bit U-LE PCM"}, 418240609Shselasky {UA20_FMT_PCM8, 32, AFMT_U32_LE, "32-bit U-LE PCM"}, 419240609Shselasky 420240609Shselasky {UA20_FMT_ALAW, 8, AFMT_A_LAW, "8-bit A-Law"}, 421240609Shselasky {UA20_FMT_MULAW, 8, AFMT_MU_LAW, "8-bit mu-Law"}, 422240609Shselasky 423240609Shselasky {0, 0, 0, NULL} 424240609Shselasky}; 425240609Shselasky 426184610Salfred#define UAC_OUTPUT 0 427184610Salfred#define UAC_INPUT 1 428184610Salfred#define UAC_EQUAL 2 429184610Salfred#define UAC_RECORD 3 430184610Salfred#define UAC_NCLASSES 4 431184610Salfred 432207077Sthompsa#ifdef USB_DEBUG 433184610Salfredstatic const char *uac_names[] = { 434184610Salfred "outputs", "inputs", "equalization", "record" 435184610Salfred}; 436184610Salfred 437184610Salfred#endif 438184610Salfred 439184610Salfred/* prototypes */ 440184610Salfred 441184610Salfredstatic device_probe_t uaudio_probe; 442184610Salfredstatic device_attach_t uaudio_attach; 443184610Salfredstatic device_detach_t uaudio_detach; 444184610Salfred 445193045Sthompsastatic usb_callback_t uaudio_chan_play_callback; 446242223Shselaskystatic usb_callback_t uaudio_chan_play_sync_callback; 447193045Sthompsastatic usb_callback_t uaudio_chan_record_callback; 448242223Shselaskystatic usb_callback_t uaudio_chan_record_sync_callback; 449193045Sthompsastatic usb_callback_t uaudio_mixer_write_cfg_callback; 450193045Sthompsastatic usb_callback_t umidi_bulk_read_callback; 451193045Sthompsastatic usb_callback_t umidi_bulk_write_callback; 452246421Shselaskystatic usb_callback_t uaudio_hid_rx_callback; 453184610Salfred 454249796Shselaskystatic usb_proc_callback_t uaudio_configure_msg; 455249796Shselasky 456242438Shselasky/* ==== USB mixer ==== */ 457242438Shselasky 458242438Shselaskystatic int uaudio_mixer_sysctl_handler(SYSCTL_HANDLER_ARGS); 459242438Shselaskystatic void uaudio_mixer_ctl_free(struct uaudio_softc *); 460242438Shselaskystatic void uaudio_mixer_register_sysctl(struct uaudio_softc *, device_t); 461242438Shselaskystatic void uaudio_mixer_reload_all(struct uaudio_softc *); 462242453Shselaskystatic void uaudio_mixer_controls_create_ftu(struct uaudio_softc *); 463242438Shselasky 464240609Shselasky/* ==== USB audio v1.0 ==== */ 465240609Shselasky 466185948Sthompsastatic void uaudio_mixer_add_mixer(struct uaudio_softc *, 467185948Sthompsa const struct uaudio_terminal_node *, int); 468185948Sthompsastatic void uaudio_mixer_add_selector(struct uaudio_softc *, 469185948Sthompsa const struct uaudio_terminal_node *, int); 470185948Sthompsastatic uint32_t uaudio_mixer_feature_get_bmaControls( 471203678Sbrucec const struct usb_audio_feature_unit *, uint8_t); 472185948Sthompsastatic void uaudio_mixer_add_feature(struct uaudio_softc *, 473185948Sthompsa const struct uaudio_terminal_node *, int); 474185948Sthompsastatic void uaudio_mixer_add_processing_updown(struct uaudio_softc *, 475185948Sthompsa const struct uaudio_terminal_node *, int); 476185948Sthompsastatic void uaudio_mixer_add_processing(struct uaudio_softc *, 477185948Sthompsa const struct uaudio_terminal_node *, int); 478185948Sthompsastatic void uaudio_mixer_add_extension(struct uaudio_softc *, 479185948Sthompsa const struct uaudio_terminal_node *, int); 480203678Sbrucecstatic struct usb_audio_cluster uaudio_mixer_get_cluster(uint8_t, 481185948Sthompsa const struct uaudio_terminal_node *); 482185948Sthompsastatic uint16_t uaudio_mixer_determine_class(const struct uaudio_terminal_node *, 483185948Sthompsa struct uaudio_mixer_node *); 484185948Sthompsastatic uint16_t uaudio_mixer_feature_name(const struct uaudio_terminal_node *, 485185948Sthompsa struct uaudio_mixer_node *); 486185948Sthompsastatic void uaudio_mixer_find_inputs_sub(struct uaudio_terminal_node *, 487185948Sthompsa const uint8_t *, uint8_t, struct uaudio_search_result *); 488240609Shselaskystatic const void *uaudio_mixer_verify_desc(const void *, uint32_t); 489240609Shselaskystatic usb_error_t uaudio_set_speed(struct usb_device *, uint8_t, uint32_t); 490240609Shselaskystatic int uaudio_mixer_get(struct usb_device *, uint16_t, uint8_t, 491240609Shselasky struct uaudio_mixer_node *); 492240609Shselasky 493240609Shselasky/* ==== USB audio v2.0 ==== */ 494240609Shselasky 495240609Shselaskystatic void uaudio20_mixer_add_mixer(struct uaudio_softc *, 496240609Shselasky const struct uaudio_terminal_node *, int); 497240609Shselaskystatic void uaudio20_mixer_add_selector(struct uaudio_softc *, 498240609Shselasky const struct uaudio_terminal_node *, int); 499240609Shselaskystatic void uaudio20_mixer_add_feature(struct uaudio_softc *, 500240609Shselasky const struct uaudio_terminal_node *, int); 501240609Shselaskystatic struct usb_audio20_cluster uaudio20_mixer_get_cluster(uint8_t, 502240609Shselasky const struct uaudio_terminal_node *); 503240609Shselaskystatic uint16_t uaudio20_mixer_determine_class(const struct uaudio_terminal_node *, 504240609Shselasky struct uaudio_mixer_node *); 505240609Shselaskystatic uint16_t uaudio20_mixer_feature_name(const struct uaudio_terminal_node *, 506240609Shselasky struct uaudio_mixer_node *); 507240609Shselaskystatic void uaudio20_mixer_find_inputs_sub(struct uaudio_terminal_node *, 508240609Shselasky const uint8_t *, uint8_t, struct uaudio_search_result *); 509240609Shselaskystatic const void *uaudio20_mixer_verify_desc(const void *, uint32_t); 510240609Shselaskystatic usb_error_t uaudio20_set_speed(struct usb_device *, uint8_t, 511240609Shselasky uint8_t, uint32_t); 512240609Shselasky 513240609Shselasky/* USB audio v1.0 and v2.0 */ 514240609Shselasky 515240609Shselaskystatic void uaudio_chan_fill_info_sub(struct uaudio_softc *, 516240609Shselasky struct usb_device *, uint32_t, uint8_t, uint8_t); 517240609Shselaskystatic void uaudio_chan_fill_info(struct uaudio_softc *, 518240609Shselasky struct usb_device *); 519240609Shselaskystatic void uaudio_mixer_add_ctl_sub(struct uaudio_softc *, 520240609Shselasky struct uaudio_mixer_node *); 521240609Shselaskystatic void uaudio_mixer_add_ctl(struct uaudio_softc *, 522240609Shselasky struct uaudio_mixer_node *); 523185948Sthompsastatic void uaudio_mixer_fill_info(struct uaudio_softc *, 524192984Sthompsa struct usb_device *, void *); 525185948Sthompsastatic void uaudio_mixer_ctl_set(struct uaudio_softc *, 526185948Sthompsa struct uaudio_mixer_node *, uint8_t, int32_t val); 527185948Sthompsastatic int uaudio_mixer_signext(uint8_t, int); 528185948Sthompsastatic int uaudio_mixer_bsd2value(struct uaudio_mixer_node *, int32_t val); 529185948Sthompsastatic void uaudio_mixer_init(struct uaudio_softc *); 530240609Shselaskystatic const struct uaudio_terminal_node *uaudio_mixer_get_input( 531240609Shselasky const struct uaudio_terminal_node *, uint8_t); 532240609Shselaskystatic const struct uaudio_terminal_node *uaudio_mixer_get_output( 533240609Shselasky const struct uaudio_terminal_node *, uint8_t); 534240609Shselaskystatic void uaudio_mixer_find_outputs_sub(struct uaudio_terminal_node *, 535240609Shselasky uint8_t, uint8_t, struct uaudio_search_result *); 536185948Sthompsastatic uint8_t umidi_convert_to_usb(struct umidi_sub_chan *, uint8_t, uint8_t); 537192984Sthompsastatic struct umidi_sub_chan *umidi_sub_by_fifo(struct usb_fifo *); 538192984Sthompsastatic void umidi_start_read(struct usb_fifo *); 539192984Sthompsastatic void umidi_stop_read(struct usb_fifo *); 540192984Sthompsastatic void umidi_start_write(struct usb_fifo *); 541192984Sthompsastatic void umidi_stop_write(struct usb_fifo *); 542192984Sthompsastatic int umidi_open(struct usb_fifo *, int); 543192984Sthompsastatic int umidi_ioctl(struct usb_fifo *, u_long cmd, void *, int); 544192984Sthompsastatic void umidi_close(struct usb_fifo *, int); 545185948Sthompsastatic void umidi_init(device_t dev); 546218988Shselaskystatic int umidi_probe(device_t dev); 547218988Shselaskystatic int umidi_detach(device_t dev); 548246421Shselaskystatic int uaudio_hid_probe(struct uaudio_softc *sc, 549246421Shselasky struct usb_attach_arg *uaa); 550246421Shselaskystatic void uaudio_hid_detach(struct uaudio_softc *sc); 551184610Salfred 552207077Sthompsa#ifdef USB_DEBUG 553185948Sthompsastatic void uaudio_chan_dump_ep_desc( 554203678Sbrucec const usb_endpoint_descriptor_audio_t *); 555184610Salfred#endif 556184610Salfred 557192984Sthompsastatic const struct usb_config 558242223Shselasky uaudio_cfg_record[UAUDIO_NCHANBUFS + 1] = { 559184610Salfred [0] = { 560184610Salfred .type = UE_ISOCHRONOUS, 561184610Salfred .endpoint = UE_ADDR_ANY, 562184610Salfred .direction = UE_DIR_IN, 563190734Sthompsa .bufsize = 0, /* use "wMaxPacketSize * frames" */ 564199060Sthompsa .frames = UAUDIO_NFRAMES, 565190734Sthompsa .flags = {.short_xfer_ok = 1,}, 566190734Sthompsa .callback = &uaudio_chan_record_callback, 567184610Salfred }, 568184610Salfred 569184610Salfred [1] = { 570184610Salfred .type = UE_ISOCHRONOUS, 571184610Salfred .endpoint = UE_ADDR_ANY, 572184610Salfred .direction = UE_DIR_IN, 573190734Sthompsa .bufsize = 0, /* use "wMaxPacketSize * frames" */ 574199060Sthompsa .frames = UAUDIO_NFRAMES, 575190734Sthompsa .flags = {.short_xfer_ok = 1,}, 576190734Sthompsa .callback = &uaudio_chan_record_callback, 577184610Salfred }, 578242223Shselasky 579242223Shselasky [2] = { 580242223Shselasky .type = UE_ISOCHRONOUS, 581242223Shselasky .endpoint = UE_ADDR_ANY, 582242223Shselasky .direction = UE_DIR_OUT, 583242223Shselasky .bufsize = 0, /* use "wMaxPacketSize * frames" */ 584242223Shselasky .frames = 1, 585242223Shselasky .flags = {.no_pipe_ok = 1,.short_xfer_ok = 1,}, 586242223Shselasky .callback = &uaudio_chan_record_sync_callback, 587242223Shselasky }, 588184610Salfred}; 589184610Salfred 590192984Sthompsastatic const struct usb_config 591242223Shselasky uaudio_cfg_play[UAUDIO_NCHANBUFS + 1] = { 592184610Salfred [0] = { 593184610Salfred .type = UE_ISOCHRONOUS, 594184610Salfred .endpoint = UE_ADDR_ANY, 595184610Salfred .direction = UE_DIR_OUT, 596190734Sthompsa .bufsize = 0, /* use "wMaxPacketSize * frames" */ 597199060Sthompsa .frames = UAUDIO_NFRAMES, 598190734Sthompsa .flags = {.short_xfer_ok = 1,}, 599190734Sthompsa .callback = &uaudio_chan_play_callback, 600184610Salfred }, 601184610Salfred 602184610Salfred [1] = { 603184610Salfred .type = UE_ISOCHRONOUS, 604184610Salfred .endpoint = UE_ADDR_ANY, 605184610Salfred .direction = UE_DIR_OUT, 606190734Sthompsa .bufsize = 0, /* use "wMaxPacketSize * frames" */ 607199060Sthompsa .frames = UAUDIO_NFRAMES, 608190734Sthompsa .flags = {.short_xfer_ok = 1,}, 609190734Sthompsa .callback = &uaudio_chan_play_callback, 610184610Salfred }, 611242223Shselasky 612242223Shselasky [2] = { 613242223Shselasky .type = UE_ISOCHRONOUS, 614242223Shselasky .endpoint = UE_ADDR_ANY, 615242223Shselasky .direction = UE_DIR_IN, 616242223Shselasky .bufsize = 0, /* use "wMaxPacketSize * frames" */ 617242223Shselasky .frames = 1, 618242223Shselasky .flags = {.no_pipe_ok = 1,.short_xfer_ok = 1,}, 619242223Shselasky .callback = &uaudio_chan_play_sync_callback, 620242223Shselasky }, 621184610Salfred}; 622184610Salfred 623192984Sthompsastatic const struct usb_config 624184610Salfred uaudio_mixer_config[1] = { 625184610Salfred [0] = { 626184610Salfred .type = UE_CONTROL, 627184610Salfred .endpoint = 0x00, /* Control pipe */ 628184610Salfred .direction = UE_DIR_ANY, 629192984Sthompsa .bufsize = (sizeof(struct usb_device_request) + 4), 630190734Sthompsa .callback = &uaudio_mixer_write_cfg_callback, 631190734Sthompsa .timeout = 1000, /* 1 second */ 632184610Salfred }, 633184610Salfred}; 634184610Salfred 635184610Salfredstatic const 636184610Salfreduint8_t umidi_cmd_to_len[16] = { 637184610Salfred [0x0] = 0, /* reserved */ 638184610Salfred [0x1] = 0, /* reserved */ 639184610Salfred [0x2] = 2, /* bytes */ 640184610Salfred [0x3] = 3, /* bytes */ 641184610Salfred [0x4] = 3, /* bytes */ 642184610Salfred [0x5] = 1, /* bytes */ 643184610Salfred [0x6] = 2, /* bytes */ 644184610Salfred [0x7] = 3, /* bytes */ 645184610Salfred [0x8] = 3, /* bytes */ 646184610Salfred [0x9] = 3, /* bytes */ 647184610Salfred [0xA] = 3, /* bytes */ 648184610Salfred [0xB] = 3, /* bytes */ 649184610Salfred [0xC] = 2, /* bytes */ 650184610Salfred [0xD] = 2, /* bytes */ 651184610Salfred [0xE] = 3, /* bytes */ 652184610Salfred [0xF] = 1, /* bytes */ 653184610Salfred}; 654184610Salfred 655192984Sthompsastatic const struct usb_config 656184610Salfred umidi_config[UMIDI_N_TRANSFER] = { 657218791Shselasky [UMIDI_TX_TRANSFER] = { 658184610Salfred .type = UE_BULK, 659184610Salfred .endpoint = UE_ADDR_ANY, 660184610Salfred .direction = UE_DIR_OUT, 661223727Shselasky .bufsize = UMIDI_TX_BUFFER, 662190734Sthompsa .callback = &umidi_bulk_write_callback, 663184610Salfred }, 664184610Salfred 665218791Shselasky [UMIDI_RX_TRANSFER] = { 666184610Salfred .type = UE_BULK, 667184610Salfred .endpoint = UE_ADDR_ANY, 668184610Salfred .direction = UE_DIR_IN, 669209450Sthompsa .bufsize = 4, /* bytes */ 670223727Shselasky .flags = {.short_xfer_ok = 1,.proxy_buffer = 1,}, 671190734Sthompsa .callback = &umidi_bulk_read_callback, 672184610Salfred }, 673184610Salfred}; 674184610Salfred 675246421Shselaskystatic const struct usb_config 676246421Shselasky uaudio_hid_config[UAUDIO_HID_N_TRANSFER] = { 677246421Shselasky [UAUDIO_HID_RX_TRANSFER] = { 678246421Shselasky .type = UE_INTERRUPT, 679246421Shselasky .endpoint = UE_ADDR_ANY, 680246421Shselasky .direction = UE_DIR_IN, 681246421Shselasky .bufsize = 0, /* use wMaxPacketSize */ 682246421Shselasky .flags = {.short_xfer_ok = 1,}, 683246421Shselasky .callback = &uaudio_hid_rx_callback, 684246421Shselasky }, 685246421Shselasky}; 686246421Shselasky 687184610Salfredstatic devclass_t uaudio_devclass; 688184610Salfred 689184610Salfredstatic device_method_t uaudio_methods[] = { 690184610Salfred DEVMETHOD(device_probe, uaudio_probe), 691184610Salfred DEVMETHOD(device_attach, uaudio_attach), 692184610Salfred DEVMETHOD(device_detach, uaudio_detach), 693184610Salfred DEVMETHOD(device_suspend, bus_generic_suspend), 694184610Salfred DEVMETHOD(device_resume, bus_generic_resume), 695184610Salfred DEVMETHOD(device_shutdown, bus_generic_shutdown), 696227843Smarius 697227843Smarius DEVMETHOD_END 698184610Salfred}; 699184610Salfred 700184610Salfredstatic driver_t uaudio_driver = { 701184610Salfred .name = "uaudio", 702184610Salfred .methods = uaudio_methods, 703184610Salfred .size = sizeof(struct uaudio_softc), 704184610Salfred}; 705184610Salfred 706244027Shselasky/* The following table is derived from Linux's quirks-table.h */ 707244027Shselaskystatic const STRUCT_USB_HOST_ID uaudio_vendor_midi[] = { 708244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1000, 0) }, /* UX256 */ 709244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1001, 0) }, /* MU1000 */ 710244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1002, 0) }, /* MU2000 */ 711244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1003, 0) }, /* MU500 */ 712244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1004, 3) }, /* UW500 */ 713244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1005, 0) }, /* MOTIF6 */ 714244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1006, 0) }, /* MOTIF7 */ 715244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1007, 0) }, /* MOTIF8 */ 716244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1008, 0) }, /* UX96 */ 717244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1009, 0) }, /* UX16 */ 718244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x100a, 3) }, /* EOS BX */ 719244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x100c, 0) }, /* UC-MX */ 720244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x100d, 0) }, /* UC-KX */ 721244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x100e, 0) }, /* S08 */ 722244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x100f, 0) }, /* CLP-150 */ 723244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1010, 0) }, /* CLP-170 */ 724244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1011, 0) }, /* P-250 */ 725244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1012, 0) }, /* TYROS */ 726244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1013, 0) }, /* PF-500 */ 727244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1014, 0) }, /* S90 */ 728244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1015, 0) }, /* MOTIF-R */ 729244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1016, 0) }, /* MDP-5 */ 730244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1017, 0) }, /* CVP-204 */ 731244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1018, 0) }, /* CVP-206 */ 732244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1019, 0) }, /* CVP-208 */ 733244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x101a, 0) }, /* CVP-210 */ 734244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x101b, 0) }, /* PSR-1100 */ 735244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x101c, 0) }, /* PSR-2100 */ 736244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x101d, 0) }, /* CLP-175 */ 737244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x101e, 0) }, /* PSR-K1 */ 738244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x101f, 0) }, /* EZ-J24 */ 739244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1020, 0) }, /* EZ-250i */ 740244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1021, 0) }, /* MOTIF ES 6 */ 741244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1022, 0) }, /* MOTIF ES 7 */ 742244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1023, 0) }, /* MOTIF ES 8 */ 743244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1024, 0) }, /* CVP-301 */ 744244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1025, 0) }, /* CVP-303 */ 745244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1026, 0) }, /* CVP-305 */ 746244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1027, 0) }, /* CVP-307 */ 747244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1028, 0) }, /* CVP-309 */ 748244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1029, 0) }, /* CVP-309GP */ 749244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x102a, 0) }, /* PSR-1500 */ 750244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x102b, 0) }, /* PSR-3000 */ 751244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x102e, 0) }, /* ELS-01/01C */ 752244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1030, 0) }, /* PSR-295/293 */ 753244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1031, 0) }, /* DGX-205/203 */ 754244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1032, 0) }, /* DGX-305 */ 755244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1033, 0) }, /* DGX-505 */ 756244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1034, 0) }, /* NULL */ 757244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1035, 0) }, /* NULL */ 758244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1036, 0) }, /* NULL */ 759244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1037, 0) }, /* NULL */ 760244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1038, 0) }, /* NULL */ 761244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1039, 0) }, /* NULL */ 762244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x103a, 0) }, /* NULL */ 763244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x103b, 0) }, /* NULL */ 764244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x103c, 0) }, /* NULL */ 765244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x103d, 0) }, /* NULL */ 766244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x103e, 0) }, /* NULL */ 767244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x103f, 0) }, /* NULL */ 768244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1040, 0) }, /* NULL */ 769244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1041, 0) }, /* NULL */ 770244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1042, 0) }, /* NULL */ 771244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1043, 0) }, /* NULL */ 772244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1044, 0) }, /* NULL */ 773244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1045, 0) }, /* NULL */ 774244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x104e, 0) }, /* NULL */ 775244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x104f, 0) }, /* NULL */ 776244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1050, 0) }, /* NULL */ 777244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1051, 0) }, /* NULL */ 778244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1052, 0) }, /* NULL */ 779244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1053, 0) }, /* NULL */ 780244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1054, 0) }, /* NULL */ 781244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1055, 0) }, /* NULL */ 782244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1056, 0) }, /* NULL */ 783244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1057, 0) }, /* NULL */ 784244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1058, 0) }, /* NULL */ 785244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1059, 0) }, /* NULL */ 786244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x105a, 0) }, /* NULL */ 787244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x105b, 0) }, /* NULL */ 788244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x105c, 0) }, /* NULL */ 789244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x105d, 0) }, /* NULL */ 790244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x1503, 3) }, /* MOX6/MOX8 */ 791244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x2000, 0) }, /* DGP-7 */ 792244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x2001, 0) }, /* DGP-5 */ 793244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x2002, 0) }, /* NULL */ 794244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x2003, 0) }, /* NULL */ 795244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x5000, 0) }, /* CS1D */ 796244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x5001, 0) }, /* DSP1D */ 797244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x5002, 0) }, /* DME32 */ 798244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x5003, 0) }, /* DM2000 */ 799244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x5004, 0) }, /* 02R96 */ 800244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x5005, 0) }, /* ACU16-C */ 801244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x5006, 0) }, /* NHB32-C */ 802244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x5007, 0) }, /* DM1000 */ 803244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x5008, 0) }, /* 01V96 */ 804244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x5009, 0) }, /* SPX2000 */ 805244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x500a, 0) }, /* PM5D */ 806244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x500b, 0) }, /* DME64N */ 807244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x500c, 0) }, /* DME24N */ 808244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x500d, 0) }, /* NULL */ 809244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x500e, 0) }, /* NULL */ 810244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x500f, 0) }, /* NULL */ 811244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x7000, 0) }, /* DTX */ 812244027Shselasky { USB_VPI(USB_VENDOR_YAMAHA, 0x7010, 0) }, /* UB99 */ 813244027Shselasky}; 814244027Shselasky 815223486Shselaskystatic const STRUCT_USB_HOST_ID __used uaudio_devs[] = { 816223486Shselasky /* Generic USB audio class match */ 817223486Shselasky {USB_IFACE_CLASS(UICLASS_AUDIO), 818223486Shselasky USB_IFACE_SUBCLASS(UISUBCLASS_AUDIOCONTROL),}, 819223486Shselasky /* Generic USB MIDI class match */ 820223486Shselasky {USB_IFACE_CLASS(UICLASS_AUDIO), 821223486Shselasky USB_IFACE_SUBCLASS(UISUBCLASS_MIDISTREAM),}, 822223486Shselasky}; 823223486Shselasky 824184610Salfredstatic int 825184610Salfreduaudio_probe(device_t dev) 826184610Salfred{ 827192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 828184610Salfred 829192505Sthompsa if (uaa->usb_mode != USB_MODE_HOST) 830184610Salfred return (ENXIO); 831188416Sthompsa 832244027Shselasky /* lookup non-standard device(s) */ 833184610Salfred 834244027Shselasky if (usbd_lookup_id_by_uaa(uaudio_vendor_midi, 835244027Shselasky sizeof(uaudio_vendor_midi), uaa) == 0) { 836244027Shselasky return (BUS_PROBE_SPECIFIC); 837244027Shselasky } 838244027Shselasky 839218988Shselasky if (uaa->info.bInterfaceClass != UICLASS_AUDIO) { 840242129Shselasky if (uaa->info.bInterfaceClass != UICLASS_VENDOR || 841242129Shselasky usb_test_quirk(uaa, UQ_AU_VENDOR_CLASS) == 0) 842218988Shselasky return (ENXIO); 843218988Shselasky } 844218988Shselasky 845218988Shselasky /* check for AUDIO control interface */ 846218988Shselasky 847218988Shselasky if (uaa->info.bInterfaceSubClass == UISUBCLASS_AUDIOCONTROL) { 848194228Sthompsa if (usb_test_quirk(uaa, UQ_BAD_AUDIO)) 849184610Salfred return (ENXIO); 850184610Salfred else 851222051Savg return (BUS_PROBE_GENERIC); 852184610Salfred } 853199677Sthompsa 854199677Sthompsa /* check for MIDI stream */ 855199677Sthompsa 856218988Shselasky if (uaa->info.bInterfaceSubClass == UISUBCLASS_MIDISTREAM) { 857218988Shselasky if (usb_test_quirk(uaa, UQ_BAD_MIDI)) 858218988Shselasky return (ENXIO); 859218988Shselasky else 860222051Savg return (BUS_PROBE_GENERIC); 861199677Sthompsa } 862184610Salfred return (ENXIO); 863184610Salfred} 864184610Salfred 865184610Salfredstatic int 866184610Salfreduaudio_attach(device_t dev) 867184610Salfred{ 868192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 869184610Salfred struct uaudio_softc *sc = device_get_softc(dev); 870192984Sthompsa struct usb_interface_descriptor *id; 871250763Shselasky usb_error_t err; 872184610Salfred device_t child; 873184610Salfred 874184610Salfred sc->sc_play_chan.priv_sc = sc; 875184610Salfred sc->sc_rec_chan.priv_sc = sc; 876184610Salfred sc->sc_udev = uaa->device; 877199060Sthompsa sc->sc_mixer_iface_index = uaa->info.bIfaceIndex; 878199060Sthompsa sc->sc_mixer_iface_no = uaa->info.bIfaceNum; 879249796Shselasky sc->sc_config_msg[0].hdr.pm_callback = &uaudio_configure_msg; 880249796Shselasky sc->sc_config_msg[0].sc = sc; 881249796Shselasky sc->sc_config_msg[1].hdr.pm_callback = &uaudio_configure_msg; 882249796Shselasky sc->sc_config_msg[1].sc = sc; 883184610Salfred 884194228Sthompsa if (usb_test_quirk(uaa, UQ_AUDIO_SWAP_LR)) 885184610Salfred sc->sc_uq_audio_swap_lr = 1; 886184610Salfred 887194228Sthompsa if (usb_test_quirk(uaa, UQ_AU_INP_ASYNC)) 888184610Salfred sc->sc_uq_au_inp_async = 1; 889184610Salfred 890194228Sthompsa if (usb_test_quirk(uaa, UQ_AU_NO_XU)) 891184610Salfred sc->sc_uq_au_no_xu = 1; 892184610Salfred 893194228Sthompsa if (usb_test_quirk(uaa, UQ_BAD_ADC)) 894184610Salfred sc->sc_uq_bad_adc = 1; 895184610Salfred 896218988Shselasky if (usb_test_quirk(uaa, UQ_AU_VENDOR_CLASS)) 897218988Shselasky sc->sc_uq_au_vendor_class = 1; 898218988Shselasky 899184610Salfred umidi_init(dev); 900184610Salfred 901194228Sthompsa device_set_usb_desc(dev); 902184610Salfred 903194228Sthompsa id = usbd_get_interface_descriptor(uaa->iface); 904184610Salfred 905240609Shselasky /* must fill mixer info before channel info */ 906240609Shselasky uaudio_mixer_fill_info(sc, uaa->device, id); 907240609Shselasky 908240609Shselasky /* fill channel info */ 909184610Salfred uaudio_chan_fill_info(sc, uaa->device); 910184610Salfred 911184610Salfred DPRINTF("audio rev %d.%02x\n", 912184610Salfred sc->sc_audio_rev >> 8, 913184610Salfred sc->sc_audio_rev & 0xff); 914184610Salfred 915242453Shselasky if (sc->sc_mixer_count == 0) { 916242453Shselasky if (uaa->info.idVendor == USB_VENDOR_MAUDIO && 917242453Shselasky (uaa->info.idProduct == USB_PRODUCT_MAUDIO_FASTTRACKULTRA || 918242453Shselasky uaa->info.idProduct == USB_PRODUCT_MAUDIO_FASTTRACKULTRA8R)) { 919242453Shselasky DPRINTF("Generating mixer descriptors\n"); 920242453Shselasky uaudio_mixer_controls_create_ftu(sc); 921242453Shselasky } 922242453Shselasky } 923242453Shselasky 924184610Salfred DPRINTF("%d mixer controls\n", 925184610Salfred sc->sc_mixer_count); 926184610Salfred 927249796Shselasky if (sc->sc_play_chan.num_alt > 0) { 928249796Shselasky uint8_t x; 929250763Shselasky 930250763Shselasky /* 931250763Shselasky * Need to set a default alternate interface, else 932250763Shselasky * some USB audio devices might go into an infinte 933250763Shselasky * re-enumeration loop: 934250763Shselasky */ 935250763Shselasky err = usbd_set_alt_interface_index(sc->sc_udev, 936250763Shselasky sc->sc_play_chan.usb_alt[0].iface_index, 937250763Shselasky sc->sc_play_chan.usb_alt[0].iface_alt_index); 938250763Shselasky if (err) { 939250763Shselasky DPRINTF("setting of alternate index failed: %s!\n", 940250763Shselasky usbd_errstr(err)); 941250763Shselasky } 942249796Shselasky for (x = 0; x != sc->sc_play_chan.num_alt; x++) { 943249796Shselasky device_printf(dev, "Play: %d Hz, %d ch, %s format, " 944249796Shselasky "2x8ms buffer.\n", 945249796Shselasky sc->sc_play_chan.usb_alt[x].sample_rate, 946249796Shselasky sc->sc_play_chan.usb_alt[x].channels, 947249796Shselasky sc->sc_play_chan.usb_alt[x].p_fmt->description); 948249796Shselasky } 949184610Salfred } else { 950232039Shselasky device_printf(dev, "No playback.\n"); 951184610Salfred } 952184610Salfred 953249796Shselasky if (sc->sc_rec_chan.num_alt > 0) { 954249796Shselasky uint8_t x; 955250763Shselasky 956250763Shselasky /* 957250763Shselasky * Need to set a default alternate interface, else 958250763Shselasky * some USB audio devices might go into an infinte 959250763Shselasky * re-enumeration loop: 960250763Shselasky */ 961250763Shselasky err = usbd_set_alt_interface_index(sc->sc_udev, 962250763Shselasky sc->sc_rec_chan.usb_alt[0].iface_index, 963250763Shselasky sc->sc_rec_chan.usb_alt[0].iface_alt_index); 964250763Shselasky if (err) { 965250763Shselasky DPRINTF("setting of alternate index failed: %s!\n", 966250763Shselasky usbd_errstr(err)); 967250763Shselasky } 968249796Shselasky for (x = 0; x != sc->sc_rec_chan.num_alt; x++) { 969249796Shselasky device_printf(dev, "Record: %d Hz, %d ch, %s format, " 970249796Shselasky "2x8ms buffer.\n", 971249796Shselasky sc->sc_rec_chan.usb_alt[x].sample_rate, 972249796Shselasky sc->sc_rec_chan.usb_alt[x].channels, 973249796Shselasky sc->sc_rec_chan.usb_alt[x].p_fmt->description); 974249796Shselasky } 975184610Salfred } else { 976232039Shselasky device_printf(dev, "No recording.\n"); 977184610Salfred } 978184610Salfred 979244027Shselasky if (sc->sc_midi_chan.valid == 0) { 980244027Shselasky if (usbd_lookup_id_by_uaa(uaudio_vendor_midi, 981244027Shselasky sizeof(uaudio_vendor_midi), uaa) == 0) { 982244027Shselasky sc->sc_midi_chan.iface_index = 983244027Shselasky (uint8_t)uaa->driver_info; 984244027Shselasky sc->sc_midi_chan.iface_alt_index = 0; 985244027Shselasky sc->sc_midi_chan.valid = 1; 986244027Shselasky } 987244027Shselasky } 988244027Shselasky 989184610Salfred if (sc->sc_midi_chan.valid) { 990184610Salfred 991184610Salfred if (umidi_probe(dev)) { 992184610Salfred goto detach; 993184610Salfred } 994232039Shselasky device_printf(dev, "MIDI sequencer.\n"); 995184610Salfred } else { 996246421Shselasky device_printf(dev, "No MIDI sequencer.\n"); 997184610Salfred } 998184610Salfred 999184610Salfred DPRINTF("doing child attach\n"); 1000184610Salfred 1001184610Salfred /* attach the children */ 1002184610Salfred 1003184610Salfred sc->sc_sndcard_func.func = SCF_PCM; 1004184610Salfred 1005232039Shselasky /* 1006232039Shselasky * Only attach a PCM device if we have a playback, recording 1007232039Shselasky * or mixer device present: 1008232039Shselasky */ 1009249796Shselasky if (sc->sc_play_chan.num_alt > 0 || 1010249796Shselasky sc->sc_rec_chan.num_alt > 0 || 1011232039Shselasky sc->sc_mix_info) { 1012232039Shselasky child = device_add_child(dev, "pcm", -1); 1013184610Salfred 1014232039Shselasky if (child == NULL) { 1015232039Shselasky DPRINTF("out of memory\n"); 1016232039Shselasky goto detach; 1017232039Shselasky } 1018232039Shselasky device_set_ivars(child, &sc->sc_sndcard_func); 1019184610Salfred } 1020184610Salfred 1021184610Salfred if (bus_generic_attach(dev)) { 1022184610Salfred DPRINTF("child attach failed\n"); 1023184610Salfred goto detach; 1024184610Salfred } 1025242438Shselasky 1026246421Shselasky if (uaudio_hid_probe(sc, uaa) == 0) { 1027246421Shselasky device_printf(dev, "HID volume keys found.\n"); 1028246421Shselasky } else { 1029246421Shselasky device_printf(dev, "No HID volume keys found.\n"); 1030246421Shselasky } 1031246421Shselasky 1032242438Shselasky /* reload all mixer settings */ 1033242438Shselasky uaudio_mixer_reload_all(sc); 1034242438Shselasky 1035184610Salfred return (0); /* success */ 1036184610Salfred 1037184610Salfreddetach: 1038184610Salfred uaudio_detach(dev); 1039184610Salfred return (ENXIO); 1040184610Salfred} 1041184610Salfred 1042184610Salfredstatic void 1043184610Salfreduaudio_pcm_setflags(device_t dev, uint32_t flags) 1044184610Salfred{ 1045184610Salfred pcm_setflags(dev, pcm_getflags(dev) | flags); 1046184610Salfred} 1047184610Salfred 1048184610Salfredint 1049184610Salfreduaudio_attach_sub(device_t dev, kobj_class_t mixer_class, kobj_class_t chan_class) 1050184610Salfred{ 1051184610Salfred struct uaudio_softc *sc = device_get_softc(device_get_parent(dev)); 1052184610Salfred char status[SND_STATUSLEN]; 1053184610Salfred 1054184610Salfred uaudio_mixer_init(sc); 1055184610Salfred 1056184610Salfred if (sc->sc_uq_audio_swap_lr) { 1057184610Salfred DPRINTF("hardware has swapped left and right\n"); 1058193640Sariff /* uaudio_pcm_setflags(dev, SD_F_PSWAPLR); */ 1059184610Salfred } 1060184610Salfred if (!(sc->sc_mix_info & SOUND_MASK_PCM)) { 1061184610Salfred 1062184610Salfred DPRINTF("emulating master volume\n"); 1063184610Salfred 1064184610Salfred /* 1065184610Salfred * Emulate missing pcm mixer controller 1066184610Salfred * through FEEDER_VOLUME 1067184610Salfred */ 1068184610Salfred uaudio_pcm_setflags(dev, SD_F_SOFTPCMVOL); 1069184610Salfred } 1070242438Shselasky if (mixer_init(dev, mixer_class, sc)) 1071184610Salfred goto detach; 1072184610Salfred sc->sc_mixer_init = 1; 1073184610Salfred 1074246454Shselasky mixer_hwvol_init(dev); 1075246454Shselasky 1076184610Salfred snprintf(status, sizeof(status), "at ? %s", PCM_KLDSTRING(snd_uaudio)); 1077184610Salfred 1078184610Salfred if (pcm_register(dev, sc, 1079249796Shselasky (sc->sc_play_chan.num_alt > 0) ? 1 : 0, 1080249796Shselasky (sc->sc_rec_chan.num_alt > 0) ? 1 : 0)) { 1081184610Salfred goto detach; 1082184610Salfred } 1083193640Sariff 1084193640Sariff uaudio_pcm_setflags(dev, SD_F_MPSAFE); 1085184610Salfred sc->sc_pcm_registered = 1; 1086184610Salfred 1087249796Shselasky if (sc->sc_play_chan.num_alt > 0) { 1088184610Salfred pcm_addchan(dev, PCMDIR_PLAY, chan_class, sc); 1089184610Salfred } 1090249796Shselasky if (sc->sc_rec_chan.num_alt > 0) { 1091184610Salfred pcm_addchan(dev, PCMDIR_REC, chan_class, sc); 1092184610Salfred } 1093184610Salfred pcm_setstatus(dev, status); 1094184610Salfred 1095242438Shselasky uaudio_mixer_register_sysctl(sc, dev); 1096242438Shselasky 1097184610Salfred return (0); /* success */ 1098184610Salfred 1099184610Salfreddetach: 1100184610Salfred uaudio_detach_sub(dev); 1101184610Salfred return (ENXIO); 1102184610Salfred} 1103184610Salfred 1104184610Salfredint 1105184610Salfreduaudio_detach_sub(device_t dev) 1106184610Salfred{ 1107184610Salfred struct uaudio_softc *sc = device_get_softc(device_get_parent(dev)); 1108184610Salfred int error = 0; 1109184610Salfred 1110184610Salfredrepeat: 1111184610Salfred if (sc->sc_pcm_registered) { 1112184610Salfred error = pcm_unregister(dev); 1113184610Salfred } else { 1114184610Salfred if (sc->sc_mixer_init) { 1115184610Salfred error = mixer_uninit(dev); 1116184610Salfred } 1117184610Salfred } 1118184610Salfred 1119184610Salfred if (error) { 1120184610Salfred device_printf(dev, "Waiting for sound application to exit!\n"); 1121194228Sthompsa usb_pause_mtx(NULL, 2 * hz); 1122184610Salfred goto repeat; /* try again */ 1123184610Salfred } 1124184610Salfred return (0); /* success */ 1125184610Salfred} 1126184610Salfred 1127184610Salfredstatic int 1128184610Salfreduaudio_detach(device_t dev) 1129184610Salfred{ 1130184610Salfred struct uaudio_softc *sc = device_get_softc(dev); 1131184610Salfred 1132228484Shselasky /* 1133228484Shselasky * Stop USB transfers early so that any audio applications 1134228484Shselasky * will time out and close opened /dev/dspX.Y device(s), if 1135228484Shselasky * any. 1136228484Shselasky */ 1137249796Shselasky usb_proc_explore_lock(sc->sc_udev); 1138249796Shselasky sc->sc_play_chan.operation = CHAN_OP_DRAIN; 1139249796Shselasky sc->sc_rec_chan.operation = CHAN_OP_DRAIN; 1140249796Shselasky usb_proc_explore_mwait(sc->sc_udev, 1141249796Shselasky &sc->sc_config_msg[0], &sc->sc_config_msg[1]); 1142249796Shselasky usb_proc_explore_unlock(sc->sc_udev); 1143228484Shselasky 1144249796Shselasky usbd_transfer_unsetup(sc->sc_play_chan.xfer, UAUDIO_NCHANBUFS + 1); 1145249796Shselasky usbd_transfer_unsetup(sc->sc_rec_chan.xfer, UAUDIO_NCHANBUFS + 1); 1146249796Shselasky 1147246421Shselasky uaudio_hid_detach(sc); 1148246421Shselasky 1149228484Shselasky if (bus_generic_detach(dev) != 0) { 1150184610Salfred DPRINTF("detach failed!\n"); 1151184610Salfred } 1152184610Salfred sbuf_delete(&sc->sc_sndstat); 1153184610Salfred sc->sc_sndstat_valid = 0; 1154184610Salfred 1155184610Salfred umidi_detach(dev); 1156184610Salfred 1157242438Shselasky /* free mixer data */ 1158242438Shselasky 1159242438Shselasky uaudio_mixer_ctl_free(sc); 1160242438Shselasky 1161184610Salfred return (0); 1162184610Salfred} 1163184610Salfred 1164249796Shselaskystatic uint32_t 1165249796Shselaskyuaudio_get_buffer_size(struct uaudio_chan *ch, uint8_t alt) 1166249796Shselasky{ 1167249796Shselasky struct uaudio_chan_alt *chan_alt = &ch->usb_alt[alt]; 1168249796Shselasky /* We use 2 times 8ms of buffer */ 1169249796Shselasky uint32_t buf_size = (((chan_alt->sample_rate * (UAUDIO_NFRAMES / 8)) + 1170249796Shselasky 1000 - 1) / 1000) * chan_alt->sample_size; 1171249796Shselasky return (buf_size); 1172249796Shselasky} 1173249796Shselasky 1174249796Shselaskystatic void 1175249796Shselaskyuaudio_configure_msg_sub(struct uaudio_softc *sc, 1176249796Shselasky struct uaudio_chan *chan, int dir) 1177249796Shselasky{ 1178249796Shselasky struct uaudio_chan_alt *chan_alt; 1179249796Shselasky uint32_t frames; 1180249796Shselasky uint32_t buf_size; 1181249796Shselasky uint16_t fps; 1182249796Shselasky uint8_t set_alt; 1183249796Shselasky uint8_t fps_shift; 1184249796Shselasky uint8_t operation; 1185249796Shselasky usb_error_t err; 1186249796Shselasky 1187249796Shselasky if (chan->num_alt <= 0) 1188249796Shselasky return; 1189249796Shselasky 1190249796Shselasky DPRINTF("\n"); 1191249796Shselasky 1192249796Shselasky usb_proc_explore_lock(sc->sc_udev); 1193249796Shselasky operation = chan->operation; 1194249796Shselasky chan->operation = CHAN_OP_NONE; 1195249796Shselasky usb_proc_explore_unlock(sc->sc_udev); 1196249796Shselasky 1197249796Shselasky mtx_lock(chan->pcm_mtx); 1198249796Shselasky if (chan->cur_alt != chan->set_alt) 1199249796Shselasky set_alt = chan->set_alt; 1200249796Shselasky else 1201249796Shselasky set_alt = CHAN_MAX_ALT; 1202249796Shselasky mtx_unlock(chan->pcm_mtx); 1203249796Shselasky 1204249796Shselasky if (set_alt >= chan->num_alt) 1205249796Shselasky goto done; 1206249796Shselasky 1207249796Shselasky chan_alt = chan->usb_alt + set_alt; 1208249796Shselasky 1209249796Shselasky usbd_transfer_unsetup(chan->xfer, UAUDIO_NCHANBUFS + 1); 1210249796Shselasky 1211249796Shselasky err = usbd_set_alt_interface_index(sc->sc_udev, 1212249796Shselasky chan_alt->iface_index, chan_alt->iface_alt_index); 1213249796Shselasky if (err) { 1214249796Shselasky DPRINTF("setting of alternate index failed: %s!\n", 1215249796Shselasky usbd_errstr(err)); 1216249796Shselasky goto error; 1217249796Shselasky } 1218249796Shselasky 1219249796Shselasky /* 1220249796Shselasky * Only set the sample rate if the channel reports that it 1221249796Shselasky * supports the frequency control. 1222249796Shselasky */ 1223249796Shselasky 1224249796Shselasky if (sc->sc_audio_rev >= UAUDIO_VERSION_30) { 1225249796Shselasky /* FALLTHROUGH */ 1226249796Shselasky } else if (sc->sc_audio_rev >= UAUDIO_VERSION_20) { 1227249796Shselasky unsigned int x; 1228249796Shselasky 1229249796Shselasky for (x = 0; x != 256; x++) { 1230249796Shselasky if (dir == PCMDIR_PLAY) { 1231249796Shselasky if (!(sc->sc_mixer_clocks.bit_output[x / 8] & 1232249796Shselasky (1 << (x % 8)))) { 1233249796Shselasky continue; 1234249796Shselasky } 1235249796Shselasky } else { 1236249796Shselasky if (!(sc->sc_mixer_clocks.bit_input[x / 8] & 1237249796Shselasky (1 << (x % 8)))) { 1238249796Shselasky continue; 1239249796Shselasky } 1240249796Shselasky } 1241249796Shselasky 1242249796Shselasky if (uaudio20_set_speed(sc->sc_udev, 1243249796Shselasky sc->sc_mixer_iface_no, x, chan_alt->sample_rate)) { 1244249796Shselasky /* 1245249796Shselasky * If the endpoint is adaptive setting 1246249796Shselasky * the speed may fail. 1247249796Shselasky */ 1248249796Shselasky DPRINTF("setting of sample rate failed! " 1249249796Shselasky "(continuing anyway)\n"); 1250249796Shselasky } 1251249796Shselasky } 1252249796Shselasky } else if (chan_alt->p_sed.v1->bmAttributes & UA_SED_FREQ_CONTROL) { 1253249796Shselasky if (uaudio_set_speed(sc->sc_udev, 1254249796Shselasky chan_alt->p_ed1->bEndpointAddress, chan_alt->sample_rate)) { 1255249796Shselasky /* 1256249796Shselasky * If the endpoint is adaptive setting the 1257249796Shselasky * speed may fail. 1258249796Shselasky */ 1259249796Shselasky DPRINTF("setting of sample rate failed! " 1260249796Shselasky "(continuing anyway)\n"); 1261249796Shselasky } 1262249796Shselasky } 1263249796Shselasky if (usbd_transfer_setup(sc->sc_udev, &chan_alt->iface_index, chan->xfer, 1264249796Shselasky chan_alt->usb_cfg, UAUDIO_NCHANBUFS + 1, chan, chan->pcm_mtx)) { 1265249796Shselasky DPRINTF("could not allocate USB transfers!\n"); 1266249796Shselasky goto error; 1267249796Shselasky } 1268249796Shselasky 1269249796Shselasky fps = usbd_get_isoc_fps(sc->sc_udev); 1270249796Shselasky 1271249796Shselasky if (fps < 8000) { 1272249796Shselasky /* FULL speed USB */ 1273249796Shselasky frames = 8; 1274249796Shselasky } else { 1275249796Shselasky /* HIGH speed USB */ 1276249796Shselasky frames = UAUDIO_NFRAMES; 1277249796Shselasky } 1278249796Shselasky 1279249796Shselasky fps_shift = usbd_xfer_get_fps_shift(chan->xfer[0]); 1280249796Shselasky 1281249796Shselasky /* down shift number of frames per second, if any */ 1282249796Shselasky fps >>= fps_shift; 1283249796Shselasky frames >>= fps_shift; 1284249796Shselasky 1285249796Shselasky /* bytes per frame should not be zero */ 1286249796Shselasky chan->bytes_per_frame[0] = 1287249796Shselasky ((chan_alt->sample_rate / fps) * chan_alt->sample_size); 1288249796Shselasky chan->bytes_per_frame[1] = 1289249796Shselasky (((chan_alt->sample_rate + fps - 1) / fps) * chan_alt->sample_size); 1290249796Shselasky 1291249796Shselasky /* setup data rate dithering, if any */ 1292249796Shselasky chan->frames_per_second = fps; 1293249796Shselasky chan->sample_rem = chan_alt->sample_rate % fps; 1294249796Shselasky chan->sample_curr = 0; 1295249796Shselasky chan->frames_per_second = fps; 1296249796Shselasky 1297249796Shselasky /* compute required buffer size */ 1298249796Shselasky buf_size = (chan->bytes_per_frame[1] * frames); 1299249796Shselasky 1300249796Shselasky if (buf_size > (chan->end - chan->start)) { 1301249796Shselasky DPRINTF("buffer size is too big\n"); 1302249796Shselasky goto error; 1303249796Shselasky } 1304249796Shselasky 1305249796Shselasky chan->intr_frames = frames; 1306249796Shselasky 1307249796Shselasky DPRINTF("fps=%d sample_rem=%d\n", (int)fps, (int)chan->sample_rem); 1308249796Shselasky 1309249796Shselasky if (chan->intr_frames == 0) { 1310249796Shselasky DPRINTF("frame shift is too high!\n"); 1311249796Shselasky goto error; 1312249796Shselasky } 1313249796Shselasky 1314249796Shselasky mtx_lock(chan->pcm_mtx); 1315249796Shselasky chan->cur_alt = set_alt; 1316249796Shselasky mtx_unlock(chan->pcm_mtx); 1317249796Shselasky 1318249796Shselaskydone: 1319249796Shselasky#if (UAUDIO_NCHANBUFS != 2) 1320249796Shselasky#error "please update code" 1321249796Shselasky#endif 1322249796Shselasky switch (operation) { 1323249796Shselasky case CHAN_OP_START: 1324249796Shselasky mtx_lock(chan->pcm_mtx); 1325249796Shselasky usbd_transfer_start(chan->xfer[0]); 1326249796Shselasky usbd_transfer_start(chan->xfer[1]); 1327249796Shselasky mtx_unlock(chan->pcm_mtx); 1328249796Shselasky break; 1329249796Shselasky case CHAN_OP_STOP: 1330249796Shselasky mtx_lock(chan->pcm_mtx); 1331249796Shselasky usbd_transfer_stop(chan->xfer[0]); 1332249796Shselasky usbd_transfer_stop(chan->xfer[1]); 1333249796Shselasky mtx_unlock(chan->pcm_mtx); 1334249796Shselasky break; 1335249796Shselasky default: 1336249796Shselasky break; 1337249796Shselasky } 1338249796Shselasky return; 1339249796Shselasky 1340249796Shselaskyerror: 1341249796Shselasky usbd_transfer_unsetup(chan->xfer, UAUDIO_NCHANBUFS + 1); 1342249796Shselasky 1343249796Shselasky mtx_lock(chan->pcm_mtx); 1344249796Shselasky chan->cur_alt = CHAN_MAX_ALT; 1345249796Shselasky mtx_unlock(chan->pcm_mtx); 1346249796Shselasky} 1347249796Shselasky 1348249796Shselaskystatic void 1349249796Shselaskyuaudio_configure_msg(struct usb_proc_msg *pm) 1350249796Shselasky{ 1351249796Shselasky struct uaudio_softc *sc = ((struct uaudio_configure_msg *)pm)->sc; 1352249796Shselasky 1353249796Shselasky usb_proc_explore_unlock(sc->sc_udev); 1354249796Shselasky uaudio_configure_msg_sub(sc, &sc->sc_play_chan, PCMDIR_PLAY); 1355249796Shselasky uaudio_configure_msg_sub(sc, &sc->sc_rec_chan, PCMDIR_REC); 1356249796Shselasky usb_proc_explore_lock(sc->sc_udev); 1357249796Shselasky} 1358249796Shselasky 1359184610Salfred/*========================================================================* 1360184610Salfred * AS - Audio Stream - routines 1361184610Salfred *========================================================================*/ 1362184610Salfred 1363207077Sthompsa#ifdef USB_DEBUG 1364184610Salfredstatic void 1365203678Sbrucecuaudio_chan_dump_ep_desc(const usb_endpoint_descriptor_audio_t *ed) 1366184610Salfred{ 1367184610Salfred if (ed) { 1368184610Salfred DPRINTF("endpoint=%p bLength=%d bDescriptorType=%d \n" 1369184610Salfred "bEndpointAddress=%d bmAttributes=0x%x \n" 1370184610Salfred "wMaxPacketSize=%d bInterval=%d \n" 1371184610Salfred "bRefresh=%d bSynchAddress=%d\n", 1372184610Salfred ed, ed->bLength, ed->bDescriptorType, 1373184610Salfred ed->bEndpointAddress, ed->bmAttributes, 1374184610Salfred UGETW(ed->wMaxPacketSize), ed->bInterval, 1375209452Sthompsa UEP_HAS_REFRESH(ed) ? ed->bRefresh : 0, 1376209452Sthompsa UEP_HAS_SYNCADDR(ed) ? ed->bSynchAddress : 0); 1377184610Salfred } 1378184610Salfred} 1379184610Salfred 1380184610Salfred#endif 1381184610Salfred 1382221695Shselasky/* 1383221695Shselasky * The following is a workaround for broken no-name USB audio devices 1384221695Shselasky * sold by dealextreme called "3D sound". The problem is that the 1385221695Shselasky * manufacturer computed wMaxPacketSize is too small to hold the 1386221695Shselasky * actual data sent. In other words the device sometimes sends more 1387221695Shselasky * data than it actually reports it can send in a single isochronous 1388221695Shselasky * packet. 1389221695Shselasky */ 1390184610Salfredstatic void 1391221695Shselaskyuaudio_record_fix_fs(usb_endpoint_descriptor_audio_t *ep, 1392221695Shselasky uint32_t xps, uint32_t add) 1393221695Shselasky{ 1394221695Shselasky uint32_t mps; 1395221695Shselasky 1396221695Shselasky mps = UGETW(ep->wMaxPacketSize); 1397221695Shselasky 1398221695Shselasky /* 1399221695Shselasky * If the device indicates it can send more data than what the 1400221695Shselasky * sample rate indicates, we apply the workaround. 1401221695Shselasky */ 1402221695Shselasky if (mps > xps) { 1403221695Shselasky 1404221695Shselasky /* allow additional data */ 1405221695Shselasky xps += add; 1406221695Shselasky 1407221695Shselasky /* check against the maximum USB 1.x length */ 1408221695Shselasky if (xps > 1023) 1409221695Shselasky xps = 1023; 1410221695Shselasky 1411221695Shselasky /* check if we should do an update */ 1412221695Shselasky if (mps < xps) { 1413221695Shselasky /* simply update the wMaxPacketSize field */ 1414221695Shselasky USETW(ep->wMaxPacketSize, xps); 1415221695Shselasky DPRINTF("Workaround: Updated wMaxPacketSize " 1416221695Shselasky "from %d to %d bytes.\n", 1417221695Shselasky (int)mps, (int)xps); 1418221695Shselasky } 1419221695Shselasky } 1420221695Shselasky} 1421221695Shselasky 1422240609Shselaskystatic usb_error_t 1423240609Shselaskyuaudio20_check_rate(struct usb_device *udev, uint8_t iface_no, 1424240609Shselasky uint8_t clockid, uint32_t rate) 1425240609Shselasky{ 1426240609Shselasky struct usb_device_request req; 1427240609Shselasky usb_error_t error; 1428240609Shselasky uint8_t data[255]; 1429240609Shselasky uint16_t actlen; 1430240609Shselasky uint16_t rates; 1431240609Shselasky uint16_t x; 1432240609Shselasky 1433240609Shselasky DPRINTFN(6, "ifaceno=%d clockid=%d rate=%u\n", 1434240609Shselasky iface_no, clockid, rate); 1435240609Shselasky 1436240609Shselasky req.bmRequestType = UT_READ_CLASS_INTERFACE; 1437240609Shselasky req.bRequest = UA20_CS_RANGE; 1438240609Shselasky USETW2(req.wValue, UA20_CS_SAM_FREQ_CONTROL, 0); 1439240609Shselasky USETW2(req.wIndex, clockid, iface_no); 1440240609Shselasky USETW(req.wLength, 255); 1441240609Shselasky 1442240609Shselasky error = usbd_do_request_flags(udev, NULL, &req, data, 1443240609Shselasky USB_SHORT_XFER_OK, &actlen, USB_DEFAULT_TIMEOUT); 1444240609Shselasky 1445240609Shselasky if (error != 0 || actlen < 2) 1446240609Shselasky return (USB_ERR_INVAL); 1447240609Shselasky 1448240609Shselasky rates = data[0] | (data[1] << 8); 1449240609Shselasky actlen = (actlen - 2) / 12; 1450240609Shselasky 1451240609Shselasky if (rates > actlen) { 1452240609Shselasky DPRINTF("Too many rates\n"); 1453240609Shselasky rates = actlen; 1454240609Shselasky } 1455240609Shselasky 1456240609Shselasky for (x = 0; x != rates; x++) { 1457240609Shselasky uint32_t min = UGETDW(data + 2 + (12 * x)); 1458240609Shselasky uint32_t max = UGETDW(data + 6 + (12 * x)); 1459240609Shselasky uint32_t res = UGETDW(data + 10 + (12 * x)); 1460240609Shselasky 1461240609Shselasky if (res == 0) { 1462240609Shselasky DPRINTF("Zero residue\n"); 1463240609Shselasky res = 1; 1464240609Shselasky } 1465240609Shselasky 1466240609Shselasky if (min > max) { 1467240609Shselasky DPRINTF("Swapped max and min\n"); 1468240609Shselasky uint32_t temp; 1469240609Shselasky temp = min; 1470240609Shselasky min = max; 1471240609Shselasky max = temp; 1472240609Shselasky } 1473240609Shselasky 1474240609Shselasky if (rate >= min && rate <= max && 1475240609Shselasky (((rate - min) % res) == 0)) { 1476240609Shselasky return (0); 1477240609Shselasky } 1478240609Shselasky } 1479240609Shselasky return (USB_ERR_INVAL); 1480240609Shselasky} 1481240609Shselasky 1482221695Shselaskystatic void 1483192984Sthompsauaudio_chan_fill_info_sub(struct uaudio_softc *sc, struct usb_device *udev, 1484200825Sthompsa uint32_t rate, uint8_t channels, uint8_t bit_resolution) 1485184610Salfred{ 1486192984Sthompsa struct usb_descriptor *desc = NULL; 1487240609Shselasky union uaudio_asid asid = { NULL }; 1488240609Shselasky union uaudio_asf1d asf1d = { NULL }; 1489240609Shselasky union uaudio_sed sed = { NULL }; 1490272423Shselasky struct usb_midi_streaming_endpoint_descriptor *msid = NULL; 1491221695Shselasky usb_endpoint_descriptor_audio_t *ed1 = NULL; 1492240609Shselasky const struct usb_audio_control_descriptor *acdp = NULL; 1493194228Sthompsa struct usb_config_descriptor *cd = usbd_get_config_descriptor(udev); 1494192984Sthompsa struct usb_interface_descriptor *id; 1495240609Shselasky const struct uaudio_format *p_fmt = NULL; 1496184610Salfred struct uaudio_chan *chan; 1497249796Shselasky struct uaudio_chan_alt *chan_alt; 1498249796Shselasky uint32_t format; 1499184610Salfred uint16_t curidx = 0xFFFF; 1500184610Salfred uint16_t lastidx = 0xFFFF; 1501184610Salfred uint16_t alt_index = 0; 1502240609Shselasky uint16_t audio_rev = 0; 1503240609Shselasky uint16_t x; 1504184610Salfred uint8_t ep_dir; 1505184610Salfred uint8_t bChannels; 1506184610Salfred uint8_t bBitResolution; 1507184610Salfred uint8_t audio_if = 0; 1508272423Shselasky uint8_t midi_if = 0; 1509218988Shselasky uint8_t uma_if_class; 1510184610Salfred 1511194228Sthompsa while ((desc = usb_desc_foreach(cd, desc))) { 1512184610Salfred 1513184610Salfred if ((desc->bDescriptorType == UDESC_INTERFACE) && 1514184610Salfred (desc->bLength >= sizeof(*id))) { 1515184610Salfred 1516184610Salfred id = (void *)desc; 1517184610Salfred 1518184610Salfred if (id->bInterfaceNumber != lastidx) { 1519184610Salfred lastidx = id->bInterfaceNumber; 1520184610Salfred curidx++; 1521184610Salfred alt_index = 0; 1522184610Salfred 1523184610Salfred } else { 1524184610Salfred alt_index++; 1525184610Salfred } 1526184610Salfred 1527246421Shselasky if ((!(sc->sc_hid.flags & UAUDIO_HID_VALID)) && 1528246421Shselasky (id->bInterfaceClass == UICLASS_HID) && 1529246421Shselasky (id->bInterfaceSubClass == 0) && 1530246421Shselasky (id->bInterfaceProtocol == 0) && 1531246421Shselasky (alt_index == 0) && 1532246421Shselasky usbd_get_iface(udev, curidx) != NULL) { 1533246421Shselasky DPRINTF("Found HID interface at %d\n", 1534246421Shselasky curidx); 1535246421Shselasky sc->sc_hid.flags |= UAUDIO_HID_VALID; 1536246421Shselasky sc->sc_hid.iface_index = curidx; 1537246421Shselasky } 1538246421Shselasky 1539218988Shselasky uma_if_class = 1540218988Shselasky ((id->bInterfaceClass == UICLASS_AUDIO) || 1541218988Shselasky ((id->bInterfaceClass == UICLASS_VENDOR) && 1542218988Shselasky (sc->sc_uq_au_vendor_class != 0))); 1543218988Shselasky 1544272423Shselasky if ((uma_if_class != 0) && 1545272423Shselasky (id->bInterfaceSubClass == UISUBCLASS_AUDIOSTREAM)) { 1546184610Salfred audio_if = 1; 1547184610Salfred } else { 1548184610Salfred audio_if = 0; 1549184610Salfred } 1550184610Salfred 1551218988Shselasky if ((uma_if_class != 0) && 1552184610Salfred (id->bInterfaceSubClass == UISUBCLASS_MIDISTREAM)) { 1553184610Salfred 1554184610Salfred /* 1555184610Salfred * XXX could allow multiple MIDI interfaces 1556184610Salfred */ 1557272423Shselasky midi_if = 1; 1558184610Salfred 1559184610Salfred if ((sc->sc_midi_chan.valid == 0) && 1560272423Shselasky (usbd_get_iface(udev, curidx) != NULL)) { 1561184610Salfred sc->sc_midi_chan.iface_index = curidx; 1562184610Salfred sc->sc_midi_chan.iface_alt_index = alt_index; 1563184610Salfred sc->sc_midi_chan.valid = 1; 1564184610Salfred } 1565272423Shselasky } else { 1566272423Shselasky midi_if = 0; 1567184610Salfred } 1568240609Shselasky asid.v1 = NULL; 1569240609Shselasky asf1d.v1 = NULL; 1570184610Salfred ed1 = NULL; 1571240609Shselasky sed.v1 = NULL; 1572184610Salfred } 1573240609Shselasky 1574241988Shselasky if (audio_if == 0) { 1575272423Shselasky if (midi_if == 0) { 1576272423Shselasky if ((acdp == NULL) && 1577272423Shselasky (desc->bDescriptorType == UDESC_CS_INTERFACE) && 1578272423Shselasky (desc->bDescriptorSubtype == UDESCSUB_AC_HEADER) && 1579272423Shselasky (desc->bLength >= sizeof(*acdp))) { 1580272423Shselasky acdp = (void *)desc; 1581272423Shselasky audio_rev = UGETW(acdp->bcdADC); 1582272423Shselasky } 1583272423Shselasky } else { 1584272423Shselasky msid = (void *)desc; 1585272423Shselasky 1586272423Shselasky /* get the maximum number of embedded jacks in use, if any */ 1587272423Shselasky if (msid->bLength >= sizeof(*msid) && 1588272423Shselasky msid->bDescriptorType == UDESC_CS_ENDPOINT && 1589272423Shselasky msid->bDescriptorSubtype == MS_GENERAL && 1590272423Shselasky msid->bNumEmbMIDIJack > sc->sc_midi_chan.max_emb_jack) { 1591272423Shselasky sc->sc_midi_chan.max_emb_jack = msid->bNumEmbMIDIJack; 1592272423Shselasky } 1593241988Shselasky } 1594241988Shselasky /* 1595241988Shselasky * Don't collect any USB audio descriptors if 1596241988Shselasky * this is not an USB audio stream interface. 1597241988Shselasky */ 1598241988Shselasky continue; 1599240609Shselasky } 1600240609Shselasky 1601240609Shselasky if ((acdp != NULL) && 1602240609Shselasky (desc->bDescriptorType == UDESC_CS_INTERFACE) && 1603240609Shselasky (desc->bDescriptorSubtype == AS_GENERAL) && 1604240609Shselasky (asid.v1 == NULL)) { 1605240609Shselasky if (audio_rev >= UAUDIO_VERSION_30) { 1606240609Shselasky /* FALLTHROUGH */ 1607240609Shselasky } else if (audio_rev >= UAUDIO_VERSION_20) { 1608240609Shselasky if (desc->bLength >= sizeof(*asid.v2)) { 1609240609Shselasky asid.v2 = (void *)desc; 1610240609Shselasky } 1611240609Shselasky } else { 1612240609Shselasky if (desc->bLength >= sizeof(*asid.v1)) { 1613240609Shselasky asid.v1 = (void *)desc; 1614240609Shselasky } 1615184610Salfred } 1616184610Salfred } 1617240609Shselasky if ((acdp != NULL) && 1618240609Shselasky (desc->bDescriptorType == UDESC_CS_INTERFACE) && 1619184610Salfred (desc->bDescriptorSubtype == FORMAT_TYPE) && 1620240609Shselasky (asf1d.v1 == NULL)) { 1621240609Shselasky if (audio_rev >= UAUDIO_VERSION_30) { 1622240609Shselasky /* FALLTHROUGH */ 1623240609Shselasky } else if (audio_rev >= UAUDIO_VERSION_20) { 1624240609Shselasky if (desc->bLength >= sizeof(*asf1d.v2)) 1625240609Shselasky asf1d.v2 = (void *)desc; 1626240609Shselasky } else { 1627240609Shselasky if (desc->bLength >= sizeof(*asf1d.v1)) { 1628240609Shselasky asf1d.v1 = (void *)desc; 1629240609Shselasky 1630240609Shselasky if (asf1d.v1->bFormatType != FORMAT_TYPE_I) { 1631240609Shselasky DPRINTFN(11, "ignored bFormatType = %d\n", 1632240609Shselasky asf1d.v1->bFormatType); 1633240609Shselasky asf1d.v1 = NULL; 1634240609Shselasky continue; 1635240609Shselasky } 1636240609Shselasky if (desc->bLength < (sizeof(*asf1d.v1) + 1637240609Shselasky ((asf1d.v1->bSamFreqType == 0) ? 6 : 1638240609Shselasky (asf1d.v1->bSamFreqType * 3)))) { 1639240609Shselasky DPRINTFN(11, "invalid descriptor, " 1640240609Shselasky "too short\n"); 1641240609Shselasky asf1d.v1 = NULL; 1642240609Shselasky continue; 1643240609Shselasky } 1644184610Salfred } 1645184610Salfred } 1646184610Salfred } 1647184610Salfred if ((desc->bDescriptorType == UDESC_ENDPOINT) && 1648240609Shselasky (desc->bLength >= UEP_MINSIZE) && 1649240609Shselasky (ed1 == NULL)) { 1650240609Shselasky ed1 = (void *)desc; 1651240609Shselasky if (UE_GET_XFERTYPE(ed1->bmAttributes) != UE_ISOCHRONOUS) { 1652240609Shselasky ed1 = NULL; 1653240609Shselasky continue; 1654184610Salfred } 1655184610Salfred } 1656240609Shselasky if ((acdp != NULL) && 1657240609Shselasky (desc->bDescriptorType == UDESC_CS_ENDPOINT) && 1658184610Salfred (desc->bDescriptorSubtype == AS_GENERAL) && 1659240609Shselasky (sed.v1 == NULL)) { 1660240609Shselasky if (audio_rev >= UAUDIO_VERSION_30) { 1661240609Shselasky /* FALLTHROUGH */ 1662240609Shselasky } else if (audio_rev >= UAUDIO_VERSION_20) { 1663240609Shselasky if (desc->bLength >= sizeof(*sed.v2)) 1664240609Shselasky sed.v2 = (void *)desc; 1665240609Shselasky } else { 1666240609Shselasky if (desc->bLength >= sizeof(*sed.v1)) 1667240609Shselasky sed.v1 = (void *)desc; 1668184610Salfred } 1669184610Salfred } 1670241988Shselasky if (asid.v1 == NULL || asf1d.v1 == NULL || 1671241988Shselasky ed1 == NULL || sed.v1 == NULL) { 1672240609Shselasky /* need more descriptors */ 1673240609Shselasky continue; 1674240609Shselasky } 1675184610Salfred 1676240609Shselasky ep_dir = UE_GET_DIR(ed1->bEndpointAddress); 1677184610Salfred 1678240609Shselasky /* We ignore sync endpoint information until further. */ 1679184610Salfred 1680240609Shselasky if (audio_rev >= UAUDIO_VERSION_30) { 1681240609Shselasky goto next_ep; 1682240609Shselasky } else if (audio_rev >= UAUDIO_VERSION_20) { 1683184610Salfred 1684240609Shselasky uint32_t dwFormat; 1685240609Shselasky 1686240609Shselasky dwFormat = UGETDW(asid.v2->bmFormats); 1687240609Shselasky bChannels = asid.v2->bNrChannels; 1688270717Shselasky bBitResolution = asf1d.v2->bSubslotSize * 8; 1689240609Shselasky 1690240609Shselasky if ((bChannels != channels) || 1691240609Shselasky (bBitResolution != bit_resolution)) { 1692240609Shselasky DPRINTF("Wrong number of channels\n"); 1693240609Shselasky goto next_ep; 1694240609Shselasky } 1695240609Shselasky 1696240609Shselasky for (p_fmt = uaudio20_formats; 1697240609Shselasky p_fmt->wFormat != 0; p_fmt++) { 1698240609Shselasky if ((p_fmt->wFormat & dwFormat) && 1699240609Shselasky (p_fmt->bPrecision == bBitResolution)) 1700240609Shselasky break; 1701240609Shselasky } 1702240609Shselasky 1703240609Shselasky if (p_fmt->wFormat == 0) { 1704240609Shselasky DPRINTF("Unsupported audio format\n"); 1705240609Shselasky goto next_ep; 1706240609Shselasky } 1707240609Shselasky 1708240609Shselasky for (x = 0; x != 256; x++) { 1709240609Shselasky if (ep_dir == UE_DIR_OUT) { 1710240609Shselasky if (!(sc->sc_mixer_clocks.bit_output[x / 8] & 1711240609Shselasky (1 << (x % 8)))) { 1712240609Shselasky continue; 1713240609Shselasky } 1714240609Shselasky } else { 1715240609Shselasky if (!(sc->sc_mixer_clocks.bit_input[x / 8] & 1716240609Shselasky (1 << (x % 8)))) { 1717240609Shselasky continue; 1718240609Shselasky } 1719240609Shselasky } 1720240609Shselasky 1721240609Shselasky DPRINTF("Checking clock ID=%d\n", x); 1722240609Shselasky 1723240609Shselasky if (uaudio20_check_rate(udev, 1724240609Shselasky sc->sc_mixer_iface_no, x, rate)) { 1725240609Shselasky DPRINTF("Unsupported sampling " 1726240609Shselasky "rate, id=%d\n", x); 1727240609Shselasky goto next_ep; 1728240609Shselasky } 1729240609Shselasky } 1730240609Shselasky } else { 1731240609Shselasky uint16_t wFormat; 1732240609Shselasky 1733240609Shselasky wFormat = UGETW(asid.v1->wFormatTag); 1734240609Shselasky bChannels = UAUDIO_MAX_CHAN(asf1d.v1->bNrChannels); 1735270717Shselasky bBitResolution = asf1d.v1->bSubFrameSize * 8; 1736240609Shselasky 1737240609Shselasky if (asf1d.v1->bSamFreqType == 0) { 1738184610Salfred DPRINTFN(16, "Sample rate: %d-%dHz\n", 1739240609Shselasky UA_SAMP_LO(asf1d.v1), 1740240609Shselasky UA_SAMP_HI(asf1d.v1)); 1741184610Salfred 1742240609Shselasky if ((rate >= UA_SAMP_LO(asf1d.v1)) && 1743240609Shselasky (rate <= UA_SAMP_HI(asf1d.v1))) 1744184610Salfred goto found_rate; 1745184610Salfred } else { 1746184610Salfred 1747240609Shselasky for (x = 0; x < asf1d.v1->bSamFreqType; x++) { 1748184610Salfred DPRINTFN(16, "Sample rate = %dHz\n", 1749240609Shselasky UA_GETSAMP(asf1d.v1, x)); 1750184610Salfred 1751240609Shselasky if (rate == UA_GETSAMP(asf1d.v1, x)) 1752184610Salfred goto found_rate; 1753184610Salfred } 1754184610Salfred } 1755240609Shselasky goto next_ep; 1756184610Salfred 1757184610Salfred found_rate: 1758240609Shselasky for (p_fmt = uaudio10_formats; 1759240609Shselasky p_fmt->wFormat != 0; p_fmt++) { 1760184610Salfred if ((p_fmt->wFormat == wFormat) && 1761240609Shselasky (p_fmt->bPrecision == bBitResolution)) 1762240609Shselasky break; 1763184610Salfred } 1764240609Shselasky if (p_fmt->wFormat == 0) { 1765240609Shselasky DPRINTF("Unsupported audio format\n"); 1766240609Shselasky goto next_ep; 1767240609Shselasky } 1768184610Salfred 1769240609Shselasky if ((bChannels != channels) || 1770240609Shselasky (bBitResolution != bit_resolution)) { 1771240609Shselasky DPRINTF("Wrong number of channels\n"); 1772240609Shselasky goto next_ep; 1773240609Shselasky } 1774240609Shselasky } 1775184610Salfred 1776240609Shselasky chan = (ep_dir == UE_DIR_IN) ? 1777240609Shselasky &sc->sc_rec_chan : &sc->sc_play_chan; 1778184610Salfred 1779249796Shselasky if (usbd_get_iface(udev, curidx) == NULL) { 1780249796Shselasky DPRINTF("Interface is not valid\n"); 1781240609Shselasky goto next_ep; 1782240609Shselasky } 1783249796Shselasky if (chan->num_alt == CHAN_MAX_ALT) { 1784249796Shselasky DPRINTF("Too many alternate settings\n"); 1785249796Shselasky goto next_ep; 1786249796Shselasky } 1787249796Shselasky chan->set_alt = 0; 1788249796Shselasky chan->cur_alt = CHAN_MAX_ALT; 1789184610Salfred 1790249796Shselasky chan_alt = &chan->usb_alt[chan->num_alt++]; 1791249796Shselasky 1792207077Sthompsa#ifdef USB_DEBUG 1793240609Shselasky uaudio_chan_dump_ep_desc(ed1); 1794184610Salfred#endif 1795240609Shselasky DPRINTF("Sample rate = %dHz, channels = %d, " 1796240609Shselasky "bits = %d, format = %s\n", rate, channels, 1797240609Shselasky bit_resolution, p_fmt->description); 1798184610Salfred 1799249796Shselasky chan_alt->sample_rate = rate; 1800249796Shselasky chan_alt->p_asf1d = asf1d; 1801249796Shselasky chan_alt->p_ed1 = ed1; 1802249796Shselasky chan_alt->p_fmt = p_fmt; 1803249796Shselasky chan_alt->p_sed = sed; 1804249796Shselasky chan_alt->iface_index = curidx; 1805249796Shselasky chan_alt->iface_alt_index = alt_index; 1806184610Salfred 1807249796Shselasky usbd_set_parent_iface(sc->sc_udev, curidx, 1808249796Shselasky sc->sc_mixer_iface_index); 1809249796Shselasky 1810240609Shselasky if (ep_dir == UE_DIR_IN) 1811249796Shselasky chan_alt->usb_cfg = uaudio_cfg_record; 1812240609Shselasky else 1813249796Shselasky chan_alt->usb_cfg = uaudio_cfg_play; 1814184610Salfred 1815249796Shselasky chan_alt->sample_size = (UAUDIO_MAX_CHAN(channels) * 1816240609Shselasky p_fmt->bPrecision) / 8; 1817249796Shselasky chan_alt->channels = channels; 1818184610Salfred 1819240609Shselasky if (ep_dir == UE_DIR_IN && 1820240609Shselasky usbd_get_speed(udev) == USB_SPEED_FULL) { 1821240609Shselasky uaudio_record_fix_fs(ed1, 1822249796Shselasky chan_alt->sample_size * (rate / 1000), 1823249796Shselasky chan_alt->sample_size * (rate / 4000)); 1824240609Shselasky } 1825221695Shselasky 1826249796Shselasky /* setup play/record format */ 1827249796Shselasky 1828249796Shselasky format = chan_alt->p_fmt->freebsd_fmt; 1829249796Shselasky 1830249796Shselasky switch (chan_alt->channels) { 1831249796Shselasky case 2: 1832249796Shselasky /* stereo */ 1833249796Shselasky format = SND_FORMAT(format, 2, 0); 1834249796Shselasky break; 1835249796Shselasky case 1: 1836249796Shselasky /* mono */ 1837249796Shselasky format = SND_FORMAT(format, 1, 0); 1838249796Shselasky break; 1839249796Shselasky default: 1840249796Shselasky /* surround and more */ 1841249796Shselasky format = feeder_matrix_default_format( 1842249796Shselasky SND_FORMAT(format, chan_alt->channels, 0)); 1843249796Shselasky break; 1844249796Shselasky } 1845249796Shselasky 1846249796Shselasky /* check if format is not supported */ 1847249796Shselasky if (format == 0) { 1848249796Shselasky DPRINTF("The selected audio format is not supported\n"); 1849249796Shselasky chan->num_alt--; 1850249796Shselasky goto next_ep; 1851249796Shselasky } 1852249845Shselasky if (chan->num_alt > 1) { 1853249845Shselasky /* we only accumulate one format at different sample rates */ 1854249845Shselasky if (chan->pcm_format[0] != format) { 1855249845Shselasky DPRINTF("Multiple formats is not supported\n"); 1856249845Shselasky chan->num_alt--; 1857249845Shselasky goto next_ep; 1858249845Shselasky } 1859249845Shselasky /* ignore if duplicate sample rate entry */ 1860249845Shselasky if (rate == chan->usb_alt[chan->num_alt - 2].sample_rate) { 1861249845Shselasky DPRINTF("Duplicate sample rate detected\n"); 1862249845Shselasky chan->num_alt--; 1863249845Shselasky goto next_ep; 1864249845Shselasky } 1865249796Shselasky } 1866249796Shselasky chan->pcm_cap.fmtlist = chan->pcm_format; 1867249796Shselasky chan->pcm_cap.fmtlist[0] = format; 1868249796Shselasky 1869249796Shselasky if (rate < chan->pcm_cap.minspeed || chan->pcm_cap.minspeed == 0) 1870249796Shselasky chan->pcm_cap.minspeed = rate; 1871249796Shselasky if (rate > chan->pcm_cap.maxspeed || chan->pcm_cap.maxspeed == 0) 1872249796Shselasky chan->pcm_cap.maxspeed = rate; 1873249796Shselasky 1874240609Shselasky if (sc->sc_sndstat_valid != 0) { 1875240609Shselasky sbuf_printf(&sc->sc_sndstat, "\n\t" 1876240609Shselasky "mode %d.%d:(%s) %dch, %dbit, %s, %dHz", 1877240609Shselasky curidx, alt_index, 1878240609Shselasky (ep_dir == UE_DIR_IN) ? "input" : "output", 1879240609Shselasky channels, p_fmt->bPrecision, 1880240609Shselasky p_fmt->description, rate); 1881184610Salfred } 1882240609Shselasky 1883240609Shselasky next_ep: 1884240609Shselasky sed.v1 = NULL; 1885240609Shselasky ed1 = NULL; 1886184610Salfred } 1887184610Salfred} 1888184610Salfred 1889200825Sthompsa/* This structure defines all the supported rates. */ 1890200825Sthompsa 1891249796Shselaskystatic const uint32_t uaudio_rate_list[CHAN_MAX_ALT] = { 1892263642Shselasky 384000, 1893263642Shselasky 352800, 1894263642Shselasky 192000, 1895263642Shselasky 176400, 1896200825Sthompsa 96000, 1897249796Shselasky 88200, 1898200825Sthompsa 88000, 1899200825Sthompsa 80000, 1900200825Sthompsa 72000, 1901200825Sthompsa 64000, 1902200825Sthompsa 56000, 1903200825Sthompsa 48000, 1904200825Sthompsa 44100, 1905200825Sthompsa 40000, 1906200825Sthompsa 32000, 1907200825Sthompsa 24000, 1908200825Sthompsa 22050, 1909200825Sthompsa 16000, 1910200825Sthompsa 11025, 1911200825Sthompsa 8000, 1912200825Sthompsa 0 1913200825Sthompsa}; 1914200825Sthompsa 1915184610Salfredstatic void 1916192984Sthompsauaudio_chan_fill_info(struct uaudio_softc *sc, struct usb_device *udev) 1917184610Salfred{ 1918184610Salfred uint32_t rate = uaudio_default_rate; 1919200825Sthompsa uint8_t z; 1920184610Salfred uint8_t bits = uaudio_default_bits; 1921184610Salfred uint8_t y; 1922184610Salfred uint8_t channels = uaudio_default_channels; 1923184610Salfred uint8_t x; 1924184610Salfred 1925184610Salfred bits -= (bits % 8); 1926186730Salfred if ((bits == 0) || (bits > 32)) { 1927186730Salfred /* set a valid value */ 1928186730Salfred bits = 32; 1929186730Salfred } 1930200825Sthompsa if (channels == 0) { 1931200825Sthompsa switch (usbd_get_speed(udev)) { 1932200825Sthompsa case USB_SPEED_LOW: 1933200825Sthompsa case USB_SPEED_FULL: 1934200825Sthompsa /* 1935200825Sthompsa * Due to high bandwidth usage and problems 1936200825Sthompsa * with HIGH-speed split transactions we 1937200825Sthompsa * disable surround setups on FULL-speed USB 1938200825Sthompsa * by default 1939200825Sthompsa */ 1940241988Shselasky channels = 4; 1941200825Sthompsa break; 1942200825Sthompsa default: 1943200825Sthompsa channels = 16; 1944200825Sthompsa break; 1945200825Sthompsa } 1946200825Sthompsa } else if (channels > 16) { 1947200825Sthompsa channels = 16; 1948186730Salfred } 1949184610Salfred if (sbuf_new(&sc->sc_sndstat, NULL, 4096, SBUF_AUTOEXTEND)) { 1950184610Salfred sc->sc_sndstat_valid = 1; 1951184610Salfred } 1952184610Salfred /* try to search for a valid config */ 1953184610Salfred 1954184610Salfred for (x = channels; x; x--) { 1955184610Salfred for (y = bits; y; y -= 8) { 1956184610Salfred 1957200825Sthompsa /* try user defined rate, if any */ 1958200825Sthompsa if (rate != 0) 1959200825Sthompsa uaudio_chan_fill_info_sub(sc, udev, rate, x, y); 1960200825Sthompsa 1961200825Sthompsa /* try find a matching rate, if any */ 1962249796Shselasky for (z = 0; uaudio_rate_list[z]; z++) 1963200825Sthompsa uaudio_chan_fill_info_sub(sc, udev, uaudio_rate_list[z], x, y); 1964184610Salfred } 1965184610Salfred } 1966249796Shselasky if (sc->sc_sndstat_valid) 1967184610Salfred sbuf_finish(&sc->sc_sndstat); 1968184610Salfred} 1969184610Salfred 1970184610Salfredstatic void 1971242223Shselaskyuaudio_chan_play_sync_callback(struct usb_xfer *xfer, usb_error_t error) 1972242223Shselasky{ 1973242223Shselasky struct uaudio_chan *ch = usbd_xfer_softc(xfer); 1974242223Shselasky struct usb_page_cache *pc; 1975249796Shselasky uint64_t sample_rate = ch->usb_alt[ch->cur_alt].sample_rate; 1976242223Shselasky uint8_t buf[4]; 1977242223Shselasky uint64_t temp; 1978242223Shselasky int len; 1979242223Shselasky int actlen; 1980242223Shselasky int nframes; 1981242223Shselasky 1982242223Shselasky usbd_xfer_status(xfer, &actlen, NULL, NULL, &nframes); 1983242223Shselasky 1984242223Shselasky switch (USB_GET_STATE(xfer)) { 1985242223Shselasky case USB_ST_TRANSFERRED: 1986242223Shselasky 1987242223Shselasky DPRINTFN(6, "transferred %d bytes\n", actlen); 1988242223Shselasky 1989242223Shselasky if (nframes == 0) 1990242223Shselasky break; 1991242223Shselasky len = usbd_xfer_frame_len(xfer, 0); 1992242223Shselasky if (len == 0) 1993242223Shselasky break; 1994242223Shselasky if (len > sizeof(buf)) 1995242223Shselasky len = sizeof(buf); 1996242223Shselasky 1997242223Shselasky memset(buf, 0, sizeof(buf)); 1998242223Shselasky 1999242223Shselasky pc = usbd_xfer_get_frame(xfer, 0); 2000242223Shselasky usbd_copy_out(pc, 0, buf, len); 2001242223Shselasky 2002242223Shselasky temp = UGETDW(buf); 2003242223Shselasky 2004242223Shselasky DPRINTF("Value = 0x%08x\n", (int)temp); 2005242223Shselasky 2006242223Shselasky /* auto-detect SYNC format */ 2007242223Shselasky 2008242223Shselasky if (len == 4) 2009242223Shselasky temp &= 0x0fffffff; 2010242223Shselasky 2011242223Shselasky /* check for no data */ 2012242223Shselasky 2013242223Shselasky if (temp == 0) 2014242223Shselasky break; 2015242223Shselasky 2016242223Shselasky /* correctly scale value */ 2017242223Shselasky 2018242223Shselasky temp = (temp * 125ULL) - 64; 2019242223Shselasky 2020242223Shselasky /* auto adjust */ 2021242223Shselasky 2022249796Shselasky while (temp < (sample_rate - (sample_rate / 4))) 2023242223Shselasky temp *= 2; 2024242223Shselasky 2025249796Shselasky while (temp > (sample_rate + (sample_rate / 2))) 2026242223Shselasky temp /= 2; 2027242223Shselasky 2028242223Shselasky /* compare */ 2029242223Shselasky 2030242223Shselasky DPRINTF("Comparing %d < %d\n", 2031249796Shselasky (int)temp, (int)sample_rate); 2032242223Shselasky 2033249796Shselasky if (temp == sample_rate) 2034242223Shselasky ch->last_sync_state = UAUDIO_SYNC_NONE; 2035249796Shselasky else if (temp > sample_rate) 2036242223Shselasky ch->last_sync_state = UAUDIO_SYNC_MORE; 2037242223Shselasky else 2038242223Shselasky ch->last_sync_state = UAUDIO_SYNC_LESS; 2039242223Shselasky break; 2040242223Shselasky 2041242223Shselasky case USB_ST_SETUP: 2042242223Shselasky usbd_xfer_set_frames(xfer, 1); 2043242223Shselasky usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_framelen(xfer)); 2044242223Shselasky usbd_transfer_submit(xfer); 2045242223Shselasky break; 2046242223Shselasky 2047242223Shselasky default: /* Error */ 2048242223Shselasky break; 2049242223Shselasky } 2050242223Shselasky} 2051242223Shselasky 2052242223Shselaskystatic void 2053194677Sthompsauaudio_chan_play_callback(struct usb_xfer *xfer, usb_error_t error) 2054184610Salfred{ 2055194677Sthompsa struct uaudio_chan *ch = usbd_xfer_softc(xfer); 2056194677Sthompsa struct usb_page_cache *pc; 2057249796Shselasky uint32_t sample_size = ch->usb_alt[ch->cur_alt].sample_size; 2058242223Shselasky uint32_t mfl; 2059186730Salfred uint32_t total; 2060184610Salfred uint32_t blockcount; 2061184610Salfred uint32_t n; 2062184610Salfred uint32_t offset; 2063200825Sthompsa int actlen; 2064200825Sthompsa int sumlen; 2065184610Salfred 2066194677Sthompsa usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 2067194677Sthompsa 2068199060Sthompsa if (ch->end == ch->start) { 2069199060Sthompsa DPRINTF("no buffer!\n"); 2070199060Sthompsa return; 2071199060Sthompsa } 2072199060Sthompsa 2073184610Salfred switch (USB_GET_STATE(xfer)) { 2074184610Salfred case USB_ST_TRANSFERRED: 2075184610Salfredtr_transferred: 2076194677Sthompsa if (actlen < sumlen) { 2077184610Salfred DPRINTF("short transfer, " 2078200825Sthompsa "%d of %d bytes\n", actlen, sumlen); 2079184610Salfred } 2080184610Salfred chn_intr(ch->pcm_ch); 2081184610Salfred 2082242223Shselasky /* start SYNC transfer, if any */ 2083242223Shselasky if ((ch->last_sync_time++ & 7) == 0) 2084242223Shselasky usbd_transfer_start(ch->xfer[UAUDIO_NCHANBUFS]); 2085242223Shselasky 2086184610Salfred case USB_ST_SETUP: 2087242223Shselasky mfl = usbd_xfer_max_framelen(xfer); 2088242223Shselasky 2089242223Shselasky if (ch->bytes_per_frame[1] > mfl) { 2090184610Salfred DPRINTF("bytes per transfer, %d, " 2091184610Salfred "exceeds maximum, %d!\n", 2092200825Sthompsa ch->bytes_per_frame[1], 2093242223Shselasky mfl); 2094184610Salfred break; 2095184610Salfred } 2096200825Sthompsa 2097200825Sthompsa blockcount = ch->intr_frames; 2098200825Sthompsa 2099200825Sthompsa /* setup number of frames */ 2100194677Sthompsa usbd_xfer_set_frames(xfer, blockcount); 2101184610Salfred 2102200825Sthompsa /* reset total length */ 2103200825Sthompsa total = 0; 2104200825Sthompsa 2105200825Sthompsa /* setup frame lengths */ 2106200825Sthompsa for (n = 0; n != blockcount; n++) { 2107242223Shselasky uint32_t frame_len; 2108242223Shselasky 2109200825Sthompsa ch->sample_curr += ch->sample_rem; 2110200825Sthompsa if (ch->sample_curr >= ch->frames_per_second) { 2111200825Sthompsa ch->sample_curr -= ch->frames_per_second; 2112242223Shselasky frame_len = ch->bytes_per_frame[1]; 2113200825Sthompsa } else { 2114242223Shselasky frame_len = ch->bytes_per_frame[0]; 2115200825Sthompsa } 2116242223Shselasky 2117242223Shselasky if (n == (blockcount - 1)) { 2118242223Shselasky switch (ch->last_sync_state) { 2119242223Shselasky case UAUDIO_SYNC_MORE: 2120242223Shselasky DPRINTFN(6, "sending one sample more\n"); 2121249796Shselasky if ((frame_len + sample_size) <= mfl) 2122249796Shselasky frame_len += sample_size; 2123242223Shselasky ch->last_sync_state = UAUDIO_SYNC_NONE; 2124242223Shselasky break; 2125242223Shselasky case UAUDIO_SYNC_LESS: 2126242223Shselasky DPRINTFN(6, "sending one sample less\n"); 2127249796Shselasky if (frame_len >= sample_size) 2128249796Shselasky frame_len -= sample_size; 2129242223Shselasky ch->last_sync_state = UAUDIO_SYNC_NONE; 2130242223Shselasky break; 2131242223Shselasky default: 2132242223Shselasky break; 2133242223Shselasky } 2134242223Shselasky } 2135242223Shselasky 2136242223Shselasky usbd_xfer_set_frame_len(xfer, n, frame_len); 2137242223Shselasky total += frame_len; 2138200825Sthompsa } 2139200825Sthompsa 2140184610Salfred DPRINTFN(6, "transfer %d bytes\n", total); 2141184610Salfred 2142184610Salfred offset = 0; 2143184610Salfred 2144194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 2145184610Salfred while (total > 0) { 2146184610Salfred 2147184610Salfred n = (ch->end - ch->cur); 2148184610Salfred if (n > total) { 2149184610Salfred n = total; 2150184610Salfred } 2151194677Sthompsa usbd_copy_in(pc, offset, ch->cur, n); 2152184610Salfred 2153184610Salfred total -= n; 2154184610Salfred ch->cur += n; 2155184610Salfred offset += n; 2156184610Salfred 2157184610Salfred if (ch->cur >= ch->end) { 2158184610Salfred ch->cur = ch->start; 2159184610Salfred } 2160184610Salfred } 2161184610Salfred 2162194228Sthompsa usbd_transfer_submit(xfer); 2163184610Salfred break; 2164184610Salfred 2165184610Salfred default: /* Error */ 2166194677Sthompsa if (error == USB_ERR_CANCELLED) { 2167184610Salfred break; 2168184610Salfred } 2169184610Salfred goto tr_transferred; 2170184610Salfred } 2171184610Salfred} 2172184610Salfred 2173184610Salfredstatic void 2174242223Shselaskyuaudio_chan_record_sync_callback(struct usb_xfer *xfer, usb_error_t error) 2175242223Shselasky{ 2176242223Shselasky /* TODO */ 2177242223Shselasky} 2178242223Shselasky 2179242223Shselaskystatic void 2180194677Sthompsauaudio_chan_record_callback(struct usb_xfer *xfer, usb_error_t error) 2181184610Salfred{ 2182194677Sthompsa struct uaudio_chan *ch = usbd_xfer_softc(xfer); 2183194677Sthompsa struct usb_page_cache *pc; 2184184610Salfred uint32_t offset0; 2185184610Salfred uint32_t offset1; 2186199060Sthompsa uint32_t mfl; 2187233774Shselasky int m; 2188233774Shselasky int n; 2189194677Sthompsa int len; 2190199060Sthompsa int actlen; 2191199060Sthompsa int nframes; 2192233774Shselasky int blockcount; 2193184610Salfred 2194194677Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, &nframes); 2195199060Sthompsa mfl = usbd_xfer_max_framelen(xfer); 2196194677Sthompsa 2197199060Sthompsa if (ch->end == ch->start) { 2198199060Sthompsa DPRINTF("no buffer!\n"); 2199199060Sthompsa return; 2200199060Sthompsa } 2201199060Sthompsa 2202184610Salfred switch (USB_GET_STATE(xfer)) { 2203184610Salfred case USB_ST_TRANSFERRED: 2204184610Salfred 2205200825Sthompsa DPRINTFN(6, "transferred %d bytes\n", actlen); 2206200825Sthompsa 2207184610Salfred offset0 = 0; 2208199060Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 2209184610Salfred 2210194677Sthompsa for (n = 0; n != nframes; n++) { 2211184610Salfred 2212184610Salfred offset1 = offset0; 2213194682Sthompsa len = usbd_xfer_frame_len(xfer, n); 2214184610Salfred 2215194677Sthompsa while (len > 0) { 2216184610Salfred 2217184610Salfred m = (ch->end - ch->cur); 2218184610Salfred 2219233774Shselasky if (m > len) 2220194677Sthompsa m = len; 2221233774Shselasky 2222194677Sthompsa usbd_copy_out(pc, offset1, ch->cur, m); 2223184610Salfred 2224194677Sthompsa len -= m; 2225184610Salfred offset1 += m; 2226184610Salfred ch->cur += m; 2227184610Salfred 2228184610Salfred if (ch->cur >= ch->end) { 2229184610Salfred ch->cur = ch->start; 2230184610Salfred } 2231184610Salfred } 2232184610Salfred 2233199060Sthompsa offset0 += mfl; 2234184610Salfred } 2235184610Salfred 2236184610Salfred chn_intr(ch->pcm_ch); 2237184610Salfred 2238184610Salfred case USB_ST_SETUP: 2239199060Sthompsatr_setup: 2240200825Sthompsa blockcount = ch->intr_frames; 2241200825Sthompsa 2242194677Sthompsa usbd_xfer_set_frames(xfer, blockcount); 2243194677Sthompsa for (n = 0; n < blockcount; n++) { 2244199060Sthompsa usbd_xfer_set_frame_len(xfer, n, mfl); 2245184610Salfred } 2246184610Salfred 2247194228Sthompsa usbd_transfer_submit(xfer); 2248199060Sthompsa break; 2249184610Salfred 2250184610Salfred default: /* Error */ 2251194677Sthompsa if (error == USB_ERR_CANCELLED) { 2252199060Sthompsa break; 2253184610Salfred } 2254199060Sthompsa goto tr_setup; 2255184610Salfred } 2256184610Salfred} 2257184610Salfred 2258184610Salfredvoid * 2259184610Salfreduaudio_chan_init(struct uaudio_softc *sc, struct snd_dbuf *b, 2260184610Salfred struct pcm_channel *c, int dir) 2261184610Salfred{ 2262184610Salfred struct uaudio_chan *ch = ((dir == PCMDIR_PLAY) ? 2263184610Salfred &sc->sc_play_chan : &sc->sc_rec_chan); 2264186730Salfred uint32_t buf_size; 2265249796Shselasky uint8_t x; 2266184610Salfred 2267249796Shselasky /* store mutex and PCM channel */ 2268200825Sthompsa 2269199576Sthompsa ch->pcm_ch = c; 2270199576Sthompsa ch->pcm_mtx = c->lock; 2271199576Sthompsa 2272249796Shselasky /* compute worst case buffer */ 2273184610Salfred 2274249796Shselasky buf_size = 0; 2275249796Shselasky for (x = 0; x != ch->num_alt; x++) { 2276249796Shselasky uint32_t temp = uaudio_get_buffer_size(ch, x); 2277249796Shselasky if (temp > buf_size) 2278249796Shselasky buf_size = temp; 2279200825Sthompsa } 2280200825Sthompsa 2281249796Shselasky /* allow double buffering */ 2282249796Shselasky buf_size *= 2; 2283184610Salfred 2284249796Shselasky DPRINTF("Worst case buffer is %d bytes\n", (int)buf_size); 2285200825Sthompsa 2286199060Sthompsa ch->buf = malloc(buf_size, M_DEVBUF, M_WAITOK | M_ZERO); 2287199060Sthompsa if (ch->buf == NULL) 2288199060Sthompsa goto error; 2289199060Sthompsa if (sndbuf_setup(b, ch->buf, buf_size) != 0) 2290199060Sthompsa goto error; 2291199060Sthompsa 2292199060Sthompsa ch->start = ch->buf; 2293199060Sthompsa ch->end = ch->buf + buf_size; 2294199060Sthompsa ch->cur = ch->buf; 2295199060Sthompsa ch->pcm_buf = b; 2296249796Shselasky ch->max_buf = buf_size; 2297199060Sthompsa 2298199060Sthompsa if (ch->pcm_mtx == NULL) { 2299199060Sthompsa DPRINTF("ERROR: PCM channels does not have a mutex!\n"); 2300199060Sthompsa goto error; 2301199060Sthompsa } 2302184610Salfred return (ch); 2303184610Salfred 2304184610Salfrederror: 2305184610Salfred uaudio_chan_free(ch); 2306184610Salfred return (NULL); 2307184610Salfred} 2308184610Salfred 2309184610Salfredint 2310184610Salfreduaudio_chan_free(struct uaudio_chan *ch) 2311184610Salfred{ 2312184610Salfred if (ch->buf != NULL) { 2313184610Salfred free(ch->buf, M_DEVBUF); 2314184610Salfred ch->buf = NULL; 2315184610Salfred } 2316242223Shselasky usbd_transfer_unsetup(ch->xfer, UAUDIO_NCHANBUFS + 1); 2317184610Salfred 2318249796Shselasky ch->num_alt = 0; 2319184610Salfred 2320184610Salfred return (0); 2321184610Salfred} 2322184610Salfred 2323184610Salfredint 2324184610Salfreduaudio_chan_set_param_blocksize(struct uaudio_chan *ch, uint32_t blocksize) 2325184610Salfred{ 2326249796Shselasky uint32_t temp = 2 * uaudio_get_buffer_size(ch, ch->set_alt); 2327249796Shselasky 2328249796Shselasky sndbuf_setup(ch->pcm_buf, ch->buf, temp); 2329249796Shselasky 2330249796Shselasky ch->start = ch->buf; 2331249796Shselasky ch->end = ch->buf + temp; 2332249796Shselasky ch->cur = ch->buf; 2333249796Shselasky 2334249796Shselasky return (temp / 2); 2335184610Salfred} 2336184610Salfred 2337184610Salfredint 2338184610Salfreduaudio_chan_set_param_fragments(struct uaudio_chan *ch, uint32_t blocksize, 2339184610Salfred uint32_t blockcount) 2340184610Salfred{ 2341184610Salfred return (1); 2342184610Salfred} 2343184610Salfred 2344184610Salfredint 2345184610Salfreduaudio_chan_set_param_speed(struct uaudio_chan *ch, uint32_t speed) 2346184610Salfred{ 2347249796Shselasky uint8_t x; 2348249796Shselasky 2349249796Shselasky for (x = 0; x < ch->num_alt; x++) { 2350249796Shselasky if (ch->usb_alt[x].sample_rate < speed) { 2351249796Shselasky /* sample rate is too low */ 2352249796Shselasky break; 2353249796Shselasky } 2354184610Salfred } 2355249796Shselasky 2356249796Shselasky if (x != 0) 2357249796Shselasky x--; 2358249796Shselasky 2359249796Shselasky ch->set_alt = x; 2360249796Shselasky 2361249796Shselasky DPRINTF("Selecting alt %d\n", (int)x); 2362249796Shselasky 2363249796Shselasky return (ch->usb_alt[x].sample_rate); 2364184610Salfred} 2365184610Salfred 2366184610Salfredint 2367184610Salfreduaudio_chan_getptr(struct uaudio_chan *ch) 2368184610Salfred{ 2369184610Salfred return (ch->cur - ch->start); 2370184610Salfred} 2371184610Salfred 2372184610Salfredstruct pcmchan_caps * 2373184610Salfreduaudio_chan_getcaps(struct uaudio_chan *ch) 2374184610Salfred{ 2375184610Salfred return (&ch->pcm_cap); 2376184610Salfred} 2377184610Salfred 2378193640Sariffstatic struct pcmchan_matrix uaudio_chan_matrix_swap_2_0 = { 2379193640Sariff .id = SND_CHN_MATRIX_DRV, 2380193640Sariff .channels = 2, 2381193640Sariff .ext = 0, 2382193640Sariff .map = { 2383193640Sariff /* Right */ 2384193640Sariff [0] = { 2385193640Sariff .type = SND_CHN_T_FR, 2386193640Sariff .members = 2387193640Sariff SND_CHN_T_MASK_FR | SND_CHN_T_MASK_FC | 2388193640Sariff SND_CHN_T_MASK_LF | SND_CHN_T_MASK_BR | 2389193640Sariff SND_CHN_T_MASK_BC | SND_CHN_T_MASK_SR 2390193640Sariff }, 2391193640Sariff /* Left */ 2392193640Sariff [1] = { 2393193640Sariff .type = SND_CHN_T_FL, 2394193640Sariff .members = 2395193640Sariff SND_CHN_T_MASK_FL | SND_CHN_T_MASK_FC | 2396193640Sariff SND_CHN_T_MASK_LF | SND_CHN_T_MASK_BL | 2397193640Sariff SND_CHN_T_MASK_BC | SND_CHN_T_MASK_SL 2398193640Sariff }, 2399193640Sariff [2] = { 2400193640Sariff .type = SND_CHN_T_MAX, 2401193640Sariff .members = 0 2402193640Sariff } 2403193640Sariff }, 2404193640Sariff .mask = SND_CHN_T_MASK_FR | SND_CHN_T_MASK_FL, 2405193640Sariff .offset = { 1, 0, -1, -1, -1, -1, -1, -1, -1, 2406193640Sariff -1, -1, -1, -1, -1, -1, -1, -1, -1 } 2407193640Sariff}; 2408193640Sariff 2409193640Sariffstruct pcmchan_matrix * 2410193640Sariffuaudio_chan_getmatrix(struct uaudio_chan *ch, uint32_t format) 2411193640Sariff{ 2412193640Sariff struct uaudio_softc *sc; 2413193640Sariff 2414193640Sariff sc = ch->priv_sc; 2415193640Sariff 2416193640Sariff if (sc != NULL && sc->sc_uq_audio_swap_lr != 0 && 2417193640Sariff AFMT_CHANNEL(format) == 2) 2418193640Sariff return (&uaudio_chan_matrix_swap_2_0); 2419193640Sariff 2420193640Sariff return (feeder_matrix_format_map(format)); 2421193640Sariff} 2422193640Sariff 2423184610Salfredint 2424184610Salfreduaudio_chan_set_param_format(struct uaudio_chan *ch, uint32_t format) 2425184610Salfred{ 2426249796Shselasky DPRINTF("Selecting format 0x%08x\n", (unsigned int)format); 2427184610Salfred return (0); 2428184610Salfred} 2429184610Salfred 2430184610Salfredint 2431184610Salfreduaudio_chan_start(struct uaudio_chan *ch) 2432184610Salfred{ 2433249796Shselasky struct uaudio_softc *sc = ch->priv_sc; 2434249796Shselasky int do_start = 0; 2435184610Salfred 2436249796Shselasky usb_proc_explore_lock(sc->sc_udev); 2437249796Shselasky if (ch->operation != CHAN_OP_DRAIN) { 2438249796Shselasky if (ch->cur_alt == ch->set_alt && 2439249796Shselasky ch->operation == CHAN_OP_NONE) { 2440249796Shselasky /* save doing the explore task */ 2441249796Shselasky do_start = 1; 2442249796Shselasky } else { 2443249796Shselasky ch->operation = CHAN_OP_START; 2444249796Shselasky (void)usb_proc_explore_msignal(sc->sc_udev, 2445249796Shselasky &sc->sc_config_msg[0], &sc->sc_config_msg[1]); 2446249796Shselasky } 2447249796Shselasky } 2448249796Shselasky usb_proc_explore_unlock(sc->sc_udev); 2449249796Shselasky 2450249796Shselasky if (do_start) { 2451249796Shselasky usbd_transfer_start(ch->xfer[0]); 2452249796Shselasky usbd_transfer_start(ch->xfer[1]); 2453249796Shselasky } 2454184610Salfred return (0); 2455184610Salfred} 2456184610Salfred 2457184610Salfredint 2458184610Salfreduaudio_chan_stop(struct uaudio_chan *ch) 2459184610Salfred{ 2460249796Shselasky struct uaudio_softc *sc = ch->priv_sc; 2461249796Shselasky int do_stop = 0; 2462249796Shselasky 2463249796Shselasky usb_proc_explore_lock(sc->sc_udev); 2464249796Shselasky if (ch->operation != CHAN_OP_DRAIN) { 2465249796Shselasky if (ch->cur_alt == ch->set_alt && 2466249796Shselasky ch->operation == CHAN_OP_NONE) { 2467249796Shselasky /* save doing the explore task */ 2468249796Shselasky do_stop = 1; 2469249796Shselasky } else { 2470249796Shselasky ch->operation = CHAN_OP_STOP; 2471249796Shselasky (void)usb_proc_explore_msignal(sc->sc_udev, 2472249796Shselasky &sc->sc_config_msg[0], &sc->sc_config_msg[1]); 2473249796Shselasky } 2474249796Shselasky } 2475249796Shselasky usb_proc_explore_unlock(sc->sc_udev); 2476249796Shselasky 2477249796Shselasky if (do_stop) { 2478249796Shselasky usbd_transfer_stop(ch->xfer[0]); 2479249796Shselasky usbd_transfer_stop(ch->xfer[1]); 2480249796Shselasky } 2481184610Salfred return (0); 2482184610Salfred} 2483184610Salfred 2484184610Salfred/*========================================================================* 2485184610Salfred * AC - Audio Controller - routines 2486184610Salfred *========================================================================*/ 2487184610Salfred 2488242438Shselaskystatic int 2489242438Shselaskyuaudio_mixer_sysctl_handler(SYSCTL_HANDLER_ARGS) 2490242438Shselasky{ 2491242438Shselasky struct uaudio_softc *sc; 2492242438Shselasky struct uaudio_mixer_node *pmc; 2493242438Shselasky int hint; 2494242438Shselasky int error; 2495242438Shselasky int temp = 0; 2496242438Shselasky int chan = 0; 2497242438Shselasky 2498242438Shselasky sc = (struct uaudio_softc *)oidp->oid_arg1; 2499242438Shselasky hint = oidp->oid_arg2; 2500242438Shselasky 2501242438Shselasky if (sc->sc_mixer_lock == NULL) 2502242438Shselasky return (ENXIO); 2503242438Shselasky 2504242438Shselasky /* lookup mixer node */ 2505242438Shselasky 2506242438Shselasky mtx_lock(sc->sc_mixer_lock); 2507242438Shselasky for (pmc = sc->sc_mixer_root; pmc != NULL; pmc = pmc->next) { 2508242438Shselasky for (chan = 0; chan != (int)pmc->nchan; chan++) { 2509242438Shselasky if (pmc->wValue[chan] != -1 && 2510242438Shselasky pmc->wValue[chan] == hint) { 2511242438Shselasky temp = pmc->wData[chan]; 2512242438Shselasky goto found; 2513242438Shselasky } 2514242438Shselasky } 2515242438Shselasky } 2516242438Shselaskyfound: 2517242438Shselasky mtx_unlock(sc->sc_mixer_lock); 2518242438Shselasky 2519242438Shselasky error = sysctl_handle_int(oidp, &temp, 0, req); 2520242438Shselasky if (error != 0 || req->newptr == NULL) 2521242438Shselasky return (error); 2522242438Shselasky 2523242438Shselasky /* update mixer value */ 2524242438Shselasky 2525242438Shselasky mtx_lock(sc->sc_mixer_lock); 2526242438Shselasky if (pmc != NULL && 2527242438Shselasky temp >= pmc->minval && 2528242438Shselasky temp <= pmc->maxval) { 2529242438Shselasky 2530242438Shselasky pmc->wData[chan] = temp; 2531242438Shselasky pmc->update[(chan / 8)] |= (1 << (chan % 8)); 2532242438Shselasky 2533242438Shselasky /* start the transfer, if not already started */ 2534242438Shselasky usbd_transfer_start(sc->sc_mixer_xfer[0]); 2535242438Shselasky } 2536242438Shselasky mtx_unlock(sc->sc_mixer_lock); 2537242438Shselasky 2538242438Shselasky return (0); 2539242438Shselasky} 2540242438Shselasky 2541184610Salfredstatic void 2542242438Shselaskyuaudio_mixer_ctl_free(struct uaudio_softc *sc) 2543242438Shselasky{ 2544242438Shselasky struct uaudio_mixer_node *p_mc; 2545242438Shselasky 2546242438Shselasky while ((p_mc = sc->sc_mixer_root) != NULL) { 2547242438Shselasky sc->sc_mixer_root = p_mc->next; 2548242438Shselasky free(p_mc, M_USBDEV); 2549242438Shselasky } 2550242438Shselasky} 2551242438Shselasky 2552242438Shselaskystatic void 2553242438Shselaskyuaudio_mixer_register_sysctl(struct uaudio_softc *sc, device_t dev) 2554242438Shselasky{ 2555242438Shselasky struct uaudio_mixer_node *pmc; 2556242438Shselasky struct sysctl_oid *mixer_tree; 2557242438Shselasky struct sysctl_oid *control_tree; 2558242438Shselasky char buf[32]; 2559242438Shselasky int chan; 2560242438Shselasky int n; 2561242438Shselasky 2562242453Shselasky mixer_tree = SYSCTL_ADD_NODE(device_get_sysctl_ctx(dev), 2563242438Shselasky SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "mixer", 2564242438Shselasky CTLFLAG_RD, NULL, ""); 2565242438Shselasky 2566242438Shselasky if (mixer_tree == NULL) 2567242438Shselasky return; 2568242438Shselasky 2569242438Shselasky for (n = 0, pmc = sc->sc_mixer_root; pmc != NULL; 2570242438Shselasky pmc = pmc->next, n++) { 2571242438Shselasky 2572242438Shselasky for (chan = 0; chan < pmc->nchan; chan++) { 2573242438Shselasky 2574242438Shselasky if (pmc->nchan > 1) { 2575242438Shselasky snprintf(buf, sizeof(buf), "%s_%d_%d", 2576242438Shselasky pmc->name, n, chan); 2577242438Shselasky } else { 2578242438Shselasky snprintf(buf, sizeof(buf), "%s_%d", 2579242438Shselasky pmc->name, n); 2580242438Shselasky } 2581242438Shselasky 2582242453Shselasky control_tree = SYSCTL_ADD_NODE(device_get_sysctl_ctx(dev), 2583242438Shselasky SYSCTL_CHILDREN(mixer_tree), OID_AUTO, buf, 2584242453Shselasky CTLFLAG_RD, NULL, "Mixer control nodes"); 2585242438Shselasky 2586242438Shselasky if (control_tree == NULL) 2587242438Shselasky continue; 2588242438Shselasky 2589242453Shselasky SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 2590242438Shselasky SYSCTL_CHILDREN(control_tree), 2591242438Shselasky OID_AUTO, "val", CTLTYPE_INT | CTLFLAG_RW, sc, 2592242438Shselasky pmc->wValue[chan], 2593242438Shselasky uaudio_mixer_sysctl_handler, "I", "Current value"); 2594242438Shselasky 2595242453Shselasky SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 2596242438Shselasky SYSCTL_CHILDREN(control_tree), 2597242438Shselasky OID_AUTO, "min", CTLFLAG_RD, 0, pmc->minval, 2598242438Shselasky "Minimum value"); 2599242438Shselasky 2600242453Shselasky SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 2601242438Shselasky SYSCTL_CHILDREN(control_tree), 2602242438Shselasky OID_AUTO, "max", CTLFLAG_RD, 0, pmc->maxval, 2603242438Shselasky "Maximum value"); 2604242438Shselasky 2605242453Shselasky SYSCTL_ADD_STRING(device_get_sysctl_ctx(dev), 2606242438Shselasky SYSCTL_CHILDREN(control_tree), 2607242438Shselasky OID_AUTO, "desc", CTLFLAG_RD, pmc->desc, 0, 2608242438Shselasky "Description"); 2609242438Shselasky } 2610242438Shselasky } 2611242438Shselasky} 2612242438Shselasky 2613242453Shselasky/* M-Audio FastTrack Ultra Mixer Description */ 2614242453Shselasky/* Origin: Linux USB Audio driver */ 2615242438Shselaskystatic void 2616242453Shselaskyuaudio_mixer_controls_create_ftu(struct uaudio_softc *sc) 2617242453Shselasky{ 2618242453Shselasky int chx; 2619242453Shselasky int chy; 2620242453Shselasky 2621244567Shselasky memset(&MIX(sc), 0, sizeof(MIX(sc))); 2622244567Shselasky MIX(sc).wIndex = MAKE_WORD(6, sc->sc_mixer_iface_no); 2623244567Shselasky MIX(sc).wValue[0] = MAKE_WORD(8, 0); 2624244567Shselasky MIX(sc).class = UAC_OUTPUT; 2625244567Shselasky MIX(sc).type = MIX_UNSIGNED_16; 2626244567Shselasky MIX(sc).ctl = SOUND_MIXER_NRDEVICES; 2627244567Shselasky MIX(sc).name = "effect"; 2628244567Shselasky MIX(sc).minval = 0; 2629244567Shselasky MIX(sc).maxval = 7; 2630244567Shselasky MIX(sc).mul = 7; 2631244567Shselasky MIX(sc).nchan = 1; 2632244567Shselasky MIX(sc).update[0] = 1; 2633244567Shselasky strlcpy(MIX(sc).desc, "Room1,2,3,Hall1,2,Plate,Delay,Echo", sizeof(MIX(sc).desc)); 2634244567Shselasky uaudio_mixer_add_ctl_sub(sc, &MIX(sc)); 2635242453Shselasky 2636244567Shselasky memset(&MIX(sc), 0, sizeof(MIX(sc))); 2637244567Shselasky MIX(sc).wIndex = MAKE_WORD(5, sc->sc_mixer_iface_no); 2638242453Shselasky 2639242453Shselasky for (chx = 0; chx != 8; chx++) { 2640242453Shselasky for (chy = 0; chy != 8; chy++) { 2641242453Shselasky 2642244567Shselasky MIX(sc).wValue[0] = MAKE_WORD(chx + 1, chy + 1); 2643244567Shselasky MIX(sc).type = MIX_SIGNED_16; 2644244567Shselasky MIX(sc).ctl = SOUND_MIXER_NRDEVICES; 2645244567Shselasky MIX(sc).name = "mix_rec"; 2646244567Shselasky MIX(sc).nchan = 1; 2647244567Shselasky MIX(sc).update[0] = 1; 2648244567Shselasky MIX(sc).val_default = 0; 2649244567Shselasky snprintf(MIX(sc).desc, sizeof(MIX(sc).desc), 2650242453Shselasky "AIn%d - Out%d Record Volume", chy + 1, chx + 1); 2651242453Shselasky 2652244567Shselasky uaudio_mixer_add_ctl(sc, &MIX(sc)); 2653242453Shselasky 2654244567Shselasky MIX(sc).wValue[0] = MAKE_WORD(chx + 1, chy + 1 + 8); 2655244567Shselasky MIX(sc).type = MIX_SIGNED_16; 2656244567Shselasky MIX(sc).ctl = SOUND_MIXER_NRDEVICES; 2657244567Shselasky MIX(sc).name = "mix_play"; 2658244567Shselasky MIX(sc).nchan = 1; 2659244567Shselasky MIX(sc).update[0] = 1; 2660244567Shselasky MIX(sc).val_default = (chx == chy) ? 2 : 0; 2661244567Shselasky snprintf(MIX(sc).desc, sizeof(MIX(sc).desc), 2662242453Shselasky "DIn%d - Out%d Playback Volume", chy + 1, chx + 1); 2663242453Shselasky 2664244567Shselasky uaudio_mixer_add_ctl(sc, &MIX(sc)); 2665242453Shselasky } 2666242453Shselasky } 2667242453Shselasky 2668244567Shselasky memset(&MIX(sc), 0, sizeof(MIX(sc))); 2669244567Shselasky MIX(sc).wIndex = MAKE_WORD(6, sc->sc_mixer_iface_no); 2670244567Shselasky MIX(sc).wValue[0] = MAKE_WORD(2, 0); 2671244567Shselasky MIX(sc).class = UAC_OUTPUT; 2672244567Shselasky MIX(sc).type = MIX_SIGNED_8; 2673244567Shselasky MIX(sc).ctl = SOUND_MIXER_NRDEVICES; 2674244567Shselasky MIX(sc).name = "effect_vol"; 2675244567Shselasky MIX(sc).nchan = 1; 2676244567Shselasky MIX(sc).update[0] = 1; 2677244567Shselasky MIX(sc).minval = 0; 2678244567Shselasky MIX(sc).maxval = 0x7f; 2679244567Shselasky MIX(sc).mul = 0x7f; 2680244567Shselasky MIX(sc).nchan = 1; 2681244567Shselasky MIX(sc).update[0] = 1; 2682244567Shselasky strlcpy(MIX(sc).desc, "Effect Volume", sizeof(MIX(sc).desc)); 2683244567Shselasky uaudio_mixer_add_ctl_sub(sc, &MIX(sc)); 2684242453Shselasky 2685244567Shselasky memset(&MIX(sc), 0, sizeof(MIX(sc))); 2686244567Shselasky MIX(sc).wIndex = MAKE_WORD(6, sc->sc_mixer_iface_no); 2687244567Shselasky MIX(sc).wValue[0] = MAKE_WORD(3, 0); 2688244567Shselasky MIX(sc).class = UAC_OUTPUT; 2689244567Shselasky MIX(sc).type = MIX_SIGNED_16; 2690244567Shselasky MIX(sc).ctl = SOUND_MIXER_NRDEVICES; 2691244567Shselasky MIX(sc).name = "effect_dur"; 2692244567Shselasky MIX(sc).nchan = 1; 2693244567Shselasky MIX(sc).update[0] = 1; 2694244567Shselasky MIX(sc).minval = 0; 2695244567Shselasky MIX(sc).maxval = 0x7f00; 2696244567Shselasky MIX(sc).mul = 0x7f00; 2697244567Shselasky MIX(sc).nchan = 1; 2698244567Shselasky MIX(sc).update[0] = 1; 2699244567Shselasky strlcpy(MIX(sc).desc, "Effect Duration", sizeof(MIX(sc).desc)); 2700244567Shselasky uaudio_mixer_add_ctl_sub(sc, &MIX(sc)); 2701242453Shselasky 2702244567Shselasky memset(&MIX(sc), 0, sizeof(MIX(sc))); 2703244567Shselasky MIX(sc).wIndex = MAKE_WORD(6, sc->sc_mixer_iface_no); 2704244567Shselasky MIX(sc).wValue[0] = MAKE_WORD(4, 0); 2705244567Shselasky MIX(sc).class = UAC_OUTPUT; 2706244567Shselasky MIX(sc).type = MIX_SIGNED_8; 2707244567Shselasky MIX(sc).ctl = SOUND_MIXER_NRDEVICES; 2708244567Shselasky MIX(sc).name = "effect_fb"; 2709244567Shselasky MIX(sc).nchan = 1; 2710244567Shselasky MIX(sc).update[0] = 1; 2711244567Shselasky MIX(sc).minval = 0; 2712244567Shselasky MIX(sc).maxval = 0x7f; 2713244567Shselasky MIX(sc).mul = 0x7f; 2714244567Shselasky MIX(sc).nchan = 1; 2715244567Shselasky MIX(sc).update[0] = 1; 2716244567Shselasky strlcpy(MIX(sc).desc, "Effect Feedback Volume", sizeof(MIX(sc).desc)); 2717244567Shselasky uaudio_mixer_add_ctl_sub(sc, &MIX(sc)); 2718242453Shselasky 2719244567Shselasky memset(&MIX(sc), 0, sizeof(MIX(sc))); 2720244567Shselasky MIX(sc).wIndex = MAKE_WORD(7, sc->sc_mixer_iface_no); 2721242453Shselasky for (chy = 0; chy != 4; chy++) { 2722242453Shselasky 2723244567Shselasky MIX(sc).wValue[0] = MAKE_WORD(7, chy + 1); 2724244567Shselasky MIX(sc).type = MIX_SIGNED_16; 2725244567Shselasky MIX(sc).ctl = SOUND_MIXER_NRDEVICES; 2726244567Shselasky MIX(sc).name = "effect_ret"; 2727244567Shselasky MIX(sc).nchan = 1; 2728244567Shselasky MIX(sc).update[0] = 1; 2729244567Shselasky snprintf(MIX(sc).desc, sizeof(MIX(sc).desc), 2730242453Shselasky "Effect Return %d Volume", chy + 1); 2731242453Shselasky 2732244567Shselasky uaudio_mixer_add_ctl(sc, &MIX(sc)); 2733242453Shselasky } 2734242453Shselasky 2735244567Shselasky memset(&MIX(sc), 0, sizeof(MIX(sc))); 2736244567Shselasky MIX(sc).wIndex = MAKE_WORD(5, sc->sc_mixer_iface_no); 2737242453Shselasky 2738242453Shselasky for (chy = 0; chy != 8; chy++) { 2739244567Shselasky MIX(sc).wValue[0] = MAKE_WORD(9, chy + 1); 2740244567Shselasky MIX(sc).type = MIX_SIGNED_16; 2741244567Shselasky MIX(sc).ctl = SOUND_MIXER_NRDEVICES; 2742244567Shselasky MIX(sc).name = "effect_send"; 2743244567Shselasky MIX(sc).nchan = 1; 2744244567Shselasky MIX(sc).update[0] = 1; 2745244567Shselasky snprintf(MIX(sc).desc, sizeof(MIX(sc).desc), 2746242453Shselasky "Effect Send AIn%d Volume", chy + 1); 2747242453Shselasky 2748244567Shselasky uaudio_mixer_add_ctl(sc, &MIX(sc)); 2749242453Shselasky 2750271375Shselasky MIX(sc).wValue[0] = MAKE_WORD(9, chy + 1 + 8); 2751244567Shselasky MIX(sc).type = MIX_SIGNED_16; 2752244567Shselasky MIX(sc).ctl = SOUND_MIXER_NRDEVICES; 2753244567Shselasky MIX(sc).name = "effect_send"; 2754244567Shselasky MIX(sc).nchan = 1; 2755244567Shselasky MIX(sc).update[0] = 1; 2756244567Shselasky snprintf(MIX(sc).desc, sizeof(MIX(sc).desc), 2757271375Shselasky "Effect Send DIn%d Volume", chy + 1); 2758242453Shselasky 2759244567Shselasky uaudio_mixer_add_ctl(sc, &MIX(sc)); 2760242453Shselasky } 2761242453Shselasky} 2762242453Shselasky 2763242453Shselaskystatic void 2764242438Shselaskyuaudio_mixer_reload_all(struct uaudio_softc *sc) 2765242438Shselasky{ 2766242438Shselasky struct uaudio_mixer_node *pmc; 2767242438Shselasky int chan; 2768242438Shselasky 2769242438Shselasky if (sc->sc_mixer_lock == NULL) 2770242438Shselasky return; 2771242438Shselasky 2772242438Shselasky mtx_lock(sc->sc_mixer_lock); 2773242438Shselasky for (pmc = sc->sc_mixer_root; pmc != NULL; pmc = pmc->next) { 2774242453Shselasky /* use reset defaults for non-oss controlled settings */ 2775242453Shselasky if (pmc->ctl == SOUND_MIXER_NRDEVICES) 2776242453Shselasky continue; 2777242438Shselasky for (chan = 0; chan < pmc->nchan; chan++) 2778242438Shselasky pmc->update[chan / 8] |= (1 << (chan % 8)); 2779242438Shselasky } 2780242438Shselasky usbd_transfer_start(sc->sc_mixer_xfer[0]); 2781246421Shselasky 2782246421Shselasky /* start HID volume keys, if any */ 2783246421Shselasky usbd_transfer_start(sc->sc_hid.xfer[0]); 2784242438Shselasky mtx_unlock(sc->sc_mixer_lock); 2785242438Shselasky} 2786242438Shselasky 2787242438Shselaskystatic void 2788184610Salfreduaudio_mixer_add_ctl_sub(struct uaudio_softc *sc, struct uaudio_mixer_node *mc) 2789184610Salfred{ 2790184610Salfred struct uaudio_mixer_node *p_mc_new = 2791218791Shselasky malloc(sizeof(*p_mc_new), M_USBDEV, M_WAITOK); 2792242453Shselasky int ch; 2793184610Salfred 2794218791Shselasky if (p_mc_new != NULL) { 2795218791Shselasky memcpy(p_mc_new, mc, sizeof(*p_mc_new)); 2796184610Salfred p_mc_new->next = sc->sc_mixer_root; 2797184610Salfred sc->sc_mixer_root = p_mc_new; 2798184610Salfred sc->sc_mixer_count++; 2799242453Shselasky 2800242453Shselasky /* set default value for all channels */ 2801242453Shselasky for (ch = 0; ch < p_mc_new->nchan; ch++) { 2802242453Shselasky switch (p_mc_new->val_default) { 2803242453Shselasky case 1: 2804242455Shselasky /* 50% */ 2805242453Shselasky p_mc_new->wData[ch] = (p_mc_new->maxval + p_mc_new->minval) / 2; 2806242453Shselasky break; 2807242453Shselasky case 2: 2808242455Shselasky /* 100% */ 2809242453Shselasky p_mc_new->wData[ch] = p_mc_new->maxval; 2810242453Shselasky break; 2811242453Shselasky default: 2812242455Shselasky /* 0% */ 2813242453Shselasky p_mc_new->wData[ch] = p_mc_new->minval; 2814242453Shselasky break; 2815242453Shselasky } 2816242453Shselasky } 2817184610Salfred } else { 2818184610Salfred DPRINTF("out of memory\n"); 2819184610Salfred } 2820184610Salfred} 2821184610Salfred 2822184610Salfredstatic void 2823184610Salfreduaudio_mixer_add_ctl(struct uaudio_softc *sc, struct uaudio_mixer_node *mc) 2824184610Salfred{ 2825184610Salfred int32_t res; 2826184610Salfred 2827184610Salfred if (mc->class < UAC_NCLASSES) { 2828184610Salfred DPRINTF("adding %s.%d\n", 2829184610Salfred uac_names[mc->class], mc->ctl); 2830184610Salfred } else { 2831184610Salfred DPRINTF("adding %d\n", mc->ctl); 2832184610Salfred } 2833184610Salfred 2834184610Salfred if (mc->type == MIX_ON_OFF) { 2835184610Salfred mc->minval = 0; 2836184610Salfred mc->maxval = 1; 2837184610Salfred } else if (mc->type == MIX_SELECTOR) { 2838184610Salfred } else { 2839184610Salfred 2840184610Salfred /* determine min and max values */ 2841184610Salfred 2842240609Shselasky mc->minval = uaudio_mixer_get(sc->sc_udev, 2843240609Shselasky sc->sc_audio_rev, GET_MIN, mc); 2844240609Shselasky mc->maxval = uaudio_mixer_get(sc->sc_udev, 2845240609Shselasky sc->sc_audio_rev, GET_MAX, mc); 2846184610Salfred 2847199060Sthompsa /* check if max and min was swapped */ 2848199060Sthompsa 2849199060Sthompsa if (mc->maxval < mc->minval) { 2850199060Sthompsa res = mc->maxval; 2851199060Sthompsa mc->maxval = mc->minval; 2852199060Sthompsa mc->minval = res; 2853199060Sthompsa } 2854199060Sthompsa 2855199060Sthompsa /* compute value range */ 2856184610Salfred mc->mul = mc->maxval - mc->minval; 2857199060Sthompsa if (mc->mul == 0) 2858184610Salfred mc->mul = 1; 2859199060Sthompsa 2860199060Sthompsa /* compute value alignment */ 2861240609Shselasky res = uaudio_mixer_get(sc->sc_udev, 2862240609Shselasky sc->sc_audio_rev, GET_RES, mc); 2863199576Sthompsa 2864199576Sthompsa DPRINTF("Resolution = %d\n", (int)res); 2865184610Salfred } 2866184610Salfred 2867184610Salfred uaudio_mixer_add_ctl_sub(sc, mc); 2868184610Salfred 2869207077Sthompsa#ifdef USB_DEBUG 2870184610Salfred if (uaudio_debug > 2) { 2871184610Salfred uint8_t i; 2872184610Salfred 2873184610Salfred for (i = 0; i < mc->nchan; i++) { 2874184610Salfred DPRINTF("[mix] wValue=%04x\n", mc->wValue[0]); 2875184610Salfred } 2876184610Salfred DPRINTF("[mix] wIndex=%04x type=%d ctl='%d' " 2877184610Salfred "min=%d max=%d\n", 2878184610Salfred mc->wIndex, mc->type, mc->ctl, 2879184610Salfred mc->minval, mc->maxval); 2880184610Salfred } 2881184610Salfred#endif 2882184610Salfred} 2883184610Salfred 2884184610Salfredstatic void 2885240609Shselaskyuaudio_mixer_add_mixer(struct uaudio_softc *sc, 2886184610Salfred const struct uaudio_terminal_node *iot, int id) 2887184610Salfred{ 2888240609Shselasky const struct usb_audio_mixer_unit_0 *d0 = iot[id].u.mu_v1; 2889240609Shselasky const struct usb_audio_mixer_unit_1 *d1; 2890184610Salfred 2891240609Shselasky uint32_t bno; /* bit number */ 2892240609Shselasky uint32_t p; /* bit number accumulator */ 2893240609Shselasky uint32_t mo; /* matching outputs */ 2894240609Shselasky uint32_t mc; /* matching channels */ 2895240609Shselasky uint32_t ichs; /* input channels */ 2896240609Shselasky uint32_t ochs; /* output channels */ 2897240609Shselasky uint32_t c; 2898240609Shselasky uint32_t chs; /* channels */ 2899240609Shselasky uint32_t i; 2900240609Shselasky uint32_t o; 2901184610Salfred 2902240609Shselasky DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n", 2903240609Shselasky d0->bUnitId, d0->bNrInPins); 2904240609Shselasky 2905240609Shselasky /* compute the number of input channels */ 2906240609Shselasky 2907240609Shselasky ichs = 0; 2908240609Shselasky for (i = 0; i < d0->bNrInPins; i++) { 2909240609Shselasky ichs += uaudio_mixer_get_cluster( 2910240609Shselasky d0->baSourceId[i], iot).bNrChannels; 2911240609Shselasky } 2912240609Shselasky 2913240609Shselasky d1 = (const void *)(d0->baSourceId + d0->bNrInPins); 2914240609Shselasky 2915240609Shselasky /* and the number of output channels */ 2916240609Shselasky 2917240609Shselasky ochs = d1->bNrChannels; 2918240609Shselasky 2919240609Shselasky DPRINTFN(3, "ichs=%d ochs=%d\n", ichs, ochs); 2920240609Shselasky 2921244567Shselasky memset(&MIX(sc), 0, sizeof(MIX(sc))); 2922240609Shselasky 2923244567Shselasky MIX(sc).wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 2924244567Shselasky uaudio_mixer_determine_class(&iot[id], &MIX(sc)); 2925244567Shselasky MIX(sc).type = MIX_SIGNED_16; 2926240609Shselasky 2927240609Shselasky if (uaudio_mixer_verify_desc(d0, ((ichs * ochs) + 7) / 8) == NULL) 2928240609Shselasky return; 2929240609Shselasky 2930240609Shselasky for (p = i = 0; i < d0->bNrInPins; i++) { 2931240609Shselasky chs = uaudio_mixer_get_cluster( 2932240609Shselasky d0->baSourceId[i], iot).bNrChannels; 2933240609Shselasky mc = 0; 2934240609Shselasky for (c = 0; c < chs; c++) { 2935240609Shselasky mo = 0; 2936240609Shselasky for (o = 0; o < ochs; o++) { 2937240609Shselasky bno = ((p + c) * ochs) + o; 2938240609Shselasky if (BIT_TEST(d1->bmControls, bno)) 2939240609Shselasky mo++; 2940240609Shselasky } 2941240609Shselasky if (mo == 1) 2942240609Shselasky mc++; 2943240609Shselasky } 2944240609Shselasky if ((mc == chs) && (chs <= MIX_MAX_CHAN)) { 2945240609Shselasky 2946240609Shselasky /* repeat bit-scan */ 2947240609Shselasky 2948240609Shselasky mc = 0; 2949240609Shselasky for (c = 0; c < chs; c++) { 2950240609Shselasky for (o = 0; o < ochs; o++) { 2951240609Shselasky bno = ((p + c) * ochs) + o; 2952240609Shselasky if (BIT_TEST(d1->bmControls, bno)) 2953244567Shselasky MIX(sc).wValue[mc++] = MAKE_WORD(p + c + 1, o + 1); 2954240609Shselasky } 2955240609Shselasky } 2956244567Shselasky MIX(sc).nchan = chs; 2957244567Shselasky uaudio_mixer_add_ctl(sc, &MIX(sc)); 2958240609Shselasky } 2959240609Shselasky p += chs; 2960240609Shselasky } 2961184610Salfred} 2962184610Salfred 2963184610Salfredstatic void 2964240609Shselaskyuaudio20_mixer_add_mixer(struct uaudio_softc *sc, 2965184610Salfred const struct uaudio_terminal_node *iot, int id) 2966184610Salfred{ 2967240609Shselasky const struct usb_audio20_mixer_unit_0 *d0 = iot[id].u.mu_v2; 2968240609Shselasky const struct usb_audio20_mixer_unit_1 *d1; 2969184610Salfred 2970184610Salfred uint32_t bno; /* bit number */ 2971184610Salfred uint32_t p; /* bit number accumulator */ 2972184610Salfred uint32_t mo; /* matching outputs */ 2973184610Salfred uint32_t mc; /* matching channels */ 2974184610Salfred uint32_t ichs; /* input channels */ 2975184610Salfred uint32_t ochs; /* output channels */ 2976184610Salfred uint32_t c; 2977184610Salfred uint32_t chs; /* channels */ 2978184610Salfred uint32_t i; 2979184610Salfred uint32_t o; 2980184610Salfred 2981184610Salfred DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n", 2982184610Salfred d0->bUnitId, d0->bNrInPins); 2983184610Salfred 2984184610Salfred /* compute the number of input channels */ 2985184610Salfred 2986184610Salfred ichs = 0; 2987184610Salfred for (i = 0; i < d0->bNrInPins; i++) { 2988240609Shselasky ichs += uaudio20_mixer_get_cluster( 2989240609Shselasky d0->baSourceId[i], iot).bNrChannels; 2990184610Salfred } 2991184610Salfred 2992184610Salfred d1 = (const void *)(d0->baSourceId + d0->bNrInPins); 2993184610Salfred 2994184610Salfred /* and the number of output channels */ 2995184610Salfred 2996184610Salfred ochs = d1->bNrChannels; 2997184610Salfred 2998184610Salfred DPRINTFN(3, "ichs=%d ochs=%d\n", ichs, ochs); 2999184610Salfred 3000244567Shselasky memset(&MIX(sc), 0, sizeof(MIX(sc))); 3001184610Salfred 3002244567Shselasky MIX(sc).wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 3003244567Shselasky uaudio20_mixer_determine_class(&iot[id], &MIX(sc)); 3004244567Shselasky MIX(sc).type = MIX_SIGNED_16; 3005184610Salfred 3006240609Shselasky if (uaudio20_mixer_verify_desc(d0, ((ichs * ochs) + 7) / 8) == NULL) 3007184610Salfred return; 3008240609Shselasky 3009184610Salfred for (p = i = 0; i < d0->bNrInPins; i++) { 3010240609Shselasky chs = uaudio20_mixer_get_cluster( 3011240609Shselasky d0->baSourceId[i], iot).bNrChannels; 3012184610Salfred mc = 0; 3013184610Salfred for (c = 0; c < chs; c++) { 3014184610Salfred mo = 0; 3015184610Salfred for (o = 0; o < ochs; o++) { 3016184610Salfred bno = ((p + c) * ochs) + o; 3017240609Shselasky if (BIT_TEST(d1->bmControls, bno)) 3018184610Salfred mo++; 3019184610Salfred } 3020240609Shselasky if (mo == 1) 3021184610Salfred mc++; 3022184610Salfred } 3023184610Salfred if ((mc == chs) && (chs <= MIX_MAX_CHAN)) { 3024184610Salfred 3025184610Salfred /* repeat bit-scan */ 3026184610Salfred 3027184610Salfred mc = 0; 3028184610Salfred for (c = 0; c < chs; c++) { 3029184610Salfred for (o = 0; o < ochs; o++) { 3030184610Salfred bno = ((p + c) * ochs) + o; 3031240609Shselasky if (BIT_TEST(d1->bmControls, bno)) 3032244567Shselasky MIX(sc).wValue[mc++] = MAKE_WORD(p + c + 1, o + 1); 3033184610Salfred } 3034184610Salfred } 3035244567Shselasky MIX(sc).nchan = chs; 3036244567Shselasky uaudio_mixer_add_ctl(sc, &MIX(sc)); 3037184610Salfred } 3038184610Salfred p += chs; 3039184610Salfred } 3040184610Salfred} 3041184610Salfred 3042184610Salfredstatic void 3043184610Salfreduaudio_mixer_add_selector(struct uaudio_softc *sc, 3044184610Salfred const struct uaudio_terminal_node *iot, int id) 3045184610Salfred{ 3046240609Shselasky const struct usb_audio_selector_unit *d = iot[id].u.su_v1; 3047184610Salfred uint16_t i; 3048184610Salfred 3049184610Salfred DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n", 3050184610Salfred d->bUnitId, d->bNrInPins); 3051184610Salfred 3052242438Shselasky if (d->bNrInPins == 0) 3053184610Salfred return; 3054242438Shselasky 3055244567Shselasky memset(&MIX(sc), 0, sizeof(MIX(sc))); 3056184610Salfred 3057244567Shselasky MIX(sc).wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no); 3058244567Shselasky MIX(sc).wValue[0] = MAKE_WORD(0, 0); 3059244567Shselasky uaudio_mixer_determine_class(&iot[id], &MIX(sc)); 3060244567Shselasky MIX(sc).nchan = 1; 3061244567Shselasky MIX(sc).type = MIX_SELECTOR; 3062244567Shselasky MIX(sc).ctl = SOUND_MIXER_NRDEVICES; 3063244567Shselasky MIX(sc).minval = 1; 3064244567Shselasky MIX(sc).maxval = d->bNrInPins; 3065244567Shselasky MIX(sc).name = "selector"; 3066184610Salfred 3067242438Shselasky i = d->baSourceId[d->bNrInPins]; 3068242438Shselasky if (i == 0 || 3069242438Shselasky usbd_req_get_string_any(sc->sc_udev, NULL, 3070244567Shselasky MIX(sc).desc, sizeof(MIX(sc).desc), i) != 0) { 3071244567Shselasky MIX(sc).desc[0] = 0; 3072242438Shselasky } 3073242438Shselasky 3074244567Shselasky if (MIX(sc).maxval > MAX_SELECTOR_INPUT_PIN) { 3075244567Shselasky MIX(sc).maxval = MAX_SELECTOR_INPUT_PIN; 3076184610Salfred } 3077244567Shselasky MIX(sc).mul = (MIX(sc).maxval - MIX(sc).minval); 3078184610Salfred for (i = 0; i < MAX_SELECTOR_INPUT_PIN; i++) { 3079244567Shselasky MIX(sc).slctrtype[i] = SOUND_MIXER_NRDEVICES; 3080184610Salfred } 3081184610Salfred 3082244567Shselasky for (i = 0; i < MIX(sc).maxval; i++) { 3083244567Shselasky MIX(sc).slctrtype[i] = uaudio_mixer_feature_name( 3084244567Shselasky &iot[d->baSourceId[i]], &MIX(sc)); 3085184610Salfred } 3086184610Salfred 3087244567Shselasky MIX(sc).class = 0; /* not used */ 3088184610Salfred 3089244567Shselasky uaudio_mixer_add_ctl(sc, &MIX(sc)); 3090184610Salfred} 3091184610Salfred 3092240609Shselaskystatic void 3093240609Shselaskyuaudio20_mixer_add_selector(struct uaudio_softc *sc, 3094240609Shselasky const struct uaudio_terminal_node *iot, int id) 3095240609Shselasky{ 3096240609Shselasky const struct usb_audio20_selector_unit *d = iot[id].u.su_v2; 3097240609Shselasky uint16_t i; 3098240609Shselasky 3099240609Shselasky DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n", 3100240609Shselasky d->bUnitId, d->bNrInPins); 3101240609Shselasky 3102240609Shselasky if (d->bNrInPins == 0) 3103240609Shselasky return; 3104240609Shselasky 3105244567Shselasky memset(&MIX(sc), 0, sizeof(MIX(sc))); 3106240609Shselasky 3107244567Shselasky MIX(sc).wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no); 3108244567Shselasky MIX(sc).wValue[0] = MAKE_WORD(0, 0); 3109244567Shselasky uaudio20_mixer_determine_class(&iot[id], &MIX(sc)); 3110244567Shselasky MIX(sc).nchan = 1; 3111244567Shselasky MIX(sc).type = MIX_SELECTOR; 3112244567Shselasky MIX(sc).ctl = SOUND_MIXER_NRDEVICES; 3113244567Shselasky MIX(sc).minval = 1; 3114244567Shselasky MIX(sc).maxval = d->bNrInPins; 3115244567Shselasky MIX(sc).name = "selector"; 3116240609Shselasky 3117242438Shselasky i = d->baSourceId[d->bNrInPins]; 3118242438Shselasky if (i == 0 || 3119242438Shselasky usbd_req_get_string_any(sc->sc_udev, NULL, 3120244567Shselasky MIX(sc).desc, sizeof(MIX(sc).desc), i) != 0) { 3121244567Shselasky MIX(sc).desc[0] = 0; 3122242438Shselasky } 3123242438Shselasky 3124244567Shselasky if (MIX(sc).maxval > MAX_SELECTOR_INPUT_PIN) 3125244567Shselasky MIX(sc).maxval = MAX_SELECTOR_INPUT_PIN; 3126240609Shselasky 3127244567Shselasky MIX(sc).mul = (MIX(sc).maxval - MIX(sc).minval); 3128240609Shselasky for (i = 0; i < MAX_SELECTOR_INPUT_PIN; i++) 3129244567Shselasky MIX(sc).slctrtype[i] = SOUND_MIXER_NRDEVICES; 3130240609Shselasky 3131244567Shselasky for (i = 0; i < MIX(sc).maxval; i++) { 3132244567Shselasky MIX(sc).slctrtype[i] = uaudio20_mixer_feature_name( 3133244567Shselasky &iot[d->baSourceId[i]], &MIX(sc)); 3134240609Shselasky } 3135240609Shselasky 3136244567Shselasky MIX(sc).class = 0; /* not used */ 3137240609Shselasky 3138244567Shselasky uaudio_mixer_add_ctl(sc, &MIX(sc)); 3139240609Shselasky} 3140240609Shselasky 3141184610Salfredstatic uint32_t 3142203678Sbrucecuaudio_mixer_feature_get_bmaControls(const struct usb_audio_feature_unit *d, 3143233774Shselasky uint8_t i) 3144184610Salfred{ 3145184610Salfred uint32_t temp = 0; 3146233774Shselasky uint32_t offset = (i * d->bControlSize); 3147184610Salfred 3148184610Salfred if (d->bControlSize > 0) { 3149184610Salfred temp |= d->bmaControls[offset]; 3150184610Salfred if (d->bControlSize > 1) { 3151184610Salfred temp |= d->bmaControls[offset + 1] << 8; 3152184610Salfred if (d->bControlSize > 2) { 3153184610Salfred temp |= d->bmaControls[offset + 2] << 16; 3154184610Salfred if (d->bControlSize > 3) { 3155184610Salfred temp |= d->bmaControls[offset + 3] << 24; 3156184610Salfred } 3157184610Salfred } 3158184610Salfred } 3159184610Salfred } 3160184610Salfred return (temp); 3161184610Salfred} 3162184610Salfred 3163184610Salfredstatic void 3164184610Salfreduaudio_mixer_add_feature(struct uaudio_softc *sc, 3165184610Salfred const struct uaudio_terminal_node *iot, int id) 3166184610Salfred{ 3167240609Shselasky const struct usb_audio_feature_unit *d = iot[id].u.fu_v1; 3168184610Salfred uint32_t fumask; 3169184610Salfred uint32_t mmask; 3170184610Salfred uint32_t cmask; 3171184610Salfred uint16_t mixernumber; 3172184610Salfred uint8_t nchan; 3173184610Salfred uint8_t chan; 3174184610Salfred uint8_t ctl; 3175184610Salfred uint8_t i; 3176184610Salfred 3177242438Shselasky if (d->bControlSize == 0) 3178184610Salfred return; 3179242438Shselasky 3180244567Shselasky memset(&MIX(sc), 0, sizeof(MIX(sc))); 3181184610Salfred 3182184610Salfred nchan = (d->bLength - 7) / d->bControlSize; 3183184610Salfred mmask = uaudio_mixer_feature_get_bmaControls(d, 0); 3184184610Salfred cmask = 0; 3185184610Salfred 3186242438Shselasky if (nchan == 0) 3187184610Salfred return; 3188242438Shselasky 3189184610Salfred /* figure out what we can control */ 3190184610Salfred 3191184610Salfred for (chan = 1; chan < nchan; chan++) { 3192184610Salfred DPRINTFN(10, "chan=%d mask=%x\n", 3193184610Salfred chan, uaudio_mixer_feature_get_bmaControls(d, chan)); 3194184610Salfred 3195184610Salfred cmask |= uaudio_mixer_feature_get_bmaControls(d, chan); 3196184610Salfred } 3197184610Salfred 3198184610Salfred if (nchan > MIX_MAX_CHAN) { 3199184610Salfred nchan = MIX_MAX_CHAN; 3200184610Salfred } 3201244567Shselasky MIX(sc).wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no); 3202184610Salfred 3203242438Shselasky i = d->bmaControls[d->bControlSize]; 3204242438Shselasky if (i == 0 || 3205242438Shselasky usbd_req_get_string_any(sc->sc_udev, NULL, 3206244567Shselasky MIX(sc).desc, sizeof(MIX(sc).desc), i) != 0) { 3207244567Shselasky MIX(sc).desc[0] = 0; 3208242438Shselasky } 3209242438Shselasky 3210184610Salfred for (ctl = 1; ctl <= LOUDNESS_CONTROL; ctl++) { 3211184610Salfred 3212184610Salfred fumask = FU_MASK(ctl); 3213184610Salfred 3214184610Salfred DPRINTFN(5, "ctl=%d fumask=0x%04x\n", 3215184610Salfred ctl, fumask); 3216184610Salfred 3217184610Salfred if (mmask & fumask) { 3218244567Shselasky MIX(sc).nchan = 1; 3219244567Shselasky MIX(sc).wValue[0] = MAKE_WORD(ctl, 0); 3220184610Salfred } else if (cmask & fumask) { 3221244567Shselasky MIX(sc).nchan = nchan - 1; 3222184610Salfred for (i = 1; i < nchan; i++) { 3223184610Salfred if (uaudio_mixer_feature_get_bmaControls(d, i) & fumask) 3224244567Shselasky MIX(sc).wValue[i - 1] = MAKE_WORD(ctl, i); 3225184610Salfred else 3226244567Shselasky MIX(sc).wValue[i - 1] = -1; 3227184610Salfred } 3228184610Salfred } else { 3229184610Salfred continue; 3230184610Salfred } 3231184610Salfred 3232244567Shselasky mixernumber = uaudio_mixer_feature_name(&iot[id], &MIX(sc)); 3233184610Salfred 3234184610Salfred switch (ctl) { 3235184610Salfred case MUTE_CONTROL: 3236244567Shselasky MIX(sc).type = MIX_ON_OFF; 3237244567Shselasky MIX(sc).ctl = SOUND_MIXER_NRDEVICES; 3238244567Shselasky MIX(sc).name = "mute"; 3239184610Salfred break; 3240184610Salfred 3241184610Salfred case VOLUME_CONTROL: 3242244567Shselasky MIX(sc).type = MIX_SIGNED_16; 3243244567Shselasky MIX(sc).ctl = mixernumber; 3244244567Shselasky MIX(sc).name = "vol"; 3245184610Salfred break; 3246184610Salfred 3247184610Salfred case BASS_CONTROL: 3248244567Shselasky MIX(sc).type = MIX_SIGNED_8; 3249244567Shselasky MIX(sc).ctl = SOUND_MIXER_BASS; 3250244567Shselasky MIX(sc).name = "bass"; 3251184610Salfred break; 3252184610Salfred 3253184610Salfred case MID_CONTROL: 3254244567Shselasky MIX(sc).type = MIX_SIGNED_8; 3255244567Shselasky MIX(sc).ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 3256244567Shselasky MIX(sc).name = "mid"; 3257184610Salfred break; 3258184610Salfred 3259184610Salfred case TREBLE_CONTROL: 3260244567Shselasky MIX(sc).type = MIX_SIGNED_8; 3261244567Shselasky MIX(sc).ctl = SOUND_MIXER_TREBLE; 3262244567Shselasky MIX(sc).name = "treble"; 3263184610Salfred break; 3264184610Salfred 3265184610Salfred case GRAPHIC_EQUALIZER_CONTROL: 3266184610Salfred continue; /* XXX don't add anything */ 3267184610Salfred 3268184610Salfred case AGC_CONTROL: 3269244567Shselasky MIX(sc).type = MIX_ON_OFF; 3270244567Shselasky MIX(sc).ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 3271244567Shselasky MIX(sc).name = "agc"; 3272184610Salfred break; 3273184610Salfred 3274184610Salfred case DELAY_CONTROL: 3275244567Shselasky MIX(sc).type = MIX_UNSIGNED_16; 3276244567Shselasky MIX(sc).ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 3277244567Shselasky MIX(sc).name = "delay"; 3278184610Salfred break; 3279184610Salfred 3280184610Salfred case BASS_BOOST_CONTROL: 3281244567Shselasky MIX(sc).type = MIX_ON_OFF; 3282244567Shselasky MIX(sc).ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 3283244567Shselasky MIX(sc).name = "boost"; 3284184610Salfred break; 3285184610Salfred 3286184610Salfred case LOUDNESS_CONTROL: 3287244567Shselasky MIX(sc).type = MIX_ON_OFF; 3288244567Shselasky MIX(sc).ctl = SOUND_MIXER_LOUD; /* Is this correct ? */ 3289244567Shselasky MIX(sc).name = "loudness"; 3290184610Salfred break; 3291184610Salfred 3292184610Salfred default: 3293244567Shselasky MIX(sc).type = MIX_UNKNOWN; 3294184610Salfred break; 3295184610Salfred } 3296184610Salfred 3297244567Shselasky if (MIX(sc).type != MIX_UNKNOWN) 3298244567Shselasky uaudio_mixer_add_ctl(sc, &MIX(sc)); 3299240609Shselasky } 3300240609Shselasky} 3301240609Shselasky 3302240609Shselaskystatic void 3303240609Shselaskyuaudio20_mixer_add_feature(struct uaudio_softc *sc, 3304240609Shselasky const struct uaudio_terminal_node *iot, int id) 3305240609Shselasky{ 3306240609Shselasky const struct usb_audio20_feature_unit *d = iot[id].u.fu_v2; 3307240609Shselasky uint32_t ctl; 3308240609Shselasky uint32_t mmask; 3309240609Shselasky uint32_t cmask; 3310240609Shselasky uint16_t mixernumber; 3311240609Shselasky uint8_t nchan; 3312240609Shselasky uint8_t chan; 3313240609Shselasky uint8_t i; 3314240609Shselasky uint8_t what; 3315240609Shselasky 3316240609Shselasky if (UGETDW(d->bmaControls[0]) == 0) 3317240609Shselasky return; 3318240609Shselasky 3319244567Shselasky memset(&MIX(sc), 0, sizeof(MIX(sc))); 3320240609Shselasky 3321240609Shselasky nchan = (d->bLength - 6) / 4; 3322240609Shselasky mmask = UGETDW(d->bmaControls[0]); 3323240609Shselasky cmask = 0; 3324240609Shselasky 3325240609Shselasky if (nchan == 0) 3326240609Shselasky return; 3327240609Shselasky 3328240609Shselasky /* figure out what we can control */ 3329240609Shselasky 3330240609Shselasky for (chan = 1; chan < nchan; chan++) 3331240609Shselasky cmask |= UGETDW(d->bmaControls[chan]); 3332240609Shselasky 3333240609Shselasky if (nchan > MIX_MAX_CHAN) 3334240609Shselasky nchan = MIX_MAX_CHAN; 3335240609Shselasky 3336244567Shselasky MIX(sc).wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no); 3337240609Shselasky 3338242438Shselasky i = d->bmaControls[nchan][0]; 3339242438Shselasky if (i == 0 || 3340242438Shselasky usbd_req_get_string_any(sc->sc_udev, NULL, 3341244567Shselasky MIX(sc).desc, sizeof(MIX(sc).desc), i) != 0) { 3342244567Shselasky MIX(sc).desc[0] = 0; 3343242438Shselasky } 3344242438Shselasky 3345240609Shselasky for (ctl = 3; ctl != 0; ctl <<= 2) { 3346240609Shselasky 3347244567Shselasky mixernumber = uaudio20_mixer_feature_name(&iot[id], &MIX(sc)); 3348240609Shselasky 3349240609Shselasky switch (ctl) { 3350240609Shselasky case (3 << 0): 3351244567Shselasky MIX(sc).type = MIX_ON_OFF; 3352244567Shselasky MIX(sc).ctl = SOUND_MIXER_NRDEVICES; 3353244567Shselasky MIX(sc).name = "mute"; 3354240609Shselasky what = MUTE_CONTROL; 3355240609Shselasky break; 3356240609Shselasky case (3 << 2): 3357244567Shselasky MIX(sc).type = MIX_SIGNED_16; 3358244567Shselasky MIX(sc).ctl = mixernumber; 3359244567Shselasky MIX(sc).name = "vol"; 3360240609Shselasky what = VOLUME_CONTROL; 3361240609Shselasky break; 3362240609Shselasky case (3 << 4): 3363244567Shselasky MIX(sc).type = MIX_SIGNED_8; 3364244567Shselasky MIX(sc).ctl = SOUND_MIXER_BASS; 3365244567Shselasky MIX(sc).name = "bass"; 3366240609Shselasky what = BASS_CONTROL; 3367240609Shselasky break; 3368240609Shselasky case (3 << 6): 3369244567Shselasky MIX(sc).type = MIX_SIGNED_8; 3370244567Shselasky MIX(sc).ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 3371244567Shselasky MIX(sc).name = "mid"; 3372240609Shselasky what = MID_CONTROL; 3373240609Shselasky break; 3374240609Shselasky case (3 << 8): 3375244567Shselasky MIX(sc).type = MIX_SIGNED_8; 3376244567Shselasky MIX(sc).ctl = SOUND_MIXER_TREBLE; 3377244567Shselasky MIX(sc).name = "treble"; 3378240609Shselasky what = TREBLE_CONTROL; 3379240609Shselasky break; 3380240609Shselasky case (3 << 12): 3381244567Shselasky MIX(sc).type = MIX_ON_OFF; 3382244567Shselasky MIX(sc).ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 3383244567Shselasky MIX(sc).name = "agc"; 3384240609Shselasky what = AGC_CONTROL; 3385240609Shselasky break; 3386240609Shselasky case (3 << 14): 3387244567Shselasky MIX(sc).type = MIX_UNSIGNED_16; 3388244567Shselasky MIX(sc).ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 3389244567Shselasky MIX(sc).name = "delay"; 3390240609Shselasky what = DELAY_CONTROL; 3391240609Shselasky break; 3392240609Shselasky case (3 << 16): 3393244567Shselasky MIX(sc).type = MIX_ON_OFF; 3394244567Shselasky MIX(sc).ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 3395244567Shselasky MIX(sc).name = "boost"; 3396240609Shselasky what = BASS_BOOST_CONTROL; 3397240609Shselasky break; 3398240609Shselasky case (3 << 18): 3399244567Shselasky MIX(sc).type = MIX_ON_OFF; 3400244567Shselasky MIX(sc).ctl = SOUND_MIXER_LOUD; /* Is this correct ? */ 3401244567Shselasky MIX(sc).name = "loudness"; 3402240609Shselasky what = LOUDNESS_CONTROL; 3403240609Shselasky break; 3404240609Shselasky case (3 << 20): 3405244567Shselasky MIX(sc).type = MIX_SIGNED_16; 3406244567Shselasky MIX(sc).ctl = mixernumber; 3407244567Shselasky MIX(sc).name = "igain"; 3408240609Shselasky what = INPUT_GAIN_CONTROL; 3409240609Shselasky break; 3410240609Shselasky case (3 << 22): 3411244567Shselasky MIX(sc).type = MIX_SIGNED_16; 3412244567Shselasky MIX(sc).ctl = mixernumber; 3413244567Shselasky MIX(sc).name = "igainpad"; 3414240609Shselasky what = INPUT_GAIN_PAD_CONTROL; 3415240609Shselasky break; 3416240609Shselasky default: 3417240609Shselasky continue; 3418184610Salfred } 3419240609Shselasky 3420240609Shselasky if ((mmask & ctl) == ctl) { 3421244567Shselasky MIX(sc).nchan = 1; 3422244567Shselasky MIX(sc).wValue[0] = MAKE_WORD(what, 0); 3423240609Shselasky } else if ((cmask & ctl) == ctl) { 3424244567Shselasky MIX(sc).nchan = nchan - 1; 3425240609Shselasky for (i = 1; i < nchan; i++) { 3426240609Shselasky if ((UGETDW(d->bmaControls[i]) & ctl) == ctl) 3427244567Shselasky MIX(sc).wValue[i - 1] = MAKE_WORD(what, i); 3428240609Shselasky else 3429244567Shselasky MIX(sc).wValue[i - 1] = -1; 3430240609Shselasky } 3431240609Shselasky } else { 3432240609Shselasky continue; 3433240609Shselasky } 3434240609Shselasky 3435244567Shselasky if (MIX(sc).type != MIX_UNKNOWN) 3436244567Shselasky uaudio_mixer_add_ctl(sc, &MIX(sc)); 3437184610Salfred } 3438184610Salfred} 3439184610Salfred 3440184610Salfredstatic void 3441184610Salfreduaudio_mixer_add_processing_updown(struct uaudio_softc *sc, 3442184610Salfred const struct uaudio_terminal_node *iot, int id) 3443184610Salfred{ 3444240609Shselasky const struct usb_audio_processing_unit_0 *d0 = iot[id].u.pu_v1; 3445203678Sbrucec const struct usb_audio_processing_unit_1 *d1 = 3446244567Shselasky (const void *)(d0->baSourceId + d0->bNrInPins); 3447203678Sbrucec const struct usb_audio_processing_unit_updown *ud = 3448244567Shselasky (const void *)(d1->bmControls + d1->bControlSize); 3449184610Salfred uint8_t i; 3450184610Salfred 3451184610Salfred if (uaudio_mixer_verify_desc(d0, sizeof(*ud)) == NULL) { 3452184610Salfred return; 3453184610Salfred } 3454184610Salfred if (uaudio_mixer_verify_desc(d0, sizeof(*ud) + (2 * ud->bNrModes)) 3455184610Salfred == NULL) { 3456184610Salfred return; 3457184610Salfred } 3458184610Salfred DPRINTFN(3, "bUnitId=%d bNrModes=%d\n", 3459184610Salfred d0->bUnitId, ud->bNrModes); 3460184610Salfred 3461184610Salfred if (!(d1->bmControls[0] & UA_PROC_MASK(UD_MODE_SELECT_CONTROL))) { 3462184610Salfred DPRINTF("no mode select\n"); 3463184610Salfred return; 3464184610Salfred } 3465244567Shselasky memset(&MIX(sc), 0, sizeof(MIX(sc))); 3466184610Salfred 3467244567Shselasky MIX(sc).wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 3468244567Shselasky MIX(sc).nchan = 1; 3469244567Shselasky MIX(sc).wValue[0] = MAKE_WORD(UD_MODE_SELECT_CONTROL, 0); 3470244567Shselasky uaudio_mixer_determine_class(&iot[id], &MIX(sc)); 3471244567Shselasky MIX(sc).type = MIX_ON_OFF; /* XXX */ 3472184610Salfred 3473184610Salfred for (i = 0; i < ud->bNrModes; i++) { 3474184610Salfred DPRINTFN(3, "i=%d bm=0x%x\n", i, UGETW(ud->waModes[i])); 3475184610Salfred /* XXX */ 3476184610Salfred } 3477184610Salfred 3478244567Shselasky uaudio_mixer_add_ctl(sc, &MIX(sc)); 3479184610Salfred} 3480184610Salfred 3481184610Salfredstatic void 3482184610Salfreduaudio_mixer_add_processing(struct uaudio_softc *sc, 3483184610Salfred const struct uaudio_terminal_node *iot, int id) 3484184610Salfred{ 3485240609Shselasky const struct usb_audio_processing_unit_0 *d0 = iot[id].u.pu_v1; 3486203678Sbrucec const struct usb_audio_processing_unit_1 *d1 = 3487244567Shselasky (const void *)(d0->baSourceId + d0->bNrInPins); 3488184610Salfred uint16_t ptype; 3489184610Salfred 3490244567Shselasky memset(&MIX(sc), 0, sizeof(MIX(sc))); 3491184610Salfred 3492184610Salfred ptype = UGETW(d0->wProcessType); 3493184610Salfred 3494184610Salfred DPRINTFN(3, "wProcessType=%d bUnitId=%d " 3495184610Salfred "bNrInPins=%d\n", ptype, d0->bUnitId, d0->bNrInPins); 3496184610Salfred 3497184610Salfred if (d1->bControlSize == 0) { 3498184610Salfred return; 3499184610Salfred } 3500184610Salfred if (d1->bmControls[0] & UA_PROC_ENABLE_MASK) { 3501244567Shselasky MIX(sc).wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 3502244567Shselasky MIX(sc).nchan = 1; 3503244567Shselasky MIX(sc).wValue[0] = MAKE_WORD(XX_ENABLE_CONTROL, 0); 3504244567Shselasky uaudio_mixer_determine_class(&iot[id], &MIX(sc)); 3505244567Shselasky MIX(sc).type = MIX_ON_OFF; 3506244567Shselasky uaudio_mixer_add_ctl(sc, &MIX(sc)); 3507184610Salfred } 3508184610Salfred switch (ptype) { 3509184610Salfred case UPDOWNMIX_PROCESS: 3510184610Salfred uaudio_mixer_add_processing_updown(sc, iot, id); 3511184610Salfred break; 3512184610Salfred 3513184610Salfred case DOLBY_PROLOGIC_PROCESS: 3514184610Salfred case P3D_STEREO_EXTENDER_PROCESS: 3515184610Salfred case REVERBATION_PROCESS: 3516184610Salfred case CHORUS_PROCESS: 3517184610Salfred case DYN_RANGE_COMP_PROCESS: 3518184610Salfred default: 3519184610Salfred DPRINTF("unit %d, type=%d is not implemented\n", 3520184610Salfred d0->bUnitId, ptype); 3521184610Salfred break; 3522184610Salfred } 3523184610Salfred} 3524184610Salfred 3525184610Salfredstatic void 3526184610Salfreduaudio_mixer_add_extension(struct uaudio_softc *sc, 3527184610Salfred const struct uaudio_terminal_node *iot, int id) 3528184610Salfred{ 3529240609Shselasky const struct usb_audio_extension_unit_0 *d0 = iot[id].u.eu_v1; 3530203678Sbrucec const struct usb_audio_extension_unit_1 *d1 = 3531244567Shselasky (const void *)(d0->baSourceId + d0->bNrInPins); 3532184610Salfred 3533184610Salfred DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n", 3534184610Salfred d0->bUnitId, d0->bNrInPins); 3535184610Salfred 3536184610Salfred if (sc->sc_uq_au_no_xu) { 3537184610Salfred return; 3538184610Salfred } 3539184610Salfred if (d1->bControlSize == 0) { 3540184610Salfred return; 3541184610Salfred } 3542184610Salfred if (d1->bmControls[0] & UA_EXT_ENABLE_MASK) { 3543184610Salfred 3544244567Shselasky memset(&MIX(sc), 0, sizeof(MIX(sc))); 3545184610Salfred 3546244567Shselasky MIX(sc).wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 3547244567Shselasky MIX(sc).nchan = 1; 3548244567Shselasky MIX(sc).wValue[0] = MAKE_WORD(UA_EXT_ENABLE, 0); 3549244567Shselasky uaudio_mixer_determine_class(&iot[id], &MIX(sc)); 3550244567Shselasky MIX(sc).type = MIX_ON_OFF; 3551184610Salfred 3552244567Shselasky uaudio_mixer_add_ctl(sc, &MIX(sc)); 3553184610Salfred } 3554184610Salfred} 3555184610Salfred 3556184610Salfredstatic const void * 3557184610Salfreduaudio_mixer_verify_desc(const void *arg, uint32_t len) 3558184610Salfred{ 3559203678Sbrucec const struct usb_audio_mixer_unit_1 *d1; 3560203678Sbrucec const struct usb_audio_extension_unit_1 *e1; 3561203678Sbrucec const struct usb_audio_processing_unit_1 *u1; 3562184610Salfred 3563184610Salfred union { 3564192984Sthompsa const struct usb_descriptor *desc; 3565203678Sbrucec const struct usb_audio_input_terminal *it; 3566203678Sbrucec const struct usb_audio_output_terminal *ot; 3567203678Sbrucec const struct usb_audio_mixer_unit_0 *mu; 3568203678Sbrucec const struct usb_audio_selector_unit *su; 3569203678Sbrucec const struct usb_audio_feature_unit *fu; 3570203678Sbrucec const struct usb_audio_processing_unit_0 *pu; 3571203678Sbrucec const struct usb_audio_extension_unit_0 *eu; 3572184610Salfred } u; 3573184610Salfred 3574184610Salfred u.desc = arg; 3575184610Salfred 3576184610Salfred if (u.desc == NULL) { 3577184610Salfred goto error; 3578184610Salfred } 3579184610Salfred if (u.desc->bDescriptorType != UDESC_CS_INTERFACE) { 3580184610Salfred goto error; 3581184610Salfred } 3582184610Salfred switch (u.desc->bDescriptorSubtype) { 3583184610Salfred case UDESCSUB_AC_INPUT: 3584184610Salfred len += sizeof(*u.it); 3585184610Salfred break; 3586184610Salfred 3587184610Salfred case UDESCSUB_AC_OUTPUT: 3588184610Salfred len += sizeof(*u.ot); 3589184610Salfred break; 3590184610Salfred 3591184610Salfred case UDESCSUB_AC_MIXER: 3592184610Salfred len += sizeof(*u.mu); 3593184610Salfred 3594184610Salfred if (u.desc->bLength < len) { 3595184610Salfred goto error; 3596184610Salfred } 3597184610Salfred len += u.mu->bNrInPins; 3598184610Salfred 3599184610Salfred if (u.desc->bLength < len) { 3600184610Salfred goto error; 3601184610Salfred } 3602184610Salfred d1 = (const void *)(u.mu->baSourceId + u.mu->bNrInPins); 3603184610Salfred 3604184610Salfred len += sizeof(*d1); 3605184610Salfred break; 3606184610Salfred 3607184610Salfred case UDESCSUB_AC_SELECTOR: 3608184610Salfred len += sizeof(*u.su); 3609184610Salfred 3610184610Salfred if (u.desc->bLength < len) { 3611184610Salfred goto error; 3612184610Salfred } 3613242438Shselasky len += u.su->bNrInPins + 1; 3614184610Salfred break; 3615184610Salfred 3616184610Salfred case UDESCSUB_AC_FEATURE: 3617242438Shselasky len += sizeof(*u.fu) + 1; 3618242438Shselasky 3619242438Shselasky if (u.desc->bLength < len) 3620242438Shselasky goto error; 3621242438Shselasky 3622242438Shselasky len += u.fu->bControlSize; 3623184610Salfred break; 3624184610Salfred 3625184610Salfred case UDESCSUB_AC_PROCESSING: 3626184610Salfred len += sizeof(*u.pu); 3627184610Salfred 3628184610Salfred if (u.desc->bLength < len) { 3629184610Salfred goto error; 3630184610Salfred } 3631184610Salfred len += u.pu->bNrInPins; 3632184610Salfred 3633184610Salfred if (u.desc->bLength < len) { 3634184610Salfred goto error; 3635184610Salfred } 3636184610Salfred u1 = (const void *)(u.pu->baSourceId + u.pu->bNrInPins); 3637184610Salfred 3638184610Salfred len += sizeof(*u1); 3639184610Salfred 3640184610Salfred if (u.desc->bLength < len) { 3641184610Salfred goto error; 3642184610Salfred } 3643184610Salfred len += u1->bControlSize; 3644184610Salfred 3645184610Salfred break; 3646184610Salfred 3647184610Salfred case UDESCSUB_AC_EXTENSION: 3648184610Salfred len += sizeof(*u.eu); 3649184610Salfred 3650184610Salfred if (u.desc->bLength < len) { 3651184610Salfred goto error; 3652184610Salfred } 3653184610Salfred len += u.eu->bNrInPins; 3654184610Salfred 3655184610Salfred if (u.desc->bLength < len) { 3656184610Salfred goto error; 3657184610Salfred } 3658184610Salfred e1 = (const void *)(u.eu->baSourceId + u.eu->bNrInPins); 3659184610Salfred 3660184610Salfred len += sizeof(*e1); 3661184610Salfred 3662184610Salfred if (u.desc->bLength < len) { 3663184610Salfred goto error; 3664184610Salfred } 3665184610Salfred len += e1->bControlSize; 3666184610Salfred break; 3667184610Salfred 3668184610Salfred default: 3669184610Salfred goto error; 3670184610Salfred } 3671184610Salfred 3672184610Salfred if (u.desc->bLength < len) { 3673184610Salfred goto error; 3674184610Salfred } 3675184610Salfred return (u.desc); 3676184610Salfred 3677184610Salfrederror: 3678184610Salfred if (u.desc) { 3679184610Salfred DPRINTF("invalid descriptor, type=%d, " 3680184610Salfred "sub_type=%d, len=%d of %d bytes\n", 3681184610Salfred u.desc->bDescriptorType, 3682184610Salfred u.desc->bDescriptorSubtype, 3683184610Salfred u.desc->bLength, len); 3684184610Salfred } 3685184610Salfred return (NULL); 3686184610Salfred} 3687184610Salfred 3688240609Shselaskystatic const void * 3689240609Shselaskyuaudio20_mixer_verify_desc(const void *arg, uint32_t len) 3690184610Salfred{ 3691240609Shselasky const struct usb_audio20_mixer_unit_1 *d1; 3692240609Shselasky const struct usb_audio20_extension_unit_1 *e1; 3693240609Shselasky const struct usb_audio20_processing_unit_1 *u1; 3694240609Shselasky const struct usb_audio20_clock_selector_unit_1 *c1; 3695184610Salfred 3696240609Shselasky union { 3697240609Shselasky const struct usb_descriptor *desc; 3698240609Shselasky const struct usb_audio20_clock_source_unit *csrc; 3699240609Shselasky const struct usb_audio20_clock_selector_unit_0 *csel; 3700240609Shselasky const struct usb_audio20_clock_multiplier_unit *cmul; 3701240609Shselasky const struct usb_audio20_input_terminal *it; 3702240609Shselasky const struct usb_audio20_output_terminal *ot; 3703240609Shselasky const struct usb_audio20_mixer_unit_0 *mu; 3704240609Shselasky const struct usb_audio20_selector_unit *su; 3705240609Shselasky const struct usb_audio20_feature_unit *fu; 3706240609Shselasky const struct usb_audio20_sample_rate_unit *ru; 3707240609Shselasky const struct usb_audio20_processing_unit_0 *pu; 3708240609Shselasky const struct usb_audio20_extension_unit_0 *eu; 3709240609Shselasky const struct usb_audio20_effect_unit *ef; 3710240609Shselasky } u; 3711184610Salfred 3712240609Shselasky u.desc = arg; 3713184610Salfred 3714240609Shselasky if (u.desc == NULL) 3715240609Shselasky goto error; 3716240609Shselasky 3717240609Shselasky if (u.desc->bDescriptorType != UDESC_CS_INTERFACE) 3718240609Shselasky goto error; 3719240609Shselasky 3720240609Shselasky switch (u.desc->bDescriptorSubtype) { 3721240609Shselasky case UDESCSUB_AC_INPUT: 3722240609Shselasky len += sizeof(*u.it); 3723240609Shselasky break; 3724240609Shselasky 3725240609Shselasky case UDESCSUB_AC_OUTPUT: 3726240609Shselasky len += sizeof(*u.ot); 3727240609Shselasky break; 3728240609Shselasky 3729240609Shselasky case UDESCSUB_AC_MIXER: 3730240609Shselasky len += sizeof(*u.mu); 3731240609Shselasky 3732240609Shselasky if (u.desc->bLength < len) 3733240609Shselasky goto error; 3734240609Shselasky len += u.mu->bNrInPins; 3735240609Shselasky 3736240609Shselasky if (u.desc->bLength < len) 3737240609Shselasky goto error; 3738240609Shselasky 3739240609Shselasky d1 = (const void *)(u.mu->baSourceId + u.mu->bNrInPins); 3740240609Shselasky 3741240609Shselasky len += sizeof(*d1) + d1->bNrChannels; 3742240609Shselasky break; 3743240609Shselasky 3744240609Shselasky case UDESCSUB_AC_SELECTOR: 3745240609Shselasky len += sizeof(*u.su); 3746240609Shselasky 3747240609Shselasky if (u.desc->bLength < len) 3748240609Shselasky goto error; 3749240609Shselasky 3750242438Shselasky len += u.su->bNrInPins + 1; 3751240609Shselasky break; 3752240609Shselasky 3753240609Shselasky case UDESCSUB_AC_FEATURE: 3754240609Shselasky len += sizeof(*u.fu) + 1; 3755240609Shselasky break; 3756240609Shselasky 3757240609Shselasky case UDESCSUB_AC_EFFECT: 3758240609Shselasky len += sizeof(*u.ef) + 4; 3759240609Shselasky break; 3760240609Shselasky 3761240609Shselasky case UDESCSUB_AC_PROCESSING_V2: 3762240609Shselasky len += sizeof(*u.pu); 3763240609Shselasky 3764240609Shselasky if (u.desc->bLength < len) 3765240609Shselasky goto error; 3766240609Shselasky 3767240609Shselasky len += u.pu->bNrInPins; 3768240609Shselasky 3769240609Shselasky if (u.desc->bLength < len) 3770240609Shselasky goto error; 3771240609Shselasky 3772240609Shselasky u1 = (const void *)(u.pu->baSourceId + u.pu->bNrInPins); 3773240609Shselasky 3774240609Shselasky len += sizeof(*u1); 3775240609Shselasky break; 3776240609Shselasky 3777240609Shselasky case UDESCSUB_AC_EXTENSION_V2: 3778240609Shselasky len += sizeof(*u.eu); 3779240609Shselasky 3780240609Shselasky if (u.desc->bLength < len) 3781240609Shselasky goto error; 3782240609Shselasky 3783240609Shselasky len += u.eu->bNrInPins; 3784240609Shselasky 3785240609Shselasky if (u.desc->bLength < len) 3786240609Shselasky goto error; 3787240609Shselasky 3788240609Shselasky e1 = (const void *)(u.eu->baSourceId + u.eu->bNrInPins); 3789240609Shselasky 3790240609Shselasky len += sizeof(*e1); 3791240609Shselasky break; 3792240609Shselasky 3793240609Shselasky case UDESCSUB_AC_CLOCK_SRC: 3794240609Shselasky len += sizeof(*u.csrc); 3795240609Shselasky break; 3796240609Shselasky 3797240609Shselasky case UDESCSUB_AC_CLOCK_SEL: 3798240609Shselasky len += sizeof(*u.csel); 3799240609Shselasky 3800240609Shselasky if (u.desc->bLength < len) 3801240609Shselasky goto error; 3802240609Shselasky 3803240609Shselasky len += u.csel->bNrInPins; 3804240609Shselasky 3805240609Shselasky if (u.desc->bLength < len) 3806240609Shselasky goto error; 3807240609Shselasky 3808240609Shselasky c1 = (const void *)(u.csel->baCSourceId + u.csel->bNrInPins); 3809240609Shselasky 3810240609Shselasky len += sizeof(*c1); 3811240609Shselasky break; 3812240609Shselasky 3813240609Shselasky case UDESCSUB_AC_CLOCK_MUL: 3814240609Shselasky len += sizeof(*u.cmul); 3815240609Shselasky break; 3816240609Shselasky 3817240609Shselasky case UDESCSUB_AC_SAMPLE_RT: 3818240609Shselasky len += sizeof(*u.ru); 3819240609Shselasky break; 3820240609Shselasky 3821240609Shselasky default: 3822240609Shselasky goto error; 3823184610Salfred } 3824240609Shselasky 3825240609Shselasky if (u.desc->bLength < len) 3826240609Shselasky goto error; 3827240609Shselasky 3828240609Shselasky return (u.desc); 3829240609Shselasky 3830240609Shselaskyerror: 3831240609Shselasky if (u.desc) { 3832240609Shselasky DPRINTF("invalid descriptor, type=%d, " 3833240609Shselasky "sub_type=%d, len=%d of %d bytes\n", 3834240609Shselasky u.desc->bDescriptorType, 3835240609Shselasky u.desc->bDescriptorSubtype, 3836240609Shselasky u.desc->bLength, len); 3837240609Shselasky } 3838240609Shselasky return (NULL); 3839184610Salfred} 3840184610Salfred 3841203678Sbrucecstatic struct usb_audio_cluster 3842184610Salfreduaudio_mixer_get_cluster(uint8_t id, const struct uaudio_terminal_node *iot) 3843184610Salfred{ 3844203678Sbrucec struct usb_audio_cluster r; 3845192984Sthompsa const struct usb_descriptor *dp; 3846184610Salfred uint8_t i; 3847184610Salfred 3848184610Salfred for (i = 0; i < UAUDIO_RECURSE_LIMIT; i++) { /* avoid infinite loops */ 3849184610Salfred dp = iot[id].u.desc; 3850184610Salfred if (dp == NULL) { 3851184610Salfred goto error; 3852184610Salfred } 3853184610Salfred switch (dp->bDescriptorSubtype) { 3854184610Salfred case UDESCSUB_AC_INPUT: 3855240609Shselasky r.bNrChannels = iot[id].u.it_v1->bNrChannels; 3856240609Shselasky r.wChannelConfig[0] = iot[id].u.it_v1->wChannelConfig[0]; 3857240609Shselasky r.wChannelConfig[1] = iot[id].u.it_v1->wChannelConfig[1]; 3858240609Shselasky r.iChannelNames = iot[id].u.it_v1->iChannelNames; 3859184610Salfred goto done; 3860184610Salfred 3861184610Salfred case UDESCSUB_AC_OUTPUT: 3862240609Shselasky id = iot[id].u.ot_v1->bSourceId; 3863184610Salfred break; 3864184610Salfred 3865184610Salfred case UDESCSUB_AC_MIXER: 3866203678Sbrucec r = *(const struct usb_audio_cluster *) 3867240609Shselasky &iot[id].u.mu_v1->baSourceId[ 3868240609Shselasky iot[id].u.mu_v1->bNrInPins]; 3869184610Salfred goto done; 3870184610Salfred 3871184610Salfred case UDESCSUB_AC_SELECTOR: 3872240609Shselasky if (iot[id].u.su_v1->bNrInPins > 0) { 3873184610Salfred /* XXX This is not really right */ 3874240609Shselasky id = iot[id].u.su_v1->baSourceId[0]; 3875184610Salfred } 3876184610Salfred break; 3877184610Salfred 3878184610Salfred case UDESCSUB_AC_FEATURE: 3879240609Shselasky id = iot[id].u.fu_v1->bSourceId; 3880184610Salfred break; 3881184610Salfred 3882184610Salfred case UDESCSUB_AC_PROCESSING: 3883203678Sbrucec r = *((const struct usb_audio_cluster *) 3884240609Shselasky &iot[id].u.pu_v1->baSourceId[ 3885240609Shselasky iot[id].u.pu_v1->bNrInPins]); 3886184610Salfred goto done; 3887184610Salfred 3888184610Salfred case UDESCSUB_AC_EXTENSION: 3889203678Sbrucec r = *((const struct usb_audio_cluster *) 3890240609Shselasky &iot[id].u.eu_v1->baSourceId[ 3891240609Shselasky iot[id].u.eu_v1->bNrInPins]); 3892184610Salfred goto done; 3893184610Salfred 3894184610Salfred default: 3895184610Salfred goto error; 3896184610Salfred } 3897184610Salfred } 3898184610Salfrederror: 3899184610Salfred DPRINTF("bad data\n"); 3900218791Shselasky memset(&r, 0, sizeof(r)); 3901184610Salfreddone: 3902184610Salfred return (r); 3903184610Salfred} 3904184610Salfred 3905240609Shselaskystatic struct usb_audio20_cluster 3906240609Shselaskyuaudio20_mixer_get_cluster(uint8_t id, const struct uaudio_terminal_node *iot) 3907240609Shselasky{ 3908240609Shselasky struct usb_audio20_cluster r; 3909240609Shselasky const struct usb_descriptor *dp; 3910240609Shselasky uint8_t i; 3911184610Salfred 3912240609Shselasky for (i = 0; i < UAUDIO_RECURSE_LIMIT; i++) { /* avoid infinite loops */ 3913240609Shselasky dp = iot[id].u.desc; 3914240609Shselasky if (dp == NULL) 3915240609Shselasky goto error; 3916184610Salfred 3917240609Shselasky switch (dp->bDescriptorSubtype) { 3918240609Shselasky case UDESCSUB_AC_INPUT: 3919240609Shselasky r.bNrChannels = iot[id].u.it_v2->bNrChannels; 3920240609Shselasky r.bmChannelConfig[0] = iot[id].u.it_v2->bmChannelConfig[0]; 3921240609Shselasky r.bmChannelConfig[1] = iot[id].u.it_v2->bmChannelConfig[1]; 3922240609Shselasky r.bmChannelConfig[2] = iot[id].u.it_v2->bmChannelConfig[2]; 3923240609Shselasky r.bmChannelConfig[3] = iot[id].u.it_v2->bmChannelConfig[3]; 3924240609Shselasky r.iChannelNames = iot[id].u.it_v2->iTerminal; 3925240609Shselasky goto done; 3926184610Salfred 3927240609Shselasky case UDESCSUB_AC_OUTPUT: 3928240609Shselasky id = iot[id].u.ot_v2->bSourceId; 3929240609Shselasky break; 3930184610Salfred 3931240609Shselasky case UDESCSUB_AC_MIXER: 3932240609Shselasky r = *(const struct usb_audio20_cluster *) 3933240609Shselasky &iot[id].u.mu_v2->baSourceId[ 3934240609Shselasky iot[id].u.mu_v2->bNrInPins]; 3935240609Shselasky goto done; 3936184610Salfred 3937240609Shselasky case UDESCSUB_AC_SELECTOR: 3938240609Shselasky if (iot[id].u.su_v2->bNrInPins > 0) { 3939240609Shselasky /* XXX This is not really right */ 3940240609Shselasky id = iot[id].u.su_v2->baSourceId[0]; 3941240609Shselasky } 3942240609Shselasky break; 3943184610Salfred 3944240609Shselasky case UDESCSUB_AC_SAMPLE_RT: 3945240609Shselasky id = iot[id].u.ru_v2->bSourceId; 3946240609Shselasky break; 3947184610Salfred 3948240609Shselasky case UDESCSUB_AC_EFFECT: 3949240609Shselasky id = iot[id].u.ef_v2->bSourceId; 3950240609Shselasky break; 3951184610Salfred 3952240609Shselasky case UDESCSUB_AC_FEATURE: 3953240609Shselasky id = iot[id].u.fu_v2->bSourceId; 3954240609Shselasky break; 3955184610Salfred 3956240609Shselasky case UDESCSUB_AC_PROCESSING_V2: 3957240609Shselasky r = *((const struct usb_audio20_cluster *) 3958240609Shselasky &iot[id].u.pu_v2->baSourceId[ 3959240609Shselasky iot[id].u.pu_v2->bNrInPins]); 3960240609Shselasky goto done; 3961184610Salfred 3962240609Shselasky case UDESCSUB_AC_EXTENSION_V2: 3963240609Shselasky r = *((const struct usb_audio20_cluster *) 3964240609Shselasky &iot[id].u.eu_v2->baSourceId[ 3965240609Shselasky iot[id].u.eu_v2->bNrInPins]); 3966240609Shselasky goto done; 3967184610Salfred 3968240609Shselasky default: 3969240609Shselasky goto error; 3970184610Salfred } 3971184610Salfred } 3972240609Shselaskyerror: 3973240609Shselasky DPRINTF("Bad data!\n"); 3974240609Shselasky memset(&r, 0, sizeof(r)); 3975240609Shselaskydone: 3976240609Shselasky return (r); 3977184610Salfred} 3978184610Salfred 3979184610Salfredstatic uint16_t 3980184610Salfreduaudio_mixer_determine_class(const struct uaudio_terminal_node *iot, 3981184610Salfred struct uaudio_mixer_node *mix) 3982184610Salfred{ 3983184610Salfred uint16_t terminal_type = 0x0000; 3984184610Salfred const struct uaudio_terminal_node *input[2]; 3985184610Salfred const struct uaudio_terminal_node *output[2]; 3986184610Salfred 3987184610Salfred input[0] = uaudio_mixer_get_input(iot, 0); 3988184610Salfred input[1] = uaudio_mixer_get_input(iot, 1); 3989184610Salfred 3990184610Salfred output[0] = uaudio_mixer_get_output(iot, 0); 3991184610Salfred output[1] = uaudio_mixer_get_output(iot, 1); 3992184610Salfred 3993184610Salfred /* 3994184610Salfred * check if there is only 3995184610Salfred * one output terminal: 3996184610Salfred */ 3997184610Salfred if (output[0] && (!output[1])) { 3998240609Shselasky terminal_type = 3999240609Shselasky UGETW(output[0]->u.ot_v1->wTerminalType); 4000184610Salfred } 4001184610Salfred /* 4002184610Salfred * If the only output terminal is USB, 4003184610Salfred * the class is UAC_RECORD. 4004184610Salfred */ 4005184610Salfred if ((terminal_type & 0xff00) == (UAT_UNDEFINED & 0xff00)) { 4006184610Salfred 4007184610Salfred mix->class = UAC_RECORD; 4008184610Salfred if (input[0] && (!input[1])) { 4009240609Shselasky terminal_type = 4010240609Shselasky UGETW(input[0]->u.it_v1->wTerminalType); 4011184610Salfred } else { 4012184610Salfred terminal_type = 0; 4013184610Salfred } 4014184610Salfred goto done; 4015184610Salfred } 4016184610Salfred /* 4017184610Salfred * if the unit is connected to just 4018184610Salfred * one input terminal, the 4019184610Salfred * class is UAC_INPUT: 4020184610Salfred */ 4021184610Salfred if (input[0] && (!input[1])) { 4022184610Salfred mix->class = UAC_INPUT; 4023240609Shselasky terminal_type = 4024240609Shselasky UGETW(input[0]->u.it_v1->wTerminalType); 4025184610Salfred goto done; 4026184610Salfred } 4027184610Salfred /* 4028184610Salfred * Otherwise, the class is UAC_OUTPUT. 4029184610Salfred */ 4030184610Salfred mix->class = UAC_OUTPUT; 4031184610Salfreddone: 4032184610Salfred return (terminal_type); 4033184610Salfred} 4034184610Salfred 4035240609Shselaskystatic uint16_t 4036240609Shselaskyuaudio20_mixer_determine_class(const struct uaudio_terminal_node *iot, 4037240609Shselasky struct uaudio_mixer_node *mix) 4038240609Shselasky{ 4039240609Shselasky uint16_t terminal_type = 0x0000; 4040240609Shselasky const struct uaudio_terminal_node *input[2]; 4041240609Shselasky const struct uaudio_terminal_node *output[2]; 4042240609Shselasky 4043240609Shselasky input[0] = uaudio_mixer_get_input(iot, 0); 4044240609Shselasky input[1] = uaudio_mixer_get_input(iot, 1); 4045240609Shselasky 4046240609Shselasky output[0] = uaudio_mixer_get_output(iot, 0); 4047240609Shselasky output[1] = uaudio_mixer_get_output(iot, 1); 4048240609Shselasky 4049240609Shselasky /* 4050240609Shselasky * check if there is only 4051240609Shselasky * one output terminal: 4052240609Shselasky */ 4053240609Shselasky if (output[0] && (!output[1])) 4054240609Shselasky terminal_type = UGETW(output[0]->u.ot_v2->wTerminalType); 4055240609Shselasky /* 4056240609Shselasky * If the only output terminal is USB, 4057240609Shselasky * the class is UAC_RECORD. 4058240609Shselasky */ 4059240609Shselasky if ((terminal_type & 0xff00) == (UAT_UNDEFINED & 0xff00)) { 4060240609Shselasky 4061240609Shselasky mix->class = UAC_RECORD; 4062240609Shselasky if (input[0] && (!input[1])) { 4063240609Shselasky terminal_type = 4064240609Shselasky UGETW(input[0]->u.it_v2->wTerminalType); 4065240609Shselasky } else { 4066240609Shselasky terminal_type = 0; 4067240609Shselasky } 4068240609Shselasky goto done; 4069240609Shselasky } 4070240609Shselasky /* 4071240609Shselasky * if the unit is connected to just 4072240609Shselasky * one input terminal, the 4073240609Shselasky * class is UAC_INPUT: 4074240609Shselasky */ 4075240609Shselasky if (input[0] && (!input[1])) { 4076240609Shselasky mix->class = UAC_INPUT; 4077240609Shselasky terminal_type = 4078240609Shselasky UGETW(input[0]->u.it_v2->wTerminalType); 4079240609Shselasky goto done; 4080240609Shselasky } 4081240609Shselasky /* 4082240609Shselasky * Otherwise, the class is UAC_OUTPUT. 4083240609Shselasky */ 4084240609Shselasky mix->class = UAC_OUTPUT; 4085240609Shselaskydone: 4086240609Shselasky return (terminal_type); 4087240609Shselasky} 4088240609Shselasky 4089184610Salfredstruct uaudio_tt_to_feature { 4090184610Salfred uint16_t terminal_type; 4091184610Salfred uint16_t feature; 4092184610Salfred}; 4093184610Salfred 4094184610Salfredstatic const struct uaudio_tt_to_feature uaudio_tt_to_feature[] = { 4095184610Salfred 4096184610Salfred {UAT_STREAM, SOUND_MIXER_PCM}, 4097184610Salfred 4098184610Salfred {UATI_MICROPHONE, SOUND_MIXER_MIC}, 4099184610Salfred {UATI_DESKMICROPHONE, SOUND_MIXER_MIC}, 4100184610Salfred {UATI_PERSONALMICROPHONE, SOUND_MIXER_MIC}, 4101184610Salfred {UATI_OMNIMICROPHONE, SOUND_MIXER_MIC}, 4102184610Salfred {UATI_MICROPHONEARRAY, SOUND_MIXER_MIC}, 4103184610Salfred {UATI_PROCMICROPHONEARR, SOUND_MIXER_MIC}, 4104184610Salfred 4105184610Salfred {UATO_SPEAKER, SOUND_MIXER_SPEAKER}, 4106184610Salfred {UATO_DESKTOPSPEAKER, SOUND_MIXER_SPEAKER}, 4107184610Salfred {UATO_ROOMSPEAKER, SOUND_MIXER_SPEAKER}, 4108184610Salfred {UATO_COMMSPEAKER, SOUND_MIXER_SPEAKER}, 4109184610Salfred 4110184610Salfred {UATE_ANALOGCONN, SOUND_MIXER_LINE}, 4111184610Salfred {UATE_LINECONN, SOUND_MIXER_LINE}, 4112184610Salfred {UATE_LEGACYCONN, SOUND_MIXER_LINE}, 4113184610Salfred 4114184610Salfred {UATE_DIGITALAUIFC, SOUND_MIXER_ALTPCM}, 4115184610Salfred {UATE_SPDIF, SOUND_MIXER_ALTPCM}, 4116184610Salfred {UATE_1394DA, SOUND_MIXER_ALTPCM}, 4117184610Salfred {UATE_1394DV, SOUND_MIXER_ALTPCM}, 4118184610Salfred 4119184610Salfred {UATF_CDPLAYER, SOUND_MIXER_CD}, 4120184610Salfred 4121184610Salfred {UATF_SYNTHESIZER, SOUND_MIXER_SYNTH}, 4122184610Salfred 4123184610Salfred {UATF_VIDEODISCAUDIO, SOUND_MIXER_VIDEO}, 4124184610Salfred {UATF_DVDAUDIO, SOUND_MIXER_VIDEO}, 4125184610Salfred {UATF_TVTUNERAUDIO, SOUND_MIXER_VIDEO}, 4126184610Salfred 4127184610Salfred /* telephony terminal types */ 4128184610Salfred {UATT_UNDEFINED, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 4129184610Salfred {UATT_PHONELINE, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 4130184610Salfred {UATT_TELEPHONE, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 4131184610Salfred {UATT_DOWNLINEPHONE, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 4132184610Salfred 4133184610Salfred {UATF_RADIORECV, SOUND_MIXER_RADIO}, 4134184610Salfred {UATF_RADIOXMIT, SOUND_MIXER_RADIO}, 4135184610Salfred 4136184610Salfred {UAT_UNDEFINED, SOUND_MIXER_VOLUME}, 4137184610Salfred {UAT_VENDOR, SOUND_MIXER_VOLUME}, 4138184610Salfred {UATI_UNDEFINED, SOUND_MIXER_VOLUME}, 4139184610Salfred 4140184610Salfred /* output terminal types */ 4141184610Salfred {UATO_UNDEFINED, SOUND_MIXER_VOLUME}, 4142184610Salfred {UATO_DISPLAYAUDIO, SOUND_MIXER_VOLUME}, 4143184610Salfred {UATO_SUBWOOFER, SOUND_MIXER_VOLUME}, 4144184610Salfred {UATO_HEADPHONES, SOUND_MIXER_VOLUME}, 4145184610Salfred 4146184610Salfred /* bidir terminal types */ 4147184610Salfred {UATB_UNDEFINED, SOUND_MIXER_VOLUME}, 4148184610Salfred {UATB_HANDSET, SOUND_MIXER_VOLUME}, 4149184610Salfred {UATB_HEADSET, SOUND_MIXER_VOLUME}, 4150184610Salfred {UATB_SPEAKERPHONE, SOUND_MIXER_VOLUME}, 4151184610Salfred {UATB_SPEAKERPHONEESUP, SOUND_MIXER_VOLUME}, 4152184610Salfred {UATB_SPEAKERPHONEECANC, SOUND_MIXER_VOLUME}, 4153184610Salfred 4154184610Salfred /* external terminal types */ 4155184610Salfred {UATE_UNDEFINED, SOUND_MIXER_VOLUME}, 4156184610Salfred 4157184610Salfred /* embedded function terminal types */ 4158184610Salfred {UATF_UNDEFINED, SOUND_MIXER_VOLUME}, 4159184610Salfred {UATF_CALIBNOISE, SOUND_MIXER_VOLUME}, 4160184610Salfred {UATF_EQUNOISE, SOUND_MIXER_VOLUME}, 4161184610Salfred {UATF_DAT, SOUND_MIXER_VOLUME}, 4162184610Salfred {UATF_DCC, SOUND_MIXER_VOLUME}, 4163184610Salfred {UATF_MINIDISK, SOUND_MIXER_VOLUME}, 4164184610Salfred {UATF_ANALOGTAPE, SOUND_MIXER_VOLUME}, 4165184610Salfred {UATF_PHONOGRAPH, SOUND_MIXER_VOLUME}, 4166184610Salfred {UATF_VCRAUDIO, SOUND_MIXER_VOLUME}, 4167184610Salfred {UATF_SATELLITE, SOUND_MIXER_VOLUME}, 4168184610Salfred {UATF_CABLETUNER, SOUND_MIXER_VOLUME}, 4169184610Salfred {UATF_DSS, SOUND_MIXER_VOLUME}, 4170184610Salfred {UATF_MULTITRACK, SOUND_MIXER_VOLUME}, 4171184610Salfred {0xffff, SOUND_MIXER_VOLUME}, 4172184610Salfred 4173184610Salfred /* default */ 4174184610Salfred {0x0000, SOUND_MIXER_VOLUME}, 4175184610Salfred}; 4176184610Salfred 4177184610Salfredstatic uint16_t 4178184610Salfreduaudio_mixer_feature_name(const struct uaudio_terminal_node *iot, 4179184610Salfred struct uaudio_mixer_node *mix) 4180184610Salfred{ 4181184610Salfred const struct uaudio_tt_to_feature *uat = uaudio_tt_to_feature; 4182184610Salfred uint16_t terminal_type = uaudio_mixer_determine_class(iot, mix); 4183184610Salfred 4184184610Salfred if ((mix->class == UAC_RECORD) && (terminal_type == 0)) { 4185184610Salfred return (SOUND_MIXER_IMIX); 4186184610Salfred } 4187184610Salfred while (uat->terminal_type) { 4188184610Salfred if (uat->terminal_type == terminal_type) { 4189184610Salfred break; 4190184610Salfred } 4191184610Salfred uat++; 4192184610Salfred } 4193184610Salfred 4194240609Shselasky DPRINTF("terminal_type=0x%04x -> %d\n", 4195184610Salfred terminal_type, uat->feature); 4196184610Salfred 4197184610Salfred return (uat->feature); 4198184610Salfred} 4199184610Salfred 4200240609Shselaskystatic uint16_t 4201240609Shselaskyuaudio20_mixer_feature_name(const struct uaudio_terminal_node *iot, 4202240609Shselasky struct uaudio_mixer_node *mix) 4203240609Shselasky{ 4204240609Shselasky const struct uaudio_tt_to_feature *uat; 4205240609Shselasky uint16_t terminal_type = uaudio20_mixer_determine_class(iot, mix); 4206240609Shselasky 4207240609Shselasky if ((mix->class == UAC_RECORD) && (terminal_type == 0)) 4208240609Shselasky return (SOUND_MIXER_IMIX); 4209240609Shselasky 4210240609Shselasky for (uat = uaudio_tt_to_feature; uat->terminal_type != 0; uat++) { 4211240609Shselasky if (uat->terminal_type == terminal_type) 4212240609Shselasky break; 4213240609Shselasky } 4214240609Shselasky 4215240609Shselasky DPRINTF("terminal_type=0x%04x -> %d\n", 4216240609Shselasky terminal_type, uat->feature); 4217240609Shselasky 4218240609Shselasky return (uat->feature); 4219240609Shselasky} 4220240609Shselasky 4221233774Shselaskystatic const struct uaudio_terminal_node * 4222233774Shselaskyuaudio_mixer_get_input(const struct uaudio_terminal_node *iot, uint8_t i) 4223184610Salfred{ 4224184610Salfred struct uaudio_terminal_node *root = iot->root; 4225184610Salfred uint8_t n; 4226184610Salfred 4227184610Salfred n = iot->usr.id_max; 4228184610Salfred do { 4229184610Salfred if (iot->usr.bit_input[n / 8] & (1 << (n % 8))) { 4230233774Shselasky if (!i--) 4231184610Salfred return (root + n); 4232184610Salfred } 4233184610Salfred } while (n--); 4234184610Salfred 4235184610Salfred return (NULL); 4236184610Salfred} 4237184610Salfred 4238233774Shselaskystatic const struct uaudio_terminal_node * 4239233774Shselaskyuaudio_mixer_get_output(const struct uaudio_terminal_node *iot, uint8_t i) 4240184610Salfred{ 4241184610Salfred struct uaudio_terminal_node *root = iot->root; 4242184610Salfred uint8_t n; 4243184610Salfred 4244184610Salfred n = iot->usr.id_max; 4245184610Salfred do { 4246184610Salfred if (iot->usr.bit_output[n / 8] & (1 << (n % 8))) { 4247233774Shselasky if (!i--) 4248184610Salfred return (root + n); 4249184610Salfred } 4250184610Salfred } while (n--); 4251184610Salfred 4252184610Salfred return (NULL); 4253184610Salfred} 4254184610Salfred 4255184610Salfredstatic void 4256184610Salfreduaudio_mixer_find_inputs_sub(struct uaudio_terminal_node *root, 4257184610Salfred const uint8_t *p_id, uint8_t n_id, 4258184610Salfred struct uaudio_search_result *info) 4259184610Salfred{ 4260184610Salfred struct uaudio_terminal_node *iot; 4261184610Salfred uint8_t n; 4262184610Salfred uint8_t i; 4263240609Shselasky uint8_t is_last; 4264184610Salfred 4265240609Shselaskytop: 4266184610Salfred for (n = 0; n < n_id; n++) { 4267184610Salfred 4268184610Salfred i = p_id[n]; 4269184610Salfred 4270240609Shselasky if (info->recurse_level == UAUDIO_RECURSE_LIMIT) { 4271184610Salfred DPRINTF("avoided going into a circle at id=%d!\n", i); 4272240609Shselasky return; 4273184610Salfred } 4274184610Salfred 4275240609Shselasky info->recurse_level++; 4276240609Shselasky 4277184610Salfred iot = (root + i); 4278184610Salfred 4279240609Shselasky if (iot->u.desc == NULL) 4280184610Salfred continue; 4281240609Shselasky 4282240609Shselasky is_last = ((n + 1) == n_id); 4283240609Shselasky 4284184610Salfred switch (iot->u.desc->bDescriptorSubtype) { 4285184610Salfred case UDESCSUB_AC_INPUT: 4286184610Salfred info->bit_input[i / 8] |= (1 << (i % 8)); 4287184610Salfred break; 4288184610Salfred 4289184610Salfred case UDESCSUB_AC_FEATURE: 4290240609Shselasky if (is_last) { 4291240609Shselasky p_id = &iot->u.fu_v1->bSourceId; 4292240609Shselasky n_id = 1; 4293240609Shselasky goto top; 4294240609Shselasky } 4295240609Shselasky uaudio_mixer_find_inputs_sub( 4296240609Shselasky root, &iot->u.fu_v1->bSourceId, 1, info); 4297184610Salfred break; 4298184610Salfred 4299184610Salfred case UDESCSUB_AC_OUTPUT: 4300240609Shselasky if (is_last) { 4301240609Shselasky p_id = &iot->u.ot_v1->bSourceId; 4302240609Shselasky n_id = 1; 4303240609Shselasky goto top; 4304240609Shselasky } 4305240609Shselasky uaudio_mixer_find_inputs_sub( 4306240609Shselasky root, &iot->u.ot_v1->bSourceId, 1, info); 4307184610Salfred break; 4308184610Salfred 4309184610Salfred case UDESCSUB_AC_MIXER: 4310240609Shselasky if (is_last) { 4311240609Shselasky p_id = iot->u.mu_v1->baSourceId; 4312240609Shselasky n_id = iot->u.mu_v1->bNrInPins; 4313240609Shselasky goto top; 4314240609Shselasky } 4315240609Shselasky uaudio_mixer_find_inputs_sub( 4316240609Shselasky root, iot->u.mu_v1->baSourceId, 4317240609Shselasky iot->u.mu_v1->bNrInPins, info); 4318184610Salfred break; 4319184610Salfred 4320184610Salfred case UDESCSUB_AC_SELECTOR: 4321240609Shselasky if (is_last) { 4322240609Shselasky p_id = iot->u.su_v1->baSourceId; 4323240609Shselasky n_id = iot->u.su_v1->bNrInPins; 4324240609Shselasky goto top; 4325240609Shselasky } 4326240609Shselasky uaudio_mixer_find_inputs_sub( 4327240609Shselasky root, iot->u.su_v1->baSourceId, 4328240609Shselasky iot->u.su_v1->bNrInPins, info); 4329184610Salfred break; 4330184610Salfred 4331184610Salfred case UDESCSUB_AC_PROCESSING: 4332240609Shselasky if (is_last) { 4333240609Shselasky p_id = iot->u.pu_v1->baSourceId; 4334240609Shselasky n_id = iot->u.pu_v1->bNrInPins; 4335240609Shselasky goto top; 4336240609Shselasky } 4337240609Shselasky uaudio_mixer_find_inputs_sub( 4338240609Shselasky root, iot->u.pu_v1->baSourceId, 4339240609Shselasky iot->u.pu_v1->bNrInPins, info); 4340184610Salfred break; 4341184610Salfred 4342184610Salfred case UDESCSUB_AC_EXTENSION: 4343240609Shselasky if (is_last) { 4344240609Shselasky p_id = iot->u.eu_v1->baSourceId; 4345240609Shselasky n_id = iot->u.eu_v1->bNrInPins; 4346240609Shselasky goto top; 4347240609Shselasky } 4348240609Shselasky uaudio_mixer_find_inputs_sub( 4349240609Shselasky root, iot->u.eu_v1->baSourceId, 4350240609Shselasky iot->u.eu_v1->bNrInPins, info); 4351184610Salfred break; 4352184610Salfred 4353184610Salfred default: 4354184610Salfred break; 4355184610Salfred } 4356184610Salfred } 4357184610Salfred} 4358184610Salfred 4359184610Salfredstatic void 4360240609Shselaskyuaudio20_mixer_find_inputs_sub(struct uaudio_terminal_node *root, 4361240609Shselasky const uint8_t *p_id, uint8_t n_id, 4362240609Shselasky struct uaudio_search_result *info) 4363240609Shselasky{ 4364240609Shselasky struct uaudio_terminal_node *iot; 4365240609Shselasky uint8_t n; 4366240609Shselasky uint8_t i; 4367240609Shselasky uint8_t is_last; 4368240609Shselasky 4369240609Shselaskytop: 4370240609Shselasky for (n = 0; n < n_id; n++) { 4371240609Shselasky 4372240609Shselasky i = p_id[n]; 4373240609Shselasky 4374240609Shselasky if (info->recurse_level == UAUDIO_RECURSE_LIMIT) { 4375240609Shselasky DPRINTF("avoided going into a circle at id=%d!\n", i); 4376240609Shselasky return; 4377240609Shselasky } 4378240609Shselasky 4379240609Shselasky info->recurse_level++; 4380240609Shselasky 4381240609Shselasky iot = (root + i); 4382240609Shselasky 4383240609Shselasky if (iot->u.desc == NULL) 4384240609Shselasky continue; 4385240609Shselasky 4386240609Shselasky is_last = ((n + 1) == n_id); 4387240609Shselasky 4388240609Shselasky switch (iot->u.desc->bDescriptorSubtype) { 4389240609Shselasky case UDESCSUB_AC_INPUT: 4390240609Shselasky info->bit_input[i / 8] |= (1 << (i % 8)); 4391240609Shselasky break; 4392240609Shselasky 4393240609Shselasky case UDESCSUB_AC_OUTPUT: 4394240609Shselasky if (is_last) { 4395240609Shselasky p_id = &iot->u.ot_v2->bSourceId; 4396240609Shselasky n_id = 1; 4397240609Shselasky goto top; 4398240609Shselasky } 4399240609Shselasky uaudio20_mixer_find_inputs_sub( 4400240609Shselasky root, &iot->u.ot_v2->bSourceId, 1, info); 4401240609Shselasky break; 4402240609Shselasky 4403240609Shselasky case UDESCSUB_AC_MIXER: 4404240609Shselasky if (is_last) { 4405240609Shselasky p_id = iot->u.mu_v2->baSourceId; 4406240609Shselasky n_id = iot->u.mu_v2->bNrInPins; 4407240609Shselasky goto top; 4408240609Shselasky } 4409240609Shselasky uaudio20_mixer_find_inputs_sub( 4410240609Shselasky root, iot->u.mu_v2->baSourceId, 4411240609Shselasky iot->u.mu_v2->bNrInPins, info); 4412240609Shselasky break; 4413240609Shselasky 4414240609Shselasky case UDESCSUB_AC_SELECTOR: 4415240609Shselasky if (is_last) { 4416240609Shselasky p_id = iot->u.su_v2->baSourceId; 4417240609Shselasky n_id = iot->u.su_v2->bNrInPins; 4418240609Shselasky goto top; 4419240609Shselasky } 4420240609Shselasky uaudio20_mixer_find_inputs_sub( 4421240609Shselasky root, iot->u.su_v2->baSourceId, 4422240609Shselasky iot->u.su_v2->bNrInPins, info); 4423240609Shselasky break; 4424240609Shselasky 4425240609Shselasky case UDESCSUB_AC_SAMPLE_RT: 4426240609Shselasky if (is_last) { 4427240609Shselasky p_id = &iot->u.ru_v2->bSourceId; 4428240609Shselasky n_id = 1; 4429240609Shselasky goto top; 4430240609Shselasky } 4431240609Shselasky uaudio20_mixer_find_inputs_sub( 4432240609Shselasky root, &iot->u.ru_v2->bSourceId, 4433240609Shselasky 1, info); 4434240609Shselasky break; 4435240609Shselasky 4436240609Shselasky case UDESCSUB_AC_EFFECT: 4437240609Shselasky if (is_last) { 4438240609Shselasky p_id = &iot->u.ef_v2->bSourceId; 4439240609Shselasky n_id = 1; 4440240609Shselasky goto top; 4441240609Shselasky } 4442240609Shselasky uaudio20_mixer_find_inputs_sub( 4443240609Shselasky root, &iot->u.ef_v2->bSourceId, 4444240609Shselasky 1, info); 4445240609Shselasky break; 4446240609Shselasky 4447240609Shselasky case UDESCSUB_AC_FEATURE: 4448240609Shselasky if (is_last) { 4449240609Shselasky p_id = &iot->u.fu_v2->bSourceId; 4450240609Shselasky n_id = 1; 4451240609Shselasky goto top; 4452240609Shselasky } 4453240609Shselasky uaudio20_mixer_find_inputs_sub( 4454240609Shselasky root, &iot->u.fu_v2->bSourceId, 1, info); 4455240609Shselasky break; 4456240609Shselasky 4457240609Shselasky case UDESCSUB_AC_PROCESSING_V2: 4458240609Shselasky if (is_last) { 4459240609Shselasky p_id = iot->u.pu_v2->baSourceId; 4460240609Shselasky n_id = iot->u.pu_v2->bNrInPins; 4461240609Shselasky goto top; 4462240609Shselasky } 4463240609Shselasky uaudio20_mixer_find_inputs_sub( 4464240609Shselasky root, iot->u.pu_v2->baSourceId, 4465240609Shselasky iot->u.pu_v2->bNrInPins, info); 4466240609Shselasky break; 4467240609Shselasky 4468240609Shselasky case UDESCSUB_AC_EXTENSION_V2: 4469240609Shselasky if (is_last) { 4470240609Shselasky p_id = iot->u.eu_v2->baSourceId; 4471240609Shselasky n_id = iot->u.eu_v2->bNrInPins; 4472240609Shselasky goto top; 4473240609Shselasky } 4474240609Shselasky uaudio20_mixer_find_inputs_sub( 4475240609Shselasky root, iot->u.eu_v2->baSourceId, 4476240609Shselasky iot->u.eu_v2->bNrInPins, info); 4477240609Shselasky break; 4478240609Shselasky default: 4479240609Shselasky break; 4480240609Shselasky } 4481240609Shselasky } 4482240609Shselasky} 4483240609Shselasky 4484240609Shselaskystatic void 4485240609Shselaskyuaudio20_mixer_find_clocks_sub(struct uaudio_terminal_node *root, 4486240609Shselasky const uint8_t *p_id, uint8_t n_id, 4487240609Shselasky struct uaudio_search_result *info) 4488240609Shselasky{ 4489240609Shselasky struct uaudio_terminal_node *iot; 4490240609Shselasky uint8_t n; 4491240609Shselasky uint8_t i; 4492240609Shselasky uint8_t is_last; 4493240609Shselasky uint8_t id; 4494240609Shselasky 4495240609Shselaskytop: 4496240609Shselasky for (n = 0; n < n_id; n++) { 4497240609Shselasky 4498240609Shselasky i = p_id[n]; 4499240609Shselasky 4500240609Shselasky if (info->recurse_level == UAUDIO_RECURSE_LIMIT) { 4501240609Shselasky DPRINTF("avoided going into a circle at id=%d!\n", i); 4502240609Shselasky return; 4503240609Shselasky } 4504240609Shselasky 4505240609Shselasky info->recurse_level++; 4506240609Shselasky 4507240609Shselasky iot = (root + i); 4508240609Shselasky 4509240609Shselasky if (iot->u.desc == NULL) 4510240609Shselasky continue; 4511240609Shselasky 4512240609Shselasky is_last = ((n + 1) == n_id); 4513240609Shselasky 4514240609Shselasky switch (iot->u.desc->bDescriptorSubtype) { 4515240609Shselasky case UDESCSUB_AC_INPUT: 4516240609Shselasky info->is_input = 1; 4517240609Shselasky if (is_last) { 4518240609Shselasky p_id = &iot->u.it_v2->bCSourceId; 4519240609Shselasky n_id = 1; 4520240609Shselasky goto top; 4521240609Shselasky } 4522240609Shselasky uaudio20_mixer_find_clocks_sub(root, 4523240609Shselasky &iot->u.it_v2->bCSourceId, 1, info); 4524240609Shselasky break; 4525240609Shselasky 4526240609Shselasky case UDESCSUB_AC_OUTPUT: 4527240609Shselasky info->is_input = 0; 4528240609Shselasky if (is_last) { 4529240609Shselasky p_id = &iot->u.ot_v2->bCSourceId; 4530240609Shselasky n_id = 1; 4531240609Shselasky goto top; 4532240609Shselasky } 4533240609Shselasky uaudio20_mixer_find_clocks_sub(root, 4534240609Shselasky &iot->u.ot_v2->bCSourceId, 1, info); 4535240609Shselasky break; 4536240609Shselasky 4537240609Shselasky case UDESCSUB_AC_CLOCK_SEL: 4538240609Shselasky if (is_last) { 4539240609Shselasky p_id = iot->u.csel_v2->baCSourceId; 4540240609Shselasky n_id = iot->u.csel_v2->bNrInPins; 4541240609Shselasky goto top; 4542240609Shselasky } 4543240609Shselasky uaudio20_mixer_find_clocks_sub(root, 4544240609Shselasky iot->u.csel_v2->baCSourceId, 4545240609Shselasky iot->u.csel_v2->bNrInPins, info); 4546240609Shselasky break; 4547240609Shselasky 4548240609Shselasky case UDESCSUB_AC_CLOCK_MUL: 4549240609Shselasky if (is_last) { 4550240609Shselasky p_id = &iot->u.cmul_v2->bCSourceId; 4551240609Shselasky n_id = 1; 4552240609Shselasky goto top; 4553240609Shselasky } 4554240609Shselasky uaudio20_mixer_find_clocks_sub(root, 4555240609Shselasky &iot->u.cmul_v2->bCSourceId, 4556240609Shselasky 1, info); 4557240609Shselasky break; 4558240609Shselasky 4559240609Shselasky case UDESCSUB_AC_CLOCK_SRC: 4560240609Shselasky 4561240609Shselasky id = iot->u.csrc_v2->bClockId; 4562240609Shselasky 4563240609Shselasky switch (info->is_input) { 4564240609Shselasky case 0: 4565240609Shselasky info->bit_output[id / 8] |= (1 << (id % 8)); 4566240609Shselasky break; 4567240609Shselasky case 1: 4568240609Shselasky info->bit_input[id / 8] |= (1 << (id % 8)); 4569240609Shselasky break; 4570240609Shselasky default: 4571240609Shselasky break; 4572240609Shselasky } 4573240609Shselasky break; 4574240609Shselasky 4575240609Shselasky default: 4576240609Shselasky break; 4577240609Shselasky } 4578240609Shselasky } 4579240609Shselasky} 4580240609Shselasky 4581240609Shselaskystatic void 4582184610Salfreduaudio_mixer_find_outputs_sub(struct uaudio_terminal_node *root, uint8_t id, 4583184610Salfred uint8_t n_id, struct uaudio_search_result *info) 4584184610Salfred{ 4585184610Salfred struct uaudio_terminal_node *iot = (root + id); 4586184610Salfred uint8_t j; 4587184610Salfred 4588184610Salfred j = n_id; 4589184610Salfred do { 4590184610Salfred if ((j != id) && ((root + j)->u.desc) && 4591184610Salfred ((root + j)->u.desc->bDescriptorSubtype == UDESCSUB_AC_OUTPUT)) { 4592184610Salfred 4593184610Salfred /* 4594184610Salfred * "j" (output) <--- virtual wire <--- "id" (input) 4595184610Salfred * 4596184610Salfred * if "j" has "id" on the input, then "id" have "j" on 4597184610Salfred * the output, because they are connected: 4598184610Salfred */ 4599184610Salfred if ((root + j)->usr.bit_input[id / 8] & (1 << (id % 8))) { 4600184610Salfred iot->usr.bit_output[j / 8] |= (1 << (j % 8)); 4601184610Salfred } 4602184610Salfred } 4603184610Salfred } while (j--); 4604184610Salfred} 4605184610Salfred 4606184610Salfredstatic void 4607240609Shselaskyuaudio_mixer_fill_info(struct uaudio_softc *sc, 4608240609Shselasky struct usb_device *udev, void *desc) 4609184610Salfred{ 4610203678Sbrucec const struct usb_audio_control_descriptor *acdp; 4611194228Sthompsa struct usb_config_descriptor *cd = usbd_get_config_descriptor(udev); 4612192984Sthompsa const struct usb_descriptor *dp; 4613203678Sbrucec const struct usb_audio_unit *au; 4614184610Salfred struct uaudio_terminal_node *iot = NULL; 4615184610Salfred uint16_t wTotalLen; 4616184610Salfred uint8_t ID_max = 0; /* inclusive */ 4617184610Salfred uint8_t i; 4618184610Salfred 4619194228Sthompsa desc = usb_desc_foreach(cd, desc); 4620184610Salfred 4621184610Salfred if (desc == NULL) { 4622184610Salfred DPRINTF("no Audio Control header\n"); 4623184610Salfred goto done; 4624184610Salfred } 4625184610Salfred acdp = desc; 4626184610Salfred 4627184610Salfred if ((acdp->bLength < sizeof(*acdp)) || 4628184610Salfred (acdp->bDescriptorType != UDESC_CS_INTERFACE) || 4629184610Salfred (acdp->bDescriptorSubtype != UDESCSUB_AC_HEADER)) { 4630184610Salfred DPRINTF("invalid Audio Control header\n"); 4631184610Salfred goto done; 4632184610Salfred } 4633186730Salfred /* "wTotalLen" is allowed to be corrupt */ 4634186730Salfred wTotalLen = UGETW(acdp->wTotalLength) - acdp->bLength; 4635186730Salfred 4636186730Salfred /* get USB audio revision */ 4637184610Salfred sc->sc_audio_rev = UGETW(acdp->bcdADC); 4638184610Salfred 4639184610Salfred DPRINTFN(3, "found AC header, vers=%03x, len=%d\n", 4640184610Salfred sc->sc_audio_rev, wTotalLen); 4641184610Salfred 4642184610Salfred iot = malloc(sizeof(struct uaudio_terminal_node) * 256, M_TEMP, 4643184610Salfred M_WAITOK | M_ZERO); 4644184610Salfred 4645184610Salfred if (iot == NULL) { 4646184610Salfred DPRINTF("no memory!\n"); 4647184610Salfred goto done; 4648184610Salfred } 4649194228Sthompsa while ((desc = usb_desc_foreach(cd, desc))) { 4650184610Salfred 4651184610Salfred dp = desc; 4652184610Salfred 4653184610Salfred if (dp->bLength > wTotalLen) { 4654184610Salfred break; 4655184610Salfred } else { 4656184610Salfred wTotalLen -= dp->bLength; 4657184610Salfred } 4658184610Salfred 4659240609Shselasky if (sc->sc_audio_rev >= UAUDIO_VERSION_30) 4660240609Shselasky au = NULL; 4661240609Shselasky else if (sc->sc_audio_rev >= UAUDIO_VERSION_20) 4662240609Shselasky au = uaudio20_mixer_verify_desc(dp, 0); 4663240609Shselasky else 4664240609Shselasky au = uaudio_mixer_verify_desc(dp, 0); 4665184610Salfred 4666184610Salfred if (au) { 4667184610Salfred iot[au->bUnitId].u.desc = (const void *)au; 4668240609Shselasky if (au->bUnitId > ID_max) 4669184610Salfred ID_max = au->bUnitId; 4670184610Salfred } 4671184610Salfred } 4672184610Salfred 4673184610Salfred DPRINTF("Maximum ID=%d\n", ID_max); 4674184610Salfred 4675184610Salfred /* 4676184610Salfred * determine sourcing inputs for 4677184610Salfred * all nodes in the tree: 4678184610Salfred */ 4679184610Salfred i = ID_max; 4680184610Salfred do { 4681240609Shselasky if (sc->sc_audio_rev >= UAUDIO_VERSION_30) { 4682240609Shselasky /* FALLTHROUGH */ 4683240609Shselasky } else if (sc->sc_audio_rev >= UAUDIO_VERSION_20) { 4684240609Shselasky uaudio20_mixer_find_inputs_sub(iot, 4685240609Shselasky &i, 1, &((iot + i)->usr)); 4686240609Shselasky 4687240609Shselasky sc->sc_mixer_clocks.is_input = 255; 4688240609Shselasky sc->sc_mixer_clocks.recurse_level = 0; 4689240609Shselasky 4690240609Shselasky uaudio20_mixer_find_clocks_sub(iot, 4691240609Shselasky &i, 1, &sc->sc_mixer_clocks); 4692240609Shselasky } else { 4693240609Shselasky uaudio_mixer_find_inputs_sub(iot, 4694240609Shselasky &i, 1, &((iot + i)->usr)); 4695240609Shselasky } 4696184610Salfred } while (i--); 4697184610Salfred 4698184610Salfred /* 4699184610Salfred * determine outputs for 4700184610Salfred * all nodes in the tree: 4701184610Salfred */ 4702184610Salfred i = ID_max; 4703184610Salfred do { 4704240609Shselasky uaudio_mixer_find_outputs_sub(iot, 4705240609Shselasky i, ID_max, &((iot + i)->usr)); 4706184610Salfred } while (i--); 4707184610Salfred 4708184610Salfred /* set "id_max" and "root" */ 4709184610Salfred 4710184610Salfred i = ID_max; 4711184610Salfred do { 4712184610Salfred (iot + i)->usr.id_max = ID_max; 4713184610Salfred (iot + i)->root = iot; 4714184610Salfred } while (i--); 4715184610Salfred 4716240609Shselasky /* 4717240609Shselasky * Scan the config to create a linked list of "mixer" nodes: 4718240609Shselasky */ 4719240609Shselasky 4720184610Salfred i = ID_max; 4721184610Salfred do { 4722240609Shselasky dp = iot[i].u.desc; 4723184610Salfred 4724240609Shselasky if (dp == NULL) 4725184610Salfred continue; 4726184610Salfred 4727240609Shselasky DPRINTFN(11, "id=%d subtype=%d\n", 4728240609Shselasky i, dp->bDescriptorSubtype); 4729184610Salfred 4730240609Shselasky if (sc->sc_audio_rev >= UAUDIO_VERSION_30) { 4731240609Shselasky continue; 4732240609Shselasky } else if (sc->sc_audio_rev >= UAUDIO_VERSION_20) { 4733184610Salfred 4734240609Shselasky switch (dp->bDescriptorSubtype) { 4735240609Shselasky case UDESCSUB_AC_HEADER: 4736240609Shselasky DPRINTF("unexpected AC header\n"); 4737240609Shselasky break; 4738184610Salfred 4739240609Shselasky case UDESCSUB_AC_INPUT: 4740240609Shselasky case UDESCSUB_AC_OUTPUT: 4741240609Shselasky case UDESCSUB_AC_PROCESSING_V2: 4742240609Shselasky case UDESCSUB_AC_EXTENSION_V2: 4743240609Shselasky case UDESCSUB_AC_EFFECT: 4744240609Shselasky case UDESCSUB_AC_CLOCK_SRC: 4745240609Shselasky case UDESCSUB_AC_CLOCK_SEL: 4746240609Shselasky case UDESCSUB_AC_CLOCK_MUL: 4747240609Shselasky case UDESCSUB_AC_SAMPLE_RT: 4748240609Shselasky break; 4749184610Salfred 4750240609Shselasky case UDESCSUB_AC_MIXER: 4751240609Shselasky uaudio20_mixer_add_mixer(sc, iot, i); 4752240609Shselasky break; 4753184610Salfred 4754240609Shselasky case UDESCSUB_AC_SELECTOR: 4755240609Shselasky uaudio20_mixer_add_selector(sc, iot, i); 4756240609Shselasky break; 4757184610Salfred 4758240609Shselasky case UDESCSUB_AC_FEATURE: 4759240609Shselasky uaudio20_mixer_add_feature(sc, iot, i); 4760240609Shselasky break; 4761184610Salfred 4762240609Shselasky default: 4763240609Shselasky DPRINTF("bad AC desc subtype=0x%02x\n", 4764240609Shselasky dp->bDescriptorSubtype); 4765240609Shselasky break; 4766184610Salfred } 4767184610Salfred continue; 4768184610Salfred } 4769184610Salfred 4770184610Salfred switch (dp->bDescriptorSubtype) { 4771184610Salfred case UDESCSUB_AC_HEADER: 4772184610Salfred DPRINTF("unexpected AC header\n"); 4773184610Salfred break; 4774184610Salfred 4775184610Salfred case UDESCSUB_AC_INPUT: 4776184610Salfred case UDESCSUB_AC_OUTPUT: 4777184610Salfred break; 4778184610Salfred 4779184610Salfred case UDESCSUB_AC_MIXER: 4780184610Salfred uaudio_mixer_add_mixer(sc, iot, i); 4781184610Salfred break; 4782184610Salfred 4783184610Salfred case UDESCSUB_AC_SELECTOR: 4784184610Salfred uaudio_mixer_add_selector(sc, iot, i); 4785184610Salfred break; 4786184610Salfred 4787184610Salfred case UDESCSUB_AC_FEATURE: 4788184610Salfred uaudio_mixer_add_feature(sc, iot, i); 4789184610Salfred break; 4790184610Salfred 4791184610Salfred case UDESCSUB_AC_PROCESSING: 4792184610Salfred uaudio_mixer_add_processing(sc, iot, i); 4793184610Salfred break; 4794184610Salfred 4795184610Salfred case UDESCSUB_AC_EXTENSION: 4796184610Salfred uaudio_mixer_add_extension(sc, iot, i); 4797184610Salfred break; 4798184610Salfred 4799184610Salfred default: 4800184610Salfred DPRINTF("bad AC desc subtype=0x%02x\n", 4801184610Salfred dp->bDescriptorSubtype); 4802184610Salfred break; 4803184610Salfred } 4804184610Salfred 4805184610Salfred } while (i--); 4806184610Salfred 4807184610Salfreddone: 4808240609Shselasky free(iot, M_TEMP); 4809184610Salfred} 4810184610Salfred 4811240609Shselaskystatic int 4812240609Shselaskyuaudio_mixer_get(struct usb_device *udev, uint16_t audio_rev, 4813240609Shselasky uint8_t what, struct uaudio_mixer_node *mc) 4814184610Salfred{ 4815192984Sthompsa struct usb_device_request req; 4816240609Shselasky int val; 4817240609Shselasky uint8_t data[2 + (2 * 3)]; 4818193045Sthompsa usb_error_t err; 4819184610Salfred 4820240609Shselasky if (mc->wValue[0] == -1) 4821184610Salfred return (0); 4822240609Shselasky 4823240609Shselasky if (audio_rev >= UAUDIO_VERSION_30) 4824240609Shselasky return (0); 4825240609Shselasky else if (audio_rev >= UAUDIO_VERSION_20) { 4826240609Shselasky if (what == GET_CUR) { 4827240609Shselasky req.bRequest = UA20_CS_CUR; 4828240609Shselasky USETW(req.wLength, 2); 4829240609Shselasky } else { 4830240609Shselasky req.bRequest = UA20_CS_RANGE; 4831240609Shselasky USETW(req.wLength, 8); 4832240609Shselasky } 4833240609Shselasky } else { 4834240609Shselasky uint16_t len = MIX_SIZE(mc->type); 4835240609Shselasky 4836240609Shselasky req.bRequest = what; 4837240609Shselasky USETW(req.wLength, len); 4838184610Salfred } 4839240609Shselasky 4840184610Salfred req.bmRequestType = UT_READ_CLASS_INTERFACE; 4841184610Salfred USETW(req.wValue, mc->wValue[0]); 4842184610Salfred USETW(req.wIndex, mc->wIndex); 4843184610Salfred 4844240609Shselasky memset(data, 0, sizeof(data)); 4845240609Shselasky 4846196487Salfred err = usbd_do_request(udev, NULL, &req, data); 4847184610Salfred if (err) { 4848194228Sthompsa DPRINTF("err=%s\n", usbd_errstr(err)); 4849184610Salfred return (0); 4850184610Salfred } 4851240609Shselasky 4852240609Shselasky if (audio_rev >= UAUDIO_VERSION_30) { 4853240609Shselasky val = 0; 4854240609Shselasky } else if (audio_rev >= UAUDIO_VERSION_20) { 4855240609Shselasky switch (what) { 4856240609Shselasky case GET_CUR: 4857240609Shselasky val = (data[0] | (data[1] << 8)); 4858240609Shselasky break; 4859240609Shselasky case GET_MIN: 4860240609Shselasky val = (data[2] | (data[3] << 8)); 4861240609Shselasky break; 4862240609Shselasky case GET_MAX: 4863240609Shselasky val = (data[4] | (data[5] << 8)); 4864240609Shselasky break; 4865240609Shselasky case GET_RES: 4866240609Shselasky val = (data[6] | (data[7] << 8)); 4867240609Shselasky break; 4868240609Shselasky default: 4869240609Shselasky val = 0; 4870240609Shselasky break; 4871240609Shselasky } 4872240609Shselasky } else { 4873240609Shselasky val = (data[0] | (data[1] << 8)); 4874184610Salfred } 4875184610Salfred 4876240609Shselasky if (what == GET_CUR || what == GET_MIN || what == GET_MAX) 4877240609Shselasky val = uaudio_mixer_signext(mc->type, val); 4878240609Shselasky 4879184610Salfred DPRINTFN(3, "val=%d\n", val); 4880184610Salfred 4881184610Salfred return (val); 4882184610Salfred} 4883184610Salfred 4884184610Salfredstatic void 4885194677Sthompsauaudio_mixer_write_cfg_callback(struct usb_xfer *xfer, usb_error_t error) 4886184610Salfred{ 4887192984Sthompsa struct usb_device_request req; 4888194677Sthompsa struct uaudio_softc *sc = usbd_xfer_softc(xfer); 4889184610Salfred struct uaudio_mixer_node *mc = sc->sc_mixer_curr; 4890194677Sthompsa struct usb_page_cache *pc; 4891184610Salfred uint16_t len; 4892184610Salfred uint8_t repeat = 1; 4893184610Salfred uint8_t update; 4894184610Salfred uint8_t chan; 4895184610Salfred uint8_t buf[2]; 4896184610Salfred 4897187165Sthompsa DPRINTF("\n"); 4898187165Sthompsa 4899184610Salfred switch (USB_GET_STATE(xfer)) { 4900184610Salfred case USB_ST_TRANSFERRED: 4901184610Salfredtr_transferred: 4902184610Salfred case USB_ST_SETUP: 4903184610Salfredtr_setup: 4904184610Salfred 4905184610Salfred if (mc == NULL) { 4906184610Salfred mc = sc->sc_mixer_root; 4907184610Salfred sc->sc_mixer_curr = mc; 4908184610Salfred sc->sc_mixer_chan = 0; 4909184610Salfred repeat = 0; 4910184610Salfred } 4911184610Salfred while (mc) { 4912184610Salfred while (sc->sc_mixer_chan < mc->nchan) { 4913184610Salfred 4914184610Salfred chan = sc->sc_mixer_chan; 4915184610Salfred 4916184610Salfred sc->sc_mixer_chan++; 4917184610Salfred 4918184610Salfred update = ((mc->update[chan / 8] & (1 << (chan % 8))) && 4919184610Salfred (mc->wValue[chan] != -1)); 4920184610Salfred 4921184610Salfred mc->update[chan / 8] &= ~(1 << (chan % 8)); 4922184610Salfred 4923184610Salfred if (update) { 4924184610Salfred 4925184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 4926184610Salfred USETW(req.wValue, mc->wValue[chan]); 4927184610Salfred USETW(req.wIndex, mc->wIndex); 4928184610Salfred 4929240609Shselasky if (sc->sc_audio_rev >= UAUDIO_VERSION_30) { 4930240609Shselasky return; 4931240609Shselasky } else if (sc->sc_audio_rev >= UAUDIO_VERSION_20) { 4932240609Shselasky len = 2; 4933240609Shselasky req.bRequest = UA20_CS_CUR; 4934240609Shselasky USETW(req.wLength, len); 4935240609Shselasky } else { 4936240609Shselasky len = MIX_SIZE(mc->type); 4937240609Shselasky req.bRequest = SET_CUR; 4938240609Shselasky USETW(req.wLength, len); 4939184610Salfred } 4940240609Shselasky 4941240609Shselasky buf[0] = (mc->wData[chan] & 0xFF); 4942240609Shselasky buf[1] = (mc->wData[chan] >> 8) & 0xFF; 4943240609Shselasky 4944194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 4945194677Sthompsa usbd_copy_in(pc, 0, &req, sizeof(req)); 4946194677Sthompsa pc = usbd_xfer_get_frame(xfer, 1); 4947194677Sthompsa usbd_copy_in(pc, 0, buf, len); 4948184610Salfred 4949194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 4950194677Sthompsa usbd_xfer_set_frame_len(xfer, 1, len); 4951194677Sthompsa usbd_xfer_set_frames(xfer, len ? 2 : 1); 4952194228Sthompsa usbd_transfer_submit(xfer); 4953184610Salfred return; 4954184610Salfred } 4955184610Salfred } 4956184610Salfred 4957184610Salfred mc = mc->next; 4958184610Salfred sc->sc_mixer_curr = mc; 4959184610Salfred sc->sc_mixer_chan = 0; 4960184610Salfred } 4961184610Salfred 4962184610Salfred if (repeat) { 4963184610Salfred goto tr_setup; 4964184610Salfred } 4965187165Sthompsa break; 4966184610Salfred 4967184610Salfred default: /* Error */ 4968194677Sthompsa DPRINTF("error=%s\n", usbd_errstr(error)); 4969194677Sthompsa if (error == USB_ERR_CANCELLED) { 4970187165Sthompsa /* do nothing - we are detaching */ 4971187165Sthompsa break; 4972187165Sthompsa } 4973184610Salfred goto tr_transferred; 4974184610Salfred } 4975184610Salfred} 4976184610Salfred 4977193045Sthompsastatic usb_error_t 4978192984Sthompsauaudio_set_speed(struct usb_device *udev, uint8_t endpt, uint32_t speed) 4979184610Salfred{ 4980192984Sthompsa struct usb_device_request req; 4981184610Salfred uint8_t data[3]; 4982184610Salfred 4983184610Salfred DPRINTFN(6, "endpt=%d speed=%u\n", endpt, speed); 4984184610Salfred 4985184610Salfred req.bmRequestType = UT_WRITE_CLASS_ENDPOINT; 4986184610Salfred req.bRequest = SET_CUR; 4987184610Salfred USETW2(req.wValue, SAMPLING_FREQ_CONTROL, 0); 4988184610Salfred USETW(req.wIndex, endpt); 4989184610Salfred USETW(req.wLength, 3); 4990184610Salfred data[0] = speed; 4991184610Salfred data[1] = speed >> 8; 4992184610Salfred data[2] = speed >> 16; 4993184610Salfred 4994196487Salfred return (usbd_do_request(udev, NULL, &req, data)); 4995184610Salfred} 4996184610Salfred 4997240609Shselaskystatic usb_error_t 4998240609Shselaskyuaudio20_set_speed(struct usb_device *udev, uint8_t iface_no, 4999240609Shselasky uint8_t clockid, uint32_t speed) 5000240609Shselasky{ 5001240609Shselasky struct usb_device_request req; 5002240609Shselasky uint8_t data[4]; 5003240609Shselasky 5004240609Shselasky DPRINTFN(6, "ifaceno=%d clockid=%d speed=%u\n", 5005240609Shselasky iface_no, clockid, speed); 5006240609Shselasky 5007240609Shselasky req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 5008240609Shselasky req.bRequest = UA20_CS_CUR; 5009240609Shselasky USETW2(req.wValue, UA20_CS_SAM_FREQ_CONTROL, 0); 5010240609Shselasky USETW2(req.wIndex, clockid, iface_no); 5011240609Shselasky USETW(req.wLength, 4); 5012240609Shselasky data[0] = speed; 5013240609Shselasky data[1] = speed >> 8; 5014240609Shselasky data[2] = speed >> 16; 5015240609Shselasky data[3] = speed >> 24; 5016240609Shselasky 5017240609Shselasky return (usbd_do_request(udev, NULL, &req, data)); 5018240609Shselasky} 5019240609Shselasky 5020184610Salfredstatic int 5021184610Salfreduaudio_mixer_signext(uint8_t type, int val) 5022184610Salfred{ 5023184610Salfred if (!MIX_UNSIGNED(type)) { 5024184610Salfred if (MIX_SIZE(type) == 2) { 5025184610Salfred val = (int16_t)val; 5026184610Salfred } else { 5027184610Salfred val = (int8_t)val; 5028184610Salfred } 5029184610Salfred } 5030184610Salfred return (val); 5031184610Salfred} 5032184610Salfred 5033184610Salfredstatic int 5034184610Salfreduaudio_mixer_bsd2value(struct uaudio_mixer_node *mc, int32_t val) 5035184610Salfred{ 5036184610Salfred if (mc->type == MIX_ON_OFF) { 5037184610Salfred val = (val != 0); 5038184610Salfred } else if (mc->type == MIX_SELECTOR) { 5039184610Salfred if ((val < mc->minval) || 5040184610Salfred (val > mc->maxval)) { 5041184610Salfred val = mc->minval; 5042184610Salfred } 5043184610Salfred } else { 5044199060Sthompsa 5045199060Sthompsa /* compute actual volume */ 5046199060Sthompsa val = (val * mc->mul) / 255; 5047199060Sthompsa 5048199060Sthompsa /* add lower offset */ 5049199060Sthompsa val = val + mc->minval; 5050199060Sthompsa 5051199060Sthompsa /* make sure we don't write a value out of range */ 5052199060Sthompsa if (val > mc->maxval) 5053199060Sthompsa val = mc->maxval; 5054199060Sthompsa else if (val < mc->minval) 5055199060Sthompsa val = mc->minval; 5056184610Salfred } 5057184610Salfred 5058185087Salfred DPRINTFN(6, "type=0x%03x val=%d min=%d max=%d val=%d\n", 5059185087Salfred mc->type, val, mc->minval, mc->maxval, val); 5060184610Salfred return (val); 5061184610Salfred} 5062184610Salfred 5063184610Salfredstatic void 5064184610Salfreduaudio_mixer_ctl_set(struct uaudio_softc *sc, struct uaudio_mixer_node *mc, 5065184610Salfred uint8_t chan, int32_t val) 5066184610Salfred{ 5067184610Salfred val = uaudio_mixer_bsd2value(mc, val); 5068184610Salfred 5069184610Salfred mc->update[chan / 8] |= (1 << (chan % 8)); 5070184610Salfred mc->wData[chan] = val; 5071184610Salfred 5072184610Salfred /* start the transfer, if not already started */ 5073184610Salfred 5074194228Sthompsa usbd_transfer_start(sc->sc_mixer_xfer[0]); 5075184610Salfred} 5076184610Salfred 5077184610Salfredstatic void 5078184610Salfreduaudio_mixer_init(struct uaudio_softc *sc) 5079184610Salfred{ 5080184610Salfred struct uaudio_mixer_node *mc; 5081184610Salfred int32_t i; 5082184610Salfred 5083184610Salfred for (mc = sc->sc_mixer_root; mc; 5084184610Salfred mc = mc->next) { 5085184610Salfred 5086184610Salfred if (mc->ctl != SOUND_MIXER_NRDEVICES) { 5087184610Salfred /* 5088184610Salfred * Set device mask bits. See 5089184610Salfred * /usr/include/machine/soundcard.h 5090184610Salfred */ 5091184610Salfred sc->sc_mix_info |= (1 << mc->ctl); 5092184610Salfred } 5093184610Salfred if ((mc->ctl == SOUND_MIXER_NRDEVICES) && 5094184610Salfred (mc->type == MIX_SELECTOR)) { 5095184610Salfred 5096184610Salfred for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { 5097184610Salfred if (mc->slctrtype[i - 1] == SOUND_MIXER_NRDEVICES) { 5098184610Salfred continue; 5099184610Salfred } 5100184610Salfred sc->sc_recsrc_info |= 1 << mc->slctrtype[i - 1]; 5101184610Salfred } 5102184610Salfred } 5103184610Salfred } 5104184610Salfred} 5105184610Salfred 5106184610Salfredint 5107184610Salfreduaudio_mixer_init_sub(struct uaudio_softc *sc, struct snd_mixer *m) 5108184610Salfred{ 5109184610Salfred DPRINTF("\n"); 5110184610Salfred 5111242438Shselasky sc->sc_mixer_lock = mixer_get_lock(m); 5112246421Shselasky sc->sc_mixer_dev = m; 5113242438Shselasky 5114194228Sthompsa if (usbd_transfer_setup(sc->sc_udev, &sc->sc_mixer_iface_index, 5115184610Salfred sc->sc_mixer_xfer, uaudio_mixer_config, 1, sc, 5116242438Shselasky sc->sc_mixer_lock)) { 5117184610Salfred DPRINTFN(0, "could not allocate USB " 5118184610Salfred "transfer for audio mixer!\n"); 5119184610Salfred return (ENOMEM); 5120184610Salfred } 5121184610Salfred if (!(sc->sc_mix_info & SOUND_MASK_VOLUME)) { 5122184610Salfred mix_setparentchild(m, SOUND_MIXER_VOLUME, SOUND_MASK_PCM); 5123184610Salfred mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE); 5124184610Salfred } 5125184610Salfred mix_setdevs(m, sc->sc_mix_info); 5126184610Salfred mix_setrecdevs(m, sc->sc_recsrc_info); 5127184610Salfred return (0); 5128184610Salfred} 5129184610Salfred 5130184610Salfredint 5131184610Salfreduaudio_mixer_uninit_sub(struct uaudio_softc *sc) 5132184610Salfred{ 5133184610Salfred DPRINTF("\n"); 5134184610Salfred 5135194228Sthompsa usbd_transfer_unsetup(sc->sc_mixer_xfer, 1); 5136184610Salfred 5137242438Shselasky sc->sc_mixer_lock = NULL; 5138242438Shselasky 5139184610Salfred return (0); 5140184610Salfred} 5141184610Salfred 5142184610Salfredvoid 5143184610Salfreduaudio_mixer_set(struct uaudio_softc *sc, unsigned type, 5144184610Salfred unsigned left, unsigned right) 5145184610Salfred{ 5146184610Salfred struct uaudio_mixer_node *mc; 5147242438Shselasky int chan; 5148184610Salfred 5149242438Shselasky for (mc = sc->sc_mixer_root; mc != NULL; mc = mc->next) { 5150184610Salfred 5151184610Salfred if (mc->ctl == type) { 5152242438Shselasky for (chan = 0; chan < mc->nchan; chan++) { 5153242438Shselasky uaudio_mixer_ctl_set(sc, mc, chan, 5154242438Shselasky (int)((chan == 0 ? left : right) * 5155242438Shselasky 255) / 100); 5156184610Salfred } 5157184610Salfred } 5158184610Salfred } 5159184610Salfred} 5160184610Salfred 5161184610Salfreduint32_t 5162184610Salfreduaudio_mixer_setrecsrc(struct uaudio_softc *sc, uint32_t src) 5163184610Salfred{ 5164184610Salfred struct uaudio_mixer_node *mc; 5165184610Salfred uint32_t mask; 5166184610Salfred uint32_t temp; 5167184610Salfred int32_t i; 5168184610Salfred 5169184610Salfred for (mc = sc->sc_mixer_root; mc; 5170184610Salfred mc = mc->next) { 5171184610Salfred 5172184610Salfred if ((mc->ctl == SOUND_MIXER_NRDEVICES) && 5173184610Salfred (mc->type == MIX_SELECTOR)) { 5174184610Salfred 5175184610Salfred /* compute selector mask */ 5176184610Salfred 5177184610Salfred mask = 0; 5178184610Salfred for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { 5179184610Salfred mask |= (1 << mc->slctrtype[i - 1]); 5180184610Salfred } 5181184610Salfred 5182184610Salfred temp = mask & src; 5183184610Salfred if (temp == 0) { 5184184610Salfred continue; 5185184610Salfred } 5186184610Salfred /* find the first set bit */ 5187184610Salfred temp = (-temp) & temp; 5188184610Salfred 5189184610Salfred /* update "src" */ 5190184610Salfred src &= ~mask; 5191184610Salfred src |= temp; 5192184610Salfred 5193184610Salfred for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { 5194184610Salfred if (temp != (1 << mc->slctrtype[i - 1])) { 5195184610Salfred continue; 5196184610Salfred } 5197184610Salfred uaudio_mixer_ctl_set(sc, mc, 0, i); 5198184610Salfred break; 5199184610Salfred } 5200184610Salfred } 5201184610Salfred } 5202184610Salfred return (src); 5203184610Salfred} 5204184610Salfred 5205184610Salfred/*========================================================================* 5206184610Salfred * MIDI support routines 5207184610Salfred *========================================================================*/ 5208184610Salfred 5209184610Salfredstatic void 5210194677Sthompsaumidi_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 5211184610Salfred{ 5212194677Sthompsa struct umidi_chan *chan = usbd_xfer_softc(xfer); 5213184610Salfred struct umidi_sub_chan *sub; 5214194677Sthompsa struct usb_page_cache *pc; 5215218791Shselasky uint8_t buf[4]; 5216184610Salfred uint8_t cmd_len; 5217184610Salfred uint8_t cn; 5218184610Salfred uint16_t pos; 5219194677Sthompsa int actlen; 5220184610Salfred 5221194677Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 5222194677Sthompsa 5223184610Salfred switch (USB_GET_STATE(xfer)) { 5224184610Salfred case USB_ST_TRANSFERRED: 5225184610Salfred 5226194677Sthompsa DPRINTF("actlen=%d bytes\n", actlen); 5227184610Salfred 5228184610Salfred pos = 0; 5229194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 5230184610Salfred 5231194677Sthompsa while (actlen >= 4) { 5232184610Salfred 5233218791Shselasky /* copy out the MIDI data */ 5234218791Shselasky usbd_copy_out(pc, pos, buf, 4); 5235218791Shselasky /* command length */ 5236218791Shselasky cmd_len = umidi_cmd_to_len[buf[0] & 0xF]; 5237218791Shselasky /* cable number */ 5238218791Shselasky cn = buf[0] >> 4; 5239218791Shselasky /* 5240218791Shselasky * Lookup sub-channel. The index is range 5241218791Shselasky * checked below. 5242218791Shselasky */ 5243184610Salfred sub = &chan->sub[cn]; 5244184610Salfred 5245272423Shselasky if ((cmd_len != 0) && (cn < chan->max_emb_jack) && 5246218791Shselasky (sub->read_open != 0)) { 5247218791Shselasky 5248218791Shselasky /* Send data to the application */ 5249218791Shselasky usb_fifo_put_data_linear( 5250218791Shselasky sub->fifo.fp[USB_FIFO_RX], 5251218791Shselasky buf + 1, cmd_len, 1); 5252184610Salfred } 5253194677Sthompsa actlen -= 4; 5254184610Salfred pos += 4; 5255184610Salfred } 5256184610Salfred 5257184610Salfred case USB_ST_SETUP: 5258184610Salfred DPRINTF("start\n"); 5259218791Shselaskytr_setup: 5260194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 5261194228Sthompsa usbd_transfer_submit(xfer); 5262218791Shselasky break; 5263184610Salfred 5264184610Salfred default: 5265194677Sthompsa DPRINTF("error=%s\n", usbd_errstr(error)); 5266184610Salfred 5267194677Sthompsa if (error != USB_ERR_CANCELLED) { 5268184610Salfred /* try to clear stall first */ 5269218791Shselasky usbd_xfer_set_stall(xfer); 5270218791Shselasky goto tr_setup; 5271184610Salfred } 5272218791Shselasky break; 5273184610Salfred } 5274184610Salfred} 5275184610Salfred 5276184610Salfred/* 5277184610Salfred * The following statemachine, that converts MIDI commands to 5278184610Salfred * USB MIDI packets, derives from Linux's usbmidi.c, which 5279184610Salfred * was written by "Clemens Ladisch": 5280184610Salfred * 5281184610Salfred * Returns: 5282184610Salfred * 0: No command 5283184610Salfred * Else: Command is complete 5284184610Salfred */ 5285184610Salfredstatic uint8_t 5286184610Salfredumidi_convert_to_usb(struct umidi_sub_chan *sub, uint8_t cn, uint8_t b) 5287184610Salfred{ 5288184610Salfred uint8_t p0 = (cn << 4); 5289184610Salfred 5290184610Salfred if (b >= 0xf8) { 5291184610Salfred sub->temp_0[0] = p0 | 0x0f; 5292184610Salfred sub->temp_0[1] = b; 5293184610Salfred sub->temp_0[2] = 0; 5294184610Salfred sub->temp_0[3] = 0; 5295184610Salfred sub->temp_cmd = sub->temp_0; 5296184610Salfred return (1); 5297184610Salfred 5298184610Salfred } else if (b >= 0xf0) { 5299184610Salfred switch (b) { 5300184610Salfred case 0xf0: /* system exclusive begin */ 5301184610Salfred sub->temp_1[1] = b; 5302184610Salfred sub->state = UMIDI_ST_SYSEX_1; 5303184610Salfred break; 5304184610Salfred case 0xf1: /* MIDI time code */ 5305184610Salfred case 0xf3: /* song select */ 5306184610Salfred sub->temp_1[1] = b; 5307184610Salfred sub->state = UMIDI_ST_1PARAM; 5308184610Salfred break; 5309184610Salfred case 0xf2: /* song position pointer */ 5310184610Salfred sub->temp_1[1] = b; 5311184610Salfred sub->state = UMIDI_ST_2PARAM_1; 5312184610Salfred break; 5313184610Salfred case 0xf4: /* unknown */ 5314184610Salfred case 0xf5: /* unknown */ 5315184610Salfred sub->state = UMIDI_ST_UNKNOWN; 5316184610Salfred break; 5317184610Salfred case 0xf6: /* tune request */ 5318184610Salfred sub->temp_1[0] = p0 | 0x05; 5319184610Salfred sub->temp_1[1] = 0xf6; 5320184610Salfred sub->temp_1[2] = 0; 5321184610Salfred sub->temp_1[3] = 0; 5322184610Salfred sub->temp_cmd = sub->temp_1; 5323184610Salfred sub->state = UMIDI_ST_UNKNOWN; 5324184610Salfred return (1); 5325184610Salfred 5326184610Salfred case 0xf7: /* system exclusive end */ 5327184610Salfred switch (sub->state) { 5328184610Salfred case UMIDI_ST_SYSEX_0: 5329184610Salfred sub->temp_1[0] = p0 | 0x05; 5330184610Salfred sub->temp_1[1] = 0xf7; 5331184610Salfred sub->temp_1[2] = 0; 5332184610Salfred sub->temp_1[3] = 0; 5333184610Salfred sub->temp_cmd = sub->temp_1; 5334184610Salfred sub->state = UMIDI_ST_UNKNOWN; 5335184610Salfred return (1); 5336184610Salfred case UMIDI_ST_SYSEX_1: 5337184610Salfred sub->temp_1[0] = p0 | 0x06; 5338184610Salfred sub->temp_1[2] = 0xf7; 5339184610Salfred sub->temp_1[3] = 0; 5340184610Salfred sub->temp_cmd = sub->temp_1; 5341184610Salfred sub->state = UMIDI_ST_UNKNOWN; 5342184610Salfred return (1); 5343184610Salfred case UMIDI_ST_SYSEX_2: 5344184610Salfred sub->temp_1[0] = p0 | 0x07; 5345184610Salfred sub->temp_1[3] = 0xf7; 5346184610Salfred sub->temp_cmd = sub->temp_1; 5347184610Salfred sub->state = UMIDI_ST_UNKNOWN; 5348184610Salfred return (1); 5349184610Salfred } 5350184610Salfred sub->state = UMIDI_ST_UNKNOWN; 5351184610Salfred break; 5352184610Salfred } 5353184610Salfred } else if (b >= 0x80) { 5354184610Salfred sub->temp_1[1] = b; 5355184610Salfred if ((b >= 0xc0) && (b <= 0xdf)) { 5356184610Salfred sub->state = UMIDI_ST_1PARAM; 5357184610Salfred } else { 5358184610Salfred sub->state = UMIDI_ST_2PARAM_1; 5359184610Salfred } 5360184610Salfred } else { /* b < 0x80 */ 5361184610Salfred switch (sub->state) { 5362184610Salfred case UMIDI_ST_1PARAM: 5363184610Salfred if (sub->temp_1[1] < 0xf0) { 5364184610Salfred p0 |= sub->temp_1[1] >> 4; 5365184610Salfred } else { 5366184610Salfred p0 |= 0x02; 5367184610Salfred sub->state = UMIDI_ST_UNKNOWN; 5368184610Salfred } 5369184610Salfred sub->temp_1[0] = p0; 5370184610Salfred sub->temp_1[2] = b; 5371184610Salfred sub->temp_1[3] = 0; 5372184610Salfred sub->temp_cmd = sub->temp_1; 5373184610Salfred return (1); 5374184610Salfred case UMIDI_ST_2PARAM_1: 5375184610Salfred sub->temp_1[2] = b; 5376184610Salfred sub->state = UMIDI_ST_2PARAM_2; 5377184610Salfred break; 5378184610Salfred case UMIDI_ST_2PARAM_2: 5379184610Salfred if (sub->temp_1[1] < 0xf0) { 5380184610Salfred p0 |= sub->temp_1[1] >> 4; 5381184610Salfred sub->state = UMIDI_ST_2PARAM_1; 5382184610Salfred } else { 5383184610Salfred p0 |= 0x03; 5384184610Salfred sub->state = UMIDI_ST_UNKNOWN; 5385184610Salfred } 5386184610Salfred sub->temp_1[0] = p0; 5387184610Salfred sub->temp_1[3] = b; 5388184610Salfred sub->temp_cmd = sub->temp_1; 5389184610Salfred return (1); 5390184610Salfred case UMIDI_ST_SYSEX_0: 5391184610Salfred sub->temp_1[1] = b; 5392184610Salfred sub->state = UMIDI_ST_SYSEX_1; 5393184610Salfred break; 5394184610Salfred case UMIDI_ST_SYSEX_1: 5395184610Salfred sub->temp_1[2] = b; 5396184610Salfred sub->state = UMIDI_ST_SYSEX_2; 5397184610Salfred break; 5398184610Salfred case UMIDI_ST_SYSEX_2: 5399184610Salfred sub->temp_1[0] = p0 | 0x04; 5400184610Salfred sub->temp_1[3] = b; 5401184610Salfred sub->temp_cmd = sub->temp_1; 5402184610Salfred sub->state = UMIDI_ST_SYSEX_0; 5403184610Salfred return (1); 5404218791Shselasky default: 5405218791Shselasky break; 5406184610Salfred } 5407184610Salfred } 5408184610Salfred return (0); 5409184610Salfred} 5410184610Salfred 5411184610Salfredstatic void 5412194677Sthompsaumidi_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 5413184610Salfred{ 5414194677Sthompsa struct umidi_chan *chan = usbd_xfer_softc(xfer); 5415184610Salfred struct umidi_sub_chan *sub; 5416194677Sthompsa struct usb_page_cache *pc; 5417184610Salfred uint32_t actlen; 5418223727Shselasky uint16_t nframes; 5419184610Salfred uint8_t buf; 5420184610Salfred uint8_t start_cable; 5421184610Salfred uint8_t tr_any; 5422194677Sthompsa int len; 5423184610Salfred 5424194677Sthompsa usbd_xfer_status(xfer, &len, NULL, NULL, NULL); 5425194677Sthompsa 5426223727Shselasky /* 5427223727Shselasky * NOTE: Some MIDI devices only accept 4 bytes of data per 5428223727Shselasky * short terminated USB transfer. 5429223727Shselasky */ 5430184610Salfred switch (USB_GET_STATE(xfer)) { 5431184610Salfred case USB_ST_TRANSFERRED: 5432194677Sthompsa DPRINTF("actlen=%d bytes\n", len); 5433184610Salfred 5434184610Salfred case USB_ST_SETUP: 5435218791Shselaskytr_setup: 5436184610Salfred DPRINTF("start\n"); 5437184610Salfred 5438223727Shselasky nframes = 0; /* reset */ 5439184610Salfred start_cable = chan->curr_cable; 5440184610Salfred tr_any = 0; 5441223736Shselasky pc = usbd_xfer_get_frame(xfer, 0); 5442184610Salfred 5443184610Salfred while (1) { 5444184610Salfred 5445184610Salfred /* round robin de-queueing */ 5446184610Salfred 5447184610Salfred sub = &chan->sub[chan->curr_cable]; 5448184610Salfred 5449184610Salfred if (sub->write_open) { 5450223727Shselasky usb_fifo_get_data_linear(sub->fifo.fp[USB_FIFO_TX], 5451223727Shselasky &buf, 1, &actlen, 0); 5452184610Salfred } else { 5453184610Salfred actlen = 0; 5454184610Salfred } 5455184610Salfred 5456184610Salfred if (actlen) { 5457184610Salfred 5458184610Salfred tr_any = 1; 5459184610Salfred 5460223727Shselasky DPRINTF("byte=0x%02x from FIFO %u\n", buf, 5461223727Shselasky (unsigned int)chan->curr_cable); 5462184610Salfred 5463184610Salfred if (umidi_convert_to_usb(sub, chan->curr_cable, buf)) { 5464184610Salfred 5465223727Shselasky DPRINTF("sub=0x%02x 0x%02x 0x%02x 0x%02x\n", 5466184610Salfred sub->temp_cmd[0], sub->temp_cmd[1], 5467184610Salfred sub->temp_cmd[2], sub->temp_cmd[3]); 5468184610Salfred 5469223736Shselasky usbd_copy_in(pc, nframes * 4, sub->temp_cmd, 4); 5470184610Salfred 5471223736Shselasky nframes++; 5472184610Salfred 5473223736Shselasky if ((nframes >= UMIDI_TX_FRAMES) || (chan->single_command != 0)) 5474184610Salfred break; 5475184610Salfred } else { 5476184610Salfred continue; 5477184610Salfred } 5478184610Salfred } 5479223727Shselasky 5480184610Salfred chan->curr_cable++; 5481272423Shselasky if (chan->curr_cable >= chan->max_emb_jack) 5482184610Salfred chan->curr_cable = 0; 5483223727Shselasky 5484184610Salfred if (chan->curr_cable == start_cable) { 5485223727Shselasky if (tr_any == 0) 5486184610Salfred break; 5487184610Salfred tr_any = 0; 5488184610Salfred } 5489184610Salfred } 5490184610Salfred 5491223736Shselasky if (nframes != 0) { 5492223727Shselasky DPRINTF("Transferring %d frames\n", (int)nframes); 5493223736Shselasky usbd_xfer_set_frame_len(xfer, 0, 4 * nframes); 5494194228Sthompsa usbd_transfer_submit(xfer); 5495184610Salfred } 5496218791Shselasky break; 5497184610Salfred 5498184610Salfred default: /* Error */ 5499184610Salfred 5500194677Sthompsa DPRINTF("error=%s\n", usbd_errstr(error)); 5501184610Salfred 5502194677Sthompsa if (error != USB_ERR_CANCELLED) { 5503184610Salfred /* try to clear stall first */ 5504218791Shselasky usbd_xfer_set_stall(xfer); 5505218791Shselasky goto tr_setup; 5506184610Salfred } 5507218791Shselasky break; 5508184610Salfred } 5509184610Salfred} 5510184610Salfred 5511184610Salfredstatic struct umidi_sub_chan * 5512192984Sthompsaumidi_sub_by_fifo(struct usb_fifo *fifo) 5513184610Salfred{ 5514194677Sthompsa struct umidi_chan *chan = usb_fifo_softc(fifo); 5515184610Salfred struct umidi_sub_chan *sub; 5516184610Salfred uint32_t n; 5517184610Salfred 5518272423Shselasky for (n = 0; n < UMIDI_EMB_JACK_MAX; n++) { 5519184610Salfred sub = &chan->sub[n]; 5520184610Salfred if ((sub->fifo.fp[USB_FIFO_RX] == fifo) || 5521184610Salfred (sub->fifo.fp[USB_FIFO_TX] == fifo)) { 5522184610Salfred return (sub); 5523184610Salfred } 5524184610Salfred } 5525184610Salfred 5526192984Sthompsa panic("%s:%d cannot find usb_fifo!\n", 5527184610Salfred __FILE__, __LINE__); 5528184610Salfred 5529184610Salfred return (NULL); 5530184610Salfred} 5531184610Salfred 5532184610Salfredstatic void 5533192984Sthompsaumidi_start_read(struct usb_fifo *fifo) 5534184610Salfred{ 5535194677Sthompsa struct umidi_chan *chan = usb_fifo_softc(fifo); 5536184610Salfred 5537218791Shselasky usbd_transfer_start(chan->xfer[UMIDI_RX_TRANSFER]); 5538184610Salfred} 5539184610Salfred 5540184610Salfredstatic void 5541192984Sthompsaumidi_stop_read(struct usb_fifo *fifo) 5542184610Salfred{ 5543194677Sthompsa struct umidi_chan *chan = usb_fifo_softc(fifo); 5544184610Salfred struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo); 5545184610Salfred 5546184610Salfred DPRINTF("\n"); 5547184610Salfred 5548184610Salfred sub->read_open = 0; 5549184610Salfred 5550184610Salfred if (--(chan->read_open_refcount) == 0) { 5551184610Salfred /* 5552184610Salfred * XXX don't stop the read transfer here, hence that causes 5553184610Salfred * problems with some MIDI adapters 5554184610Salfred */ 5555184610Salfred DPRINTF("(stopping read transfer)\n"); 5556184610Salfred } 5557184610Salfred} 5558184610Salfred 5559184610Salfredstatic void 5560192984Sthompsaumidi_start_write(struct usb_fifo *fifo) 5561184610Salfred{ 5562194677Sthompsa struct umidi_chan *chan = usb_fifo_softc(fifo); 5563184610Salfred 5564218791Shselasky usbd_transfer_start(chan->xfer[UMIDI_TX_TRANSFER]); 5565184610Salfred} 5566184610Salfred 5567184610Salfredstatic void 5568192984Sthompsaumidi_stop_write(struct usb_fifo *fifo) 5569184610Salfred{ 5570194677Sthompsa struct umidi_chan *chan = usb_fifo_softc(fifo); 5571184610Salfred struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo); 5572184610Salfred 5573184610Salfred DPRINTF("\n"); 5574184610Salfred 5575184610Salfred sub->write_open = 0; 5576184610Salfred 5577184610Salfred if (--(chan->write_open_refcount) == 0) { 5578184610Salfred DPRINTF("(stopping write transfer)\n"); 5579218791Shselasky usbd_transfer_stop(chan->xfer[UMIDI_TX_TRANSFER]); 5580184610Salfred } 5581184610Salfred} 5582184610Salfred 5583184610Salfredstatic int 5584192984Sthompsaumidi_open(struct usb_fifo *fifo, int fflags) 5585184610Salfred{ 5586194677Sthompsa struct umidi_chan *chan = usb_fifo_softc(fifo); 5587184610Salfred struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo); 5588184610Salfred 5589184610Salfred if (fflags & FREAD) { 5590194228Sthompsa if (usb_fifo_alloc_buffer(fifo, 4, (1024 / 4))) { 5591184610Salfred return (ENOMEM); 5592184610Salfred } 5593195120Sthompsa mtx_lock(&chan->mtx); 5594184610Salfred chan->read_open_refcount++; 5595184610Salfred sub->read_open = 1; 5596195120Sthompsa mtx_unlock(&chan->mtx); 5597184610Salfred } 5598184610Salfred if (fflags & FWRITE) { 5599194228Sthompsa if (usb_fifo_alloc_buffer(fifo, 32, (1024 / 32))) { 5600184610Salfred return (ENOMEM); 5601184610Salfred } 5602184610Salfred /* clear stall first */ 5603195120Sthompsa mtx_lock(&chan->mtx); 5604184610Salfred chan->write_open_refcount++; 5605184610Salfred sub->write_open = 1; 5606184610Salfred 5607184610Salfred /* reset */ 5608184610Salfred sub->state = UMIDI_ST_UNKNOWN; 5609195120Sthompsa mtx_unlock(&chan->mtx); 5610184610Salfred } 5611184610Salfred return (0); /* success */ 5612184610Salfred} 5613184610Salfred 5614184610Salfredstatic void 5615192984Sthompsaumidi_close(struct usb_fifo *fifo, int fflags) 5616184610Salfred{ 5617184610Salfred if (fflags & FREAD) { 5618194228Sthompsa usb_fifo_free_buffer(fifo); 5619184610Salfred } 5620184610Salfred if (fflags & FWRITE) { 5621194228Sthompsa usb_fifo_free_buffer(fifo); 5622184610Salfred } 5623184610Salfred} 5624184610Salfred 5625184610Salfred 5626184610Salfredstatic int 5627192984Sthompsaumidi_ioctl(struct usb_fifo *fifo, u_long cmd, void *data, 5628189110Sthompsa int fflags) 5629184610Salfred{ 5630184610Salfred return (ENODEV); 5631184610Salfred} 5632184610Salfred 5633184610Salfredstatic void 5634184610Salfredumidi_init(device_t dev) 5635184610Salfred{ 5636184610Salfred struct uaudio_softc *sc = device_get_softc(dev); 5637184610Salfred struct umidi_chan *chan = &sc->sc_midi_chan; 5638184610Salfred 5639184610Salfred mtx_init(&chan->mtx, "umidi lock", NULL, MTX_DEF | MTX_RECURSE); 5640184610Salfred} 5641184610Salfred 5642192984Sthompsastatic struct usb_fifo_methods umidi_fifo_methods = { 5643184610Salfred .f_start_read = &umidi_start_read, 5644184610Salfred .f_start_write = &umidi_start_write, 5645184610Salfred .f_stop_read = &umidi_stop_read, 5646184610Salfred .f_stop_write = &umidi_stop_write, 5647184610Salfred .f_open = &umidi_open, 5648184610Salfred .f_close = &umidi_close, 5649184610Salfred .f_ioctl = &umidi_ioctl, 5650184610Salfred .basename[0] = "umidi", 5651184610Salfred}; 5652184610Salfred 5653218988Shselaskystatic int 5654184610Salfredumidi_probe(device_t dev) 5655184610Salfred{ 5656184610Salfred struct uaudio_softc *sc = device_get_softc(dev); 5657192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 5658184610Salfred struct umidi_chan *chan = &sc->sc_midi_chan; 5659184610Salfred struct umidi_sub_chan *sub; 5660184610Salfred int unit = device_get_unit(dev); 5661184610Salfred int error; 5662184610Salfred uint32_t n; 5663184610Salfred 5664223736Shselasky if (usb_test_quirk(uaa, UQ_SINGLE_CMD_MIDI)) 5665223736Shselasky chan->single_command = 1; 5666223736Shselasky 5667194228Sthompsa if (usbd_set_alt_interface_index(sc->sc_udev, chan->iface_index, 5668184610Salfred chan->iface_alt_index)) { 5669184610Salfred DPRINTF("setting of alternate index failed!\n"); 5670184610Salfred goto detach; 5671184610Salfred } 5672218791Shselasky usbd_set_parent_iface(sc->sc_udev, chan->iface_index, 5673218791Shselasky sc->sc_mixer_iface_index); 5674184610Salfred 5675194228Sthompsa error = usbd_transfer_setup(uaa->device, &chan->iface_index, 5676184610Salfred chan->xfer, umidi_config, UMIDI_N_TRANSFER, 5677184610Salfred chan, &chan->mtx); 5678184610Salfred if (error) { 5679194228Sthompsa DPRINTF("error=%s\n", usbd_errstr(error)); 5680184610Salfred goto detach; 5681184610Salfred } 5682263643Shselasky 5683263643Shselasky /* 5684263643Shselasky * Some USB MIDI device makers couldn't resist using 5685263643Shselasky * wMaxPacketSize = 4 for RX and TX BULK endpoints, although 5686263643Shselasky * that size is an unsupported value for FULL speed BULK 5687263643Shselasky * endpoints. The same applies to some HIGH speed MIDI devices 5688263643Shselasky * which are using a wMaxPacketSize different from 512 bytes. 5689263643Shselasky * 5690263643Shselasky * Refer to section 5.8.3 in USB 2.0 PDF: Cite: "All Host 5691263643Shselasky * Controllers are required to have support for 8-, 16-, 32-, 5692263643Shselasky * and 64-byte maximum packet sizes for full-speed bulk 5693263643Shselasky * endpoints and 512 bytes for high-speed bulk endpoints." 5694263643Shselasky */ 5695263643Shselasky if (usbd_xfer_maxp_was_clamped(chan->xfer[UMIDI_TX_TRANSFER])) 5696263643Shselasky chan->single_command = 1; 5697263643Shselasky 5698263643Shselasky if (chan->single_command != 0) 5699263643Shselasky device_printf(dev, "Single command MIDI quirk enabled\n"); 5700263643Shselasky 5701272423Shselasky if ((chan->max_emb_jack == 0) || 5702272423Shselasky (chan->max_emb_jack > UMIDI_EMB_JACK_MAX)) { 5703272423Shselasky chan->max_emb_jack = UMIDI_EMB_JACK_MAX; 5704184610Salfred } 5705184610Salfred 5706272423Shselasky for (n = 0; n < chan->max_emb_jack; n++) { 5707184610Salfred 5708184610Salfred sub = &chan->sub[n]; 5709184610Salfred 5710194228Sthompsa error = usb_fifo_attach(sc->sc_udev, chan, &chan->mtx, 5711184610Salfred &umidi_fifo_methods, &sub->fifo, unit, n, 5712189110Sthompsa chan->iface_index, 5713189110Sthompsa UID_ROOT, GID_OPERATOR, 0644); 5714184610Salfred if (error) { 5715184610Salfred goto detach; 5716184610Salfred } 5717184610Salfred } 5718184610Salfred 5719184610Salfred mtx_lock(&chan->mtx); 5720184610Salfred 5721184610Salfred /* 5722218791Shselasky * NOTE: At least one device will not work properly unless the 5723218791Shselasky * BULK IN pipe is open all the time. This might have to do 5724218791Shselasky * about that the internal queues of the device overflow if we 5725218791Shselasky * don't read them regularly. 5726184610Salfred */ 5727218791Shselasky usbd_transfer_start(chan->xfer[UMIDI_RX_TRANSFER]); 5728184610Salfred 5729184610Salfred mtx_unlock(&chan->mtx); 5730184610Salfred 5731184610Salfred return (0); /* success */ 5732184610Salfred 5733184610Salfreddetach: 5734184610Salfred return (ENXIO); /* failure */ 5735184610Salfred} 5736184610Salfred 5737218988Shselaskystatic int 5738184610Salfredumidi_detach(device_t dev) 5739184610Salfred{ 5740184610Salfred struct uaudio_softc *sc = device_get_softc(dev); 5741184610Salfred struct umidi_chan *chan = &sc->sc_midi_chan; 5742184610Salfred uint32_t n; 5743184610Salfred 5744272423Shselasky for (n = 0; n < UMIDI_EMB_JACK_MAX; n++) 5745194228Sthompsa usb_fifo_detach(&chan->sub[n].fifo); 5746184610Salfred 5747184610Salfred mtx_lock(&chan->mtx); 5748184610Salfred 5749218791Shselasky usbd_transfer_stop(chan->xfer[UMIDI_RX_TRANSFER]); 5750184610Salfred 5751184610Salfred mtx_unlock(&chan->mtx); 5752184610Salfred 5753194228Sthompsa usbd_transfer_unsetup(chan->xfer, UMIDI_N_TRANSFER); 5754184610Salfred 5755184610Salfred mtx_destroy(&chan->mtx); 5756184610Salfred 5757184610Salfred return (0); 5758184610Salfred} 5759184610Salfred 5760246421Shselaskystatic void 5761246421Shselaskyuaudio_hid_rx_callback(struct usb_xfer *xfer, usb_error_t error) 5762246421Shselasky{ 5763246421Shselasky struct uaudio_softc *sc = usbd_xfer_softc(xfer); 5764246421Shselasky const uint8_t *buffer = usbd_xfer_get_frame_buffer(xfer, 0); 5765246421Shselasky struct snd_mixer *m; 5766246421Shselasky uint8_t id; 5767246421Shselasky int actlen; 5768246421Shselasky 5769246421Shselasky usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 5770246421Shselasky 5771246421Shselasky switch (USB_GET_STATE(xfer)) { 5772246421Shselasky case USB_ST_TRANSFERRED: 5773246421Shselasky DPRINTF("actlen=%d\n", actlen); 5774246421Shselasky 5775246421Shselasky if (actlen != 0 && 5776246421Shselasky (sc->sc_hid.flags & UAUDIO_HID_HAS_ID)) { 5777246421Shselasky id = *buffer; 5778246421Shselasky buffer++; 5779246421Shselasky actlen--; 5780246421Shselasky } else { 5781246421Shselasky id = 0; 5782246421Shselasky } 5783246421Shselasky 5784246421Shselasky m = sc->sc_mixer_dev; 5785246421Shselasky 5786246454Shselasky if ((sc->sc_hid.flags & UAUDIO_HID_HAS_MUTE) && 5787246454Shselasky (sc->sc_hid.mute_id == id) && 5788246454Shselasky hid_get_data(buffer, actlen, 5789246454Shselasky &sc->sc_hid.mute_loc)) { 5790246454Shselasky 5791246454Shselasky DPRINTF("Mute toggle\n"); 5792246454Shselasky 5793246454Shselasky mixer_hwvol_mute_locked(m); 5794246454Shselasky } 5795246454Shselasky 5796246421Shselasky if ((sc->sc_hid.flags & UAUDIO_HID_HAS_VOLUME_UP) && 5797246421Shselasky (sc->sc_hid.volume_up_id == id) && 5798246421Shselasky hid_get_data(buffer, actlen, 5799246421Shselasky &sc->sc_hid.volume_up_loc)) { 5800246421Shselasky 5801246421Shselasky DPRINTF("Volume Up\n"); 5802246421Shselasky 5803246454Shselasky mixer_hwvol_step_locked(m, 1, 1); 5804246421Shselasky } 5805246421Shselasky 5806246421Shselasky if ((sc->sc_hid.flags & UAUDIO_HID_HAS_VOLUME_DOWN) && 5807246421Shselasky (sc->sc_hid.volume_down_id == id) && 5808246421Shselasky hid_get_data(buffer, actlen, 5809246421Shselasky &sc->sc_hid.volume_down_loc)) { 5810246421Shselasky 5811246421Shselasky DPRINTF("Volume Down\n"); 5812246421Shselasky 5813246454Shselasky mixer_hwvol_step_locked(m, -1, -1); 5814246421Shselasky } 5815246421Shselasky 5816246421Shselasky case USB_ST_SETUP: 5817246421Shselaskytr_setup: 5818246421Shselasky /* check if we can put more data into the FIFO */ 5819246421Shselasky usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 5820246421Shselasky usbd_transfer_submit(xfer); 5821246421Shselasky break; 5822246421Shselasky 5823246421Shselasky default: /* Error */ 5824250765Shselasky 5825250765Shselasky DPRINTF("error=%s\n", usbd_errstr(error)); 5826250765Shselasky 5827246421Shselasky if (error != USB_ERR_CANCELLED) { 5828250765Shselasky /* try to clear stall first */ 5829246421Shselasky usbd_xfer_set_stall(xfer); 5830246421Shselasky goto tr_setup; 5831246421Shselasky } 5832246421Shselasky break; 5833246421Shselasky } 5834246421Shselasky} 5835246421Shselasky 5836246421Shselaskystatic int 5837246421Shselaskyuaudio_hid_probe(struct uaudio_softc *sc, 5838246421Shselasky struct usb_attach_arg *uaa) 5839246421Shselasky{ 5840246421Shselasky void *d_ptr; 5841246421Shselasky uint32_t flags; 5842246421Shselasky uint16_t d_len; 5843246421Shselasky uint8_t id; 5844246421Shselasky int error; 5845246421Shselasky 5846246421Shselasky if (!(sc->sc_hid.flags & UAUDIO_HID_VALID)) 5847246421Shselasky return (-1); 5848246421Shselasky 5849246421Shselasky if (sc->sc_mixer_lock == NULL) 5850246421Shselasky return (-1); 5851246421Shselasky 5852246421Shselasky /* Get HID descriptor */ 5853246421Shselasky error = usbd_req_get_hid_desc(uaa->device, NULL, &d_ptr, 5854246421Shselasky &d_len, M_TEMP, sc->sc_hid.iface_index); 5855246421Shselasky 5856246421Shselasky if (error) { 5857246421Shselasky DPRINTF("error reading report description\n"); 5858246421Shselasky return (-1); 5859246421Shselasky } 5860246421Shselasky 5861246421Shselasky /* check if there is an ID byte */ 5862246421Shselasky hid_report_size(d_ptr, d_len, hid_input, &id); 5863246421Shselasky 5864246421Shselasky if (id != 0) 5865246421Shselasky sc->sc_hid.flags |= UAUDIO_HID_HAS_ID; 5866246421Shselasky 5867246421Shselasky if (hid_locate(d_ptr, d_len, 5868246421Shselasky HID_USAGE2(HUP_CONSUMER, 0xE9 /* Volume Increment */), 5869246421Shselasky hid_input, 0, &sc->sc_hid.volume_up_loc, &flags, 5870246421Shselasky &sc->sc_hid.volume_up_id)) { 5871246421Shselasky if (flags & HIO_VARIABLE) 5872246421Shselasky sc->sc_hid.flags |= UAUDIO_HID_HAS_VOLUME_UP; 5873246421Shselasky DPRINTFN(1, "Found Volume Up key\n"); 5874246421Shselasky } 5875246421Shselasky 5876246421Shselasky if (hid_locate(d_ptr, d_len, 5877246421Shselasky HID_USAGE2(HUP_CONSUMER, 0xEA /* Volume Decrement */), 5878246421Shselasky hid_input, 0, &sc->sc_hid.volume_down_loc, &flags, 5879246421Shselasky &sc->sc_hid.volume_down_id)) { 5880246421Shselasky if (flags & HIO_VARIABLE) 5881246421Shselasky sc->sc_hid.flags |= UAUDIO_HID_HAS_VOLUME_DOWN; 5882246421Shselasky DPRINTFN(1, "Found Volume Down key\n"); 5883246421Shselasky } 5884246421Shselasky 5885246454Shselasky if (hid_locate(d_ptr, d_len, 5886246454Shselasky HID_USAGE2(HUP_CONSUMER, 0xE2 /* Mute */), 5887246454Shselasky hid_input, 0, &sc->sc_hid.mute_loc, &flags, 5888246454Shselasky &sc->sc_hid.mute_id)) { 5889246454Shselasky if (flags & HIO_VARIABLE) 5890246454Shselasky sc->sc_hid.flags |= UAUDIO_HID_HAS_MUTE; 5891246454Shselasky DPRINTFN(1, "Found Mute key\n"); 5892246454Shselasky } 5893246454Shselasky 5894246421Shselasky free(d_ptr, M_TEMP); 5895246421Shselasky 5896246421Shselasky if (!(sc->sc_hid.flags & (UAUDIO_HID_HAS_VOLUME_UP | 5897246454Shselasky UAUDIO_HID_HAS_VOLUME_DOWN | 5898246454Shselasky UAUDIO_HID_HAS_MUTE))) { 5899246421Shselasky DPRINTFN(1, "Did not find any volume related keys\n"); 5900246421Shselasky return (-1); 5901246421Shselasky } 5902246421Shselasky 5903246421Shselasky /* prevent the uhid driver from attaching */ 5904246421Shselasky usbd_set_parent_iface(uaa->device, sc->sc_hid.iface_index, 5905246421Shselasky sc->sc_mixer_iface_index); 5906246421Shselasky 5907246421Shselasky /* allocate USB transfers */ 5908246421Shselasky error = usbd_transfer_setup(uaa->device, &sc->sc_hid.iface_index, 5909246421Shselasky sc->sc_hid.xfer, uaudio_hid_config, UAUDIO_HID_N_TRANSFER, 5910246421Shselasky sc, sc->sc_mixer_lock); 5911246421Shselasky if (error) { 5912246421Shselasky DPRINTF("error=%s\n", usbd_errstr(error)); 5913246421Shselasky return (-1); 5914246421Shselasky } 5915246421Shselasky return (0); 5916246421Shselasky} 5917246421Shselasky 5918246421Shselaskystatic void 5919246421Shselaskyuaudio_hid_detach(struct uaudio_softc *sc) 5920246421Shselasky{ 5921246421Shselasky usbd_transfer_unsetup(sc->sc_hid.xfer, UAUDIO_HID_N_TRANSFER); 5922246421Shselasky} 5923246421Shselasky 5924266485ShselaskyDRIVER_MODULE_ORDERED(uaudio, uhub, uaudio_driver, uaudio_devclass, NULL, 0, SI_ORDER_ANY); 5925188942SthompsaMODULE_DEPEND(uaudio, usb, 1, 1, 1); 5926184610SalfredMODULE_DEPEND(uaudio, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 5927184610SalfredMODULE_VERSION(uaudio, 1); 5928