uaudio.c revision 209450
1184610Salfred/* $NetBSD: uaudio.c,v 1.91 2004/11/05 17:46:14 kent Exp $ */ 2184610Salfred/* $FreeBSD: head/sys/dev/sound/usb/uaudio.c 209450 2010-06-22 21:13:36Z thompsa $ */ 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 34184610Salfred/* 35184610Salfred * USB audio specs: http://www.usb.org/developers/devclass_docs/audio10.pdf 36184610Salfred * http://www.usb.org/developers/devclass_docs/frmts10.pdf 37184610Salfred * http://www.usb.org/developers/devclass_docs/termt10.pdf 38184610Salfred */ 39184610Salfred 40184610Salfred/* 41184610Salfred * Also merged: 42184610Salfred * $NetBSD: uaudio.c,v 1.94 2005/01/15 15:19:53 kent Exp $ 43184610Salfred * $NetBSD: uaudio.c,v 1.95 2005/01/16 06:02:19 dsainty Exp $ 44184610Salfred * $NetBSD: uaudio.c,v 1.96 2005/01/16 12:46:00 kent Exp $ 45184610Salfred * $NetBSD: uaudio.c,v 1.97 2005/02/24 08:19:38 martin Exp $ 46184610Salfred */ 47184610Salfred 48194677Sthompsa#include <sys/stdint.h> 49194677Sthompsa#include <sys/stddef.h> 50194677Sthompsa#include <sys/param.h> 51194677Sthompsa#include <sys/queue.h> 52194677Sthompsa#include <sys/types.h> 53194677Sthompsa#include <sys/systm.h> 54194677Sthompsa#include <sys/kernel.h> 55194677Sthompsa#include <sys/bus.h> 56194677Sthompsa#include <sys/linker_set.h> 57194677Sthompsa#include <sys/module.h> 58194677Sthompsa#include <sys/lock.h> 59194677Sthompsa#include <sys/mutex.h> 60194677Sthompsa#include <sys/condvar.h> 61194677Sthompsa#include <sys/sysctl.h> 62194677Sthompsa#include <sys/sx.h> 63194677Sthompsa#include <sys/unistd.h> 64194677Sthompsa#include <sys/callout.h> 65194677Sthompsa#include <sys/malloc.h> 66194677Sthompsa#include <sys/priv.h> 67194677Sthompsa 68188746Sthompsa#include "usbdevs.h" 69188942Sthompsa#include <dev/usb/usb.h> 70194677Sthompsa#include <dev/usb/usbdi.h> 71194677Sthompsa#include <dev/usb/usbdi_util.h> 72184610Salfred 73184610Salfred#define USB_DEBUG_VAR uaudio_debug 74188942Sthompsa#include <dev/usb/usb_debug.h> 75184610Salfred 76188942Sthompsa#include <dev/usb/quirk/usb_quirk.h> 77184610Salfred 78184610Salfred#include <sys/reboot.h> /* for bootverbose */ 79184610Salfred 80193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS 81193640Sariff#include "opt_snd.h" 82193640Sariff#endif 83193640Sariff 84184610Salfred#include <dev/sound/pcm/sound.h> 85188957Sthompsa#include <dev/sound/usb/uaudioreg.h> 86188957Sthompsa#include <dev/sound/usb/uaudio.h> 87184610Salfred#include <dev/sound/chip.h> 88184610Salfred#include "feeder_if.h" 89184610Salfred 90200825Sthompsastatic int uaudio_default_rate = 0; /* use rate list */ 91186730Salfredstatic int uaudio_default_bits = 32; 92200825Sthompsastatic int uaudio_default_channels = 0; /* use default */ 93186730Salfred 94207077Sthompsa#ifdef USB_DEBUG 95184610Salfredstatic int uaudio_debug = 0; 96184610Salfred 97192505SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, uaudio, CTLFLAG_RW, 0, "USB uaudio"); 98200825Sthompsa 99192505SthompsaSYSCTL_INT(_hw_usb_uaudio, OID_AUTO, debug, CTLFLAG_RW, 100184610Salfred &uaudio_debug, 0, "uaudio debug level"); 101200825Sthompsa 102200825SthompsaTUNABLE_INT("hw.usb.uaudio.default_rate", &uaudio_default_rate); 103192505SthompsaSYSCTL_INT(_hw_usb_uaudio, OID_AUTO, default_rate, CTLFLAG_RW, 104186730Salfred &uaudio_default_rate, 0, "uaudio default sample rate"); 105200825Sthompsa 106200825SthompsaTUNABLE_INT("hw.usb.uaudio.default_bits", &uaudio_default_bits); 107192505SthompsaSYSCTL_INT(_hw_usb_uaudio, OID_AUTO, default_bits, CTLFLAG_RW, 108186730Salfred &uaudio_default_bits, 0, "uaudio default sample bits"); 109200825Sthompsa 110200825SthompsaTUNABLE_INT("hw.usb.uaudio.default_channels", &uaudio_default_channels); 111192505SthompsaSYSCTL_INT(_hw_usb_uaudio, OID_AUTO, default_channels, CTLFLAG_RW, 112186730Salfred &uaudio_default_channels, 0, "uaudio default sample channels"); 113184610Salfred#endif 114184610Salfred 115199060Sthompsa#define UAUDIO_NFRAMES 64 /* must be factor of 8 due HS-USB */ 116184610Salfred#define UAUDIO_NCHANBUFS 2 /* number of outstanding request */ 117184610Salfred#define UAUDIO_RECURSE_LIMIT 24 /* rounds */ 118184610Salfred 119184610Salfred#define MAKE_WORD(h,l) (((h) << 8) | (l)) 120184610Salfred#define BIT_TEST(bm,bno) (((bm)[(bno) / 8] >> (7 - ((bno) % 8))) & 1) 121193465Sthompsa#define UAUDIO_MAX_CHAN(x) (x) 122184610Salfred 123184610Salfredstruct uaudio_mixer_node { 124184610Salfred int32_t minval; 125184610Salfred int32_t maxval; 126184610Salfred#define MIX_MAX_CHAN 8 127184610Salfred int32_t wValue[MIX_MAX_CHAN]; /* using nchan */ 128184610Salfred uint32_t mul; 129184610Salfred uint32_t ctl; 130184610Salfred 131184610Salfred uint16_t wData[MIX_MAX_CHAN]; /* using nchan */ 132184610Salfred uint16_t wIndex; 133184610Salfred 134184610Salfred uint8_t update[(MIX_MAX_CHAN + 7) / 8]; 135184610Salfred uint8_t nchan; 136184610Salfred uint8_t type; 137184610Salfred#define MIX_ON_OFF 1 138184610Salfred#define MIX_SIGNED_16 2 139184610Salfred#define MIX_UNSIGNED_16 3 140184610Salfred#define MIX_SIGNED_8 4 141184610Salfred#define MIX_SELECTOR 5 142184610Salfred#define MIX_UNKNOWN 6 143184610Salfred#define MIX_SIZE(n) ((((n) == MIX_SIGNED_16) || \ 144184610Salfred ((n) == MIX_UNSIGNED_16)) ? 2 : 1) 145184610Salfred#define MIX_UNSIGNED(n) ((n) == MIX_UNSIGNED_16) 146184610Salfred 147184610Salfred#define MAX_SELECTOR_INPUT_PIN 256 148184610Salfred uint8_t slctrtype[MAX_SELECTOR_INPUT_PIN]; 149184610Salfred uint8_t class; 150184610Salfred 151184610Salfred struct uaudio_mixer_node *next; 152184610Salfred}; 153184610Salfred 154184610Salfredstruct uaudio_chan { 155184610Salfred struct pcmchan_caps pcm_cap; /* capabilities */ 156184610Salfred 157184610Salfred struct snd_dbuf *pcm_buf; 158203678Sbrucec const struct usb_config *usb_cfg; 159184610Salfred struct mtx *pcm_mtx; /* lock protecting this structure */ 160184610Salfred struct uaudio_softc *priv_sc; 161184610Salfred struct pcm_channel *pcm_ch; 162192984Sthompsa struct usb_xfer *xfer[UAUDIO_NCHANBUFS]; 163203678Sbrucec const struct usb_audio_streaming_interface_descriptor *p_asid; 164203678Sbrucec const struct usb_audio_streaming_type1_descriptor *p_asf1d; 165203678Sbrucec const struct usb_audio_streaming_endpoint_descriptor *p_sed; 166203678Sbrucec const usb_endpoint_descriptor_audio_t *p_ed1; 167203678Sbrucec const usb_endpoint_descriptor_audio_t *p_ed2; 168184610Salfred const struct uaudio_format *p_fmt; 169184610Salfred 170184610Salfred uint8_t *buf; /* pointer to buffer */ 171184610Salfred uint8_t *start; /* upper layer buffer start */ 172184610Salfred uint8_t *end; /* upper layer buffer end */ 173184610Salfred uint8_t *cur; /* current position in upper layer 174184610Salfred * buffer */ 175184610Salfred 176186730Salfred uint32_t intr_size; /* in bytes */ 177199060Sthompsa uint32_t intr_frames; /* in units */ 178184610Salfred uint32_t sample_rate; 179200825Sthompsa uint32_t frames_per_second; 180200825Sthompsa uint32_t sample_rem; 181200825Sthompsa uint32_t sample_curr; 182200825Sthompsa 183184610Salfred uint32_t format; 184184610Salfred uint32_t pcm_format[2]; 185184610Salfred 186200825Sthompsa uint16_t bytes_per_frame[2]; 187184610Salfred 188200825Sthompsa uint16_t sample_size; 189200825Sthompsa 190184610Salfred uint8_t valid; 191184610Salfred uint8_t iface_index; 192184610Salfred uint8_t iface_alt_index; 193184610Salfred}; 194184610Salfred 195184610Salfred#define UMIDI_N_TRANSFER 4 /* units */ 196184610Salfred#define UMIDI_CABLES_MAX 16 /* units */ 197184610Salfred#define UMIDI_BULK_SIZE 1024 /* bytes */ 198184610Salfred 199184610Salfredstruct umidi_sub_chan { 200192984Sthompsa struct usb_fifo_sc fifo; 201184610Salfred uint8_t *temp_cmd; 202184610Salfred uint8_t temp_0[4]; 203184610Salfred uint8_t temp_1[4]; 204184610Salfred uint8_t state; 205184610Salfred#define UMIDI_ST_UNKNOWN 0 /* scan for command */ 206184610Salfred#define UMIDI_ST_1PARAM 1 207184610Salfred#define UMIDI_ST_2PARAM_1 2 208184610Salfred#define UMIDI_ST_2PARAM_2 3 209184610Salfred#define UMIDI_ST_SYSEX_0 4 210184610Salfred#define UMIDI_ST_SYSEX_1 5 211184610Salfred#define UMIDI_ST_SYSEX_2 6 212184610Salfred 213184610Salfred uint8_t read_open:1; 214184610Salfred uint8_t write_open:1; 215184610Salfred uint8_t unused:6; 216184610Salfred}; 217184610Salfred 218184610Salfredstruct umidi_chan { 219184610Salfred 220184610Salfred struct umidi_sub_chan sub[UMIDI_CABLES_MAX]; 221184610Salfred struct mtx mtx; 222184610Salfred 223192984Sthompsa struct usb_xfer *xfer[UMIDI_N_TRANSFER]; 224184610Salfred 225184610Salfred uint8_t iface_index; 226184610Salfred uint8_t iface_alt_index; 227184610Salfred 228184610Salfred uint8_t flags; 229184610Salfred#define UMIDI_FLAG_READ_STALL 0x01 230184610Salfred#define UMIDI_FLAG_WRITE_STALL 0x02 231184610Salfred 232184610Salfred uint8_t read_open_refcount; 233184610Salfred uint8_t write_open_refcount; 234184610Salfred 235184610Salfred uint8_t curr_cable; 236184610Salfred uint8_t max_cable; 237184610Salfred uint8_t valid; 238184610Salfred}; 239184610Salfred 240184610Salfredstruct uaudio_softc { 241184610Salfred struct sbuf sc_sndstat; 242184610Salfred struct sndcard_func sc_sndcard_func; 243184610Salfred struct uaudio_chan sc_rec_chan; 244184610Salfred struct uaudio_chan sc_play_chan; 245184610Salfred struct umidi_chan sc_midi_chan; 246184610Salfred 247192984Sthompsa struct usb_device *sc_udev; 248192984Sthompsa struct usb_xfer *sc_mixer_xfer[1]; 249184610Salfred struct uaudio_mixer_node *sc_mixer_root; 250184610Salfred struct uaudio_mixer_node *sc_mixer_curr; 251184610Salfred 252184610Salfred uint32_t sc_mix_info; 253184610Salfred uint32_t sc_recsrc_info; 254184610Salfred 255184610Salfred uint16_t sc_audio_rev; 256184610Salfred uint16_t sc_mixer_count; 257184610Salfred 258184610Salfred uint8_t sc_sndstat_valid; 259184610Salfred uint8_t sc_mixer_iface_index; 260184610Salfred uint8_t sc_mixer_iface_no; 261184610Salfred uint8_t sc_mixer_chan; 262184610Salfred uint8_t sc_pcm_registered:1; 263184610Salfred uint8_t sc_mixer_init:1; 264184610Salfred uint8_t sc_uq_audio_swap_lr:1; 265184610Salfred uint8_t sc_uq_au_inp_async:1; 266184610Salfred uint8_t sc_uq_au_no_xu:1; 267184610Salfred uint8_t sc_uq_bad_adc:1; 268184610Salfred}; 269184610Salfred 270184610Salfredstruct uaudio_search_result { 271184610Salfred uint8_t bit_input[(256 + 7) / 8]; 272184610Salfred uint8_t bit_output[(256 + 7) / 8]; 273184610Salfred uint8_t bit_visited[(256 + 7) / 8]; 274184610Salfred uint8_t recurse_level; 275184610Salfred uint8_t id_max; 276184610Salfred}; 277184610Salfred 278184610Salfredstruct uaudio_terminal_node { 279184610Salfred union { 280192984Sthompsa const struct usb_descriptor *desc; 281203678Sbrucec const struct usb_audio_input_terminal *it; 282203678Sbrucec const struct usb_audio_output_terminal *ot; 283203678Sbrucec const struct usb_audio_mixer_unit_0 *mu; 284203678Sbrucec const struct usb_audio_selector_unit *su; 285203678Sbrucec const struct usb_audio_feature_unit *fu; 286203678Sbrucec const struct usb_audio_processing_unit_0 *pu; 287203678Sbrucec const struct usb_audio_extension_unit_0 *eu; 288184610Salfred } u; 289184610Salfred struct uaudio_search_result usr; 290184610Salfred struct uaudio_terminal_node *root; 291184610Salfred}; 292184610Salfred 293184610Salfredstruct uaudio_format { 294184610Salfred uint16_t wFormat; 295184610Salfred uint8_t bPrecision; 296184610Salfred uint32_t freebsd_fmt; 297184610Salfred const char *description; 298184610Salfred}; 299184610Salfred 300184610Salfredstatic const struct uaudio_format uaudio_formats[] = { 301184610Salfred 302184610Salfred {UA_FMT_PCM8, 8, AFMT_U8, "8-bit U-LE PCM"}, 303184610Salfred {UA_FMT_PCM8, 16, AFMT_U16_LE, "16-bit U-LE PCM"}, 304184610Salfred {UA_FMT_PCM8, 24, AFMT_U24_LE, "24-bit U-LE PCM"}, 305184610Salfred {UA_FMT_PCM8, 32, AFMT_U32_LE, "32-bit U-LE PCM"}, 306184610Salfred 307184610Salfred {UA_FMT_PCM, 8, AFMT_S8, "8-bit S-LE PCM"}, 308184610Salfred {UA_FMT_PCM, 16, AFMT_S16_LE, "16-bit S-LE PCM"}, 309184610Salfred {UA_FMT_PCM, 24, AFMT_S24_LE, "24-bit S-LE PCM"}, 310184610Salfred {UA_FMT_PCM, 32, AFMT_S32_LE, "32-bit S-LE PCM"}, 311184610Salfred 312184610Salfred {UA_FMT_ALAW, 8, AFMT_A_LAW, "8-bit A-Law"}, 313184610Salfred {UA_FMT_MULAW, 8, AFMT_MU_LAW, "8-bit mu-Law"}, 314184610Salfred 315184610Salfred {0, 0, 0, NULL} 316184610Salfred}; 317184610Salfred 318184610Salfred#define UAC_OUTPUT 0 319184610Salfred#define UAC_INPUT 1 320184610Salfred#define UAC_EQUAL 2 321184610Salfred#define UAC_RECORD 3 322184610Salfred#define UAC_NCLASSES 4 323184610Salfred 324207077Sthompsa#ifdef USB_DEBUG 325184610Salfredstatic const char *uac_names[] = { 326184610Salfred "outputs", "inputs", "equalization", "record" 327184610Salfred}; 328184610Salfred 329184610Salfred#endif 330184610Salfred 331184610Salfred/* prototypes */ 332184610Salfred 333184610Salfredstatic device_probe_t uaudio_probe; 334184610Salfredstatic device_attach_t uaudio_attach; 335184610Salfredstatic device_detach_t uaudio_detach; 336184610Salfred 337193045Sthompsastatic usb_callback_t uaudio_chan_play_callback; 338193045Sthompsastatic usb_callback_t uaudio_chan_record_callback; 339193045Sthompsastatic usb_callback_t uaudio_mixer_write_cfg_callback; 340193045Sthompsastatic usb_callback_t umidi_read_clear_stall_callback; 341193045Sthompsastatic usb_callback_t umidi_bulk_read_callback; 342193045Sthompsastatic usb_callback_t umidi_write_clear_stall_callback; 343193045Sthompsastatic usb_callback_t umidi_bulk_write_callback; 344184610Salfred 345185948Sthompsastatic void uaudio_chan_fill_info_sub(struct uaudio_softc *, 346200825Sthompsa struct usb_device *, uint32_t, uint8_t, uint8_t); 347185948Sthompsastatic void uaudio_chan_fill_info(struct uaudio_softc *, 348192984Sthompsa struct usb_device *); 349185948Sthompsastatic void uaudio_mixer_add_ctl_sub(struct uaudio_softc *, 350185948Sthompsa struct uaudio_mixer_node *); 351185948Sthompsastatic void uaudio_mixer_add_ctl(struct uaudio_softc *, 352185948Sthompsa struct uaudio_mixer_node *); 353185948Sthompsastatic void uaudio_mixer_add_input(struct uaudio_softc *, 354185948Sthompsa const struct uaudio_terminal_node *, int); 355185948Sthompsastatic void uaudio_mixer_add_output(struct uaudio_softc *, 356185948Sthompsa const struct uaudio_terminal_node *, int); 357185948Sthompsastatic void uaudio_mixer_add_mixer(struct uaudio_softc *, 358185948Sthompsa const struct uaudio_terminal_node *, int); 359185948Sthompsastatic void uaudio_mixer_add_selector(struct uaudio_softc *, 360185948Sthompsa const struct uaudio_terminal_node *, int); 361185948Sthompsastatic uint32_t uaudio_mixer_feature_get_bmaControls( 362203678Sbrucec const struct usb_audio_feature_unit *, uint8_t); 363185948Sthompsastatic void uaudio_mixer_add_feature(struct uaudio_softc *, 364185948Sthompsa const struct uaudio_terminal_node *, int); 365185948Sthompsastatic void uaudio_mixer_add_processing_updown(struct uaudio_softc *, 366185948Sthompsa const struct uaudio_terminal_node *, int); 367185948Sthompsastatic void uaudio_mixer_add_processing(struct uaudio_softc *, 368185948Sthompsa const struct uaudio_terminal_node *, int); 369185948Sthompsastatic void uaudio_mixer_add_extension(struct uaudio_softc *, 370185948Sthompsa const struct uaudio_terminal_node *, int); 371203678Sbrucecstatic struct usb_audio_cluster uaudio_mixer_get_cluster(uint8_t, 372185948Sthompsa const struct uaudio_terminal_node *); 373185948Sthompsastatic uint16_t uaudio_mixer_determine_class(const struct uaudio_terminal_node *, 374185948Sthompsa struct uaudio_mixer_node *); 375185948Sthompsastatic uint16_t uaudio_mixer_feature_name(const struct uaudio_terminal_node *, 376185948Sthompsa struct uaudio_mixer_node *); 377185948Sthompsastatic const struct uaudio_terminal_node *uaudio_mixer_get_input( 378185948Sthompsa const struct uaudio_terminal_node *, uint8_t); 379185948Sthompsastatic const struct uaudio_terminal_node *uaudio_mixer_get_output( 380185948Sthompsa const struct uaudio_terminal_node *, uint8_t); 381185948Sthompsastatic void uaudio_mixer_find_inputs_sub(struct uaudio_terminal_node *, 382185948Sthompsa const uint8_t *, uint8_t, struct uaudio_search_result *); 383185948Sthompsastatic void uaudio_mixer_find_outputs_sub(struct uaudio_terminal_node *, 384185948Sthompsa uint8_t, uint8_t, struct uaudio_search_result *); 385185948Sthompsastatic void uaudio_mixer_fill_info(struct uaudio_softc *, 386192984Sthompsa struct usb_device *, void *); 387192984Sthompsastatic uint16_t uaudio_mixer_get(struct usb_device *, uint8_t, 388185948Sthompsa struct uaudio_mixer_node *); 389185948Sthompsastatic void uaudio_mixer_ctl_set(struct uaudio_softc *, 390185948Sthompsa struct uaudio_mixer_node *, uint8_t, int32_t val); 391193045Sthompsastatic usb_error_t uaudio_set_speed(struct usb_device *, uint8_t, uint32_t); 392185948Sthompsastatic int uaudio_mixer_signext(uint8_t, int); 393185948Sthompsastatic int uaudio_mixer_bsd2value(struct uaudio_mixer_node *, int32_t val); 394185948Sthompsastatic const void *uaudio_mixer_verify_desc(const void *, uint32_t); 395185948Sthompsastatic void uaudio_mixer_init(struct uaudio_softc *); 396185948Sthompsastatic uint8_t umidi_convert_to_usb(struct umidi_sub_chan *, uint8_t, uint8_t); 397192984Sthompsastatic struct umidi_sub_chan *umidi_sub_by_fifo(struct usb_fifo *); 398192984Sthompsastatic void umidi_start_read(struct usb_fifo *); 399192984Sthompsastatic void umidi_stop_read(struct usb_fifo *); 400192984Sthompsastatic void umidi_start_write(struct usb_fifo *); 401192984Sthompsastatic void umidi_stop_write(struct usb_fifo *); 402192984Sthompsastatic int umidi_open(struct usb_fifo *, int); 403192984Sthompsastatic int umidi_ioctl(struct usb_fifo *, u_long cmd, void *, int); 404192984Sthompsastatic void umidi_close(struct usb_fifo *, int); 405185948Sthompsastatic void umidi_init(device_t dev); 406185948Sthompsastatic int32_t umidi_probe(device_t dev); 407185948Sthompsastatic int32_t umidi_detach(device_t dev); 408184610Salfred 409207077Sthompsa#ifdef USB_DEBUG 410185948Sthompsastatic void uaudio_chan_dump_ep_desc( 411203678Sbrucec const usb_endpoint_descriptor_audio_t *); 412185948Sthompsastatic void uaudio_mixer_dump_cluster(uint8_t, 413185948Sthompsa const struct uaudio_terminal_node *); 414185948Sthompsastatic const char *uaudio_mixer_get_terminal_name(uint16_t); 415184610Salfred#endif 416184610Salfred 417192984Sthompsastatic const struct usb_config 418186730Salfred uaudio_cfg_record[UAUDIO_NCHANBUFS] = { 419184610Salfred [0] = { 420184610Salfred .type = UE_ISOCHRONOUS, 421184610Salfred .endpoint = UE_ADDR_ANY, 422184610Salfred .direction = UE_DIR_IN, 423190734Sthompsa .bufsize = 0, /* use "wMaxPacketSize * frames" */ 424199060Sthompsa .frames = UAUDIO_NFRAMES, 425190734Sthompsa .flags = {.short_xfer_ok = 1,}, 426190734Sthompsa .callback = &uaudio_chan_record_callback, 427184610Salfred }, 428184610Salfred 429184610Salfred [1] = { 430184610Salfred .type = UE_ISOCHRONOUS, 431184610Salfred .endpoint = UE_ADDR_ANY, 432184610Salfred .direction = UE_DIR_IN, 433190734Sthompsa .bufsize = 0, /* use "wMaxPacketSize * frames" */ 434199060Sthompsa .frames = UAUDIO_NFRAMES, 435190734Sthompsa .flags = {.short_xfer_ok = 1,}, 436190734Sthompsa .callback = &uaudio_chan_record_callback, 437184610Salfred }, 438184610Salfred}; 439184610Salfred 440192984Sthompsastatic const struct usb_config 441186730Salfred uaudio_cfg_play[UAUDIO_NCHANBUFS] = { 442184610Salfred [0] = { 443184610Salfred .type = UE_ISOCHRONOUS, 444184610Salfred .endpoint = UE_ADDR_ANY, 445184610Salfred .direction = UE_DIR_OUT, 446190734Sthompsa .bufsize = 0, /* use "wMaxPacketSize * frames" */ 447199060Sthompsa .frames = UAUDIO_NFRAMES, 448190734Sthompsa .flags = {.short_xfer_ok = 1,}, 449190734Sthompsa .callback = &uaudio_chan_play_callback, 450184610Salfred }, 451184610Salfred 452184610Salfred [1] = { 453184610Salfred .type = UE_ISOCHRONOUS, 454184610Salfred .endpoint = UE_ADDR_ANY, 455184610Salfred .direction = UE_DIR_OUT, 456190734Sthompsa .bufsize = 0, /* use "wMaxPacketSize * frames" */ 457199060Sthompsa .frames = UAUDIO_NFRAMES, 458190734Sthompsa .flags = {.short_xfer_ok = 1,}, 459190734Sthompsa .callback = &uaudio_chan_play_callback, 460184610Salfred }, 461184610Salfred}; 462184610Salfred 463192984Sthompsastatic const struct usb_config 464184610Salfred uaudio_mixer_config[1] = { 465184610Salfred [0] = { 466184610Salfred .type = UE_CONTROL, 467184610Salfred .endpoint = 0x00, /* Control pipe */ 468184610Salfred .direction = UE_DIR_ANY, 469192984Sthompsa .bufsize = (sizeof(struct usb_device_request) + 4), 470190734Sthompsa .callback = &uaudio_mixer_write_cfg_callback, 471190734Sthompsa .timeout = 1000, /* 1 second */ 472184610Salfred }, 473184610Salfred}; 474184610Salfred 475184610Salfredstatic const 476184610Salfreduint8_t umidi_cmd_to_len[16] = { 477184610Salfred [0x0] = 0, /* reserved */ 478184610Salfred [0x1] = 0, /* reserved */ 479184610Salfred [0x2] = 2, /* bytes */ 480184610Salfred [0x3] = 3, /* bytes */ 481184610Salfred [0x4] = 3, /* bytes */ 482184610Salfred [0x5] = 1, /* bytes */ 483184610Salfred [0x6] = 2, /* bytes */ 484184610Salfred [0x7] = 3, /* bytes */ 485184610Salfred [0x8] = 3, /* bytes */ 486184610Salfred [0x9] = 3, /* bytes */ 487184610Salfred [0xA] = 3, /* bytes */ 488184610Salfred [0xB] = 3, /* bytes */ 489184610Salfred [0xC] = 2, /* bytes */ 490184610Salfred [0xD] = 2, /* bytes */ 491184610Salfred [0xE] = 3, /* bytes */ 492184610Salfred [0xF] = 1, /* bytes */ 493184610Salfred}; 494184610Salfred 495192984Sthompsastatic const struct usb_config 496184610Salfred umidi_config[UMIDI_N_TRANSFER] = { 497184610Salfred [0] = { 498184610Salfred .type = UE_BULK, 499184610Salfred .endpoint = UE_ADDR_ANY, 500184610Salfred .direction = UE_DIR_OUT, 501190734Sthompsa .bufsize = UMIDI_BULK_SIZE, 502190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 503190734Sthompsa .callback = &umidi_bulk_write_callback, 504184610Salfred }, 505184610Salfred 506184610Salfred [1] = { 507184610Salfred .type = UE_BULK, 508184610Salfred .endpoint = UE_ADDR_ANY, 509184610Salfred .direction = UE_DIR_IN, 510209450Sthompsa .bufsize = 4, /* bytes */ 511209450Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,.proxy_buffer = 1,}, 512190734Sthompsa .callback = &umidi_bulk_read_callback, 513184610Salfred }, 514184610Salfred 515184610Salfred [2] = { 516184610Salfred .type = UE_CONTROL, 517184610Salfred .endpoint = 0x00, /* Control pipe */ 518184610Salfred .direction = UE_DIR_ANY, 519192984Sthompsa .bufsize = sizeof(struct usb_device_request), 520190734Sthompsa .callback = &umidi_write_clear_stall_callback, 521190734Sthompsa .timeout = 1000, /* 1 second */ 522190734Sthompsa .interval = 50, /* 50ms */ 523184610Salfred }, 524184610Salfred 525184610Salfred [3] = { 526184610Salfred .type = UE_CONTROL, 527184610Salfred .endpoint = 0x00, /* Control pipe */ 528184610Salfred .direction = UE_DIR_ANY, 529192984Sthompsa .bufsize = sizeof(struct usb_device_request), 530190734Sthompsa .callback = &umidi_read_clear_stall_callback, 531190734Sthompsa .timeout = 1000, /* 1 second */ 532190734Sthompsa .interval = 50, /* 50ms */ 533184610Salfred }, 534184610Salfred}; 535184610Salfred 536184610Salfredstatic devclass_t uaudio_devclass; 537184610Salfred 538184610Salfredstatic device_method_t uaudio_methods[] = { 539184610Salfred DEVMETHOD(device_probe, uaudio_probe), 540184610Salfred DEVMETHOD(device_attach, uaudio_attach), 541184610Salfred DEVMETHOD(device_detach, uaudio_detach), 542184610Salfred DEVMETHOD(device_suspend, bus_generic_suspend), 543184610Salfred DEVMETHOD(device_resume, bus_generic_resume), 544184610Salfred DEVMETHOD(device_shutdown, bus_generic_shutdown), 545184610Salfred DEVMETHOD(bus_print_child, bus_generic_print_child), 546184610Salfred {0, 0} 547184610Salfred}; 548184610Salfred 549184610Salfredstatic driver_t uaudio_driver = { 550184610Salfred .name = "uaudio", 551184610Salfred .methods = uaudio_methods, 552184610Salfred .size = sizeof(struct uaudio_softc), 553184610Salfred}; 554184610Salfred 555184610Salfredstatic int 556184610Salfreduaudio_probe(device_t dev) 557184610Salfred{ 558192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 559184610Salfred 560192505Sthompsa if (uaa->usb_mode != USB_MODE_HOST) 561184610Salfred return (ENXIO); 562188416Sthompsa 563188416Sthompsa if (uaa->use_generic == 0) 564188416Sthompsa return (ENXIO); 565188416Sthompsa 566184610Salfred /* trigger on the control interface */ 567184610Salfred 568184610Salfred if ((uaa->info.bInterfaceClass == UICLASS_AUDIO) && 569184610Salfred (uaa->info.bInterfaceSubClass == UISUBCLASS_AUDIOCONTROL)) { 570194228Sthompsa if (usb_test_quirk(uaa, UQ_BAD_AUDIO)) 571184610Salfred return (ENXIO); 572184610Salfred else 573184610Salfred return (0); 574184610Salfred } 575199677Sthompsa 576199677Sthompsa /* check for MIDI stream */ 577199677Sthompsa 578199677Sthompsa if ((uaa->info.bInterfaceClass == UICLASS_AUDIO) && 579199677Sthompsa (uaa->info.bInterfaceSubClass == UISUBCLASS_MIDISTREAM)) { 580199677Sthompsa return (0); 581199677Sthompsa } 582184610Salfred return (ENXIO); 583184610Salfred} 584184610Salfred 585184610Salfredstatic int 586184610Salfreduaudio_attach(device_t dev) 587184610Salfred{ 588192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 589184610Salfred struct uaudio_softc *sc = device_get_softc(dev); 590192984Sthompsa struct usb_interface_descriptor *id; 591184610Salfred device_t child; 592184610Salfred 593184610Salfred sc->sc_play_chan.priv_sc = sc; 594184610Salfred sc->sc_rec_chan.priv_sc = sc; 595184610Salfred sc->sc_udev = uaa->device; 596199060Sthompsa sc->sc_mixer_iface_index = uaa->info.bIfaceIndex; 597199060Sthompsa sc->sc_mixer_iface_no = uaa->info.bIfaceNum; 598184610Salfred 599194228Sthompsa if (usb_test_quirk(uaa, UQ_AUDIO_SWAP_LR)) 600184610Salfred sc->sc_uq_audio_swap_lr = 1; 601184610Salfred 602194228Sthompsa if (usb_test_quirk(uaa, UQ_AU_INP_ASYNC)) 603184610Salfred sc->sc_uq_au_inp_async = 1; 604184610Salfred 605194228Sthompsa if (usb_test_quirk(uaa, UQ_AU_NO_XU)) 606184610Salfred sc->sc_uq_au_no_xu = 1; 607184610Salfred 608194228Sthompsa if (usb_test_quirk(uaa, UQ_BAD_ADC)) 609184610Salfred sc->sc_uq_bad_adc = 1; 610184610Salfred 611184610Salfred umidi_init(dev); 612184610Salfred 613194228Sthompsa device_set_usb_desc(dev); 614184610Salfred 615194228Sthompsa id = usbd_get_interface_descriptor(uaa->iface); 616184610Salfred 617184610Salfred uaudio_chan_fill_info(sc, uaa->device); 618184610Salfred 619184610Salfred uaudio_mixer_fill_info(sc, uaa->device, id); 620184610Salfred 621184610Salfred DPRINTF("audio rev %d.%02x\n", 622184610Salfred sc->sc_audio_rev >> 8, 623184610Salfred sc->sc_audio_rev & 0xff); 624184610Salfred 625184610Salfred DPRINTF("%d mixer controls\n", 626184610Salfred sc->sc_mixer_count); 627184610Salfred 628184610Salfred if (sc->sc_play_chan.valid) { 629184610Salfred device_printf(dev, "Play: %d Hz, %d ch, %s format\n", 630184610Salfred sc->sc_play_chan.sample_rate, 631184610Salfred sc->sc_play_chan.p_asf1d->bNrChannels, 632184610Salfred sc->sc_play_chan.p_fmt->description); 633184610Salfred } else { 634184610Salfred device_printf(dev, "No playback!\n"); 635184610Salfred } 636184610Salfred 637184610Salfred if (sc->sc_rec_chan.valid) { 638184610Salfred device_printf(dev, "Record: %d Hz, %d ch, %s format\n", 639184610Salfred sc->sc_rec_chan.sample_rate, 640184610Salfred sc->sc_rec_chan.p_asf1d->bNrChannels, 641184610Salfred sc->sc_rec_chan.p_fmt->description); 642184610Salfred } else { 643184610Salfred device_printf(dev, "No recording!\n"); 644184610Salfred } 645184610Salfred 646184610Salfred if (sc->sc_midi_chan.valid) { 647184610Salfred 648184610Salfred if (umidi_probe(dev)) { 649184610Salfred goto detach; 650184610Salfred } 651184610Salfred device_printf(dev, "MIDI sequencer\n"); 652184610Salfred } else { 653184610Salfred device_printf(dev, "No midi sequencer\n"); 654184610Salfred } 655184610Salfred 656184610Salfred DPRINTF("doing child attach\n"); 657184610Salfred 658184610Salfred /* attach the children */ 659184610Salfred 660184610Salfred sc->sc_sndcard_func.func = SCF_PCM; 661184610Salfred 662184610Salfred child = device_add_child(dev, "pcm", -1); 663184610Salfred 664184610Salfred if (child == NULL) { 665184610Salfred DPRINTF("out of memory\n"); 666184610Salfred goto detach; 667184610Salfred } 668184610Salfred device_set_ivars(child, &sc->sc_sndcard_func); 669184610Salfred 670184610Salfred if (bus_generic_attach(dev)) { 671184610Salfred DPRINTF("child attach failed\n"); 672184610Salfred goto detach; 673184610Salfred } 674184610Salfred return (0); /* success */ 675184610Salfred 676184610Salfreddetach: 677184610Salfred uaudio_detach(dev); 678184610Salfred return (ENXIO); 679184610Salfred} 680184610Salfred 681184610Salfredstatic void 682184610Salfreduaudio_pcm_setflags(device_t dev, uint32_t flags) 683184610Salfred{ 684184610Salfred pcm_setflags(dev, pcm_getflags(dev) | flags); 685184610Salfred} 686184610Salfred 687184610Salfredint 688184610Salfreduaudio_attach_sub(device_t dev, kobj_class_t mixer_class, kobj_class_t chan_class) 689184610Salfred{ 690184610Salfred struct uaudio_softc *sc = device_get_softc(device_get_parent(dev)); 691184610Salfred char status[SND_STATUSLEN]; 692184610Salfred 693184610Salfred uaudio_mixer_init(sc); 694184610Salfred 695184610Salfred if (sc->sc_uq_audio_swap_lr) { 696184610Salfred DPRINTF("hardware has swapped left and right\n"); 697193640Sariff /* uaudio_pcm_setflags(dev, SD_F_PSWAPLR); */ 698184610Salfred } 699184610Salfred if (!(sc->sc_mix_info & SOUND_MASK_PCM)) { 700184610Salfred 701184610Salfred DPRINTF("emulating master volume\n"); 702184610Salfred 703184610Salfred /* 704184610Salfred * Emulate missing pcm mixer controller 705184610Salfred * through FEEDER_VOLUME 706184610Salfred */ 707184610Salfred uaudio_pcm_setflags(dev, SD_F_SOFTPCMVOL); 708184610Salfred } 709184610Salfred if (mixer_init(dev, mixer_class, sc)) { 710184610Salfred goto detach; 711184610Salfred } 712184610Salfred sc->sc_mixer_init = 1; 713184610Salfred 714184610Salfred snprintf(status, sizeof(status), "at ? %s", PCM_KLDSTRING(snd_uaudio)); 715184610Salfred 716184610Salfred if (pcm_register(dev, sc, 717184610Salfred sc->sc_play_chan.valid ? 1 : 0, 718184610Salfred sc->sc_rec_chan.valid ? 1 : 0)) { 719184610Salfred goto detach; 720184610Salfred } 721193640Sariff 722193640Sariff uaudio_pcm_setflags(dev, SD_F_MPSAFE); 723184610Salfred sc->sc_pcm_registered = 1; 724184610Salfred 725184610Salfred if (sc->sc_play_chan.valid) { 726184610Salfred pcm_addchan(dev, PCMDIR_PLAY, chan_class, sc); 727184610Salfred } 728184610Salfred if (sc->sc_rec_chan.valid) { 729184610Salfred pcm_addchan(dev, PCMDIR_REC, chan_class, sc); 730184610Salfred } 731184610Salfred pcm_setstatus(dev, status); 732184610Salfred 733184610Salfred return (0); /* success */ 734184610Salfred 735184610Salfreddetach: 736184610Salfred uaudio_detach_sub(dev); 737184610Salfred return (ENXIO); 738184610Salfred} 739184610Salfred 740184610Salfredint 741184610Salfreduaudio_detach_sub(device_t dev) 742184610Salfred{ 743184610Salfred struct uaudio_softc *sc = device_get_softc(device_get_parent(dev)); 744184610Salfred int error = 0; 745184610Salfred 746184610Salfredrepeat: 747184610Salfred if (sc->sc_pcm_registered) { 748184610Salfred error = pcm_unregister(dev); 749184610Salfred } else { 750184610Salfred if (sc->sc_mixer_init) { 751184610Salfred error = mixer_uninit(dev); 752184610Salfred } 753184610Salfred } 754184610Salfred 755184610Salfred if (error) { 756184610Salfred device_printf(dev, "Waiting for sound application to exit!\n"); 757194228Sthompsa usb_pause_mtx(NULL, 2 * hz); 758184610Salfred goto repeat; /* try again */ 759184610Salfred } 760184610Salfred return (0); /* success */ 761184610Salfred} 762184610Salfred 763184610Salfredstatic int 764184610Salfreduaudio_detach(device_t dev) 765184610Salfred{ 766184610Salfred struct uaudio_softc *sc = device_get_softc(dev); 767184610Salfred 768184610Salfred if (bus_generic_detach(dev)) { 769184610Salfred DPRINTF("detach failed!\n"); 770184610Salfred } 771184610Salfred sbuf_delete(&sc->sc_sndstat); 772184610Salfred sc->sc_sndstat_valid = 0; 773184610Salfred 774184610Salfred umidi_detach(dev); 775184610Salfred 776184610Salfred return (0); 777184610Salfred} 778184610Salfred 779184610Salfred/*========================================================================* 780184610Salfred * AS - Audio Stream - routines 781184610Salfred *========================================================================*/ 782184610Salfred 783207077Sthompsa#ifdef USB_DEBUG 784184610Salfredstatic void 785203678Sbrucecuaudio_chan_dump_ep_desc(const usb_endpoint_descriptor_audio_t *ed) 786184610Salfred{ 787184610Salfred if (ed) { 788184610Salfred DPRINTF("endpoint=%p bLength=%d bDescriptorType=%d \n" 789184610Salfred "bEndpointAddress=%d bmAttributes=0x%x \n" 790184610Salfred "wMaxPacketSize=%d bInterval=%d \n" 791184610Salfred "bRefresh=%d bSynchAddress=%d\n", 792184610Salfred ed, ed->bLength, ed->bDescriptorType, 793184610Salfred ed->bEndpointAddress, ed->bmAttributes, 794184610Salfred UGETW(ed->wMaxPacketSize), ed->bInterval, 795184610Salfred ed->bRefresh, ed->bSynchAddress); 796184610Salfred } 797184610Salfred} 798184610Salfred 799184610Salfred#endif 800184610Salfred 801184610Salfredstatic void 802192984Sthompsauaudio_chan_fill_info_sub(struct uaudio_softc *sc, struct usb_device *udev, 803200825Sthompsa uint32_t rate, uint8_t channels, uint8_t bit_resolution) 804184610Salfred{ 805192984Sthompsa struct usb_descriptor *desc = NULL; 806203678Sbrucec const struct usb_audio_streaming_interface_descriptor *asid = NULL; 807203678Sbrucec const struct usb_audio_streaming_type1_descriptor *asf1d = NULL; 808203678Sbrucec const struct usb_audio_streaming_endpoint_descriptor *sed = NULL; 809203678Sbrucec const usb_endpoint_descriptor_audio_t *ed1 = NULL; 810203678Sbrucec const usb_endpoint_descriptor_audio_t *ed2 = NULL; 811194228Sthompsa struct usb_config_descriptor *cd = usbd_get_config_descriptor(udev); 812192984Sthompsa struct usb_interface_descriptor *id; 813184610Salfred const struct uaudio_format *p_fmt; 814184610Salfred struct uaudio_chan *chan; 815184610Salfred uint16_t curidx = 0xFFFF; 816184610Salfred uint16_t lastidx = 0xFFFF; 817184610Salfred uint16_t alt_index = 0; 818184610Salfred uint16_t wFormat; 819184610Salfred uint8_t ep_dir; 820184610Salfred uint8_t ep_type; 821184610Salfred uint8_t ep_sync; 822184610Salfred uint8_t bChannels; 823184610Salfred uint8_t bBitResolution; 824184610Salfred uint8_t x; 825184610Salfred uint8_t audio_if = 0; 826184610Salfred 827194228Sthompsa while ((desc = usb_desc_foreach(cd, desc))) { 828184610Salfred 829184610Salfred if ((desc->bDescriptorType == UDESC_INTERFACE) && 830184610Salfred (desc->bLength >= sizeof(*id))) { 831184610Salfred 832184610Salfred id = (void *)desc; 833184610Salfred 834184610Salfred if (id->bInterfaceNumber != lastidx) { 835184610Salfred lastidx = id->bInterfaceNumber; 836184610Salfred curidx++; 837184610Salfred alt_index = 0; 838184610Salfred 839184610Salfred } else { 840184610Salfred alt_index++; 841184610Salfred } 842184610Salfred 843184610Salfred if ((id->bInterfaceClass == UICLASS_AUDIO) && 844184610Salfred (id->bInterfaceSubClass == UISUBCLASS_AUDIOSTREAM)) { 845184610Salfred audio_if = 1; 846184610Salfred } else { 847184610Salfred audio_if = 0; 848184610Salfred } 849184610Salfred 850184610Salfred if ((id->bInterfaceClass == UICLASS_AUDIO) && 851184610Salfred (id->bInterfaceSubClass == UISUBCLASS_MIDISTREAM)) { 852184610Salfred 853184610Salfred /* 854184610Salfred * XXX could allow multiple MIDI interfaces 855184610Salfred * XXX 856184610Salfred */ 857184610Salfred 858184610Salfred if ((sc->sc_midi_chan.valid == 0) && 859194228Sthompsa usbd_get_iface(udev, curidx)) { 860184610Salfred sc->sc_midi_chan.iface_index = curidx; 861184610Salfred sc->sc_midi_chan.iface_alt_index = alt_index; 862184610Salfred sc->sc_midi_chan.valid = 1; 863184610Salfred } 864184610Salfred } 865184610Salfred asid = NULL; 866184610Salfred asf1d = NULL; 867184610Salfred ed1 = NULL; 868184610Salfred ed2 = NULL; 869184610Salfred sed = NULL; 870184610Salfred } 871184610Salfred if ((desc->bDescriptorType == UDESC_CS_INTERFACE) && 872184610Salfred (desc->bDescriptorSubtype == AS_GENERAL) && 873184610Salfred (desc->bLength >= sizeof(*asid))) { 874184610Salfred if (asid == NULL) { 875184610Salfred asid = (void *)desc; 876184610Salfred } 877184610Salfred } 878184610Salfred if ((desc->bDescriptorType == UDESC_CS_INTERFACE) && 879184610Salfred (desc->bDescriptorSubtype == FORMAT_TYPE) && 880184610Salfred (desc->bLength >= sizeof(*asf1d))) { 881184610Salfred if (asf1d == NULL) { 882184610Salfred asf1d = (void *)desc; 883184610Salfred if (asf1d->bFormatType != FORMAT_TYPE_I) { 884184610Salfred DPRINTFN(11, "ignored bFormatType = %d\n", 885184610Salfred asf1d->bFormatType); 886184610Salfred asf1d = NULL; 887184610Salfred continue; 888184610Salfred } 889184610Salfred if (asf1d->bLength < (sizeof(*asf1d) + 890184610Salfred (asf1d->bSamFreqType == 0) ? 6 : 891184610Salfred (asf1d->bSamFreqType * 3))) { 892184610Salfred DPRINTFN(11, "'asf1d' descriptor is too short\n"); 893184610Salfred asf1d = NULL; 894184610Salfred continue; 895184610Salfred } 896184610Salfred } 897184610Salfred } 898184610Salfred if ((desc->bDescriptorType == UDESC_ENDPOINT) && 899184610Salfred (desc->bLength >= sizeof(*ed1))) { 900184610Salfred if (ed1 == NULL) { 901184610Salfred ed1 = (void *)desc; 902184610Salfred if (UE_GET_XFERTYPE(ed1->bmAttributes) != UE_ISOCHRONOUS) { 903184610Salfred ed1 = NULL; 904184610Salfred } 905184610Salfred } else { 906184610Salfred if (ed2 == NULL) { 907184610Salfred ed2 = (void *)desc; 908184610Salfred if (UE_GET_XFERTYPE(ed2->bmAttributes) != UE_ISOCHRONOUS) { 909184610Salfred ed2 = NULL; 910184610Salfred continue; 911184610Salfred } 912184610Salfred if (ed2->bSynchAddress != 0) { 913184610Salfred DPRINTFN(11, "invalid endpoint: bSynchAddress != 0\n"); 914184610Salfred ed2 = NULL; 915184610Salfred continue; 916184610Salfred } 917184610Salfred if (ed2->bEndpointAddress != ed1->bSynchAddress) { 918184610Salfred DPRINTFN(11, "invalid endpoint addresses: " 919184610Salfred "ep[0]->bSynchAddress=0x%x " 920184610Salfred "ep[1]->bEndpointAddress=0x%x\n", 921184610Salfred ed1->bSynchAddress, 922184610Salfred ed2->bEndpointAddress); 923184610Salfred ed2 = NULL; 924184610Salfred continue; 925184610Salfred } 926184610Salfred } 927184610Salfred } 928184610Salfred } 929184610Salfred if ((desc->bDescriptorType == UDESC_CS_ENDPOINT) && 930184610Salfred (desc->bDescriptorSubtype == AS_GENERAL) && 931184610Salfred (desc->bLength >= sizeof(*sed))) { 932184610Salfred if (sed == NULL) { 933184610Salfred sed = (void *)desc; 934184610Salfred } 935184610Salfred } 936184610Salfred if (audio_if && asid && asf1d && ed1 && sed) { 937184610Salfred 938184610Salfred ep_dir = UE_GET_DIR(ed1->bEndpointAddress); 939184610Salfred ep_type = UE_GET_ISO_TYPE(ed1->bmAttributes); 940184610Salfred ep_sync = 0; 941184610Salfred 942184610Salfred if ((sc->sc_uq_au_inp_async) && 943184610Salfred (ep_dir == UE_DIR_IN) && (ep_type == UE_ISO_ADAPT)) { 944184610Salfred ep_type = UE_ISO_ASYNC; 945184610Salfred } 946184610Salfred if ((ep_dir == UE_DIR_IN) && (ep_type == UE_ISO_ADAPT)) { 947184610Salfred ep_sync = 1; 948184610Salfred } 949184610Salfred if ((ep_dir != UE_DIR_IN) && (ep_type == UE_ISO_ASYNC)) { 950184610Salfred ep_sync = 1; 951184610Salfred } 952184610Salfred /* Ignore sync endpoint information until further. */ 953184610Salfred#if 0 954184610Salfred if (ep_sync && (!ed2)) { 955184610Salfred continue; 956184610Salfred } 957184610Salfred /* 958184610Salfred * we can't handle endpoints that need a sync pipe 959184610Salfred * yet 960184610Salfred */ 961184610Salfred 962184610Salfred if (ep_sync) { 963184610Salfred DPRINTF("skipped sync interface\n"); 964184610Salfred audio_if = 0; 965184610Salfred continue; 966184610Salfred } 967184610Salfred#endif 968184610Salfred 969184610Salfred wFormat = UGETW(asid->wFormatTag); 970192929Sthompsa bChannels = UAUDIO_MAX_CHAN(asf1d->bNrChannels); 971184610Salfred bBitResolution = asf1d->bBitResolution; 972184610Salfred 973184610Salfred if (asf1d->bSamFreqType == 0) { 974184610Salfred DPRINTFN(16, "Sample rate: %d-%dHz\n", 975184610Salfred UA_SAMP_LO(asf1d), UA_SAMP_HI(asf1d)); 976184610Salfred 977184610Salfred if ((rate >= UA_SAMP_LO(asf1d)) && 978184610Salfred (rate <= UA_SAMP_HI(asf1d))) { 979184610Salfred goto found_rate; 980184610Salfred } 981184610Salfred } else { 982184610Salfred 983184610Salfred for (x = 0; x < asf1d->bSamFreqType; x++) { 984184610Salfred DPRINTFN(16, "Sample rate = %dHz\n", 985184610Salfred UA_GETSAMP(asf1d, x)); 986184610Salfred 987184610Salfred if (rate == UA_GETSAMP(asf1d, x)) { 988184610Salfred goto found_rate; 989184610Salfred } 990184610Salfred } 991184610Salfred } 992184610Salfred 993184610Salfred audio_if = 0; 994184610Salfred continue; 995184610Salfred 996184610Salfred found_rate: 997184610Salfred 998184610Salfred for (p_fmt = uaudio_formats; 999184610Salfred p_fmt->wFormat; 1000184610Salfred p_fmt++) { 1001184610Salfred if ((p_fmt->wFormat == wFormat) && 1002184610Salfred (p_fmt->bPrecision == bBitResolution)) { 1003184610Salfred goto found_format; 1004184610Salfred } 1005184610Salfred } 1006184610Salfred 1007184610Salfred audio_if = 0; 1008184610Salfred continue; 1009184610Salfred 1010184610Salfred found_format: 1011184610Salfred 1012184610Salfred if ((bChannels == channels) && 1013184610Salfred (bBitResolution == bit_resolution)) { 1014184610Salfred 1015184610Salfred chan = (ep_dir == UE_DIR_IN) ? 1016184610Salfred &sc->sc_rec_chan : 1017184610Salfred &sc->sc_play_chan; 1018184610Salfred 1019194228Sthompsa if ((chan->valid == 0) && usbd_get_iface(udev, curidx)) { 1020184610Salfred 1021184610Salfred chan->valid = 1; 1022207077Sthompsa#ifdef USB_DEBUG 1023184610Salfred uaudio_chan_dump_ep_desc(ed1); 1024184610Salfred uaudio_chan_dump_ep_desc(ed2); 1025184610Salfred 1026184610Salfred if (sed->bmAttributes & UA_SED_FREQ_CONTROL) { 1027184610Salfred DPRINTFN(2, "FREQ_CONTROL\n"); 1028184610Salfred } 1029184610Salfred if (sed->bmAttributes & UA_SED_PITCH_CONTROL) { 1030184610Salfred DPRINTFN(2, "PITCH_CONTROL\n"); 1031184610Salfred } 1032184610Salfred#endif 1033184610Salfred DPRINTF("Sample rate = %dHz, channels = %d, " 1034184610Salfred "bits = %d, format = %s\n", rate, channels, 1035184610Salfred bit_resolution, p_fmt->description); 1036184610Salfred 1037184610Salfred chan->sample_rate = rate; 1038184610Salfred chan->p_asid = asid; 1039184610Salfred chan->p_asf1d = asf1d; 1040184610Salfred chan->p_ed1 = ed1; 1041184610Salfred chan->p_ed2 = ed2; 1042184610Salfred chan->p_fmt = p_fmt; 1043184610Salfred chan->p_sed = sed; 1044184610Salfred chan->iface_index = curidx; 1045184610Salfred chan->iface_alt_index = alt_index; 1046184610Salfred 1047186730Salfred if (ep_dir == UE_DIR_IN) 1048203678Sbrucec chan->usb_cfg = 1049186730Salfred uaudio_cfg_record; 1050186730Salfred else 1051203678Sbrucec chan->usb_cfg = 1052186730Salfred uaudio_cfg_play; 1053184610Salfred 1054200825Sthompsa chan->sample_size = (( 1055192929Sthompsa UAUDIO_MAX_CHAN(chan->p_asf1d->bNrChannels) * 1056184610Salfred chan->p_asf1d->bBitResolution) / 8); 1057184610Salfred 1058184610Salfred if (sc->sc_sndstat_valid) { 1059184610Salfred sbuf_printf(&sc->sc_sndstat, "\n\t" 1060184610Salfred "mode %d.%d:(%s) %dch, %d/%dbit, %s, %dHz", 1061184610Salfred curidx, alt_index, 1062184610Salfred (ep_dir == UE_DIR_IN) ? "input" : "output", 1063184610Salfred asf1d->bNrChannels, asf1d->bBitResolution, 1064184610Salfred asf1d->bSubFrameSize * 8, 1065184610Salfred p_fmt->description, rate); 1066184610Salfred } 1067184610Salfred } 1068184610Salfred } 1069184610Salfred audio_if = 0; 1070184610Salfred continue; 1071184610Salfred } 1072184610Salfred } 1073184610Salfred} 1074184610Salfred 1075200825Sthompsa/* This structure defines all the supported rates. */ 1076200825Sthompsa 1077200825Sthompsastatic const uint32_t uaudio_rate_list[] = { 1078200825Sthompsa 96000, 1079200825Sthompsa 88000, 1080200825Sthompsa 80000, 1081200825Sthompsa 72000, 1082200825Sthompsa 64000, 1083200825Sthompsa 56000, 1084200825Sthompsa 48000, 1085200825Sthompsa 44100, 1086200825Sthompsa 40000, 1087200825Sthompsa 32000, 1088200825Sthompsa 24000, 1089200825Sthompsa 22050, 1090200825Sthompsa 16000, 1091200825Sthompsa 11025, 1092200825Sthompsa 8000, 1093200825Sthompsa 0 1094200825Sthompsa}; 1095200825Sthompsa 1096184610Salfredstatic void 1097192984Sthompsauaudio_chan_fill_info(struct uaudio_softc *sc, struct usb_device *udev) 1098184610Salfred{ 1099184610Salfred uint32_t rate = uaudio_default_rate; 1100200825Sthompsa uint8_t z; 1101184610Salfred uint8_t bits = uaudio_default_bits; 1102184610Salfred uint8_t y; 1103184610Salfred uint8_t channels = uaudio_default_channels; 1104184610Salfred uint8_t x; 1105184610Salfred 1106184610Salfred bits -= (bits % 8); 1107186730Salfred if ((bits == 0) || (bits > 32)) { 1108186730Salfred /* set a valid value */ 1109186730Salfred bits = 32; 1110186730Salfred } 1111200825Sthompsa if (channels == 0) { 1112200825Sthompsa switch (usbd_get_speed(udev)) { 1113200825Sthompsa case USB_SPEED_LOW: 1114200825Sthompsa case USB_SPEED_FULL: 1115200825Sthompsa /* 1116200825Sthompsa * Due to high bandwidth usage and problems 1117200825Sthompsa * with HIGH-speed split transactions we 1118200825Sthompsa * disable surround setups on FULL-speed USB 1119200825Sthompsa * by default 1120200825Sthompsa */ 1121200825Sthompsa channels = 2; 1122200825Sthompsa break; 1123200825Sthompsa default: 1124200825Sthompsa channels = 16; 1125200825Sthompsa break; 1126200825Sthompsa } 1127200825Sthompsa } else if (channels > 16) { 1128200825Sthompsa channels = 16; 1129186730Salfred } 1130184610Salfred if (sbuf_new(&sc->sc_sndstat, NULL, 4096, SBUF_AUTOEXTEND)) { 1131184610Salfred sc->sc_sndstat_valid = 1; 1132184610Salfred } 1133184610Salfred /* try to search for a valid config */ 1134184610Salfred 1135184610Salfred for (x = channels; x; x--) { 1136184610Salfred for (y = bits; y; y -= 8) { 1137184610Salfred 1138200825Sthompsa /* try user defined rate, if any */ 1139200825Sthompsa if (rate != 0) 1140200825Sthompsa uaudio_chan_fill_info_sub(sc, udev, rate, x, y); 1141200825Sthompsa 1142200825Sthompsa /* try find a matching rate, if any */ 1143200825Sthompsa for (z = 0; uaudio_rate_list[z]; z++) { 1144200825Sthompsa uaudio_chan_fill_info_sub(sc, udev, uaudio_rate_list[z], x, y); 1145200825Sthompsa 1146184610Salfred if (sc->sc_rec_chan.valid && 1147184610Salfred sc->sc_play_chan.valid) { 1148184610Salfred goto done; 1149184610Salfred } 1150184610Salfred } 1151184610Salfred } 1152184610Salfred } 1153184610Salfred 1154184610Salfreddone: 1155184610Salfred if (sc->sc_sndstat_valid) { 1156184610Salfred sbuf_finish(&sc->sc_sndstat); 1157184610Salfred } 1158184610Salfred} 1159184610Salfred 1160184610Salfredstatic void 1161194677Sthompsauaudio_chan_play_callback(struct usb_xfer *xfer, usb_error_t error) 1162184610Salfred{ 1163194677Sthompsa struct uaudio_chan *ch = usbd_xfer_softc(xfer); 1164194677Sthompsa struct usb_page_cache *pc; 1165186730Salfred uint32_t total; 1166184610Salfred uint32_t blockcount; 1167184610Salfred uint32_t n; 1168184610Salfred uint32_t offset; 1169200825Sthompsa int actlen; 1170200825Sthompsa int sumlen; 1171184610Salfred 1172194677Sthompsa usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 1173194677Sthompsa 1174199060Sthompsa if (ch->end == ch->start) { 1175199060Sthompsa DPRINTF("no buffer!\n"); 1176199060Sthompsa return; 1177199060Sthompsa } 1178199060Sthompsa 1179184610Salfred switch (USB_GET_STATE(xfer)) { 1180184610Salfred case USB_ST_TRANSFERRED: 1181184610Salfredtr_transferred: 1182194677Sthompsa if (actlen < sumlen) { 1183184610Salfred DPRINTF("short transfer, " 1184200825Sthompsa "%d of %d bytes\n", actlen, sumlen); 1185184610Salfred } 1186184610Salfred chn_intr(ch->pcm_ch); 1187184610Salfred 1188184610Salfred case USB_ST_SETUP: 1189200825Sthompsa if (ch->bytes_per_frame[1] > usbd_xfer_max_framelen(xfer)) { 1190184610Salfred DPRINTF("bytes per transfer, %d, " 1191184610Salfred "exceeds maximum, %d!\n", 1192200825Sthompsa ch->bytes_per_frame[1], 1193194677Sthompsa usbd_xfer_max_framelen(xfer)); 1194184610Salfred break; 1195184610Salfred } 1196200825Sthompsa 1197200825Sthompsa blockcount = ch->intr_frames; 1198200825Sthompsa 1199200825Sthompsa /* setup number of frames */ 1200194677Sthompsa usbd_xfer_set_frames(xfer, blockcount); 1201184610Salfred 1202200825Sthompsa /* reset total length */ 1203200825Sthompsa total = 0; 1204200825Sthompsa 1205200825Sthompsa /* setup frame lengths */ 1206200825Sthompsa for (n = 0; n != blockcount; n++) { 1207200825Sthompsa ch->sample_curr += ch->sample_rem; 1208200825Sthompsa if (ch->sample_curr >= ch->frames_per_second) { 1209200825Sthompsa ch->sample_curr -= ch->frames_per_second; 1210200825Sthompsa usbd_xfer_set_frame_len(xfer, n, ch->bytes_per_frame[1]); 1211200825Sthompsa total += ch->bytes_per_frame[1]; 1212200825Sthompsa } else { 1213200825Sthompsa usbd_xfer_set_frame_len(xfer, n, ch->bytes_per_frame[0]); 1214200825Sthompsa total += ch->bytes_per_frame[0]; 1215200825Sthompsa } 1216200825Sthompsa } 1217200825Sthompsa 1218184610Salfred DPRINTFN(6, "transfer %d bytes\n", total); 1219184610Salfred 1220184610Salfred offset = 0; 1221184610Salfred 1222194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 1223184610Salfred while (total > 0) { 1224184610Salfred 1225184610Salfred n = (ch->end - ch->cur); 1226184610Salfred if (n > total) { 1227184610Salfred n = total; 1228184610Salfred } 1229194677Sthompsa usbd_copy_in(pc, offset, ch->cur, n); 1230184610Salfred 1231184610Salfred total -= n; 1232184610Salfred ch->cur += n; 1233184610Salfred offset += n; 1234184610Salfred 1235184610Salfred if (ch->cur >= ch->end) { 1236184610Salfred ch->cur = ch->start; 1237184610Salfred } 1238184610Salfred } 1239184610Salfred 1240194228Sthompsa usbd_transfer_submit(xfer); 1241184610Salfred break; 1242184610Salfred 1243184610Salfred default: /* Error */ 1244194677Sthompsa if (error == USB_ERR_CANCELLED) { 1245184610Salfred break; 1246184610Salfred } 1247184610Salfred goto tr_transferred; 1248184610Salfred } 1249184610Salfred} 1250184610Salfred 1251184610Salfredstatic void 1252194677Sthompsauaudio_chan_record_callback(struct usb_xfer *xfer, usb_error_t error) 1253184610Salfred{ 1254194677Sthompsa struct uaudio_chan *ch = usbd_xfer_softc(xfer); 1255194677Sthompsa struct usb_page_cache *pc; 1256184610Salfred uint32_t n; 1257184610Salfred uint32_t m; 1258184610Salfred uint32_t blockcount; 1259184610Salfred uint32_t offset0; 1260184610Salfred uint32_t offset1; 1261199060Sthompsa uint32_t mfl; 1262194677Sthompsa int len; 1263199060Sthompsa int actlen; 1264199060Sthompsa int nframes; 1265184610Salfred 1266194677Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, &nframes); 1267199060Sthompsa mfl = usbd_xfer_max_framelen(xfer); 1268194677Sthompsa 1269199060Sthompsa if (ch->end == ch->start) { 1270199060Sthompsa DPRINTF("no buffer!\n"); 1271199060Sthompsa return; 1272199060Sthompsa } 1273199060Sthompsa 1274184610Salfred switch (USB_GET_STATE(xfer)) { 1275184610Salfred case USB_ST_TRANSFERRED: 1276184610Salfred 1277200825Sthompsa DPRINTFN(6, "transferred %d bytes\n", actlen); 1278200825Sthompsa 1279184610Salfred offset0 = 0; 1280199060Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 1281184610Salfred 1282194677Sthompsa for (n = 0; n != nframes; n++) { 1283184610Salfred 1284184610Salfred offset1 = offset0; 1285194682Sthompsa len = usbd_xfer_frame_len(xfer, n); 1286184610Salfred 1287194677Sthompsa while (len > 0) { 1288184610Salfred 1289184610Salfred m = (ch->end - ch->cur); 1290184610Salfred 1291194677Sthompsa if (m > len) { 1292194677Sthompsa m = len; 1293184610Salfred } 1294194677Sthompsa usbd_copy_out(pc, offset1, ch->cur, m); 1295184610Salfred 1296194677Sthompsa len -= m; 1297184610Salfred offset1 += m; 1298184610Salfred ch->cur += m; 1299184610Salfred 1300184610Salfred if (ch->cur >= ch->end) { 1301184610Salfred ch->cur = ch->start; 1302184610Salfred } 1303184610Salfred } 1304184610Salfred 1305199060Sthompsa offset0 += mfl; 1306184610Salfred } 1307184610Salfred 1308184610Salfred chn_intr(ch->pcm_ch); 1309184610Salfred 1310184610Salfred case USB_ST_SETUP: 1311199060Sthompsatr_setup: 1312200825Sthompsa blockcount = ch->intr_frames; 1313200825Sthompsa 1314194677Sthompsa usbd_xfer_set_frames(xfer, blockcount); 1315194677Sthompsa for (n = 0; n < blockcount; n++) { 1316199060Sthompsa usbd_xfer_set_frame_len(xfer, n, mfl); 1317184610Salfred } 1318184610Salfred 1319194228Sthompsa usbd_transfer_submit(xfer); 1320199060Sthompsa break; 1321184610Salfred 1322184610Salfred default: /* Error */ 1323194677Sthompsa if (error == USB_ERR_CANCELLED) { 1324199060Sthompsa break; 1325184610Salfred } 1326199060Sthompsa goto tr_setup; 1327184610Salfred } 1328184610Salfred} 1329184610Salfred 1330184610Salfredvoid * 1331184610Salfreduaudio_chan_init(struct uaudio_softc *sc, struct snd_dbuf *b, 1332184610Salfred struct pcm_channel *c, int dir) 1333184610Salfred{ 1334184610Salfred struct uaudio_chan *ch = ((dir == PCMDIR_PLAY) ? 1335184610Salfred &sc->sc_play_chan : &sc->sc_rec_chan); 1336186730Salfred uint32_t buf_size; 1337199060Sthompsa uint32_t frames; 1338200825Sthompsa uint32_t format; 1339200825Sthompsa uint16_t fps; 1340184610Salfred uint8_t endpoint; 1341199060Sthompsa uint8_t blocks; 1342184610Salfred uint8_t iface_index; 1343184610Salfred uint8_t alt_index; 1344199060Sthompsa uint8_t fps_shift; 1345193045Sthompsa usb_error_t err; 1346184610Salfred 1347200825Sthompsa fps = usbd_get_isoc_fps(sc->sc_udev); 1348200825Sthompsa 1349200825Sthompsa if (fps < 8000) { 1350199060Sthompsa /* FULL speed USB */ 1351199060Sthompsa frames = 8; 1352199060Sthompsa } else { 1353199060Sthompsa /* HIGH speed USB */ 1354199060Sthompsa frames = UAUDIO_NFRAMES; 1355199060Sthompsa } 1356199060Sthompsa 1357184610Salfred /* setup play/record format */ 1358184610Salfred 1359184610Salfred ch->pcm_cap.fmtlist = ch->pcm_format; 1360184610Salfred 1361184610Salfred ch->pcm_format[0] = 0; 1362184610Salfred ch->pcm_format[1] = 0; 1363184610Salfred 1364184610Salfred ch->pcm_cap.minspeed = ch->sample_rate; 1365184610Salfred ch->pcm_cap.maxspeed = ch->sample_rate; 1366184610Salfred 1367199576Sthompsa /* setup mutex and PCM channel */ 1368199576Sthompsa 1369199576Sthompsa ch->pcm_ch = c; 1370199576Sthompsa ch->pcm_mtx = c->lock; 1371199576Sthompsa 1372200825Sthompsa format = ch->p_fmt->freebsd_fmt; 1373184610Salfred 1374200825Sthompsa switch (ch->p_asf1d->bNrChannels) { 1375200825Sthompsa case 2: 1376200825Sthompsa /* stereo */ 1377200825Sthompsa format = SND_FORMAT(format, 2, 0); 1378200825Sthompsa break; 1379200825Sthompsa case 1: 1380200825Sthompsa /* mono */ 1381200825Sthompsa format = SND_FORMAT(format, 1, 0); 1382200825Sthompsa break; 1383200825Sthompsa default: 1384200825Sthompsa /* surround and more */ 1385200825Sthompsa format = feeder_matrix_default_format( 1386200825Sthompsa SND_FORMAT(format, ch->p_asf1d->bNrChannels, 0)); 1387200825Sthompsa break; 1388200825Sthompsa } 1389200825Sthompsa 1390200825Sthompsa ch->pcm_cap.fmtlist[0] = format; 1391184610Salfred ch->pcm_cap.fmtlist[1] = 0; 1392184610Salfred 1393200825Sthompsa /* check if format is not supported */ 1394200825Sthompsa 1395200825Sthompsa if (format == 0) { 1396200825Sthompsa DPRINTF("The selected audio format is not supported\n"); 1397200825Sthompsa goto error; 1398200825Sthompsa } 1399200825Sthompsa 1400184610Salfred /* set alternate interface corresponding to the mode */ 1401184610Salfred 1402184610Salfred endpoint = ch->p_ed1->bEndpointAddress; 1403184610Salfred iface_index = ch->iface_index; 1404184610Salfred alt_index = ch->iface_alt_index; 1405184610Salfred 1406184610Salfred DPRINTF("endpoint=0x%02x, speed=%d, iface=%d alt=%d\n", 1407184610Salfred endpoint, ch->sample_rate, iface_index, alt_index); 1408184610Salfred 1409194228Sthompsa err = usbd_set_alt_interface_index(sc->sc_udev, iface_index, alt_index); 1410184610Salfred if (err) { 1411184610Salfred DPRINTF("setting of alternate index failed: %s!\n", 1412194228Sthompsa usbd_errstr(err)); 1413184610Salfred goto error; 1414184610Salfred } 1415194228Sthompsa usbd_set_parent_iface(sc->sc_udev, iface_index, sc->sc_mixer_iface_index); 1416184610Salfred 1417184610Salfred /* 1418184610Salfred * If just one sampling rate is supported, 1419184610Salfred * no need to call "uaudio_set_speed()". 1420184610Salfred * Roland SD-90 freezes by a SAMPLING_FREQ_CONTROL request. 1421184610Salfred */ 1422184610Salfred if (ch->p_asf1d->bSamFreqType != 1) { 1423184610Salfred if (uaudio_set_speed(sc->sc_udev, endpoint, ch->sample_rate)) { 1424184610Salfred /* 1425184610Salfred * If the endpoint is adaptive setting the speed may 1426184610Salfred * fail. 1427184610Salfred */ 1428184610Salfred DPRINTF("setting of sample rate failed! (continuing anyway)\n"); 1429184610Salfred } 1430184610Salfred } 1431194228Sthompsa if (usbd_transfer_setup(sc->sc_udev, &iface_index, ch->xfer, 1432203678Sbrucec ch->usb_cfg, UAUDIO_NCHANBUFS, ch, ch->pcm_mtx)) { 1433184610Salfred DPRINTF("could not allocate USB transfers!\n"); 1434184610Salfred goto error; 1435184610Salfred } 1436199060Sthompsa 1437199060Sthompsa fps_shift = usbd_xfer_get_fps_shift(ch->xfer[0]); 1438199060Sthompsa 1439200825Sthompsa /* down shift number of frames per second, if any */ 1440200825Sthompsa fps >>= fps_shift; 1441200825Sthompsa frames >>= fps_shift; 1442200825Sthompsa 1443200825Sthompsa /* bytes per frame should not be zero */ 1444200825Sthompsa ch->bytes_per_frame[0] = ((ch->sample_rate / fps) * ch->sample_size); 1445200825Sthompsa ch->bytes_per_frame[1] = (((ch->sample_rate + fps - 1) / fps) * ch->sample_size); 1446200825Sthompsa 1447200825Sthompsa /* setup data rate dithering, if any */ 1448200825Sthompsa ch->frames_per_second = fps; 1449200825Sthompsa ch->sample_rem = ch->sample_rate % fps; 1450200825Sthompsa ch->sample_curr = 0; 1451200825Sthompsa ch->frames_per_second = fps; 1452200825Sthompsa 1453200825Sthompsa /* compute required buffer size */ 1454200825Sthompsa buf_size = (ch->bytes_per_frame[1] * frames); 1455200825Sthompsa 1456199060Sthompsa ch->intr_size = buf_size; 1457200825Sthompsa ch->intr_frames = frames; 1458199060Sthompsa 1459200825Sthompsa DPRINTF("fps=%d sample_rem=%d\n", fps, ch->sample_rem); 1460200825Sthompsa 1461199060Sthompsa if (ch->intr_frames == 0) { 1462199060Sthompsa DPRINTF("frame shift is too high!\n"); 1463199060Sthompsa goto error; 1464199060Sthompsa } 1465199060Sthompsa 1466199060Sthompsa /* setup double buffering */ 1467199060Sthompsa buf_size *= 2; 1468199060Sthompsa blocks = 2; 1469199060Sthompsa 1470199060Sthompsa ch->buf = malloc(buf_size, M_DEVBUF, M_WAITOK | M_ZERO); 1471199060Sthompsa if (ch->buf == NULL) 1472199060Sthompsa goto error; 1473199060Sthompsa if (sndbuf_setup(b, ch->buf, buf_size) != 0) 1474199060Sthompsa goto error; 1475199060Sthompsa if (sndbuf_resize(b, blocks, ch->intr_size)) 1476199060Sthompsa goto error; 1477199060Sthompsa 1478199060Sthompsa ch->start = ch->buf; 1479199060Sthompsa ch->end = ch->buf + buf_size; 1480199060Sthompsa ch->cur = ch->buf; 1481199060Sthompsa ch->pcm_buf = b; 1482199060Sthompsa 1483199060Sthompsa if (ch->pcm_mtx == NULL) { 1484199060Sthompsa DPRINTF("ERROR: PCM channels does not have a mutex!\n"); 1485199060Sthompsa goto error; 1486199060Sthompsa } 1487199060Sthompsa 1488184610Salfred return (ch); 1489184610Salfred 1490184610Salfrederror: 1491184610Salfred uaudio_chan_free(ch); 1492184610Salfred return (NULL); 1493184610Salfred} 1494184610Salfred 1495184610Salfredint 1496184610Salfreduaudio_chan_free(struct uaudio_chan *ch) 1497184610Salfred{ 1498184610Salfred if (ch->buf != NULL) { 1499184610Salfred free(ch->buf, M_DEVBUF); 1500184610Salfred ch->buf = NULL; 1501184610Salfred } 1502194228Sthompsa usbd_transfer_unsetup(ch->xfer, UAUDIO_NCHANBUFS); 1503184610Salfred 1504184610Salfred ch->valid = 0; 1505184610Salfred 1506184610Salfred return (0); 1507184610Salfred} 1508184610Salfred 1509184610Salfredint 1510184610Salfreduaudio_chan_set_param_blocksize(struct uaudio_chan *ch, uint32_t blocksize) 1511184610Salfred{ 1512199060Sthompsa return (ch->intr_size); 1513184610Salfred} 1514184610Salfred 1515184610Salfredint 1516184610Salfreduaudio_chan_set_param_fragments(struct uaudio_chan *ch, uint32_t blocksize, 1517184610Salfred uint32_t blockcount) 1518184610Salfred{ 1519184610Salfred return (1); 1520184610Salfred} 1521184610Salfred 1522184610Salfredint 1523184610Salfreduaudio_chan_set_param_speed(struct uaudio_chan *ch, uint32_t speed) 1524184610Salfred{ 1525184610Salfred if (speed != ch->sample_rate) { 1526184610Salfred DPRINTF("rate conversion required\n"); 1527184610Salfred } 1528184610Salfred return (ch->sample_rate); 1529184610Salfred} 1530184610Salfred 1531184610Salfredint 1532184610Salfreduaudio_chan_getptr(struct uaudio_chan *ch) 1533184610Salfred{ 1534184610Salfred return (ch->cur - ch->start); 1535184610Salfred} 1536184610Salfred 1537184610Salfredstruct pcmchan_caps * 1538184610Salfreduaudio_chan_getcaps(struct uaudio_chan *ch) 1539184610Salfred{ 1540184610Salfred return (&ch->pcm_cap); 1541184610Salfred} 1542184610Salfred 1543193640Sariffstatic struct pcmchan_matrix uaudio_chan_matrix_swap_2_0 = { 1544193640Sariff .id = SND_CHN_MATRIX_DRV, 1545193640Sariff .channels = 2, 1546193640Sariff .ext = 0, 1547193640Sariff .map = { 1548193640Sariff /* Right */ 1549193640Sariff [0] = { 1550193640Sariff .type = SND_CHN_T_FR, 1551193640Sariff .members = 1552193640Sariff SND_CHN_T_MASK_FR | SND_CHN_T_MASK_FC | 1553193640Sariff SND_CHN_T_MASK_LF | SND_CHN_T_MASK_BR | 1554193640Sariff SND_CHN_T_MASK_BC | SND_CHN_T_MASK_SR 1555193640Sariff }, 1556193640Sariff /* Left */ 1557193640Sariff [1] = { 1558193640Sariff .type = SND_CHN_T_FL, 1559193640Sariff .members = 1560193640Sariff SND_CHN_T_MASK_FL | SND_CHN_T_MASK_FC | 1561193640Sariff SND_CHN_T_MASK_LF | SND_CHN_T_MASK_BL | 1562193640Sariff SND_CHN_T_MASK_BC | SND_CHN_T_MASK_SL 1563193640Sariff }, 1564193640Sariff [2] = { 1565193640Sariff .type = SND_CHN_T_MAX, 1566193640Sariff .members = 0 1567193640Sariff } 1568193640Sariff }, 1569193640Sariff .mask = SND_CHN_T_MASK_FR | SND_CHN_T_MASK_FL, 1570193640Sariff .offset = { 1, 0, -1, -1, -1, -1, -1, -1, -1, 1571193640Sariff -1, -1, -1, -1, -1, -1, -1, -1, -1 } 1572193640Sariff}; 1573193640Sariff 1574193640Sariffstruct pcmchan_matrix * 1575193640Sariffuaudio_chan_getmatrix(struct uaudio_chan *ch, uint32_t format) 1576193640Sariff{ 1577193640Sariff struct uaudio_softc *sc; 1578193640Sariff 1579193640Sariff sc = ch->priv_sc; 1580193640Sariff 1581193640Sariff if (sc != NULL && sc->sc_uq_audio_swap_lr != 0 && 1582193640Sariff AFMT_CHANNEL(format) == 2) 1583193640Sariff return (&uaudio_chan_matrix_swap_2_0); 1584193640Sariff 1585193640Sariff return (feeder_matrix_format_map(format)); 1586193640Sariff} 1587193640Sariff 1588184610Salfredint 1589184610Salfreduaudio_chan_set_param_format(struct uaudio_chan *ch, uint32_t format) 1590184610Salfred{ 1591184610Salfred ch->format = format; 1592184610Salfred return (0); 1593184610Salfred} 1594184610Salfred 1595184610Salfredint 1596184610Salfreduaudio_chan_start(struct uaudio_chan *ch) 1597184610Salfred{ 1598184610Salfred ch->cur = ch->start; 1599184610Salfred 1600184610Salfred#if (UAUDIO_NCHANBUFS != 2) 1601184610Salfred#error "please update code" 1602184610Salfred#endif 1603184610Salfred if (ch->xfer[0]) { 1604194228Sthompsa usbd_transfer_start(ch->xfer[0]); 1605184610Salfred } 1606184610Salfred if (ch->xfer[1]) { 1607194228Sthompsa usbd_transfer_start(ch->xfer[1]); 1608184610Salfred } 1609184610Salfred return (0); 1610184610Salfred} 1611184610Salfred 1612184610Salfredint 1613184610Salfreduaudio_chan_stop(struct uaudio_chan *ch) 1614184610Salfred{ 1615184610Salfred#if (UAUDIO_NCHANBUFS != 2) 1616184610Salfred#error "please update code" 1617184610Salfred#endif 1618194228Sthompsa usbd_transfer_stop(ch->xfer[0]); 1619194228Sthompsa usbd_transfer_stop(ch->xfer[1]); 1620184610Salfred return (0); 1621184610Salfred} 1622184610Salfred 1623184610Salfred/*========================================================================* 1624184610Salfred * AC - Audio Controller - routines 1625184610Salfred *========================================================================*/ 1626184610Salfred 1627184610Salfredstatic void 1628184610Salfreduaudio_mixer_add_ctl_sub(struct uaudio_softc *sc, struct uaudio_mixer_node *mc) 1629184610Salfred{ 1630184610Salfred struct uaudio_mixer_node *p_mc_new = 1631184610Salfred malloc(sizeof(*p_mc_new), M_USBDEV, M_WAITOK); 1632184610Salfred 1633184610Salfred if (p_mc_new) { 1634184610Salfred bcopy(mc, p_mc_new, sizeof(*p_mc_new)); 1635184610Salfred p_mc_new->next = sc->sc_mixer_root; 1636184610Salfred sc->sc_mixer_root = p_mc_new; 1637184610Salfred sc->sc_mixer_count++; 1638184610Salfred } else { 1639184610Salfred DPRINTF("out of memory\n"); 1640184610Salfred } 1641184610Salfred} 1642184610Salfred 1643184610Salfredstatic void 1644184610Salfreduaudio_mixer_add_ctl(struct uaudio_softc *sc, struct uaudio_mixer_node *mc) 1645184610Salfred{ 1646184610Salfred int32_t res; 1647184610Salfred 1648184610Salfred if (mc->class < UAC_NCLASSES) { 1649184610Salfred DPRINTF("adding %s.%d\n", 1650184610Salfred uac_names[mc->class], mc->ctl); 1651184610Salfred } else { 1652184610Salfred DPRINTF("adding %d\n", mc->ctl); 1653184610Salfred } 1654184610Salfred 1655184610Salfred if (mc->type == MIX_ON_OFF) { 1656184610Salfred mc->minval = 0; 1657184610Salfred mc->maxval = 1; 1658184610Salfred } else if (mc->type == MIX_SELECTOR) { 1659184610Salfred } else { 1660184610Salfred 1661184610Salfred /* determine min and max values */ 1662184610Salfred 1663184610Salfred mc->minval = uaudio_mixer_get(sc->sc_udev, GET_MIN, mc); 1664184610Salfred 1665184610Salfred mc->minval = uaudio_mixer_signext(mc->type, mc->minval); 1666184610Salfred 1667184610Salfred mc->maxval = uaudio_mixer_get(sc->sc_udev, GET_MAX, mc); 1668184610Salfred 1669199060Sthompsa mc->maxval = uaudio_mixer_signext(mc->type, mc->maxval); 1670184610Salfred 1671199060Sthompsa /* check if max and min was swapped */ 1672199060Sthompsa 1673199060Sthompsa if (mc->maxval < mc->minval) { 1674199060Sthompsa res = mc->maxval; 1675199060Sthompsa mc->maxval = mc->minval; 1676199060Sthompsa mc->minval = res; 1677199060Sthompsa } 1678199060Sthompsa 1679199060Sthompsa /* compute value range */ 1680184610Salfred mc->mul = mc->maxval - mc->minval; 1681199060Sthompsa if (mc->mul == 0) 1682184610Salfred mc->mul = 1; 1683199060Sthompsa 1684199060Sthompsa /* compute value alignment */ 1685184610Salfred res = uaudio_mixer_get(sc->sc_udev, GET_RES, mc); 1686199576Sthompsa 1687199576Sthompsa DPRINTF("Resolution = %d\n", (int)res); 1688184610Salfred } 1689184610Salfred 1690184610Salfred uaudio_mixer_add_ctl_sub(sc, mc); 1691184610Salfred 1692207077Sthompsa#ifdef USB_DEBUG 1693184610Salfred if (uaudio_debug > 2) { 1694184610Salfred uint8_t i; 1695184610Salfred 1696184610Salfred for (i = 0; i < mc->nchan; i++) { 1697184610Salfred DPRINTF("[mix] wValue=%04x\n", mc->wValue[0]); 1698184610Salfred } 1699184610Salfred DPRINTF("[mix] wIndex=%04x type=%d ctl='%d' " 1700184610Salfred "min=%d max=%d\n", 1701184610Salfred mc->wIndex, mc->type, mc->ctl, 1702184610Salfred mc->minval, mc->maxval); 1703184610Salfred } 1704184610Salfred#endif 1705184610Salfred} 1706184610Salfred 1707184610Salfredstatic void 1708184610Salfreduaudio_mixer_add_input(struct uaudio_softc *sc, 1709184610Salfred const struct uaudio_terminal_node *iot, int id) 1710184610Salfred{ 1711207077Sthompsa#ifdef USB_DEBUG 1712203678Sbrucec const struct usb_audio_input_terminal *d = iot[id].u.it; 1713184610Salfred 1714184610Salfred DPRINTFN(3, "bTerminalId=%d wTerminalType=0x%04x " 1715184610Salfred "bAssocTerminal=%d bNrChannels=%d wChannelConfig=%d " 1716184610Salfred "iChannelNames=%d\n", 1717184610Salfred d->bTerminalId, UGETW(d->wTerminalType), d->bAssocTerminal, 1718184610Salfred d->bNrChannels, UGETW(d->wChannelConfig), 1719184610Salfred d->iChannelNames); 1720184610Salfred#endif 1721184610Salfred} 1722184610Salfred 1723184610Salfredstatic void 1724184610Salfreduaudio_mixer_add_output(struct uaudio_softc *sc, 1725184610Salfred const struct uaudio_terminal_node *iot, int id) 1726184610Salfred{ 1727207077Sthompsa#ifdef USB_DEBUG 1728203678Sbrucec const struct usb_audio_output_terminal *d = iot[id].u.ot; 1729184610Salfred 1730184610Salfred DPRINTFN(3, "bTerminalId=%d wTerminalType=0x%04x " 1731184610Salfred "bAssocTerminal=%d bSourceId=%d iTerminal=%d\n", 1732184610Salfred d->bTerminalId, UGETW(d->wTerminalType), d->bAssocTerminal, 1733184610Salfred d->bSourceId, d->iTerminal); 1734184610Salfred#endif 1735184610Salfred} 1736184610Salfred 1737184610Salfredstatic void 1738184610Salfreduaudio_mixer_add_mixer(struct uaudio_softc *sc, 1739184610Salfred const struct uaudio_terminal_node *iot, int id) 1740184610Salfred{ 1741184610Salfred struct uaudio_mixer_node mix; 1742184610Salfred 1743203678Sbrucec const struct usb_audio_mixer_unit_0 *d0 = iot[id].u.mu; 1744203678Sbrucec const struct usb_audio_mixer_unit_1 *d1; 1745184610Salfred 1746184610Salfred uint32_t bno; /* bit number */ 1747184610Salfred uint32_t p; /* bit number accumulator */ 1748184610Salfred uint32_t mo; /* matching outputs */ 1749184610Salfred uint32_t mc; /* matching channels */ 1750184610Salfred uint32_t ichs; /* input channels */ 1751184610Salfred uint32_t ochs; /* output channels */ 1752184610Salfred uint32_t c; 1753184610Salfred uint32_t chs; /* channels */ 1754184610Salfred uint32_t i; 1755184610Salfred uint32_t o; 1756184610Salfred 1757184610Salfred DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n", 1758184610Salfred d0->bUnitId, d0->bNrInPins); 1759184610Salfred 1760184610Salfred /* compute the number of input channels */ 1761184610Salfred 1762184610Salfred ichs = 0; 1763184610Salfred for (i = 0; i < d0->bNrInPins; i++) { 1764184610Salfred ichs += (uaudio_mixer_get_cluster(d0->baSourceId[i], iot) 1765184610Salfred .bNrChannels); 1766184610Salfred } 1767184610Salfred 1768184610Salfred d1 = (const void *)(d0->baSourceId + d0->bNrInPins); 1769184610Salfred 1770184610Salfred /* and the number of output channels */ 1771184610Salfred 1772184610Salfred ochs = d1->bNrChannels; 1773184610Salfred 1774184610Salfred DPRINTFN(3, "ichs=%d ochs=%d\n", ichs, ochs); 1775184610Salfred 1776184610Salfred bzero(&mix, sizeof(mix)); 1777184610Salfred 1778184610Salfred mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 1779184610Salfred uaudio_mixer_determine_class(&iot[id], &mix); 1780184610Salfred mix.type = MIX_SIGNED_16; 1781184610Salfred 1782184610Salfred if (uaudio_mixer_verify_desc(d0, ((ichs * ochs) + 7) / 8) == NULL) { 1783184610Salfred return; 1784184610Salfred } 1785184610Salfred for (p = i = 0; i < d0->bNrInPins; i++) { 1786184610Salfred chs = uaudio_mixer_get_cluster(d0->baSourceId[i], iot).bNrChannels; 1787184610Salfred mc = 0; 1788184610Salfred for (c = 0; c < chs; c++) { 1789184610Salfred mo = 0; 1790184610Salfred for (o = 0; o < ochs; o++) { 1791184610Salfred bno = ((p + c) * ochs) + o; 1792184610Salfred if (BIT_TEST(d1->bmControls, bno)) { 1793184610Salfred mo++; 1794184610Salfred } 1795184610Salfred } 1796184610Salfred if (mo == 1) { 1797184610Salfred mc++; 1798184610Salfred } 1799184610Salfred } 1800184610Salfred if ((mc == chs) && (chs <= MIX_MAX_CHAN)) { 1801184610Salfred 1802184610Salfred /* repeat bit-scan */ 1803184610Salfred 1804184610Salfred mc = 0; 1805184610Salfred for (c = 0; c < chs; c++) { 1806184610Salfred for (o = 0; o < ochs; o++) { 1807184610Salfred bno = ((p + c) * ochs) + o; 1808184610Salfred if (BIT_TEST(d1->bmControls, bno)) { 1809184610Salfred mix.wValue[mc++] = MAKE_WORD(p + c + 1, o + 1); 1810184610Salfred } 1811184610Salfred } 1812184610Salfred } 1813184610Salfred mix.nchan = chs; 1814184610Salfred uaudio_mixer_add_ctl(sc, &mix); 1815184610Salfred } else { 1816184610Salfred /* XXX */ 1817184610Salfred } 1818184610Salfred p += chs; 1819184610Salfred } 1820184610Salfred} 1821184610Salfred 1822184610Salfredstatic void 1823184610Salfreduaudio_mixer_add_selector(struct uaudio_softc *sc, 1824184610Salfred const struct uaudio_terminal_node *iot, int id) 1825184610Salfred{ 1826203678Sbrucec const struct usb_audio_selector_unit *d = iot[id].u.su; 1827184610Salfred struct uaudio_mixer_node mix; 1828184610Salfred uint16_t i; 1829184610Salfred 1830184610Salfred DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n", 1831184610Salfred d->bUnitId, d->bNrInPins); 1832184610Salfred 1833184610Salfred if (d->bNrInPins == 0) { 1834184610Salfred return; 1835184610Salfred } 1836184610Salfred bzero(&mix, sizeof(mix)); 1837184610Salfred 1838184610Salfred mix.wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no); 1839184610Salfred mix.wValue[0] = MAKE_WORD(0, 0); 1840184610Salfred uaudio_mixer_determine_class(&iot[id], &mix); 1841184610Salfred mix.nchan = 1; 1842184610Salfred mix.type = MIX_SELECTOR; 1843184610Salfred 1844184610Salfred mix.ctl = SOUND_MIXER_NRDEVICES; 1845184610Salfred mix.minval = 1; 1846184610Salfred mix.maxval = d->bNrInPins; 1847184610Salfred 1848184610Salfred if (mix.maxval > MAX_SELECTOR_INPUT_PIN) { 1849184610Salfred mix.maxval = MAX_SELECTOR_INPUT_PIN; 1850184610Salfred } 1851184610Salfred mix.mul = (mix.maxval - mix.minval); 1852184610Salfred for (i = 0; i < MAX_SELECTOR_INPUT_PIN; i++) { 1853184610Salfred mix.slctrtype[i] = SOUND_MIXER_NRDEVICES; 1854184610Salfred } 1855184610Salfred 1856184610Salfred for (i = 0; i < mix.maxval; i++) { 1857184610Salfred mix.slctrtype[i] = uaudio_mixer_feature_name 1858184610Salfred (&iot[d->baSourceId[i]], &mix); 1859184610Salfred } 1860184610Salfred 1861184610Salfred mix.class = 0; /* not used */ 1862184610Salfred 1863184610Salfred uaudio_mixer_add_ctl(sc, &mix); 1864184610Salfred} 1865184610Salfred 1866184610Salfredstatic uint32_t 1867203678Sbrucecuaudio_mixer_feature_get_bmaControls(const struct usb_audio_feature_unit *d, 1868184610Salfred uint8_t index) 1869184610Salfred{ 1870184610Salfred uint32_t temp = 0; 1871184610Salfred uint32_t offset = (index * d->bControlSize); 1872184610Salfred 1873184610Salfred if (d->bControlSize > 0) { 1874184610Salfred temp |= d->bmaControls[offset]; 1875184610Salfred if (d->bControlSize > 1) { 1876184610Salfred temp |= d->bmaControls[offset + 1] << 8; 1877184610Salfred if (d->bControlSize > 2) { 1878184610Salfred temp |= d->bmaControls[offset + 2] << 16; 1879184610Salfred if (d->bControlSize > 3) { 1880184610Salfred temp |= d->bmaControls[offset + 3] << 24; 1881184610Salfred } 1882184610Salfred } 1883184610Salfred } 1884184610Salfred } 1885184610Salfred return (temp); 1886184610Salfred} 1887184610Salfred 1888184610Salfredstatic void 1889184610Salfreduaudio_mixer_add_feature(struct uaudio_softc *sc, 1890184610Salfred const struct uaudio_terminal_node *iot, int id) 1891184610Salfred{ 1892203678Sbrucec const struct usb_audio_feature_unit *d = iot[id].u.fu; 1893184610Salfred struct uaudio_mixer_node mix; 1894184610Salfred uint32_t fumask; 1895184610Salfred uint32_t mmask; 1896184610Salfred uint32_t cmask; 1897184610Salfred uint16_t mixernumber; 1898184610Salfred uint8_t nchan; 1899184610Salfred uint8_t chan; 1900184610Salfred uint8_t ctl; 1901184610Salfred uint8_t i; 1902184610Salfred 1903184610Salfred if (d->bControlSize == 0) { 1904184610Salfred return; 1905184610Salfred } 1906184610Salfred bzero(&mix, sizeof(mix)); 1907184610Salfred 1908184610Salfred nchan = (d->bLength - 7) / d->bControlSize; 1909184610Salfred mmask = uaudio_mixer_feature_get_bmaControls(d, 0); 1910184610Salfred cmask = 0; 1911184610Salfred 1912184610Salfred if (nchan == 0) { 1913184610Salfred return; 1914184610Salfred } 1915184610Salfred /* figure out what we can control */ 1916184610Salfred 1917184610Salfred for (chan = 1; chan < nchan; chan++) { 1918184610Salfred DPRINTFN(10, "chan=%d mask=%x\n", 1919184610Salfred chan, uaudio_mixer_feature_get_bmaControls(d, chan)); 1920184610Salfred 1921184610Salfred cmask |= uaudio_mixer_feature_get_bmaControls(d, chan); 1922184610Salfred } 1923184610Salfred 1924184610Salfred if (nchan > MIX_MAX_CHAN) { 1925184610Salfred nchan = MIX_MAX_CHAN; 1926184610Salfred } 1927184610Salfred mix.wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no); 1928184610Salfred 1929184610Salfred for (ctl = 1; ctl <= LOUDNESS_CONTROL; ctl++) { 1930184610Salfred 1931184610Salfred fumask = FU_MASK(ctl); 1932184610Salfred 1933184610Salfred DPRINTFN(5, "ctl=%d fumask=0x%04x\n", 1934184610Salfred ctl, fumask); 1935184610Salfred 1936184610Salfred if (mmask & fumask) { 1937184610Salfred mix.nchan = 1; 1938184610Salfred mix.wValue[0] = MAKE_WORD(ctl, 0); 1939184610Salfred } else if (cmask & fumask) { 1940184610Salfred mix.nchan = nchan - 1; 1941184610Salfred for (i = 1; i < nchan; i++) { 1942184610Salfred if (uaudio_mixer_feature_get_bmaControls(d, i) & fumask) 1943184610Salfred mix.wValue[i - 1] = MAKE_WORD(ctl, i); 1944184610Salfred else 1945184610Salfred mix.wValue[i - 1] = -1; 1946184610Salfred } 1947184610Salfred } else { 1948184610Salfred continue; 1949184610Salfred } 1950184610Salfred 1951184610Salfred mixernumber = uaudio_mixer_feature_name(&iot[id], &mix); 1952184610Salfred 1953184610Salfred switch (ctl) { 1954184610Salfred case MUTE_CONTROL: 1955184610Salfred mix.type = MIX_ON_OFF; 1956184610Salfred mix.ctl = SOUND_MIXER_NRDEVICES; 1957184610Salfred break; 1958184610Salfred 1959184610Salfred case VOLUME_CONTROL: 1960184610Salfred mix.type = MIX_SIGNED_16; 1961184610Salfred mix.ctl = mixernumber; 1962184610Salfred break; 1963184610Salfred 1964184610Salfred case BASS_CONTROL: 1965184610Salfred mix.type = MIX_SIGNED_8; 1966184610Salfred mix.ctl = SOUND_MIXER_BASS; 1967184610Salfred break; 1968184610Salfred 1969184610Salfred case MID_CONTROL: 1970184610Salfred mix.type = MIX_SIGNED_8; 1971184610Salfred mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 1972184610Salfred break; 1973184610Salfred 1974184610Salfred case TREBLE_CONTROL: 1975184610Salfred mix.type = MIX_SIGNED_8; 1976184610Salfred mix.ctl = SOUND_MIXER_TREBLE; 1977184610Salfred break; 1978184610Salfred 1979184610Salfred case GRAPHIC_EQUALIZER_CONTROL: 1980184610Salfred continue; /* XXX don't add anything */ 1981184610Salfred break; 1982184610Salfred 1983184610Salfred case AGC_CONTROL: 1984184610Salfred mix.type = MIX_ON_OFF; 1985184610Salfred mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 1986184610Salfred break; 1987184610Salfred 1988184610Salfred case DELAY_CONTROL: 1989184610Salfred mix.type = MIX_UNSIGNED_16; 1990184610Salfred mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 1991184610Salfred break; 1992184610Salfred 1993184610Salfred case BASS_BOOST_CONTROL: 1994184610Salfred mix.type = MIX_ON_OFF; 1995184610Salfred mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 1996184610Salfred break; 1997184610Salfred 1998184610Salfred case LOUDNESS_CONTROL: 1999184610Salfred mix.type = MIX_ON_OFF; 2000184610Salfred mix.ctl = SOUND_MIXER_LOUD; /* Is this correct ? */ 2001184610Salfred break; 2002184610Salfred 2003184610Salfred default: 2004184610Salfred mix.type = MIX_UNKNOWN; 2005184610Salfred break; 2006184610Salfred } 2007184610Salfred 2008184610Salfred if (mix.type != MIX_UNKNOWN) { 2009184610Salfred uaudio_mixer_add_ctl(sc, &mix); 2010184610Salfred } 2011184610Salfred } 2012184610Salfred} 2013184610Salfred 2014184610Salfredstatic void 2015184610Salfreduaudio_mixer_add_processing_updown(struct uaudio_softc *sc, 2016184610Salfred const struct uaudio_terminal_node *iot, int id) 2017184610Salfred{ 2018203678Sbrucec const struct usb_audio_processing_unit_0 *d0 = iot[id].u.pu; 2019203678Sbrucec const struct usb_audio_processing_unit_1 *d1 = 2020184610Salfred (const void *)(d0->baSourceId + d0->bNrInPins); 2021203678Sbrucec const struct usb_audio_processing_unit_updown *ud = 2022184610Salfred (const void *)(d1->bmControls + d1->bControlSize); 2023184610Salfred struct uaudio_mixer_node mix; 2024184610Salfred uint8_t i; 2025184610Salfred 2026184610Salfred if (uaudio_mixer_verify_desc(d0, sizeof(*ud)) == NULL) { 2027184610Salfred return; 2028184610Salfred } 2029184610Salfred if (uaudio_mixer_verify_desc(d0, sizeof(*ud) + (2 * ud->bNrModes)) 2030184610Salfred == NULL) { 2031184610Salfred return; 2032184610Salfred } 2033184610Salfred DPRINTFN(3, "bUnitId=%d bNrModes=%d\n", 2034184610Salfred d0->bUnitId, ud->bNrModes); 2035184610Salfred 2036184610Salfred if (!(d1->bmControls[0] & UA_PROC_MASK(UD_MODE_SELECT_CONTROL))) { 2037184610Salfred DPRINTF("no mode select\n"); 2038184610Salfred return; 2039184610Salfred } 2040184610Salfred bzero(&mix, sizeof(mix)); 2041184610Salfred 2042184610Salfred mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 2043184610Salfred mix.nchan = 1; 2044184610Salfred mix.wValue[0] = MAKE_WORD(UD_MODE_SELECT_CONTROL, 0); 2045184610Salfred uaudio_mixer_determine_class(&iot[id], &mix); 2046184610Salfred mix.type = MIX_ON_OFF; /* XXX */ 2047184610Salfred 2048184610Salfred for (i = 0; i < ud->bNrModes; i++) { 2049184610Salfred DPRINTFN(3, "i=%d bm=0x%x\n", i, UGETW(ud->waModes[i])); 2050184610Salfred /* XXX */ 2051184610Salfred } 2052184610Salfred 2053184610Salfred uaudio_mixer_add_ctl(sc, &mix); 2054184610Salfred} 2055184610Salfred 2056184610Salfredstatic void 2057184610Salfreduaudio_mixer_add_processing(struct uaudio_softc *sc, 2058184610Salfred const struct uaudio_terminal_node *iot, int id) 2059184610Salfred{ 2060203678Sbrucec const struct usb_audio_processing_unit_0 *d0 = iot[id].u.pu; 2061203678Sbrucec const struct usb_audio_processing_unit_1 *d1 = 2062184610Salfred (const void *)(d0->baSourceId + d0->bNrInPins); 2063184610Salfred struct uaudio_mixer_node mix; 2064184610Salfred uint16_t ptype; 2065184610Salfred 2066184610Salfred bzero(&mix, sizeof(mix)); 2067184610Salfred 2068184610Salfred ptype = UGETW(d0->wProcessType); 2069184610Salfred 2070184610Salfred DPRINTFN(3, "wProcessType=%d bUnitId=%d " 2071184610Salfred "bNrInPins=%d\n", ptype, d0->bUnitId, d0->bNrInPins); 2072184610Salfred 2073184610Salfred if (d1->bControlSize == 0) { 2074184610Salfred return; 2075184610Salfred } 2076184610Salfred if (d1->bmControls[0] & UA_PROC_ENABLE_MASK) { 2077184610Salfred mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 2078184610Salfred mix.nchan = 1; 2079184610Salfred mix.wValue[0] = MAKE_WORD(XX_ENABLE_CONTROL, 0); 2080184610Salfred uaudio_mixer_determine_class(&iot[id], &mix); 2081184610Salfred mix.type = MIX_ON_OFF; 2082184610Salfred uaudio_mixer_add_ctl(sc, &mix); 2083184610Salfred } 2084184610Salfred switch (ptype) { 2085184610Salfred case UPDOWNMIX_PROCESS: 2086184610Salfred uaudio_mixer_add_processing_updown(sc, iot, id); 2087184610Salfred break; 2088184610Salfred 2089184610Salfred case DOLBY_PROLOGIC_PROCESS: 2090184610Salfred case P3D_STEREO_EXTENDER_PROCESS: 2091184610Salfred case REVERBATION_PROCESS: 2092184610Salfred case CHORUS_PROCESS: 2093184610Salfred case DYN_RANGE_COMP_PROCESS: 2094184610Salfred default: 2095184610Salfred DPRINTF("unit %d, type=%d is not implemented\n", 2096184610Salfred d0->bUnitId, ptype); 2097184610Salfred break; 2098184610Salfred } 2099184610Salfred} 2100184610Salfred 2101184610Salfredstatic void 2102184610Salfreduaudio_mixer_add_extension(struct uaudio_softc *sc, 2103184610Salfred const struct uaudio_terminal_node *iot, int id) 2104184610Salfred{ 2105203678Sbrucec const struct usb_audio_extension_unit_0 *d0 = iot[id].u.eu; 2106203678Sbrucec const struct usb_audio_extension_unit_1 *d1 = 2107184610Salfred (const void *)(d0->baSourceId + d0->bNrInPins); 2108184610Salfred struct uaudio_mixer_node mix; 2109184610Salfred 2110184610Salfred DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n", 2111184610Salfred d0->bUnitId, d0->bNrInPins); 2112184610Salfred 2113184610Salfred if (sc->sc_uq_au_no_xu) { 2114184610Salfred return; 2115184610Salfred } 2116184610Salfred if (d1->bControlSize == 0) { 2117184610Salfred return; 2118184610Salfred } 2119184610Salfred if (d1->bmControls[0] & UA_EXT_ENABLE_MASK) { 2120184610Salfred 2121184610Salfred bzero(&mix, sizeof(mix)); 2122184610Salfred 2123184610Salfred mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 2124184610Salfred mix.nchan = 1; 2125184610Salfred mix.wValue[0] = MAKE_WORD(UA_EXT_ENABLE, 0); 2126184610Salfred uaudio_mixer_determine_class(&iot[id], &mix); 2127184610Salfred mix.type = MIX_ON_OFF; 2128184610Salfred 2129184610Salfred uaudio_mixer_add_ctl(sc, &mix); 2130184610Salfred } 2131184610Salfred} 2132184610Salfred 2133184610Salfredstatic const void * 2134184610Salfreduaudio_mixer_verify_desc(const void *arg, uint32_t len) 2135184610Salfred{ 2136203678Sbrucec const struct usb_audio_mixer_unit_1 *d1; 2137203678Sbrucec const struct usb_audio_extension_unit_1 *e1; 2138203678Sbrucec const struct usb_audio_processing_unit_1 *u1; 2139184610Salfred 2140184610Salfred union { 2141192984Sthompsa const struct usb_descriptor *desc; 2142203678Sbrucec const struct usb_audio_input_terminal *it; 2143203678Sbrucec const struct usb_audio_output_terminal *ot; 2144203678Sbrucec const struct usb_audio_mixer_unit_0 *mu; 2145203678Sbrucec const struct usb_audio_selector_unit *su; 2146203678Sbrucec const struct usb_audio_feature_unit *fu; 2147203678Sbrucec const struct usb_audio_processing_unit_0 *pu; 2148203678Sbrucec const struct usb_audio_extension_unit_0 *eu; 2149184610Salfred } u; 2150184610Salfred 2151184610Salfred u.desc = arg; 2152184610Salfred 2153184610Salfred if (u.desc == NULL) { 2154184610Salfred goto error; 2155184610Salfred } 2156184610Salfred if (u.desc->bDescriptorType != UDESC_CS_INTERFACE) { 2157184610Salfred goto error; 2158184610Salfred } 2159184610Salfred switch (u.desc->bDescriptorSubtype) { 2160184610Salfred case UDESCSUB_AC_INPUT: 2161184610Salfred len += sizeof(*u.it); 2162184610Salfred break; 2163184610Salfred 2164184610Salfred case UDESCSUB_AC_OUTPUT: 2165184610Salfred len += sizeof(*u.ot); 2166184610Salfred break; 2167184610Salfred 2168184610Salfred case UDESCSUB_AC_MIXER: 2169184610Salfred len += sizeof(*u.mu); 2170184610Salfred 2171184610Salfred if (u.desc->bLength < len) { 2172184610Salfred goto error; 2173184610Salfred } 2174184610Salfred len += u.mu->bNrInPins; 2175184610Salfred 2176184610Salfred if (u.desc->bLength < len) { 2177184610Salfred goto error; 2178184610Salfred } 2179184610Salfred d1 = (const void *)(u.mu->baSourceId + u.mu->bNrInPins); 2180184610Salfred 2181184610Salfred len += sizeof(*d1); 2182184610Salfred break; 2183184610Salfred 2184184610Salfred case UDESCSUB_AC_SELECTOR: 2185184610Salfred len += sizeof(*u.su); 2186184610Salfred 2187184610Salfred if (u.desc->bLength < len) { 2188184610Salfred goto error; 2189184610Salfred } 2190184610Salfred len += u.su->bNrInPins; 2191184610Salfred break; 2192184610Salfred 2193184610Salfred case UDESCSUB_AC_FEATURE: 2194184610Salfred len += (sizeof(*u.fu) + 1); 2195184610Salfred break; 2196184610Salfred 2197184610Salfred case UDESCSUB_AC_PROCESSING: 2198184610Salfred len += sizeof(*u.pu); 2199184610Salfred 2200184610Salfred if (u.desc->bLength < len) { 2201184610Salfred goto error; 2202184610Salfred } 2203184610Salfred len += u.pu->bNrInPins; 2204184610Salfred 2205184610Salfred if (u.desc->bLength < len) { 2206184610Salfred goto error; 2207184610Salfred } 2208184610Salfred u1 = (const void *)(u.pu->baSourceId + u.pu->bNrInPins); 2209184610Salfred 2210184610Salfred len += sizeof(*u1); 2211184610Salfred 2212184610Salfred if (u.desc->bLength < len) { 2213184610Salfred goto error; 2214184610Salfred } 2215184610Salfred len += u1->bControlSize; 2216184610Salfred 2217184610Salfred break; 2218184610Salfred 2219184610Salfred case UDESCSUB_AC_EXTENSION: 2220184610Salfred len += sizeof(*u.eu); 2221184610Salfred 2222184610Salfred if (u.desc->bLength < len) { 2223184610Salfred goto error; 2224184610Salfred } 2225184610Salfred len += u.eu->bNrInPins; 2226184610Salfred 2227184610Salfred if (u.desc->bLength < len) { 2228184610Salfred goto error; 2229184610Salfred } 2230184610Salfred e1 = (const void *)(u.eu->baSourceId + u.eu->bNrInPins); 2231184610Salfred 2232184610Salfred len += sizeof(*e1); 2233184610Salfred 2234184610Salfred if (u.desc->bLength < len) { 2235184610Salfred goto error; 2236184610Salfred } 2237184610Salfred len += e1->bControlSize; 2238184610Salfred break; 2239184610Salfred 2240184610Salfred default: 2241184610Salfred goto error; 2242184610Salfred } 2243184610Salfred 2244184610Salfred if (u.desc->bLength < len) { 2245184610Salfred goto error; 2246184610Salfred } 2247184610Salfred return (u.desc); 2248184610Salfred 2249184610Salfrederror: 2250184610Salfred if (u.desc) { 2251184610Salfred DPRINTF("invalid descriptor, type=%d, " 2252184610Salfred "sub_type=%d, len=%d of %d bytes\n", 2253184610Salfred u.desc->bDescriptorType, 2254184610Salfred u.desc->bDescriptorSubtype, 2255184610Salfred u.desc->bLength, len); 2256184610Salfred } 2257184610Salfred return (NULL); 2258184610Salfred} 2259184610Salfred 2260207077Sthompsa#ifdef USB_DEBUG 2261184610Salfredstatic void 2262184610Salfreduaudio_mixer_dump_cluster(uint8_t id, const struct uaudio_terminal_node *iot) 2263184610Salfred{ 2264184610Salfred static const char *channel_names[16] = { 2265184610Salfred "LEFT", "RIGHT", "CENTER", "LFE", 2266184610Salfred "LEFT_SURROUND", "RIGHT_SURROUND", "LEFT_CENTER", "RIGHT_CENTER", 2267184610Salfred "SURROUND", "LEFT_SIDE", "RIGHT_SIDE", "TOP", 2268184610Salfred "RESERVED12", "RESERVED13", "RESERVED14", "RESERVED15", 2269184610Salfred }; 2270184610Salfred uint16_t cc; 2271184610Salfred uint8_t i; 2272203678Sbrucec const struct usb_audio_cluster cl = uaudio_mixer_get_cluster(id, iot); 2273184610Salfred 2274184610Salfred cc = UGETW(cl.wChannelConfig); 2275184610Salfred 2276184610Salfred DPRINTF("cluster: bNrChannels=%u iChannelNames=%u wChannelConfig=" 2277184610Salfred "0x%04x:\n", cl.iChannelNames, cl.bNrChannels, cc); 2278184610Salfred 2279184610Salfred for (i = 0; cc; i++) { 2280184610Salfred if (cc & 1) { 2281184610Salfred DPRINTF(" - %s\n", channel_names[i]); 2282184610Salfred } 2283184610Salfred cc >>= 1; 2284184610Salfred } 2285184610Salfred} 2286184610Salfred 2287184610Salfred#endif 2288184610Salfred 2289203678Sbrucecstatic struct usb_audio_cluster 2290184610Salfreduaudio_mixer_get_cluster(uint8_t id, const struct uaudio_terminal_node *iot) 2291184610Salfred{ 2292203678Sbrucec struct usb_audio_cluster r; 2293192984Sthompsa const struct usb_descriptor *dp; 2294184610Salfred uint8_t i; 2295184610Salfred 2296184610Salfred for (i = 0; i < UAUDIO_RECURSE_LIMIT; i++) { /* avoid infinite loops */ 2297184610Salfred dp = iot[id].u.desc; 2298184610Salfred if (dp == NULL) { 2299184610Salfred goto error; 2300184610Salfred } 2301184610Salfred switch (dp->bDescriptorSubtype) { 2302184610Salfred case UDESCSUB_AC_INPUT: 2303184610Salfred r.bNrChannels = iot[id].u.it->bNrChannels; 2304184610Salfred r.wChannelConfig[0] = iot[id].u.it->wChannelConfig[0]; 2305184610Salfred r.wChannelConfig[1] = iot[id].u.it->wChannelConfig[1]; 2306184610Salfred r.iChannelNames = iot[id].u.it->iChannelNames; 2307184610Salfred goto done; 2308184610Salfred 2309184610Salfred case UDESCSUB_AC_OUTPUT: 2310184610Salfred id = iot[id].u.ot->bSourceId; 2311184610Salfred break; 2312184610Salfred 2313184610Salfred case UDESCSUB_AC_MIXER: 2314203678Sbrucec r = *(const struct usb_audio_cluster *) 2315184610Salfred &iot[id].u.mu->baSourceId[iot[id].u.mu-> 2316184610Salfred bNrInPins]; 2317184610Salfred goto done; 2318184610Salfred 2319184610Salfred case UDESCSUB_AC_SELECTOR: 2320184610Salfred if (iot[id].u.su->bNrInPins > 0) { 2321184610Salfred /* XXX This is not really right */ 2322184610Salfred id = iot[id].u.su->baSourceId[0]; 2323184610Salfred } 2324184610Salfred break; 2325184610Salfred 2326184610Salfred case UDESCSUB_AC_FEATURE: 2327184610Salfred id = iot[id].u.fu->bSourceId; 2328184610Salfred break; 2329184610Salfred 2330184610Salfred case UDESCSUB_AC_PROCESSING: 2331203678Sbrucec r = *((const struct usb_audio_cluster *) 2332184610Salfred &iot[id].u.pu->baSourceId[iot[id].u.pu-> 2333184610Salfred bNrInPins]); 2334184610Salfred goto done; 2335184610Salfred 2336184610Salfred case UDESCSUB_AC_EXTENSION: 2337203678Sbrucec r = *((const struct usb_audio_cluster *) 2338184610Salfred &iot[id].u.eu->baSourceId[iot[id].u.eu-> 2339184610Salfred bNrInPins]); 2340184610Salfred goto done; 2341184610Salfred 2342184610Salfred default: 2343184610Salfred goto error; 2344184610Salfred } 2345184610Salfred } 2346184610Salfrederror: 2347184610Salfred DPRINTF("bad data\n"); 2348184610Salfred bzero(&r, sizeof(r)); 2349184610Salfreddone: 2350184610Salfred return (r); 2351184610Salfred} 2352184610Salfred 2353207077Sthompsa#ifdef USB_DEBUG 2354184610Salfred 2355184610Salfredstruct uaudio_tt_to_string { 2356184610Salfred uint16_t terminal_type; 2357184610Salfred const char *desc; 2358184610Salfred}; 2359184610Salfred 2360184610Salfredstatic const struct uaudio_tt_to_string uaudio_tt_to_string[] = { 2361184610Salfred 2362184610Salfred /* USB terminal types */ 2363184610Salfred {UAT_UNDEFINED, "UAT_UNDEFINED"}, 2364184610Salfred {UAT_STREAM, "UAT_STREAM"}, 2365184610Salfred {UAT_VENDOR, "UAT_VENDOR"}, 2366184610Salfred 2367184610Salfred /* input terminal types */ 2368184610Salfred {UATI_UNDEFINED, "UATI_UNDEFINED"}, 2369184610Salfred {UATI_MICROPHONE, "UATI_MICROPHONE"}, 2370184610Salfred {UATI_DESKMICROPHONE, "UATI_DESKMICROPHONE"}, 2371184610Salfred {UATI_PERSONALMICROPHONE, "UATI_PERSONALMICROPHONE"}, 2372184610Salfred {UATI_OMNIMICROPHONE, "UATI_OMNIMICROPHONE"}, 2373184610Salfred {UATI_MICROPHONEARRAY, "UATI_MICROPHONEARRAY"}, 2374184610Salfred {UATI_PROCMICROPHONEARR, "UATI_PROCMICROPHONEARR"}, 2375184610Salfred 2376184610Salfred /* output terminal types */ 2377184610Salfred {UATO_UNDEFINED, "UATO_UNDEFINED"}, 2378184610Salfred {UATO_SPEAKER, "UATO_SPEAKER"}, 2379184610Salfred {UATO_HEADPHONES, "UATO_HEADPHONES"}, 2380184610Salfred {UATO_DISPLAYAUDIO, "UATO_DISPLAYAUDIO"}, 2381184610Salfred {UATO_DESKTOPSPEAKER, "UATO_DESKTOPSPEAKER"}, 2382184610Salfred {UATO_ROOMSPEAKER, "UATO_ROOMSPEAKER"}, 2383184610Salfred {UATO_COMMSPEAKER, "UATO_COMMSPEAKER"}, 2384184610Salfred {UATO_SUBWOOFER, "UATO_SUBWOOFER"}, 2385184610Salfred 2386184610Salfred /* bidir terminal types */ 2387184610Salfred {UATB_UNDEFINED, "UATB_UNDEFINED"}, 2388184610Salfred {UATB_HANDSET, "UATB_HANDSET"}, 2389184610Salfred {UATB_HEADSET, "UATB_HEADSET"}, 2390184610Salfred {UATB_SPEAKERPHONE, "UATB_SPEAKERPHONE"}, 2391184610Salfred {UATB_SPEAKERPHONEESUP, "UATB_SPEAKERPHONEESUP"}, 2392184610Salfred {UATB_SPEAKERPHONEECANC, "UATB_SPEAKERPHONEECANC"}, 2393184610Salfred 2394184610Salfred /* telephony terminal types */ 2395184610Salfred {UATT_UNDEFINED, "UATT_UNDEFINED"}, 2396184610Salfred {UATT_PHONELINE, "UATT_PHONELINE"}, 2397184610Salfred {UATT_TELEPHONE, "UATT_TELEPHONE"}, 2398184610Salfred {UATT_DOWNLINEPHONE, "UATT_DOWNLINEPHONE"}, 2399184610Salfred 2400184610Salfred /* external terminal types */ 2401184610Salfred {UATE_UNDEFINED, "UATE_UNDEFINED"}, 2402184610Salfred {UATE_ANALOGCONN, "UATE_ANALOGCONN"}, 2403184610Salfred {UATE_LINECONN, "UATE_LINECONN"}, 2404184610Salfred {UATE_LEGACYCONN, "UATE_LEGACYCONN"}, 2405184610Salfred {UATE_DIGITALAUIFC, "UATE_DIGITALAUIFC"}, 2406184610Salfred {UATE_SPDIF, "UATE_SPDIF"}, 2407184610Salfred {UATE_1394DA, "UATE_1394DA"}, 2408184610Salfred {UATE_1394DV, "UATE_1394DV"}, 2409184610Salfred 2410184610Salfred /* embedded function terminal types */ 2411184610Salfred {UATF_UNDEFINED, "UATF_UNDEFINED"}, 2412184610Salfred {UATF_CALIBNOISE, "UATF_CALIBNOISE"}, 2413184610Salfred {UATF_EQUNOISE, "UATF_EQUNOISE"}, 2414184610Salfred {UATF_CDPLAYER, "UATF_CDPLAYER"}, 2415184610Salfred {UATF_DAT, "UATF_DAT"}, 2416184610Salfred {UATF_DCC, "UATF_DCC"}, 2417184610Salfred {UATF_MINIDISK, "UATF_MINIDISK"}, 2418184610Salfred {UATF_ANALOGTAPE, "UATF_ANALOGTAPE"}, 2419184610Salfred {UATF_PHONOGRAPH, "UATF_PHONOGRAPH"}, 2420184610Salfred {UATF_VCRAUDIO, "UATF_VCRAUDIO"}, 2421184610Salfred {UATF_VIDEODISCAUDIO, "UATF_VIDEODISCAUDIO"}, 2422184610Salfred {UATF_DVDAUDIO, "UATF_DVDAUDIO"}, 2423184610Salfred {UATF_TVTUNERAUDIO, "UATF_TVTUNERAUDIO"}, 2424184610Salfred {UATF_SATELLITE, "UATF_SATELLITE"}, 2425184610Salfred {UATF_CABLETUNER, "UATF_CABLETUNER"}, 2426184610Salfred {UATF_DSS, "UATF_DSS"}, 2427184610Salfred {UATF_RADIORECV, "UATF_RADIORECV"}, 2428184610Salfred {UATF_RADIOXMIT, "UATF_RADIOXMIT"}, 2429184610Salfred {UATF_MULTITRACK, "UATF_MULTITRACK"}, 2430184610Salfred {UATF_SYNTHESIZER, "UATF_SYNTHESIZER"}, 2431184610Salfred 2432184610Salfred /* unknown */ 2433184610Salfred {0x0000, "UNKNOWN"}, 2434184610Salfred}; 2435184610Salfred 2436184610Salfredstatic const char * 2437184610Salfreduaudio_mixer_get_terminal_name(uint16_t terminal_type) 2438184610Salfred{ 2439184610Salfred const struct uaudio_tt_to_string *uat = uaudio_tt_to_string; 2440184610Salfred 2441184610Salfred while (uat->terminal_type) { 2442184610Salfred if (uat->terminal_type == terminal_type) { 2443184610Salfred break; 2444184610Salfred } 2445184610Salfred uat++; 2446184610Salfred } 2447184610Salfred if (uat->terminal_type == 0) { 2448184610Salfred DPRINTF("unknown terminal type (0x%04x)", terminal_type); 2449184610Salfred } 2450184610Salfred return (uat->desc); 2451184610Salfred} 2452184610Salfred 2453184610Salfred#endif 2454184610Salfred 2455184610Salfredstatic uint16_t 2456184610Salfreduaudio_mixer_determine_class(const struct uaudio_terminal_node *iot, 2457184610Salfred struct uaudio_mixer_node *mix) 2458184610Salfred{ 2459184610Salfred uint16_t terminal_type = 0x0000; 2460184610Salfred const struct uaudio_terminal_node *input[2]; 2461184610Salfred const struct uaudio_terminal_node *output[2]; 2462184610Salfred 2463184610Salfred input[0] = uaudio_mixer_get_input(iot, 0); 2464184610Salfred input[1] = uaudio_mixer_get_input(iot, 1); 2465184610Salfred 2466184610Salfred output[0] = uaudio_mixer_get_output(iot, 0); 2467184610Salfred output[1] = uaudio_mixer_get_output(iot, 1); 2468184610Salfred 2469184610Salfred /* 2470184610Salfred * check if there is only 2471184610Salfred * one output terminal: 2472184610Salfred */ 2473184610Salfred if (output[0] && (!output[1])) { 2474184610Salfred terminal_type = UGETW(output[0]->u.ot->wTerminalType); 2475184610Salfred } 2476184610Salfred /* 2477184610Salfred * If the only output terminal is USB, 2478184610Salfred * the class is UAC_RECORD. 2479184610Salfred */ 2480184610Salfred if ((terminal_type & 0xff00) == (UAT_UNDEFINED & 0xff00)) { 2481184610Salfred 2482184610Salfred mix->class = UAC_RECORD; 2483184610Salfred if (input[0] && (!input[1])) { 2484184610Salfred terminal_type = UGETW(input[0]->u.it->wTerminalType); 2485184610Salfred } else { 2486184610Salfred terminal_type = 0; 2487184610Salfred } 2488184610Salfred goto done; 2489184610Salfred } 2490184610Salfred /* 2491184610Salfred * if the unit is connected to just 2492184610Salfred * one input terminal, the 2493184610Salfred * class is UAC_INPUT: 2494184610Salfred */ 2495184610Salfred if (input[0] && (!input[1])) { 2496184610Salfred mix->class = UAC_INPUT; 2497184610Salfred terminal_type = UGETW(input[0]->u.it->wTerminalType); 2498184610Salfred goto done; 2499184610Salfred } 2500184610Salfred /* 2501184610Salfred * Otherwise, the class is UAC_OUTPUT. 2502184610Salfred */ 2503184610Salfred mix->class = UAC_OUTPUT; 2504184610Salfreddone: 2505184610Salfred return (terminal_type); 2506184610Salfred} 2507184610Salfred 2508184610Salfredstruct uaudio_tt_to_feature { 2509184610Salfred uint16_t terminal_type; 2510184610Salfred uint16_t feature; 2511184610Salfred}; 2512184610Salfred 2513184610Salfredstatic const struct uaudio_tt_to_feature uaudio_tt_to_feature[] = { 2514184610Salfred 2515184610Salfred {UAT_STREAM, SOUND_MIXER_PCM}, 2516184610Salfred 2517184610Salfred {UATI_MICROPHONE, SOUND_MIXER_MIC}, 2518184610Salfred {UATI_DESKMICROPHONE, SOUND_MIXER_MIC}, 2519184610Salfred {UATI_PERSONALMICROPHONE, SOUND_MIXER_MIC}, 2520184610Salfred {UATI_OMNIMICROPHONE, SOUND_MIXER_MIC}, 2521184610Salfred {UATI_MICROPHONEARRAY, SOUND_MIXER_MIC}, 2522184610Salfred {UATI_PROCMICROPHONEARR, SOUND_MIXER_MIC}, 2523184610Salfred 2524184610Salfred {UATO_SPEAKER, SOUND_MIXER_SPEAKER}, 2525184610Salfred {UATO_DESKTOPSPEAKER, SOUND_MIXER_SPEAKER}, 2526184610Salfred {UATO_ROOMSPEAKER, SOUND_MIXER_SPEAKER}, 2527184610Salfred {UATO_COMMSPEAKER, SOUND_MIXER_SPEAKER}, 2528184610Salfred 2529184610Salfred {UATE_ANALOGCONN, SOUND_MIXER_LINE}, 2530184610Salfred {UATE_LINECONN, SOUND_MIXER_LINE}, 2531184610Salfred {UATE_LEGACYCONN, SOUND_MIXER_LINE}, 2532184610Salfred 2533184610Salfred {UATE_DIGITALAUIFC, SOUND_MIXER_ALTPCM}, 2534184610Salfred {UATE_SPDIF, SOUND_MIXER_ALTPCM}, 2535184610Salfred {UATE_1394DA, SOUND_MIXER_ALTPCM}, 2536184610Salfred {UATE_1394DV, SOUND_MIXER_ALTPCM}, 2537184610Salfred 2538184610Salfred {UATF_CDPLAYER, SOUND_MIXER_CD}, 2539184610Salfred 2540184610Salfred {UATF_SYNTHESIZER, SOUND_MIXER_SYNTH}, 2541184610Salfred 2542184610Salfred {UATF_VIDEODISCAUDIO, SOUND_MIXER_VIDEO}, 2543184610Salfred {UATF_DVDAUDIO, SOUND_MIXER_VIDEO}, 2544184610Salfred {UATF_TVTUNERAUDIO, SOUND_MIXER_VIDEO}, 2545184610Salfred 2546184610Salfred /* telephony terminal types */ 2547184610Salfred {UATT_UNDEFINED, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 2548184610Salfred {UATT_PHONELINE, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 2549184610Salfred {UATT_TELEPHONE, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 2550184610Salfred {UATT_DOWNLINEPHONE, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 2551184610Salfred 2552184610Salfred {UATF_RADIORECV, SOUND_MIXER_RADIO}, 2553184610Salfred {UATF_RADIOXMIT, SOUND_MIXER_RADIO}, 2554184610Salfred 2555184610Salfred {UAT_UNDEFINED, SOUND_MIXER_VOLUME}, 2556184610Salfred {UAT_VENDOR, SOUND_MIXER_VOLUME}, 2557184610Salfred {UATI_UNDEFINED, SOUND_MIXER_VOLUME}, 2558184610Salfred 2559184610Salfred /* output terminal types */ 2560184610Salfred {UATO_UNDEFINED, SOUND_MIXER_VOLUME}, 2561184610Salfred {UATO_DISPLAYAUDIO, SOUND_MIXER_VOLUME}, 2562184610Salfred {UATO_SUBWOOFER, SOUND_MIXER_VOLUME}, 2563184610Salfred {UATO_HEADPHONES, SOUND_MIXER_VOLUME}, 2564184610Salfred 2565184610Salfred /* bidir terminal types */ 2566184610Salfred {UATB_UNDEFINED, SOUND_MIXER_VOLUME}, 2567184610Salfred {UATB_HANDSET, SOUND_MIXER_VOLUME}, 2568184610Salfred {UATB_HEADSET, SOUND_MIXER_VOLUME}, 2569184610Salfred {UATB_SPEAKERPHONE, SOUND_MIXER_VOLUME}, 2570184610Salfred {UATB_SPEAKERPHONEESUP, SOUND_MIXER_VOLUME}, 2571184610Salfred {UATB_SPEAKERPHONEECANC, SOUND_MIXER_VOLUME}, 2572184610Salfred 2573184610Salfred /* external terminal types */ 2574184610Salfred {UATE_UNDEFINED, SOUND_MIXER_VOLUME}, 2575184610Salfred 2576184610Salfred /* embedded function terminal types */ 2577184610Salfred {UATF_UNDEFINED, SOUND_MIXER_VOLUME}, 2578184610Salfred {UATF_CALIBNOISE, SOUND_MIXER_VOLUME}, 2579184610Salfred {UATF_EQUNOISE, SOUND_MIXER_VOLUME}, 2580184610Salfred {UATF_DAT, SOUND_MIXER_VOLUME}, 2581184610Salfred {UATF_DCC, SOUND_MIXER_VOLUME}, 2582184610Salfred {UATF_MINIDISK, SOUND_MIXER_VOLUME}, 2583184610Salfred {UATF_ANALOGTAPE, SOUND_MIXER_VOLUME}, 2584184610Salfred {UATF_PHONOGRAPH, SOUND_MIXER_VOLUME}, 2585184610Salfred {UATF_VCRAUDIO, SOUND_MIXER_VOLUME}, 2586184610Salfred {UATF_SATELLITE, SOUND_MIXER_VOLUME}, 2587184610Salfred {UATF_CABLETUNER, SOUND_MIXER_VOLUME}, 2588184610Salfred {UATF_DSS, SOUND_MIXER_VOLUME}, 2589184610Salfred {UATF_MULTITRACK, SOUND_MIXER_VOLUME}, 2590184610Salfred {0xffff, SOUND_MIXER_VOLUME}, 2591184610Salfred 2592184610Salfred /* default */ 2593184610Salfred {0x0000, SOUND_MIXER_VOLUME}, 2594184610Salfred}; 2595184610Salfred 2596184610Salfredstatic uint16_t 2597184610Salfreduaudio_mixer_feature_name(const struct uaudio_terminal_node *iot, 2598184610Salfred struct uaudio_mixer_node *mix) 2599184610Salfred{ 2600184610Salfred const struct uaudio_tt_to_feature *uat = uaudio_tt_to_feature; 2601184610Salfred uint16_t terminal_type = uaudio_mixer_determine_class(iot, mix); 2602184610Salfred 2603184610Salfred if ((mix->class == UAC_RECORD) && (terminal_type == 0)) { 2604184610Salfred return (SOUND_MIXER_IMIX); 2605184610Salfred } 2606184610Salfred while (uat->terminal_type) { 2607184610Salfred if (uat->terminal_type == terminal_type) { 2608184610Salfred break; 2609184610Salfred } 2610184610Salfred uat++; 2611184610Salfred } 2612184610Salfred 2613184610Salfred DPRINTF("terminal_type=%s (0x%04x) -> %d\n", 2614184610Salfred uaudio_mixer_get_terminal_name(terminal_type), 2615184610Salfred terminal_type, uat->feature); 2616184610Salfred 2617184610Salfred return (uat->feature); 2618184610Salfred} 2619184610Salfred 2620184610Salfredconst static struct uaudio_terminal_node * 2621184610Salfreduaudio_mixer_get_input(const struct uaudio_terminal_node *iot, uint8_t index) 2622184610Salfred{ 2623184610Salfred struct uaudio_terminal_node *root = iot->root; 2624184610Salfred uint8_t n; 2625184610Salfred 2626184610Salfred n = iot->usr.id_max; 2627184610Salfred do { 2628184610Salfred if (iot->usr.bit_input[n / 8] & (1 << (n % 8))) { 2629184610Salfred if (!index--) { 2630184610Salfred return (root + n); 2631184610Salfred } 2632184610Salfred } 2633184610Salfred } while (n--); 2634184610Salfred 2635184610Salfred return (NULL); 2636184610Salfred} 2637184610Salfred 2638184610Salfredconst static struct uaudio_terminal_node * 2639184610Salfreduaudio_mixer_get_output(const struct uaudio_terminal_node *iot, uint8_t index) 2640184610Salfred{ 2641184610Salfred struct uaudio_terminal_node *root = iot->root; 2642184610Salfred uint8_t n; 2643184610Salfred 2644184610Salfred n = iot->usr.id_max; 2645184610Salfred do { 2646184610Salfred if (iot->usr.bit_output[n / 8] & (1 << (n % 8))) { 2647184610Salfred if (!index--) { 2648184610Salfred return (root + n); 2649184610Salfred } 2650184610Salfred } 2651184610Salfred } while (n--); 2652184610Salfred 2653184610Salfred return (NULL); 2654184610Salfred} 2655184610Salfred 2656184610Salfredstatic void 2657184610Salfreduaudio_mixer_find_inputs_sub(struct uaudio_terminal_node *root, 2658184610Salfred const uint8_t *p_id, uint8_t n_id, 2659184610Salfred struct uaudio_search_result *info) 2660184610Salfred{ 2661184610Salfred struct uaudio_terminal_node *iot; 2662184610Salfred uint8_t n; 2663184610Salfred uint8_t i; 2664184610Salfred 2665184610Salfred if (info->recurse_level >= UAUDIO_RECURSE_LIMIT) { 2666184610Salfred return; 2667184610Salfred } 2668184610Salfred info->recurse_level++; 2669184610Salfred 2670184610Salfred for (n = 0; n < n_id; n++) { 2671184610Salfred 2672184610Salfred i = p_id[n]; 2673184610Salfred 2674184610Salfred if (info->bit_visited[i / 8] & (1 << (i % 8))) { 2675184610Salfred /* don't go into a circle */ 2676184610Salfred DPRINTF("avoided going into a circle at id=%d!\n", i); 2677184610Salfred continue; 2678184610Salfred } else { 2679184610Salfred info->bit_visited[i / 8] |= (1 << (i % 8)); 2680184610Salfred } 2681184610Salfred 2682184610Salfred iot = (root + i); 2683184610Salfred 2684184610Salfred if (iot->u.desc == NULL) { 2685184610Salfred continue; 2686184610Salfred } 2687184610Salfred switch (iot->u.desc->bDescriptorSubtype) { 2688184610Salfred case UDESCSUB_AC_INPUT: 2689184610Salfred info->bit_input[i / 8] |= (1 << (i % 8)); 2690184610Salfred break; 2691184610Salfred 2692184610Salfred case UDESCSUB_AC_FEATURE: 2693184610Salfred uaudio_mixer_find_inputs_sub 2694184610Salfred (root, &iot->u.fu->bSourceId, 1, info); 2695184610Salfred break; 2696184610Salfred 2697184610Salfred case UDESCSUB_AC_OUTPUT: 2698184610Salfred uaudio_mixer_find_inputs_sub 2699184610Salfred (root, &iot->u.ot->bSourceId, 1, info); 2700184610Salfred break; 2701184610Salfred 2702184610Salfred case UDESCSUB_AC_MIXER: 2703184610Salfred uaudio_mixer_find_inputs_sub 2704184610Salfred (root, iot->u.mu->baSourceId, 2705184610Salfred iot->u.mu->bNrInPins, info); 2706184610Salfred break; 2707184610Salfred 2708184610Salfred case UDESCSUB_AC_SELECTOR: 2709184610Salfred uaudio_mixer_find_inputs_sub 2710184610Salfred (root, iot->u.su->baSourceId, 2711184610Salfred iot->u.su->bNrInPins, info); 2712184610Salfred break; 2713184610Salfred 2714184610Salfred case UDESCSUB_AC_PROCESSING: 2715184610Salfred uaudio_mixer_find_inputs_sub 2716184610Salfred (root, iot->u.pu->baSourceId, 2717184610Salfred iot->u.pu->bNrInPins, info); 2718184610Salfred break; 2719184610Salfred 2720184610Salfred case UDESCSUB_AC_EXTENSION: 2721184610Salfred uaudio_mixer_find_inputs_sub 2722184610Salfred (root, iot->u.eu->baSourceId, 2723184610Salfred iot->u.eu->bNrInPins, info); 2724184610Salfred break; 2725184610Salfred 2726184610Salfred case UDESCSUB_AC_HEADER: 2727184610Salfred default: 2728184610Salfred break; 2729184610Salfred } 2730184610Salfred } 2731184610Salfred info->recurse_level--; 2732184610Salfred} 2733184610Salfred 2734184610Salfredstatic void 2735184610Salfreduaudio_mixer_find_outputs_sub(struct uaudio_terminal_node *root, uint8_t id, 2736184610Salfred uint8_t n_id, struct uaudio_search_result *info) 2737184610Salfred{ 2738184610Salfred struct uaudio_terminal_node *iot = (root + id); 2739184610Salfred uint8_t j; 2740184610Salfred 2741184610Salfred j = n_id; 2742184610Salfred do { 2743184610Salfred if ((j != id) && ((root + j)->u.desc) && 2744184610Salfred ((root + j)->u.desc->bDescriptorSubtype == UDESCSUB_AC_OUTPUT)) { 2745184610Salfred 2746184610Salfred /* 2747184610Salfred * "j" (output) <--- virtual wire <--- "id" (input) 2748184610Salfred * 2749184610Salfred * if "j" has "id" on the input, then "id" have "j" on 2750184610Salfred * the output, because they are connected: 2751184610Salfred */ 2752184610Salfred if ((root + j)->usr.bit_input[id / 8] & (1 << (id % 8))) { 2753184610Salfred iot->usr.bit_output[j / 8] |= (1 << (j % 8)); 2754184610Salfred } 2755184610Salfred } 2756184610Salfred } while (j--); 2757184610Salfred} 2758184610Salfred 2759184610Salfredstatic void 2760192984Sthompsauaudio_mixer_fill_info(struct uaudio_softc *sc, struct usb_device *udev, 2761184610Salfred void *desc) 2762184610Salfred{ 2763203678Sbrucec const struct usb_audio_control_descriptor *acdp; 2764194228Sthompsa struct usb_config_descriptor *cd = usbd_get_config_descriptor(udev); 2765192984Sthompsa const struct usb_descriptor *dp; 2766203678Sbrucec const struct usb_audio_unit *au; 2767184610Salfred struct uaudio_terminal_node *iot = NULL; 2768184610Salfred uint16_t wTotalLen; 2769184610Salfred uint8_t ID_max = 0; /* inclusive */ 2770184610Salfred uint8_t i; 2771184610Salfred 2772194228Sthompsa desc = usb_desc_foreach(cd, desc); 2773184610Salfred 2774184610Salfred if (desc == NULL) { 2775184610Salfred DPRINTF("no Audio Control header\n"); 2776184610Salfred goto done; 2777184610Salfred } 2778184610Salfred acdp = desc; 2779184610Salfred 2780184610Salfred if ((acdp->bLength < sizeof(*acdp)) || 2781184610Salfred (acdp->bDescriptorType != UDESC_CS_INTERFACE) || 2782184610Salfred (acdp->bDescriptorSubtype != UDESCSUB_AC_HEADER)) { 2783184610Salfred DPRINTF("invalid Audio Control header\n"); 2784184610Salfred goto done; 2785184610Salfred } 2786186730Salfred /* "wTotalLen" is allowed to be corrupt */ 2787186730Salfred wTotalLen = UGETW(acdp->wTotalLength) - acdp->bLength; 2788186730Salfred 2789186730Salfred /* get USB audio revision */ 2790184610Salfred sc->sc_audio_rev = UGETW(acdp->bcdADC); 2791184610Salfred 2792184610Salfred DPRINTFN(3, "found AC header, vers=%03x, len=%d\n", 2793184610Salfred sc->sc_audio_rev, wTotalLen); 2794184610Salfred 2795184610Salfred if (sc->sc_audio_rev != UAUDIO_VERSION) { 2796184610Salfred 2797184610Salfred if (sc->sc_uq_bad_adc) { 2798184610Salfred 2799184610Salfred } else { 2800184610Salfred DPRINTF("invalid audio version\n"); 2801184610Salfred goto done; 2802184610Salfred } 2803184610Salfred } 2804184610Salfred iot = malloc(sizeof(struct uaudio_terminal_node) * 256, M_TEMP, 2805184610Salfred M_WAITOK | M_ZERO); 2806184610Salfred 2807184610Salfred if (iot == NULL) { 2808184610Salfred DPRINTF("no memory!\n"); 2809184610Salfred goto done; 2810184610Salfred } 2811194228Sthompsa while ((desc = usb_desc_foreach(cd, desc))) { 2812184610Salfred 2813184610Salfred dp = desc; 2814184610Salfred 2815184610Salfred if (dp->bLength > wTotalLen) { 2816184610Salfred break; 2817184610Salfred } else { 2818184610Salfred wTotalLen -= dp->bLength; 2819184610Salfred } 2820184610Salfred 2821184610Salfred au = uaudio_mixer_verify_desc(dp, 0); 2822184610Salfred 2823184610Salfred if (au) { 2824184610Salfred iot[au->bUnitId].u.desc = (const void *)au; 2825184610Salfred if (au->bUnitId > ID_max) { 2826184610Salfred ID_max = au->bUnitId; 2827184610Salfred } 2828184610Salfred } 2829184610Salfred } 2830184610Salfred 2831184610Salfred DPRINTF("Maximum ID=%d\n", ID_max); 2832184610Salfred 2833184610Salfred /* 2834184610Salfred * determine sourcing inputs for 2835184610Salfred * all nodes in the tree: 2836184610Salfred */ 2837184610Salfred i = ID_max; 2838184610Salfred do { 2839184610Salfred uaudio_mixer_find_inputs_sub(iot, &i, 1, &((iot + i)->usr)); 2840184610Salfred } while (i--); 2841184610Salfred 2842184610Salfred /* 2843184610Salfred * determine outputs for 2844184610Salfred * all nodes in the tree: 2845184610Salfred */ 2846184610Salfred i = ID_max; 2847184610Salfred do { 2848184610Salfred uaudio_mixer_find_outputs_sub(iot, i, ID_max, &((iot + i)->usr)); 2849184610Salfred } while (i--); 2850184610Salfred 2851184610Salfred /* set "id_max" and "root" */ 2852184610Salfred 2853184610Salfred i = ID_max; 2854184610Salfred do { 2855184610Salfred (iot + i)->usr.id_max = ID_max; 2856184610Salfred (iot + i)->root = iot; 2857184610Salfred } while (i--); 2858184610Salfred 2859207077Sthompsa#ifdef USB_DEBUG 2860184610Salfred i = ID_max; 2861184610Salfred do { 2862184610Salfred uint8_t j; 2863184610Salfred 2864184610Salfred if (iot[i].u.desc == NULL) { 2865184610Salfred continue; 2866184610Salfred } 2867184610Salfred DPRINTF("id %d:\n", i); 2868184610Salfred 2869184610Salfred switch (iot[i].u.desc->bDescriptorSubtype) { 2870184610Salfred case UDESCSUB_AC_INPUT: 2871184610Salfred DPRINTF(" - AC_INPUT type=%s\n", 2872184610Salfred uaudio_mixer_get_terminal_name 2873184610Salfred (UGETW(iot[i].u.it->wTerminalType))); 2874184610Salfred uaudio_mixer_dump_cluster(i, iot); 2875184610Salfred break; 2876184610Salfred 2877184610Salfred case UDESCSUB_AC_OUTPUT: 2878184610Salfred DPRINTF(" - AC_OUTPUT type=%s " 2879184610Salfred "src=%d\n", uaudio_mixer_get_terminal_name 2880184610Salfred (UGETW(iot[i].u.ot->wTerminalType)), 2881184610Salfred iot[i].u.ot->bSourceId); 2882184610Salfred break; 2883184610Salfred 2884184610Salfred case UDESCSUB_AC_MIXER: 2885184610Salfred DPRINTF(" - AC_MIXER src:\n"); 2886184610Salfred for (j = 0; j < iot[i].u.mu->bNrInPins; j++) { 2887184610Salfred DPRINTF(" - %d\n", iot[i].u.mu->baSourceId[j]); 2888184610Salfred } 2889184610Salfred uaudio_mixer_dump_cluster(i, iot); 2890184610Salfred break; 2891184610Salfred 2892184610Salfred case UDESCSUB_AC_SELECTOR: 2893184610Salfred DPRINTF(" - AC_SELECTOR src:\n"); 2894184610Salfred for (j = 0; j < iot[i].u.su->bNrInPins; j++) { 2895184610Salfred DPRINTF(" - %d\n", iot[i].u.su->baSourceId[j]); 2896184610Salfred } 2897184610Salfred break; 2898184610Salfred 2899184610Salfred case UDESCSUB_AC_FEATURE: 2900184610Salfred DPRINTF(" - AC_FEATURE src=%d\n", iot[i].u.fu->bSourceId); 2901184610Salfred break; 2902184610Salfred 2903184610Salfred case UDESCSUB_AC_PROCESSING: 2904184610Salfred DPRINTF(" - AC_PROCESSING src:\n"); 2905184610Salfred for (j = 0; j < iot[i].u.pu->bNrInPins; j++) { 2906184610Salfred DPRINTF(" - %d\n", iot[i].u.pu->baSourceId[j]); 2907184610Salfred } 2908184610Salfred uaudio_mixer_dump_cluster(i, iot); 2909184610Salfred break; 2910184610Salfred 2911184610Salfred case UDESCSUB_AC_EXTENSION: 2912184610Salfred DPRINTF(" - AC_EXTENSION src:\n"); 2913184610Salfred for (j = 0; j < iot[i].u.eu->bNrInPins; j++) { 2914184610Salfred DPRINTF("%d ", iot[i].u.eu->baSourceId[j]); 2915184610Salfred } 2916184610Salfred uaudio_mixer_dump_cluster(i, iot); 2917184610Salfred break; 2918184610Salfred 2919184610Salfred default: 2920184610Salfred DPRINTF("unknown audio control (subtype=%d)\n", 2921184610Salfred iot[i].u.desc->bDescriptorSubtype); 2922184610Salfred } 2923184610Salfred 2924184610Salfred DPRINTF("Inputs to this ID are:\n"); 2925184610Salfred 2926184610Salfred j = ID_max; 2927184610Salfred do { 2928184610Salfred if (iot[i].usr.bit_input[j / 8] & (1 << (j % 8))) { 2929184610Salfred DPRINTF(" -- ID=%d\n", j); 2930184610Salfred } 2931184610Salfred } while (j--); 2932184610Salfred 2933184610Salfred DPRINTF("Outputs from this ID are:\n"); 2934184610Salfred 2935184610Salfred j = ID_max; 2936184610Salfred do { 2937184610Salfred if (iot[i].usr.bit_output[j / 8] & (1 << (j % 8))) { 2938184610Salfred DPRINTF(" -- ID=%d\n", j); 2939184610Salfred } 2940184610Salfred } while (j--); 2941184610Salfred 2942184610Salfred } while (i--); 2943184610Salfred#endif 2944184610Salfred 2945184610Salfred /* 2946184610Salfred * scan the config to create a linked 2947184610Salfred * list of "mixer" nodes: 2948184610Salfred */ 2949184610Salfred 2950184610Salfred i = ID_max; 2951184610Salfred do { 2952184610Salfred dp = iot[i].u.desc; 2953184610Salfred 2954184610Salfred if (dp == NULL) { 2955184610Salfred continue; 2956184610Salfred } 2957184610Salfred DPRINTFN(11, "id=%d subtype=%d\n", 2958184610Salfred i, dp->bDescriptorSubtype); 2959184610Salfred 2960184610Salfred switch (dp->bDescriptorSubtype) { 2961184610Salfred case UDESCSUB_AC_HEADER: 2962184610Salfred DPRINTF("unexpected AC header\n"); 2963184610Salfred break; 2964184610Salfred 2965184610Salfred case UDESCSUB_AC_INPUT: 2966184610Salfred uaudio_mixer_add_input(sc, iot, i); 2967184610Salfred break; 2968184610Salfred 2969184610Salfred case UDESCSUB_AC_OUTPUT: 2970184610Salfred uaudio_mixer_add_output(sc, iot, i); 2971184610Salfred break; 2972184610Salfred 2973184610Salfred case UDESCSUB_AC_MIXER: 2974184610Salfred uaudio_mixer_add_mixer(sc, iot, i); 2975184610Salfred break; 2976184610Salfred 2977184610Salfred case UDESCSUB_AC_SELECTOR: 2978184610Salfred uaudio_mixer_add_selector(sc, iot, i); 2979184610Salfred break; 2980184610Salfred 2981184610Salfred case UDESCSUB_AC_FEATURE: 2982184610Salfred uaudio_mixer_add_feature(sc, iot, i); 2983184610Salfred break; 2984184610Salfred 2985184610Salfred case UDESCSUB_AC_PROCESSING: 2986184610Salfred uaudio_mixer_add_processing(sc, iot, i); 2987184610Salfred break; 2988184610Salfred 2989184610Salfred case UDESCSUB_AC_EXTENSION: 2990184610Salfred uaudio_mixer_add_extension(sc, iot, i); 2991184610Salfred break; 2992184610Salfred 2993184610Salfred default: 2994184610Salfred DPRINTF("bad AC desc subtype=0x%02x\n", 2995184610Salfred dp->bDescriptorSubtype); 2996184610Salfred break; 2997184610Salfred } 2998184610Salfred 2999184610Salfred } while (i--); 3000184610Salfred 3001184610Salfreddone: 3002184610Salfred if (iot) { 3003184610Salfred free(iot, M_TEMP); 3004184610Salfred } 3005184610Salfred} 3006184610Salfred 3007184610Salfredstatic uint16_t 3008192984Sthompsauaudio_mixer_get(struct usb_device *udev, uint8_t what, 3009184610Salfred struct uaudio_mixer_node *mc) 3010184610Salfred{ 3011192984Sthompsa struct usb_device_request req; 3012184610Salfred uint16_t val; 3013184610Salfred uint16_t len = MIX_SIZE(mc->type); 3014184610Salfred uint8_t data[4]; 3015193045Sthompsa usb_error_t err; 3016184610Salfred 3017184610Salfred if (mc->wValue[0] == -1) { 3018184610Salfred return (0); 3019184610Salfred } 3020184610Salfred req.bmRequestType = UT_READ_CLASS_INTERFACE; 3021184610Salfred req.bRequest = what; 3022184610Salfred USETW(req.wValue, mc->wValue[0]); 3023184610Salfred USETW(req.wIndex, mc->wIndex); 3024184610Salfred USETW(req.wLength, len); 3025184610Salfred 3026196487Salfred err = usbd_do_request(udev, NULL, &req, data); 3027184610Salfred if (err) { 3028194228Sthompsa DPRINTF("err=%s\n", usbd_errstr(err)); 3029184610Salfred return (0); 3030184610Salfred } 3031184610Salfred if (len < 1) { 3032184610Salfred data[0] = 0; 3033184610Salfred } 3034184610Salfred if (len < 2) { 3035184610Salfred data[1] = 0; 3036184610Salfred } 3037184610Salfred val = (data[0] | (data[1] << 8)); 3038184610Salfred 3039184610Salfred DPRINTFN(3, "val=%d\n", val); 3040184610Salfred 3041184610Salfred return (val); 3042184610Salfred} 3043184610Salfred 3044184610Salfredstatic void 3045194677Sthompsauaudio_mixer_write_cfg_callback(struct usb_xfer *xfer, usb_error_t error) 3046184610Salfred{ 3047192984Sthompsa struct usb_device_request req; 3048194677Sthompsa struct uaudio_softc *sc = usbd_xfer_softc(xfer); 3049184610Salfred struct uaudio_mixer_node *mc = sc->sc_mixer_curr; 3050194677Sthompsa struct usb_page_cache *pc; 3051184610Salfred uint16_t len; 3052184610Salfred uint8_t repeat = 1; 3053184610Salfred uint8_t update; 3054184610Salfred uint8_t chan; 3055184610Salfred uint8_t buf[2]; 3056184610Salfred 3057187165Sthompsa DPRINTF("\n"); 3058187165Sthompsa 3059184610Salfred switch (USB_GET_STATE(xfer)) { 3060184610Salfred case USB_ST_TRANSFERRED: 3061184610Salfredtr_transferred: 3062184610Salfred case USB_ST_SETUP: 3063184610Salfredtr_setup: 3064184610Salfred 3065184610Salfred if (mc == NULL) { 3066184610Salfred mc = sc->sc_mixer_root; 3067184610Salfred sc->sc_mixer_curr = mc; 3068184610Salfred sc->sc_mixer_chan = 0; 3069184610Salfred repeat = 0; 3070184610Salfred } 3071184610Salfred while (mc) { 3072184610Salfred while (sc->sc_mixer_chan < mc->nchan) { 3073184610Salfred 3074184610Salfred len = MIX_SIZE(mc->type); 3075184610Salfred 3076184610Salfred chan = sc->sc_mixer_chan; 3077184610Salfred 3078184610Salfred sc->sc_mixer_chan++; 3079184610Salfred 3080184610Salfred update = ((mc->update[chan / 8] & (1 << (chan % 8))) && 3081184610Salfred (mc->wValue[chan] != -1)); 3082184610Salfred 3083184610Salfred mc->update[chan / 8] &= ~(1 << (chan % 8)); 3084184610Salfred 3085184610Salfred if (update) { 3086184610Salfred 3087184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 3088184610Salfred req.bRequest = SET_CUR; 3089184610Salfred USETW(req.wValue, mc->wValue[chan]); 3090184610Salfred USETW(req.wIndex, mc->wIndex); 3091184610Salfred USETW(req.wLength, len); 3092184610Salfred 3093184610Salfred if (len > 0) { 3094184610Salfred buf[0] = (mc->wData[chan] & 0xFF); 3095184610Salfred } 3096184610Salfred if (len > 1) { 3097184610Salfred buf[1] = (mc->wData[chan] >> 8) & 0xFF; 3098184610Salfred } 3099194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 3100194677Sthompsa usbd_copy_in(pc, 0, &req, sizeof(req)); 3101194677Sthompsa pc = usbd_xfer_get_frame(xfer, 1); 3102194677Sthompsa usbd_copy_in(pc, 0, buf, len); 3103184610Salfred 3104194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 3105194677Sthompsa usbd_xfer_set_frame_len(xfer, 1, len); 3106194677Sthompsa usbd_xfer_set_frames(xfer, len ? 2 : 1); 3107194228Sthompsa usbd_transfer_submit(xfer); 3108184610Salfred return; 3109184610Salfred } 3110184610Salfred } 3111184610Salfred 3112184610Salfred mc = mc->next; 3113184610Salfred sc->sc_mixer_curr = mc; 3114184610Salfred sc->sc_mixer_chan = 0; 3115184610Salfred } 3116184610Salfred 3117184610Salfred if (repeat) { 3118184610Salfred goto tr_setup; 3119184610Salfred } 3120187165Sthompsa break; 3121184610Salfred 3122184610Salfred default: /* Error */ 3123194677Sthompsa DPRINTF("error=%s\n", usbd_errstr(error)); 3124194677Sthompsa if (error == USB_ERR_CANCELLED) { 3125187165Sthompsa /* do nothing - we are detaching */ 3126187165Sthompsa break; 3127187165Sthompsa } 3128184610Salfred goto tr_transferred; 3129184610Salfred } 3130184610Salfred} 3131184610Salfred 3132193045Sthompsastatic usb_error_t 3133192984Sthompsauaudio_set_speed(struct usb_device *udev, uint8_t endpt, uint32_t speed) 3134184610Salfred{ 3135192984Sthompsa struct usb_device_request req; 3136184610Salfred uint8_t data[3]; 3137184610Salfred 3138184610Salfred DPRINTFN(6, "endpt=%d speed=%u\n", endpt, speed); 3139184610Salfred 3140184610Salfred req.bmRequestType = UT_WRITE_CLASS_ENDPOINT; 3141184610Salfred req.bRequest = SET_CUR; 3142184610Salfred USETW2(req.wValue, SAMPLING_FREQ_CONTROL, 0); 3143184610Salfred USETW(req.wIndex, endpt); 3144184610Salfred USETW(req.wLength, 3); 3145184610Salfred data[0] = speed; 3146184610Salfred data[1] = speed >> 8; 3147184610Salfred data[2] = speed >> 16; 3148184610Salfred 3149196487Salfred return (usbd_do_request(udev, NULL, &req, data)); 3150184610Salfred} 3151184610Salfred 3152184610Salfredstatic int 3153184610Salfreduaudio_mixer_signext(uint8_t type, int val) 3154184610Salfred{ 3155184610Salfred if (!MIX_UNSIGNED(type)) { 3156184610Salfred if (MIX_SIZE(type) == 2) { 3157184610Salfred val = (int16_t)val; 3158184610Salfred } else { 3159184610Salfred val = (int8_t)val; 3160184610Salfred } 3161184610Salfred } 3162184610Salfred return (val); 3163184610Salfred} 3164184610Salfred 3165184610Salfredstatic int 3166184610Salfreduaudio_mixer_bsd2value(struct uaudio_mixer_node *mc, int32_t val) 3167184610Salfred{ 3168184610Salfred if (mc->type == MIX_ON_OFF) { 3169184610Salfred val = (val != 0); 3170184610Salfred } else if (mc->type == MIX_SELECTOR) { 3171184610Salfred if ((val < mc->minval) || 3172184610Salfred (val > mc->maxval)) { 3173184610Salfred val = mc->minval; 3174184610Salfred } 3175184610Salfred } else { 3176199060Sthompsa 3177199060Sthompsa /* compute actual volume */ 3178199060Sthompsa val = (val * mc->mul) / 255; 3179199060Sthompsa 3180199060Sthompsa /* add lower offset */ 3181199060Sthompsa val = val + mc->minval; 3182199060Sthompsa 3183199060Sthompsa /* make sure we don't write a value out of range */ 3184199060Sthompsa if (val > mc->maxval) 3185199060Sthompsa val = mc->maxval; 3186199060Sthompsa else if (val < mc->minval) 3187199060Sthompsa val = mc->minval; 3188184610Salfred } 3189184610Salfred 3190185087Salfred DPRINTFN(6, "type=0x%03x val=%d min=%d max=%d val=%d\n", 3191185087Salfred mc->type, val, mc->minval, mc->maxval, val); 3192184610Salfred return (val); 3193184610Salfred} 3194184610Salfred 3195184610Salfredstatic void 3196184610Salfreduaudio_mixer_ctl_set(struct uaudio_softc *sc, struct uaudio_mixer_node *mc, 3197184610Salfred uint8_t chan, int32_t val) 3198184610Salfred{ 3199184610Salfred val = uaudio_mixer_bsd2value(mc, val); 3200184610Salfred 3201184610Salfred mc->update[chan / 8] |= (1 << (chan % 8)); 3202184610Salfred mc->wData[chan] = val; 3203184610Salfred 3204184610Salfred /* start the transfer, if not already started */ 3205184610Salfred 3206194228Sthompsa usbd_transfer_start(sc->sc_mixer_xfer[0]); 3207184610Salfred} 3208184610Salfred 3209184610Salfredstatic void 3210184610Salfreduaudio_mixer_init(struct uaudio_softc *sc) 3211184610Salfred{ 3212184610Salfred struct uaudio_mixer_node *mc; 3213184610Salfred int32_t i; 3214184610Salfred 3215184610Salfred for (mc = sc->sc_mixer_root; mc; 3216184610Salfred mc = mc->next) { 3217184610Salfred 3218184610Salfred if (mc->ctl != SOUND_MIXER_NRDEVICES) { 3219184610Salfred /* 3220184610Salfred * Set device mask bits. See 3221184610Salfred * /usr/include/machine/soundcard.h 3222184610Salfred */ 3223184610Salfred sc->sc_mix_info |= (1 << mc->ctl); 3224184610Salfred } 3225184610Salfred if ((mc->ctl == SOUND_MIXER_NRDEVICES) && 3226184610Salfred (mc->type == MIX_SELECTOR)) { 3227184610Salfred 3228184610Salfred for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { 3229184610Salfred if (mc->slctrtype[i - 1] == SOUND_MIXER_NRDEVICES) { 3230184610Salfred continue; 3231184610Salfred } 3232184610Salfred sc->sc_recsrc_info |= 1 << mc->slctrtype[i - 1]; 3233184610Salfred } 3234184610Salfred } 3235184610Salfred } 3236184610Salfred} 3237184610Salfred 3238184610Salfredint 3239184610Salfreduaudio_mixer_init_sub(struct uaudio_softc *sc, struct snd_mixer *m) 3240184610Salfred{ 3241184610Salfred DPRINTF("\n"); 3242184610Salfred 3243194228Sthompsa if (usbd_transfer_setup(sc->sc_udev, &sc->sc_mixer_iface_index, 3244184610Salfred sc->sc_mixer_xfer, uaudio_mixer_config, 1, sc, 3245184610Salfred mixer_get_lock(m))) { 3246184610Salfred DPRINTFN(0, "could not allocate USB " 3247184610Salfred "transfer for audio mixer!\n"); 3248184610Salfred return (ENOMEM); 3249184610Salfred } 3250184610Salfred if (!(sc->sc_mix_info & SOUND_MASK_VOLUME)) { 3251184610Salfred mix_setparentchild(m, SOUND_MIXER_VOLUME, SOUND_MASK_PCM); 3252184610Salfred mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE); 3253184610Salfred } 3254184610Salfred mix_setdevs(m, sc->sc_mix_info); 3255184610Salfred mix_setrecdevs(m, sc->sc_recsrc_info); 3256184610Salfred return (0); 3257184610Salfred} 3258184610Salfred 3259184610Salfredint 3260184610Salfreduaudio_mixer_uninit_sub(struct uaudio_softc *sc) 3261184610Salfred{ 3262184610Salfred DPRINTF("\n"); 3263184610Salfred 3264194228Sthompsa usbd_transfer_unsetup(sc->sc_mixer_xfer, 1); 3265184610Salfred 3266184610Salfred return (0); 3267184610Salfred} 3268184610Salfred 3269184610Salfredvoid 3270184610Salfreduaudio_mixer_set(struct uaudio_softc *sc, unsigned type, 3271184610Salfred unsigned left, unsigned right) 3272184610Salfred{ 3273184610Salfred struct uaudio_mixer_node *mc; 3274184610Salfred 3275184610Salfred for (mc = sc->sc_mixer_root; mc; 3276184610Salfred mc = mc->next) { 3277184610Salfred 3278184610Salfred if (mc->ctl == type) { 3279184610Salfred if (mc->nchan == 2) { 3280184610Salfred /* set Right */ 3281184610Salfred uaudio_mixer_ctl_set(sc, mc, 1, (int)(right * 255) / 100); 3282184610Salfred } 3283184610Salfred /* set Left or Mono */ 3284184610Salfred uaudio_mixer_ctl_set(sc, mc, 0, (int)(left * 255) / 100); 3285184610Salfred } 3286184610Salfred } 3287184610Salfred} 3288184610Salfred 3289184610Salfreduint32_t 3290184610Salfreduaudio_mixer_setrecsrc(struct uaudio_softc *sc, uint32_t src) 3291184610Salfred{ 3292184610Salfred struct uaudio_mixer_node *mc; 3293184610Salfred uint32_t mask; 3294184610Salfred uint32_t temp; 3295184610Salfred int32_t i; 3296184610Salfred 3297184610Salfred for (mc = sc->sc_mixer_root; mc; 3298184610Salfred mc = mc->next) { 3299184610Salfred 3300184610Salfred if ((mc->ctl == SOUND_MIXER_NRDEVICES) && 3301184610Salfred (mc->type == MIX_SELECTOR)) { 3302184610Salfred 3303184610Salfred /* compute selector mask */ 3304184610Salfred 3305184610Salfred mask = 0; 3306184610Salfred for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { 3307184610Salfred mask |= (1 << mc->slctrtype[i - 1]); 3308184610Salfred } 3309184610Salfred 3310184610Salfred temp = mask & src; 3311184610Salfred if (temp == 0) { 3312184610Salfred continue; 3313184610Salfred } 3314184610Salfred /* find the first set bit */ 3315184610Salfred temp = (-temp) & temp; 3316184610Salfred 3317184610Salfred /* update "src" */ 3318184610Salfred src &= ~mask; 3319184610Salfred src |= temp; 3320184610Salfred 3321184610Salfred for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { 3322184610Salfred if (temp != (1 << mc->slctrtype[i - 1])) { 3323184610Salfred continue; 3324184610Salfred } 3325184610Salfred uaudio_mixer_ctl_set(sc, mc, 0, i); 3326184610Salfred break; 3327184610Salfred } 3328184610Salfred } 3329184610Salfred } 3330184610Salfred return (src); 3331184610Salfred} 3332184610Salfred 3333184610Salfred/*========================================================================* 3334184610Salfred * MIDI support routines 3335184610Salfred *========================================================================*/ 3336184610Salfred 3337184610Salfredstatic void 3338194677Sthompsaumidi_read_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error) 3339184610Salfred{ 3340194677Sthompsa struct umidi_chan *chan = usbd_xfer_softc(xfer); 3341192984Sthompsa struct usb_xfer *xfer_other = chan->xfer[1]; 3342184610Salfred 3343194228Sthompsa if (usbd_clear_stall_callback(xfer, xfer_other)) { 3344184610Salfred DPRINTF("stall cleared\n"); 3345184610Salfred chan->flags &= ~UMIDI_FLAG_READ_STALL; 3346194228Sthompsa usbd_transfer_start(xfer_other); 3347184610Salfred } 3348184610Salfred} 3349184610Salfred 3350184610Salfredstatic void 3351194677Sthompsaumidi_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 3352184610Salfred{ 3353194677Sthompsa struct umidi_chan *chan = usbd_xfer_softc(xfer); 3354184610Salfred struct umidi_sub_chan *sub; 3355194677Sthompsa struct usb_page_cache *pc; 3356184610Salfred uint8_t buf[1]; 3357184610Salfred uint8_t cmd_len; 3358184610Salfred uint8_t cn; 3359184610Salfred uint16_t pos; 3360194677Sthompsa int actlen; 3361184610Salfred 3362194677Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 3363194677Sthompsa 3364184610Salfred switch (USB_GET_STATE(xfer)) { 3365184610Salfred case USB_ST_TRANSFERRED: 3366184610Salfred 3367194677Sthompsa DPRINTF("actlen=%d bytes\n", actlen); 3368184610Salfred 3369184610Salfred pos = 0; 3370194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 3371184610Salfred 3372194677Sthompsa while (actlen >= 4) { 3373184610Salfred 3374194677Sthompsa usbd_copy_out(pc, pos, buf, 1); 3375184610Salfred 3376184610Salfred cmd_len = umidi_cmd_to_len[buf[0] & 0xF]; /* command length */ 3377184610Salfred cn = buf[0] >> 4; /* cable number */ 3378184610Salfred sub = &chan->sub[cn]; 3379184610Salfred 3380184610Salfred if (cmd_len && (cn < chan->max_cable) && sub->read_open) { 3381194677Sthompsa usb_fifo_put_data(sub->fifo.fp[USB_FIFO_RX], pc, 3382184610Salfred pos + 1, cmd_len, 1); 3383184610Salfred } else { 3384184610Salfred /* ignore the command */ 3385184610Salfred } 3386184610Salfred 3387194677Sthompsa actlen -= 4; 3388184610Salfred pos += 4; 3389184610Salfred } 3390184610Salfred 3391184610Salfred case USB_ST_SETUP: 3392184610Salfred DPRINTF("start\n"); 3393184610Salfred 3394184610Salfred if (chan->flags & UMIDI_FLAG_READ_STALL) { 3395194228Sthompsa usbd_transfer_start(chan->xfer[3]); 3396184610Salfred return; 3397184610Salfred } 3398194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 3399194228Sthompsa usbd_transfer_submit(xfer); 3400184610Salfred return; 3401184610Salfred 3402184610Salfred default: 3403194677Sthompsa DPRINTF("error=%s\n", usbd_errstr(error)); 3404184610Salfred 3405194677Sthompsa if (error != USB_ERR_CANCELLED) { 3406184610Salfred /* try to clear stall first */ 3407184610Salfred chan->flags |= UMIDI_FLAG_READ_STALL; 3408194228Sthompsa usbd_transfer_start(chan->xfer[3]); 3409184610Salfred } 3410184610Salfred return; 3411184610Salfred 3412184610Salfred } 3413184610Salfred} 3414184610Salfred 3415184610Salfredstatic void 3416194677Sthompsaumidi_write_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error) 3417184610Salfred{ 3418194677Sthompsa struct umidi_chan *chan = usbd_xfer_softc(xfer); 3419192984Sthompsa struct usb_xfer *xfer_other = chan->xfer[0]; 3420184610Salfred 3421194228Sthompsa if (usbd_clear_stall_callback(xfer, xfer_other)) { 3422184610Salfred DPRINTF("stall cleared\n"); 3423184610Salfred chan->flags &= ~UMIDI_FLAG_WRITE_STALL; 3424194228Sthompsa usbd_transfer_start(xfer_other); 3425184610Salfred } 3426184610Salfred} 3427184610Salfred 3428184610Salfred/* 3429184610Salfred * The following statemachine, that converts MIDI commands to 3430184610Salfred * USB MIDI packets, derives from Linux's usbmidi.c, which 3431184610Salfred * was written by "Clemens Ladisch": 3432184610Salfred * 3433184610Salfred * Returns: 3434184610Salfred * 0: No command 3435184610Salfred * Else: Command is complete 3436184610Salfred */ 3437184610Salfredstatic uint8_t 3438184610Salfredumidi_convert_to_usb(struct umidi_sub_chan *sub, uint8_t cn, uint8_t b) 3439184610Salfred{ 3440184610Salfred uint8_t p0 = (cn << 4); 3441184610Salfred 3442184610Salfred if (b >= 0xf8) { 3443184610Salfred sub->temp_0[0] = p0 | 0x0f; 3444184610Salfred sub->temp_0[1] = b; 3445184610Salfred sub->temp_0[2] = 0; 3446184610Salfred sub->temp_0[3] = 0; 3447184610Salfred sub->temp_cmd = sub->temp_0; 3448184610Salfred return (1); 3449184610Salfred 3450184610Salfred } else if (b >= 0xf0) { 3451184610Salfred switch (b) { 3452184610Salfred case 0xf0: /* system exclusive begin */ 3453184610Salfred sub->temp_1[1] = b; 3454184610Salfred sub->state = UMIDI_ST_SYSEX_1; 3455184610Salfred break; 3456184610Salfred case 0xf1: /* MIDI time code */ 3457184610Salfred case 0xf3: /* song select */ 3458184610Salfred sub->temp_1[1] = b; 3459184610Salfred sub->state = UMIDI_ST_1PARAM; 3460184610Salfred break; 3461184610Salfred case 0xf2: /* song position pointer */ 3462184610Salfred sub->temp_1[1] = b; 3463184610Salfred sub->state = UMIDI_ST_2PARAM_1; 3464184610Salfred break; 3465184610Salfred case 0xf4: /* unknown */ 3466184610Salfred case 0xf5: /* unknown */ 3467184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3468184610Salfred break; 3469184610Salfred case 0xf6: /* tune request */ 3470184610Salfred sub->temp_1[0] = p0 | 0x05; 3471184610Salfred sub->temp_1[1] = 0xf6; 3472184610Salfred sub->temp_1[2] = 0; 3473184610Salfred sub->temp_1[3] = 0; 3474184610Salfred sub->temp_cmd = sub->temp_1; 3475184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3476184610Salfred return (1); 3477184610Salfred 3478184610Salfred case 0xf7: /* system exclusive end */ 3479184610Salfred switch (sub->state) { 3480184610Salfred case UMIDI_ST_SYSEX_0: 3481184610Salfred sub->temp_1[0] = p0 | 0x05; 3482184610Salfred sub->temp_1[1] = 0xf7; 3483184610Salfred sub->temp_1[2] = 0; 3484184610Salfred sub->temp_1[3] = 0; 3485184610Salfred sub->temp_cmd = sub->temp_1; 3486184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3487184610Salfred return (1); 3488184610Salfred case UMIDI_ST_SYSEX_1: 3489184610Salfred sub->temp_1[0] = p0 | 0x06; 3490184610Salfred sub->temp_1[2] = 0xf7; 3491184610Salfred sub->temp_1[3] = 0; 3492184610Salfred sub->temp_cmd = sub->temp_1; 3493184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3494184610Salfred return (1); 3495184610Salfred case UMIDI_ST_SYSEX_2: 3496184610Salfred sub->temp_1[0] = p0 | 0x07; 3497184610Salfred sub->temp_1[3] = 0xf7; 3498184610Salfred sub->temp_cmd = sub->temp_1; 3499184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3500184610Salfred return (1); 3501184610Salfred } 3502184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3503184610Salfred break; 3504184610Salfred } 3505184610Salfred } else if (b >= 0x80) { 3506184610Salfred sub->temp_1[1] = b; 3507184610Salfred if ((b >= 0xc0) && (b <= 0xdf)) { 3508184610Salfred sub->state = UMIDI_ST_1PARAM; 3509184610Salfred } else { 3510184610Salfred sub->state = UMIDI_ST_2PARAM_1; 3511184610Salfred } 3512184610Salfred } else { /* b < 0x80 */ 3513184610Salfred switch (sub->state) { 3514184610Salfred case UMIDI_ST_1PARAM: 3515184610Salfred if (sub->temp_1[1] < 0xf0) { 3516184610Salfred p0 |= sub->temp_1[1] >> 4; 3517184610Salfred } else { 3518184610Salfred p0 |= 0x02; 3519184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3520184610Salfred } 3521184610Salfred sub->temp_1[0] = p0; 3522184610Salfred sub->temp_1[2] = b; 3523184610Salfred sub->temp_1[3] = 0; 3524184610Salfred sub->temp_cmd = sub->temp_1; 3525184610Salfred return (1); 3526184610Salfred case UMIDI_ST_2PARAM_1: 3527184610Salfred sub->temp_1[2] = b; 3528184610Salfred sub->state = UMIDI_ST_2PARAM_2; 3529184610Salfred break; 3530184610Salfred case UMIDI_ST_2PARAM_2: 3531184610Salfred if (sub->temp_1[1] < 0xf0) { 3532184610Salfred p0 |= sub->temp_1[1] >> 4; 3533184610Salfred sub->state = UMIDI_ST_2PARAM_1; 3534184610Salfred } else { 3535184610Salfred p0 |= 0x03; 3536184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3537184610Salfred } 3538184610Salfred sub->temp_1[0] = p0; 3539184610Salfred sub->temp_1[3] = b; 3540184610Salfred sub->temp_cmd = sub->temp_1; 3541184610Salfred return (1); 3542184610Salfred case UMIDI_ST_SYSEX_0: 3543184610Salfred sub->temp_1[1] = b; 3544184610Salfred sub->state = UMIDI_ST_SYSEX_1; 3545184610Salfred break; 3546184610Salfred case UMIDI_ST_SYSEX_1: 3547184610Salfred sub->temp_1[2] = b; 3548184610Salfred sub->state = UMIDI_ST_SYSEX_2; 3549184610Salfred break; 3550184610Salfred case UMIDI_ST_SYSEX_2: 3551184610Salfred sub->temp_1[0] = p0 | 0x04; 3552184610Salfred sub->temp_1[3] = b; 3553184610Salfred sub->temp_cmd = sub->temp_1; 3554184610Salfred sub->state = UMIDI_ST_SYSEX_0; 3555184610Salfred return (1); 3556184610Salfred } 3557184610Salfred } 3558184610Salfred return (0); 3559184610Salfred} 3560184610Salfred 3561184610Salfredstatic void 3562194677Sthompsaumidi_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 3563184610Salfred{ 3564194677Sthompsa struct umidi_chan *chan = usbd_xfer_softc(xfer); 3565184610Salfred struct umidi_sub_chan *sub; 3566194677Sthompsa struct usb_page_cache *pc; 3567184610Salfred uint32_t actlen; 3568184610Salfred uint16_t total_length; 3569184610Salfred uint8_t buf; 3570184610Salfred uint8_t start_cable; 3571184610Salfred uint8_t tr_any; 3572194677Sthompsa int len; 3573184610Salfred 3574194677Sthompsa usbd_xfer_status(xfer, &len, NULL, NULL, NULL); 3575194677Sthompsa 3576184610Salfred switch (USB_GET_STATE(xfer)) { 3577184610Salfred case USB_ST_TRANSFERRED: 3578194677Sthompsa DPRINTF("actlen=%d bytes\n", len); 3579184610Salfred 3580184610Salfred case USB_ST_SETUP: 3581184610Salfred 3582184610Salfred DPRINTF("start\n"); 3583184610Salfred 3584184610Salfred if (chan->flags & UMIDI_FLAG_WRITE_STALL) { 3585194228Sthompsa usbd_transfer_start(chan->xfer[2]); 3586184610Salfred return; 3587184610Salfred } 3588184610Salfred total_length = 0; /* reset */ 3589184610Salfred start_cable = chan->curr_cable; 3590184610Salfred tr_any = 0; 3591194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 3592184610Salfred 3593184610Salfred while (1) { 3594184610Salfred 3595184610Salfred /* round robin de-queueing */ 3596184610Salfred 3597184610Salfred sub = &chan->sub[chan->curr_cable]; 3598184610Salfred 3599184610Salfred if (sub->write_open) { 3600194228Sthompsa usb_fifo_get_data(sub->fifo.fp[USB_FIFO_TX], 3601194677Sthompsa pc, total_length, 1, &actlen, 0); 3602184610Salfred } else { 3603184610Salfred actlen = 0; 3604184610Salfred } 3605184610Salfred 3606184610Salfred if (actlen) { 3607194677Sthompsa usbd_copy_out(pc, total_length, &buf, 1); 3608184610Salfred 3609184610Salfred tr_any = 1; 3610184610Salfred 3611184610Salfred DPRINTF("byte=0x%02x\n", buf); 3612184610Salfred 3613184610Salfred if (umidi_convert_to_usb(sub, chan->curr_cable, buf)) { 3614184610Salfred 3615184610Salfred DPRINTF("sub= %02x %02x %02x %02x\n", 3616184610Salfred sub->temp_cmd[0], sub->temp_cmd[1], 3617184610Salfred sub->temp_cmd[2], sub->temp_cmd[3]); 3618184610Salfred 3619194677Sthompsa usbd_copy_in(pc, total_length, 3620184610Salfred sub->temp_cmd, 4); 3621184610Salfred 3622184610Salfred total_length += 4; 3623184610Salfred 3624184610Salfred if (total_length >= UMIDI_BULK_SIZE) { 3625184610Salfred break; 3626184610Salfred } 3627184610Salfred } else { 3628184610Salfred continue; 3629184610Salfred } 3630184610Salfred } 3631184610Salfred chan->curr_cable++; 3632184610Salfred if (chan->curr_cable >= chan->max_cable) { 3633184610Salfred chan->curr_cable = 0; 3634184610Salfred } 3635184610Salfred if (chan->curr_cable == start_cable) { 3636184610Salfred if (tr_any == 0) { 3637184610Salfred break; 3638184610Salfred } 3639184610Salfred tr_any = 0; 3640184610Salfred } 3641184610Salfred } 3642184610Salfred 3643184610Salfred if (total_length) { 3644194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, total_length); 3645194228Sthompsa usbd_transfer_submit(xfer); 3646184610Salfred } 3647184610Salfred return; 3648184610Salfred 3649184610Salfred default: /* Error */ 3650184610Salfred 3651194677Sthompsa DPRINTF("error=%s\n", usbd_errstr(error)); 3652184610Salfred 3653194677Sthompsa if (error != USB_ERR_CANCELLED) { 3654184610Salfred /* try to clear stall first */ 3655184610Salfred chan->flags |= UMIDI_FLAG_WRITE_STALL; 3656194228Sthompsa usbd_transfer_start(chan->xfer[2]); 3657184610Salfred } 3658184610Salfred return; 3659184610Salfred 3660184610Salfred } 3661184610Salfred} 3662184610Salfred 3663184610Salfredstatic struct umidi_sub_chan * 3664192984Sthompsaumidi_sub_by_fifo(struct usb_fifo *fifo) 3665184610Salfred{ 3666194677Sthompsa struct umidi_chan *chan = usb_fifo_softc(fifo); 3667184610Salfred struct umidi_sub_chan *sub; 3668184610Salfred uint32_t n; 3669184610Salfred 3670184610Salfred for (n = 0; n < UMIDI_CABLES_MAX; n++) { 3671184610Salfred sub = &chan->sub[n]; 3672184610Salfred if ((sub->fifo.fp[USB_FIFO_RX] == fifo) || 3673184610Salfred (sub->fifo.fp[USB_FIFO_TX] == fifo)) { 3674184610Salfred return (sub); 3675184610Salfred } 3676184610Salfred } 3677184610Salfred 3678192984Sthompsa panic("%s:%d cannot find usb_fifo!\n", 3679184610Salfred __FILE__, __LINE__); 3680184610Salfred 3681184610Salfred return (NULL); 3682184610Salfred} 3683184610Salfred 3684184610Salfredstatic void 3685192984Sthompsaumidi_start_read(struct usb_fifo *fifo) 3686184610Salfred{ 3687194677Sthompsa struct umidi_chan *chan = usb_fifo_softc(fifo); 3688184610Salfred 3689194228Sthompsa usbd_transfer_start(chan->xfer[1]); 3690184610Salfred} 3691184610Salfred 3692184610Salfredstatic void 3693192984Sthompsaumidi_stop_read(struct usb_fifo *fifo) 3694184610Salfred{ 3695194677Sthompsa struct umidi_chan *chan = usb_fifo_softc(fifo); 3696184610Salfred struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo); 3697184610Salfred 3698184610Salfred DPRINTF("\n"); 3699184610Salfred 3700184610Salfred sub->read_open = 0; 3701184610Salfred 3702184610Salfred if (--(chan->read_open_refcount) == 0) { 3703184610Salfred /* 3704184610Salfred * XXX don't stop the read transfer here, hence that causes 3705184610Salfred * problems with some MIDI adapters 3706184610Salfred */ 3707184610Salfred DPRINTF("(stopping read transfer)\n"); 3708184610Salfred } 3709184610Salfred} 3710184610Salfred 3711184610Salfredstatic void 3712192984Sthompsaumidi_start_write(struct usb_fifo *fifo) 3713184610Salfred{ 3714194677Sthompsa struct umidi_chan *chan = usb_fifo_softc(fifo); 3715184610Salfred 3716194228Sthompsa usbd_transfer_start(chan->xfer[0]); 3717184610Salfred} 3718184610Salfred 3719184610Salfredstatic void 3720192984Sthompsaumidi_stop_write(struct usb_fifo *fifo) 3721184610Salfred{ 3722194677Sthompsa struct umidi_chan *chan = usb_fifo_softc(fifo); 3723184610Salfred struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo); 3724184610Salfred 3725184610Salfred DPRINTF("\n"); 3726184610Salfred 3727184610Salfred sub->write_open = 0; 3728184610Salfred 3729184610Salfred if (--(chan->write_open_refcount) == 0) { 3730184610Salfred DPRINTF("(stopping write transfer)\n"); 3731194228Sthompsa usbd_transfer_stop(chan->xfer[2]); 3732194228Sthompsa usbd_transfer_stop(chan->xfer[0]); 3733184610Salfred } 3734184610Salfred} 3735184610Salfred 3736184610Salfredstatic int 3737192984Sthompsaumidi_open(struct usb_fifo *fifo, int fflags) 3738184610Salfred{ 3739194677Sthompsa struct umidi_chan *chan = usb_fifo_softc(fifo); 3740184610Salfred struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo); 3741184610Salfred 3742184610Salfred if (fflags & FREAD) { 3743194228Sthompsa if (usb_fifo_alloc_buffer(fifo, 4, (1024 / 4))) { 3744184610Salfred return (ENOMEM); 3745184610Salfred } 3746195120Sthompsa mtx_lock(&chan->mtx); 3747184610Salfred chan->read_open_refcount++; 3748184610Salfred sub->read_open = 1; 3749195120Sthompsa mtx_unlock(&chan->mtx); 3750184610Salfred } 3751184610Salfred if (fflags & FWRITE) { 3752194228Sthompsa if (usb_fifo_alloc_buffer(fifo, 32, (1024 / 32))) { 3753184610Salfred return (ENOMEM); 3754184610Salfred } 3755184610Salfred /* clear stall first */ 3756195120Sthompsa mtx_lock(&chan->mtx); 3757184610Salfred chan->flags |= UMIDI_FLAG_WRITE_STALL; 3758184610Salfred chan->write_open_refcount++; 3759184610Salfred sub->write_open = 1; 3760184610Salfred 3761184610Salfred /* reset */ 3762184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3763195120Sthompsa mtx_unlock(&chan->mtx); 3764184610Salfred } 3765184610Salfred return (0); /* success */ 3766184610Salfred} 3767184610Salfred 3768184610Salfredstatic void 3769192984Sthompsaumidi_close(struct usb_fifo *fifo, int fflags) 3770184610Salfred{ 3771184610Salfred if (fflags & FREAD) { 3772194228Sthompsa usb_fifo_free_buffer(fifo); 3773184610Salfred } 3774184610Salfred if (fflags & FWRITE) { 3775194228Sthompsa usb_fifo_free_buffer(fifo); 3776184610Salfred } 3777184610Salfred} 3778184610Salfred 3779184610Salfred 3780184610Salfredstatic int 3781192984Sthompsaumidi_ioctl(struct usb_fifo *fifo, u_long cmd, void *data, 3782189110Sthompsa int fflags) 3783184610Salfred{ 3784184610Salfred return (ENODEV); 3785184610Salfred} 3786184610Salfred 3787184610Salfredstatic void 3788184610Salfredumidi_init(device_t dev) 3789184610Salfred{ 3790184610Salfred struct uaudio_softc *sc = device_get_softc(dev); 3791184610Salfred struct umidi_chan *chan = &sc->sc_midi_chan; 3792184610Salfred 3793184610Salfred mtx_init(&chan->mtx, "umidi lock", NULL, MTX_DEF | MTX_RECURSE); 3794184610Salfred} 3795184610Salfred 3796192984Sthompsastatic struct usb_fifo_methods umidi_fifo_methods = { 3797184610Salfred .f_start_read = &umidi_start_read, 3798184610Salfred .f_start_write = &umidi_start_write, 3799184610Salfred .f_stop_read = &umidi_stop_read, 3800184610Salfred .f_stop_write = &umidi_stop_write, 3801184610Salfred .f_open = &umidi_open, 3802184610Salfred .f_close = &umidi_close, 3803184610Salfred .f_ioctl = &umidi_ioctl, 3804184610Salfred .basename[0] = "umidi", 3805184610Salfred}; 3806184610Salfred 3807184610Salfredstatic int32_t 3808184610Salfredumidi_probe(device_t dev) 3809184610Salfred{ 3810184610Salfred struct uaudio_softc *sc = device_get_softc(dev); 3811192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 3812184610Salfred struct umidi_chan *chan = &sc->sc_midi_chan; 3813184610Salfred struct umidi_sub_chan *sub; 3814184610Salfred int unit = device_get_unit(dev); 3815184610Salfred int error; 3816184610Salfred uint32_t n; 3817184610Salfred 3818194228Sthompsa if (usbd_set_alt_interface_index(sc->sc_udev, chan->iface_index, 3819184610Salfred chan->iface_alt_index)) { 3820184610Salfred DPRINTF("setting of alternate index failed!\n"); 3821184610Salfred goto detach; 3822184610Salfred } 3823194228Sthompsa usbd_set_parent_iface(sc->sc_udev, chan->iface_index, sc->sc_mixer_iface_index); 3824184610Salfred 3825194228Sthompsa error = usbd_transfer_setup(uaa->device, &chan->iface_index, 3826184610Salfred chan->xfer, umidi_config, UMIDI_N_TRANSFER, 3827184610Salfred chan, &chan->mtx); 3828184610Salfred if (error) { 3829194228Sthompsa DPRINTF("error=%s\n", usbd_errstr(error)); 3830184610Salfred goto detach; 3831184610Salfred } 3832184610Salfred if ((chan->max_cable > UMIDI_CABLES_MAX) || 3833184610Salfred (chan->max_cable == 0)) { 3834184610Salfred chan->max_cable = UMIDI_CABLES_MAX; 3835184610Salfred } 3836184610Salfred 3837184610Salfred for (n = 0; n < chan->max_cable; n++) { 3838184610Salfred 3839184610Salfred sub = &chan->sub[n]; 3840184610Salfred 3841194228Sthompsa error = usb_fifo_attach(sc->sc_udev, chan, &chan->mtx, 3842184610Salfred &umidi_fifo_methods, &sub->fifo, unit, n, 3843189110Sthompsa chan->iface_index, 3844189110Sthompsa UID_ROOT, GID_OPERATOR, 0644); 3845184610Salfred if (error) { 3846184610Salfred goto detach; 3847184610Salfred } 3848184610Salfred } 3849184610Salfred 3850184610Salfred mtx_lock(&chan->mtx); 3851184610Salfred 3852184610Salfred /* clear stall first */ 3853184610Salfred chan->flags |= UMIDI_FLAG_READ_STALL; 3854184610Salfred 3855184610Salfred /* 3856184610Salfred * NOTE: at least one device will not work properly unless 3857184610Salfred * the BULK pipe is open all the time. 3858184610Salfred */ 3859194228Sthompsa usbd_transfer_start(chan->xfer[1]); 3860184610Salfred 3861184610Salfred mtx_unlock(&chan->mtx); 3862184610Salfred 3863184610Salfred return (0); /* success */ 3864184610Salfred 3865184610Salfreddetach: 3866184610Salfred return (ENXIO); /* failure */ 3867184610Salfred} 3868184610Salfred 3869184610Salfredstatic int32_t 3870184610Salfredumidi_detach(device_t dev) 3871184610Salfred{ 3872184610Salfred struct uaudio_softc *sc = device_get_softc(dev); 3873184610Salfred struct umidi_chan *chan = &sc->sc_midi_chan; 3874184610Salfred uint32_t n; 3875184610Salfred 3876184610Salfred for (n = 0; n < UMIDI_CABLES_MAX; n++) { 3877194228Sthompsa usb_fifo_detach(&chan->sub[n].fifo); 3878184610Salfred } 3879184610Salfred 3880184610Salfred mtx_lock(&chan->mtx); 3881184610Salfred 3882194228Sthompsa usbd_transfer_stop(chan->xfer[3]); 3883194228Sthompsa usbd_transfer_stop(chan->xfer[1]); 3884184610Salfred 3885184610Salfred mtx_unlock(&chan->mtx); 3886184610Salfred 3887194228Sthompsa usbd_transfer_unsetup(chan->xfer, UMIDI_N_TRANSFER); 3888184610Salfred 3889184610Salfred mtx_destroy(&chan->mtx); 3890184610Salfred 3891184610Salfred return (0); 3892184610Salfred} 3893184610Salfred 3894189275SthompsaDRIVER_MODULE(uaudio, uhub, uaudio_driver, uaudio_devclass, NULL, 0); 3895188942SthompsaMODULE_DEPEND(uaudio, usb, 1, 1, 1); 3896184610SalfredMODULE_DEPEND(uaudio, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 3897184610SalfredMODULE_VERSION(uaudio, 1); 3898