uaudio.c revision 209452
1184610Salfred/* $NetBSD: uaudio.c,v 1.91 2004/11/05 17:46:14 kent Exp $ */ 2184610Salfred/* $FreeBSD: head/sys/dev/sound/usb/uaudio.c 209452 2010-06-22 21:16:18Z 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, 795209452Sthompsa UEP_HAS_REFRESH(ed) ? ed->bRefresh : 0, 796209452Sthompsa UEP_HAS_SYNCADDR(ed) ? ed->bSynchAddress : 0); 797184610Salfred } 798184610Salfred} 799184610Salfred 800184610Salfred#endif 801184610Salfred 802184610Salfredstatic void 803192984Sthompsauaudio_chan_fill_info_sub(struct uaudio_softc *sc, struct usb_device *udev, 804200825Sthompsa uint32_t rate, uint8_t channels, uint8_t bit_resolution) 805184610Salfred{ 806192984Sthompsa struct usb_descriptor *desc = NULL; 807203678Sbrucec const struct usb_audio_streaming_interface_descriptor *asid = NULL; 808203678Sbrucec const struct usb_audio_streaming_type1_descriptor *asf1d = NULL; 809203678Sbrucec const struct usb_audio_streaming_endpoint_descriptor *sed = NULL; 810203678Sbrucec const usb_endpoint_descriptor_audio_t *ed1 = NULL; 811203678Sbrucec const usb_endpoint_descriptor_audio_t *ed2 = NULL; 812194228Sthompsa struct usb_config_descriptor *cd = usbd_get_config_descriptor(udev); 813192984Sthompsa struct usb_interface_descriptor *id; 814184610Salfred const struct uaudio_format *p_fmt; 815184610Salfred struct uaudio_chan *chan; 816184610Salfred uint16_t curidx = 0xFFFF; 817184610Salfred uint16_t lastidx = 0xFFFF; 818184610Salfred uint16_t alt_index = 0; 819184610Salfred uint16_t wFormat; 820184610Salfred uint8_t ep_dir; 821184610Salfred uint8_t bChannels; 822184610Salfred uint8_t bBitResolution; 823184610Salfred uint8_t x; 824184610Salfred uint8_t audio_if = 0; 825184610Salfred 826194228Sthompsa while ((desc = usb_desc_foreach(cd, desc))) { 827184610Salfred 828184610Salfred if ((desc->bDescriptorType == UDESC_INTERFACE) && 829184610Salfred (desc->bLength >= sizeof(*id))) { 830184610Salfred 831184610Salfred id = (void *)desc; 832184610Salfred 833184610Salfred if (id->bInterfaceNumber != lastidx) { 834184610Salfred lastidx = id->bInterfaceNumber; 835184610Salfred curidx++; 836184610Salfred alt_index = 0; 837184610Salfred 838184610Salfred } else { 839184610Salfred alt_index++; 840184610Salfred } 841184610Salfred 842184610Salfred if ((id->bInterfaceClass == UICLASS_AUDIO) && 843184610Salfred (id->bInterfaceSubClass == UISUBCLASS_AUDIOSTREAM)) { 844184610Salfred audio_if = 1; 845184610Salfred } else { 846184610Salfred audio_if = 0; 847184610Salfred } 848184610Salfred 849184610Salfred if ((id->bInterfaceClass == UICLASS_AUDIO) && 850184610Salfred (id->bInterfaceSubClass == UISUBCLASS_MIDISTREAM)) { 851184610Salfred 852184610Salfred /* 853184610Salfred * XXX could allow multiple MIDI interfaces 854184610Salfred * XXX 855184610Salfred */ 856184610Salfred 857184610Salfred if ((sc->sc_midi_chan.valid == 0) && 858194228Sthompsa usbd_get_iface(udev, curidx)) { 859184610Salfred sc->sc_midi_chan.iface_index = curidx; 860184610Salfred sc->sc_midi_chan.iface_alt_index = alt_index; 861184610Salfred sc->sc_midi_chan.valid = 1; 862184610Salfred } 863184610Salfred } 864184610Salfred asid = NULL; 865184610Salfred asf1d = NULL; 866184610Salfred ed1 = NULL; 867184610Salfred ed2 = NULL; 868184610Salfred sed = NULL; 869184610Salfred } 870184610Salfred if ((desc->bDescriptorType == UDESC_CS_INTERFACE) && 871184610Salfred (desc->bDescriptorSubtype == AS_GENERAL) && 872184610Salfred (desc->bLength >= sizeof(*asid))) { 873184610Salfred if (asid == NULL) { 874184610Salfred asid = (void *)desc; 875184610Salfred } 876184610Salfred } 877184610Salfred if ((desc->bDescriptorType == UDESC_CS_INTERFACE) && 878184610Salfred (desc->bDescriptorSubtype == FORMAT_TYPE) && 879184610Salfred (desc->bLength >= sizeof(*asf1d))) { 880184610Salfred if (asf1d == NULL) { 881184610Salfred asf1d = (void *)desc; 882184610Salfred if (asf1d->bFormatType != FORMAT_TYPE_I) { 883184610Salfred DPRINTFN(11, "ignored bFormatType = %d\n", 884184610Salfred asf1d->bFormatType); 885184610Salfred asf1d = NULL; 886184610Salfred continue; 887184610Salfred } 888184610Salfred if (asf1d->bLength < (sizeof(*asf1d) + 889184610Salfred (asf1d->bSamFreqType == 0) ? 6 : 890184610Salfred (asf1d->bSamFreqType * 3))) { 891184610Salfred DPRINTFN(11, "'asf1d' descriptor is too short\n"); 892184610Salfred asf1d = NULL; 893184610Salfred continue; 894184610Salfred } 895184610Salfred } 896184610Salfred } 897184610Salfred if ((desc->bDescriptorType == UDESC_ENDPOINT) && 898209452Sthompsa (desc->bLength >= UEP_MINSIZE)) { 899184610Salfred if (ed1 == NULL) { 900184610Salfred ed1 = (void *)desc; 901184610Salfred if (UE_GET_XFERTYPE(ed1->bmAttributes) != UE_ISOCHRONOUS) { 902184610Salfred ed1 = NULL; 903184610Salfred } 904184610Salfred } 905184610Salfred } 906184610Salfred if ((desc->bDescriptorType == UDESC_CS_ENDPOINT) && 907184610Salfred (desc->bDescriptorSubtype == AS_GENERAL) && 908184610Salfred (desc->bLength >= sizeof(*sed))) { 909184610Salfred if (sed == NULL) { 910184610Salfred sed = (void *)desc; 911184610Salfred } 912184610Salfred } 913184610Salfred if (audio_if && asid && asf1d && ed1 && sed) { 914184610Salfred 915184610Salfred ep_dir = UE_GET_DIR(ed1->bEndpointAddress); 916184610Salfred 917209452Sthompsa /* We ignore sync endpoint information until further. */ 918184610Salfred 919184610Salfred wFormat = UGETW(asid->wFormatTag); 920192929Sthompsa bChannels = UAUDIO_MAX_CHAN(asf1d->bNrChannels); 921184610Salfred bBitResolution = asf1d->bBitResolution; 922184610Salfred 923184610Salfred if (asf1d->bSamFreqType == 0) { 924184610Salfred DPRINTFN(16, "Sample rate: %d-%dHz\n", 925184610Salfred UA_SAMP_LO(asf1d), UA_SAMP_HI(asf1d)); 926184610Salfred 927184610Salfred if ((rate >= UA_SAMP_LO(asf1d)) && 928184610Salfred (rate <= UA_SAMP_HI(asf1d))) { 929184610Salfred goto found_rate; 930184610Salfred } 931184610Salfred } else { 932184610Salfred 933184610Salfred for (x = 0; x < asf1d->bSamFreqType; x++) { 934184610Salfred DPRINTFN(16, "Sample rate = %dHz\n", 935184610Salfred UA_GETSAMP(asf1d, x)); 936184610Salfred 937184610Salfred if (rate == UA_GETSAMP(asf1d, x)) { 938184610Salfred goto found_rate; 939184610Salfred } 940184610Salfred } 941184610Salfred } 942184610Salfred 943184610Salfred audio_if = 0; 944184610Salfred continue; 945184610Salfred 946184610Salfred found_rate: 947184610Salfred 948184610Salfred for (p_fmt = uaudio_formats; 949184610Salfred p_fmt->wFormat; 950184610Salfred p_fmt++) { 951184610Salfred if ((p_fmt->wFormat == wFormat) && 952184610Salfred (p_fmt->bPrecision == bBitResolution)) { 953184610Salfred goto found_format; 954184610Salfred } 955184610Salfred } 956184610Salfred 957184610Salfred audio_if = 0; 958184610Salfred continue; 959184610Salfred 960184610Salfred found_format: 961184610Salfred 962184610Salfred if ((bChannels == channels) && 963184610Salfred (bBitResolution == bit_resolution)) { 964184610Salfred 965184610Salfred chan = (ep_dir == UE_DIR_IN) ? 966184610Salfred &sc->sc_rec_chan : 967184610Salfred &sc->sc_play_chan; 968184610Salfred 969194228Sthompsa if ((chan->valid == 0) && usbd_get_iface(udev, curidx)) { 970184610Salfred 971184610Salfred chan->valid = 1; 972207077Sthompsa#ifdef USB_DEBUG 973184610Salfred uaudio_chan_dump_ep_desc(ed1); 974184610Salfred uaudio_chan_dump_ep_desc(ed2); 975184610Salfred 976184610Salfred if (sed->bmAttributes & UA_SED_FREQ_CONTROL) { 977184610Salfred DPRINTFN(2, "FREQ_CONTROL\n"); 978184610Salfred } 979184610Salfred if (sed->bmAttributes & UA_SED_PITCH_CONTROL) { 980184610Salfred DPRINTFN(2, "PITCH_CONTROL\n"); 981184610Salfred } 982184610Salfred#endif 983184610Salfred DPRINTF("Sample rate = %dHz, channels = %d, " 984184610Salfred "bits = %d, format = %s\n", rate, channels, 985184610Salfred bit_resolution, p_fmt->description); 986184610Salfred 987184610Salfred chan->sample_rate = rate; 988184610Salfred chan->p_asid = asid; 989184610Salfred chan->p_asf1d = asf1d; 990184610Salfred chan->p_ed1 = ed1; 991184610Salfred chan->p_ed2 = ed2; 992184610Salfred chan->p_fmt = p_fmt; 993184610Salfred chan->p_sed = sed; 994184610Salfred chan->iface_index = curidx; 995184610Salfred chan->iface_alt_index = alt_index; 996184610Salfred 997186730Salfred if (ep_dir == UE_DIR_IN) 998203678Sbrucec chan->usb_cfg = 999186730Salfred uaudio_cfg_record; 1000186730Salfred else 1001203678Sbrucec chan->usb_cfg = 1002186730Salfred uaudio_cfg_play; 1003184610Salfred 1004200825Sthompsa chan->sample_size = (( 1005192929Sthompsa UAUDIO_MAX_CHAN(chan->p_asf1d->bNrChannels) * 1006184610Salfred chan->p_asf1d->bBitResolution) / 8); 1007184610Salfred 1008184610Salfred if (sc->sc_sndstat_valid) { 1009184610Salfred sbuf_printf(&sc->sc_sndstat, "\n\t" 1010184610Salfred "mode %d.%d:(%s) %dch, %d/%dbit, %s, %dHz", 1011184610Salfred curidx, alt_index, 1012184610Salfred (ep_dir == UE_DIR_IN) ? "input" : "output", 1013184610Salfred asf1d->bNrChannels, asf1d->bBitResolution, 1014184610Salfred asf1d->bSubFrameSize * 8, 1015184610Salfred p_fmt->description, rate); 1016184610Salfred } 1017184610Salfred } 1018184610Salfred } 1019184610Salfred audio_if = 0; 1020184610Salfred continue; 1021184610Salfred } 1022184610Salfred } 1023184610Salfred} 1024184610Salfred 1025200825Sthompsa/* This structure defines all the supported rates. */ 1026200825Sthompsa 1027200825Sthompsastatic const uint32_t uaudio_rate_list[] = { 1028200825Sthompsa 96000, 1029200825Sthompsa 88000, 1030200825Sthompsa 80000, 1031200825Sthompsa 72000, 1032200825Sthompsa 64000, 1033200825Sthompsa 56000, 1034200825Sthompsa 48000, 1035200825Sthompsa 44100, 1036200825Sthompsa 40000, 1037200825Sthompsa 32000, 1038200825Sthompsa 24000, 1039200825Sthompsa 22050, 1040200825Sthompsa 16000, 1041200825Sthompsa 11025, 1042200825Sthompsa 8000, 1043200825Sthompsa 0 1044200825Sthompsa}; 1045200825Sthompsa 1046184610Salfredstatic void 1047192984Sthompsauaudio_chan_fill_info(struct uaudio_softc *sc, struct usb_device *udev) 1048184610Salfred{ 1049184610Salfred uint32_t rate = uaudio_default_rate; 1050200825Sthompsa uint8_t z; 1051184610Salfred uint8_t bits = uaudio_default_bits; 1052184610Salfred uint8_t y; 1053184610Salfred uint8_t channels = uaudio_default_channels; 1054184610Salfred uint8_t x; 1055184610Salfred 1056184610Salfred bits -= (bits % 8); 1057186730Salfred if ((bits == 0) || (bits > 32)) { 1058186730Salfred /* set a valid value */ 1059186730Salfred bits = 32; 1060186730Salfred } 1061200825Sthompsa if (channels == 0) { 1062200825Sthompsa switch (usbd_get_speed(udev)) { 1063200825Sthompsa case USB_SPEED_LOW: 1064200825Sthompsa case USB_SPEED_FULL: 1065200825Sthompsa /* 1066200825Sthompsa * Due to high bandwidth usage and problems 1067200825Sthompsa * with HIGH-speed split transactions we 1068200825Sthompsa * disable surround setups on FULL-speed USB 1069200825Sthompsa * by default 1070200825Sthompsa */ 1071200825Sthompsa channels = 2; 1072200825Sthompsa break; 1073200825Sthompsa default: 1074200825Sthompsa channels = 16; 1075200825Sthompsa break; 1076200825Sthompsa } 1077200825Sthompsa } else if (channels > 16) { 1078200825Sthompsa channels = 16; 1079186730Salfred } 1080184610Salfred if (sbuf_new(&sc->sc_sndstat, NULL, 4096, SBUF_AUTOEXTEND)) { 1081184610Salfred sc->sc_sndstat_valid = 1; 1082184610Salfred } 1083184610Salfred /* try to search for a valid config */ 1084184610Salfred 1085184610Salfred for (x = channels; x; x--) { 1086184610Salfred for (y = bits; y; y -= 8) { 1087184610Salfred 1088200825Sthompsa /* try user defined rate, if any */ 1089200825Sthompsa if (rate != 0) 1090200825Sthompsa uaudio_chan_fill_info_sub(sc, udev, rate, x, y); 1091200825Sthompsa 1092200825Sthompsa /* try find a matching rate, if any */ 1093200825Sthompsa for (z = 0; uaudio_rate_list[z]; z++) { 1094200825Sthompsa uaudio_chan_fill_info_sub(sc, udev, uaudio_rate_list[z], x, y); 1095200825Sthompsa 1096184610Salfred if (sc->sc_rec_chan.valid && 1097184610Salfred sc->sc_play_chan.valid) { 1098184610Salfred goto done; 1099184610Salfred } 1100184610Salfred } 1101184610Salfred } 1102184610Salfred } 1103184610Salfred 1104184610Salfreddone: 1105184610Salfred if (sc->sc_sndstat_valid) { 1106184610Salfred sbuf_finish(&sc->sc_sndstat); 1107184610Salfred } 1108184610Salfred} 1109184610Salfred 1110184610Salfredstatic void 1111194677Sthompsauaudio_chan_play_callback(struct usb_xfer *xfer, usb_error_t error) 1112184610Salfred{ 1113194677Sthompsa struct uaudio_chan *ch = usbd_xfer_softc(xfer); 1114194677Sthompsa struct usb_page_cache *pc; 1115186730Salfred uint32_t total; 1116184610Salfred uint32_t blockcount; 1117184610Salfred uint32_t n; 1118184610Salfred uint32_t offset; 1119200825Sthompsa int actlen; 1120200825Sthompsa int sumlen; 1121184610Salfred 1122194677Sthompsa usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 1123194677Sthompsa 1124199060Sthompsa if (ch->end == ch->start) { 1125199060Sthompsa DPRINTF("no buffer!\n"); 1126199060Sthompsa return; 1127199060Sthompsa } 1128199060Sthompsa 1129184610Salfred switch (USB_GET_STATE(xfer)) { 1130184610Salfred case USB_ST_TRANSFERRED: 1131184610Salfredtr_transferred: 1132194677Sthompsa if (actlen < sumlen) { 1133184610Salfred DPRINTF("short transfer, " 1134200825Sthompsa "%d of %d bytes\n", actlen, sumlen); 1135184610Salfred } 1136184610Salfred chn_intr(ch->pcm_ch); 1137184610Salfred 1138184610Salfred case USB_ST_SETUP: 1139200825Sthompsa if (ch->bytes_per_frame[1] > usbd_xfer_max_framelen(xfer)) { 1140184610Salfred DPRINTF("bytes per transfer, %d, " 1141184610Salfred "exceeds maximum, %d!\n", 1142200825Sthompsa ch->bytes_per_frame[1], 1143194677Sthompsa usbd_xfer_max_framelen(xfer)); 1144184610Salfred break; 1145184610Salfred } 1146200825Sthompsa 1147200825Sthompsa blockcount = ch->intr_frames; 1148200825Sthompsa 1149200825Sthompsa /* setup number of frames */ 1150194677Sthompsa usbd_xfer_set_frames(xfer, blockcount); 1151184610Salfred 1152200825Sthompsa /* reset total length */ 1153200825Sthompsa total = 0; 1154200825Sthompsa 1155200825Sthompsa /* setup frame lengths */ 1156200825Sthompsa for (n = 0; n != blockcount; n++) { 1157200825Sthompsa ch->sample_curr += ch->sample_rem; 1158200825Sthompsa if (ch->sample_curr >= ch->frames_per_second) { 1159200825Sthompsa ch->sample_curr -= ch->frames_per_second; 1160200825Sthompsa usbd_xfer_set_frame_len(xfer, n, ch->bytes_per_frame[1]); 1161200825Sthompsa total += ch->bytes_per_frame[1]; 1162200825Sthompsa } else { 1163200825Sthompsa usbd_xfer_set_frame_len(xfer, n, ch->bytes_per_frame[0]); 1164200825Sthompsa total += ch->bytes_per_frame[0]; 1165200825Sthompsa } 1166200825Sthompsa } 1167200825Sthompsa 1168184610Salfred DPRINTFN(6, "transfer %d bytes\n", total); 1169184610Salfred 1170184610Salfred offset = 0; 1171184610Salfred 1172194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 1173184610Salfred while (total > 0) { 1174184610Salfred 1175184610Salfred n = (ch->end - ch->cur); 1176184610Salfred if (n > total) { 1177184610Salfred n = total; 1178184610Salfred } 1179194677Sthompsa usbd_copy_in(pc, offset, ch->cur, n); 1180184610Salfred 1181184610Salfred total -= n; 1182184610Salfred ch->cur += n; 1183184610Salfred offset += n; 1184184610Salfred 1185184610Salfred if (ch->cur >= ch->end) { 1186184610Salfred ch->cur = ch->start; 1187184610Salfred } 1188184610Salfred } 1189184610Salfred 1190194228Sthompsa usbd_transfer_submit(xfer); 1191184610Salfred break; 1192184610Salfred 1193184610Salfred default: /* Error */ 1194194677Sthompsa if (error == USB_ERR_CANCELLED) { 1195184610Salfred break; 1196184610Salfred } 1197184610Salfred goto tr_transferred; 1198184610Salfred } 1199184610Salfred} 1200184610Salfred 1201184610Salfredstatic void 1202194677Sthompsauaudio_chan_record_callback(struct usb_xfer *xfer, usb_error_t error) 1203184610Salfred{ 1204194677Sthompsa struct uaudio_chan *ch = usbd_xfer_softc(xfer); 1205194677Sthompsa struct usb_page_cache *pc; 1206184610Salfred uint32_t n; 1207184610Salfred uint32_t m; 1208184610Salfred uint32_t blockcount; 1209184610Salfred uint32_t offset0; 1210184610Salfred uint32_t offset1; 1211199060Sthompsa uint32_t mfl; 1212194677Sthompsa int len; 1213199060Sthompsa int actlen; 1214199060Sthompsa int nframes; 1215184610Salfred 1216194677Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, &nframes); 1217199060Sthompsa mfl = usbd_xfer_max_framelen(xfer); 1218194677Sthompsa 1219199060Sthompsa if (ch->end == ch->start) { 1220199060Sthompsa DPRINTF("no buffer!\n"); 1221199060Sthompsa return; 1222199060Sthompsa } 1223199060Sthompsa 1224184610Salfred switch (USB_GET_STATE(xfer)) { 1225184610Salfred case USB_ST_TRANSFERRED: 1226184610Salfred 1227200825Sthompsa DPRINTFN(6, "transferred %d bytes\n", actlen); 1228200825Sthompsa 1229184610Salfred offset0 = 0; 1230199060Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 1231184610Salfred 1232194677Sthompsa for (n = 0; n != nframes; n++) { 1233184610Salfred 1234184610Salfred offset1 = offset0; 1235194682Sthompsa len = usbd_xfer_frame_len(xfer, n); 1236184610Salfred 1237194677Sthompsa while (len > 0) { 1238184610Salfred 1239184610Salfred m = (ch->end - ch->cur); 1240184610Salfred 1241194677Sthompsa if (m > len) { 1242194677Sthompsa m = len; 1243184610Salfred } 1244194677Sthompsa usbd_copy_out(pc, offset1, ch->cur, m); 1245184610Salfred 1246194677Sthompsa len -= m; 1247184610Salfred offset1 += m; 1248184610Salfred ch->cur += m; 1249184610Salfred 1250184610Salfred if (ch->cur >= ch->end) { 1251184610Salfred ch->cur = ch->start; 1252184610Salfred } 1253184610Salfred } 1254184610Salfred 1255199060Sthompsa offset0 += mfl; 1256184610Salfred } 1257184610Salfred 1258184610Salfred chn_intr(ch->pcm_ch); 1259184610Salfred 1260184610Salfred case USB_ST_SETUP: 1261199060Sthompsatr_setup: 1262200825Sthompsa blockcount = ch->intr_frames; 1263200825Sthompsa 1264194677Sthompsa usbd_xfer_set_frames(xfer, blockcount); 1265194677Sthompsa for (n = 0; n < blockcount; n++) { 1266199060Sthompsa usbd_xfer_set_frame_len(xfer, n, mfl); 1267184610Salfred } 1268184610Salfred 1269194228Sthompsa usbd_transfer_submit(xfer); 1270199060Sthompsa break; 1271184610Salfred 1272184610Salfred default: /* Error */ 1273194677Sthompsa if (error == USB_ERR_CANCELLED) { 1274199060Sthompsa break; 1275184610Salfred } 1276199060Sthompsa goto tr_setup; 1277184610Salfred } 1278184610Salfred} 1279184610Salfred 1280184610Salfredvoid * 1281184610Salfreduaudio_chan_init(struct uaudio_softc *sc, struct snd_dbuf *b, 1282184610Salfred struct pcm_channel *c, int dir) 1283184610Salfred{ 1284184610Salfred struct uaudio_chan *ch = ((dir == PCMDIR_PLAY) ? 1285184610Salfred &sc->sc_play_chan : &sc->sc_rec_chan); 1286186730Salfred uint32_t buf_size; 1287199060Sthompsa uint32_t frames; 1288200825Sthompsa uint32_t format; 1289200825Sthompsa uint16_t fps; 1290184610Salfred uint8_t endpoint; 1291199060Sthompsa uint8_t blocks; 1292184610Salfred uint8_t iface_index; 1293184610Salfred uint8_t alt_index; 1294199060Sthompsa uint8_t fps_shift; 1295193045Sthompsa usb_error_t err; 1296184610Salfred 1297200825Sthompsa fps = usbd_get_isoc_fps(sc->sc_udev); 1298200825Sthompsa 1299200825Sthompsa if (fps < 8000) { 1300199060Sthompsa /* FULL speed USB */ 1301199060Sthompsa frames = 8; 1302199060Sthompsa } else { 1303199060Sthompsa /* HIGH speed USB */ 1304199060Sthompsa frames = UAUDIO_NFRAMES; 1305199060Sthompsa } 1306199060Sthompsa 1307184610Salfred /* setup play/record format */ 1308184610Salfred 1309184610Salfred ch->pcm_cap.fmtlist = ch->pcm_format; 1310184610Salfred 1311184610Salfred ch->pcm_format[0] = 0; 1312184610Salfred ch->pcm_format[1] = 0; 1313184610Salfred 1314184610Salfred ch->pcm_cap.minspeed = ch->sample_rate; 1315184610Salfred ch->pcm_cap.maxspeed = ch->sample_rate; 1316184610Salfred 1317199576Sthompsa /* setup mutex and PCM channel */ 1318199576Sthompsa 1319199576Sthompsa ch->pcm_ch = c; 1320199576Sthompsa ch->pcm_mtx = c->lock; 1321199576Sthompsa 1322200825Sthompsa format = ch->p_fmt->freebsd_fmt; 1323184610Salfred 1324200825Sthompsa switch (ch->p_asf1d->bNrChannels) { 1325200825Sthompsa case 2: 1326200825Sthompsa /* stereo */ 1327200825Sthompsa format = SND_FORMAT(format, 2, 0); 1328200825Sthompsa break; 1329200825Sthompsa case 1: 1330200825Sthompsa /* mono */ 1331200825Sthompsa format = SND_FORMAT(format, 1, 0); 1332200825Sthompsa break; 1333200825Sthompsa default: 1334200825Sthompsa /* surround and more */ 1335200825Sthompsa format = feeder_matrix_default_format( 1336200825Sthompsa SND_FORMAT(format, ch->p_asf1d->bNrChannels, 0)); 1337200825Sthompsa break; 1338200825Sthompsa } 1339200825Sthompsa 1340200825Sthompsa ch->pcm_cap.fmtlist[0] = format; 1341184610Salfred ch->pcm_cap.fmtlist[1] = 0; 1342184610Salfred 1343200825Sthompsa /* check if format is not supported */ 1344200825Sthompsa 1345200825Sthompsa if (format == 0) { 1346200825Sthompsa DPRINTF("The selected audio format is not supported\n"); 1347200825Sthompsa goto error; 1348200825Sthompsa } 1349200825Sthompsa 1350184610Salfred /* set alternate interface corresponding to the mode */ 1351184610Salfred 1352184610Salfred endpoint = ch->p_ed1->bEndpointAddress; 1353184610Salfred iface_index = ch->iface_index; 1354184610Salfred alt_index = ch->iface_alt_index; 1355184610Salfred 1356184610Salfred DPRINTF("endpoint=0x%02x, speed=%d, iface=%d alt=%d\n", 1357184610Salfred endpoint, ch->sample_rate, iface_index, alt_index); 1358184610Salfred 1359194228Sthompsa err = usbd_set_alt_interface_index(sc->sc_udev, iface_index, alt_index); 1360184610Salfred if (err) { 1361184610Salfred DPRINTF("setting of alternate index failed: %s!\n", 1362194228Sthompsa usbd_errstr(err)); 1363184610Salfred goto error; 1364184610Salfred } 1365194228Sthompsa usbd_set_parent_iface(sc->sc_udev, iface_index, sc->sc_mixer_iface_index); 1366184610Salfred 1367184610Salfred /* 1368184610Salfred * If just one sampling rate is supported, 1369184610Salfred * no need to call "uaudio_set_speed()". 1370184610Salfred * Roland SD-90 freezes by a SAMPLING_FREQ_CONTROL request. 1371184610Salfred */ 1372184610Salfred if (ch->p_asf1d->bSamFreqType != 1) { 1373184610Salfred if (uaudio_set_speed(sc->sc_udev, endpoint, ch->sample_rate)) { 1374184610Salfred /* 1375184610Salfred * If the endpoint is adaptive setting the speed may 1376184610Salfred * fail. 1377184610Salfred */ 1378184610Salfred DPRINTF("setting of sample rate failed! (continuing anyway)\n"); 1379184610Salfred } 1380184610Salfred } 1381194228Sthompsa if (usbd_transfer_setup(sc->sc_udev, &iface_index, ch->xfer, 1382203678Sbrucec ch->usb_cfg, UAUDIO_NCHANBUFS, ch, ch->pcm_mtx)) { 1383184610Salfred DPRINTF("could not allocate USB transfers!\n"); 1384184610Salfred goto error; 1385184610Salfred } 1386199060Sthompsa 1387199060Sthompsa fps_shift = usbd_xfer_get_fps_shift(ch->xfer[0]); 1388199060Sthompsa 1389200825Sthompsa /* down shift number of frames per second, if any */ 1390200825Sthompsa fps >>= fps_shift; 1391200825Sthompsa frames >>= fps_shift; 1392200825Sthompsa 1393200825Sthompsa /* bytes per frame should not be zero */ 1394200825Sthompsa ch->bytes_per_frame[0] = ((ch->sample_rate / fps) * ch->sample_size); 1395200825Sthompsa ch->bytes_per_frame[1] = (((ch->sample_rate + fps - 1) / fps) * ch->sample_size); 1396200825Sthompsa 1397200825Sthompsa /* setup data rate dithering, if any */ 1398200825Sthompsa ch->frames_per_second = fps; 1399200825Sthompsa ch->sample_rem = ch->sample_rate % fps; 1400200825Sthompsa ch->sample_curr = 0; 1401200825Sthompsa ch->frames_per_second = fps; 1402200825Sthompsa 1403200825Sthompsa /* compute required buffer size */ 1404200825Sthompsa buf_size = (ch->bytes_per_frame[1] * frames); 1405200825Sthompsa 1406199060Sthompsa ch->intr_size = buf_size; 1407200825Sthompsa ch->intr_frames = frames; 1408199060Sthompsa 1409200825Sthompsa DPRINTF("fps=%d sample_rem=%d\n", fps, ch->sample_rem); 1410200825Sthompsa 1411199060Sthompsa if (ch->intr_frames == 0) { 1412199060Sthompsa DPRINTF("frame shift is too high!\n"); 1413199060Sthompsa goto error; 1414199060Sthompsa } 1415199060Sthompsa 1416199060Sthompsa /* setup double buffering */ 1417199060Sthompsa buf_size *= 2; 1418199060Sthompsa blocks = 2; 1419199060Sthompsa 1420199060Sthompsa ch->buf = malloc(buf_size, M_DEVBUF, M_WAITOK | M_ZERO); 1421199060Sthompsa if (ch->buf == NULL) 1422199060Sthompsa goto error; 1423199060Sthompsa if (sndbuf_setup(b, ch->buf, buf_size) != 0) 1424199060Sthompsa goto error; 1425199060Sthompsa if (sndbuf_resize(b, blocks, ch->intr_size)) 1426199060Sthompsa goto error; 1427199060Sthompsa 1428199060Sthompsa ch->start = ch->buf; 1429199060Sthompsa ch->end = ch->buf + buf_size; 1430199060Sthompsa ch->cur = ch->buf; 1431199060Sthompsa ch->pcm_buf = b; 1432199060Sthompsa 1433199060Sthompsa if (ch->pcm_mtx == NULL) { 1434199060Sthompsa DPRINTF("ERROR: PCM channels does not have a mutex!\n"); 1435199060Sthompsa goto error; 1436199060Sthompsa } 1437199060Sthompsa 1438184610Salfred return (ch); 1439184610Salfred 1440184610Salfrederror: 1441184610Salfred uaudio_chan_free(ch); 1442184610Salfred return (NULL); 1443184610Salfred} 1444184610Salfred 1445184610Salfredint 1446184610Salfreduaudio_chan_free(struct uaudio_chan *ch) 1447184610Salfred{ 1448184610Salfred if (ch->buf != NULL) { 1449184610Salfred free(ch->buf, M_DEVBUF); 1450184610Salfred ch->buf = NULL; 1451184610Salfred } 1452194228Sthompsa usbd_transfer_unsetup(ch->xfer, UAUDIO_NCHANBUFS); 1453184610Salfred 1454184610Salfred ch->valid = 0; 1455184610Salfred 1456184610Salfred return (0); 1457184610Salfred} 1458184610Salfred 1459184610Salfredint 1460184610Salfreduaudio_chan_set_param_blocksize(struct uaudio_chan *ch, uint32_t blocksize) 1461184610Salfred{ 1462199060Sthompsa return (ch->intr_size); 1463184610Salfred} 1464184610Salfred 1465184610Salfredint 1466184610Salfreduaudio_chan_set_param_fragments(struct uaudio_chan *ch, uint32_t blocksize, 1467184610Salfred uint32_t blockcount) 1468184610Salfred{ 1469184610Salfred return (1); 1470184610Salfred} 1471184610Salfred 1472184610Salfredint 1473184610Salfreduaudio_chan_set_param_speed(struct uaudio_chan *ch, uint32_t speed) 1474184610Salfred{ 1475184610Salfred if (speed != ch->sample_rate) { 1476184610Salfred DPRINTF("rate conversion required\n"); 1477184610Salfred } 1478184610Salfred return (ch->sample_rate); 1479184610Salfred} 1480184610Salfred 1481184610Salfredint 1482184610Salfreduaudio_chan_getptr(struct uaudio_chan *ch) 1483184610Salfred{ 1484184610Salfred return (ch->cur - ch->start); 1485184610Salfred} 1486184610Salfred 1487184610Salfredstruct pcmchan_caps * 1488184610Salfreduaudio_chan_getcaps(struct uaudio_chan *ch) 1489184610Salfred{ 1490184610Salfred return (&ch->pcm_cap); 1491184610Salfred} 1492184610Salfred 1493193640Sariffstatic struct pcmchan_matrix uaudio_chan_matrix_swap_2_0 = { 1494193640Sariff .id = SND_CHN_MATRIX_DRV, 1495193640Sariff .channels = 2, 1496193640Sariff .ext = 0, 1497193640Sariff .map = { 1498193640Sariff /* Right */ 1499193640Sariff [0] = { 1500193640Sariff .type = SND_CHN_T_FR, 1501193640Sariff .members = 1502193640Sariff SND_CHN_T_MASK_FR | SND_CHN_T_MASK_FC | 1503193640Sariff SND_CHN_T_MASK_LF | SND_CHN_T_MASK_BR | 1504193640Sariff SND_CHN_T_MASK_BC | SND_CHN_T_MASK_SR 1505193640Sariff }, 1506193640Sariff /* Left */ 1507193640Sariff [1] = { 1508193640Sariff .type = SND_CHN_T_FL, 1509193640Sariff .members = 1510193640Sariff SND_CHN_T_MASK_FL | SND_CHN_T_MASK_FC | 1511193640Sariff SND_CHN_T_MASK_LF | SND_CHN_T_MASK_BL | 1512193640Sariff SND_CHN_T_MASK_BC | SND_CHN_T_MASK_SL 1513193640Sariff }, 1514193640Sariff [2] = { 1515193640Sariff .type = SND_CHN_T_MAX, 1516193640Sariff .members = 0 1517193640Sariff } 1518193640Sariff }, 1519193640Sariff .mask = SND_CHN_T_MASK_FR | SND_CHN_T_MASK_FL, 1520193640Sariff .offset = { 1, 0, -1, -1, -1, -1, -1, -1, -1, 1521193640Sariff -1, -1, -1, -1, -1, -1, -1, -1, -1 } 1522193640Sariff}; 1523193640Sariff 1524193640Sariffstruct pcmchan_matrix * 1525193640Sariffuaudio_chan_getmatrix(struct uaudio_chan *ch, uint32_t format) 1526193640Sariff{ 1527193640Sariff struct uaudio_softc *sc; 1528193640Sariff 1529193640Sariff sc = ch->priv_sc; 1530193640Sariff 1531193640Sariff if (sc != NULL && sc->sc_uq_audio_swap_lr != 0 && 1532193640Sariff AFMT_CHANNEL(format) == 2) 1533193640Sariff return (&uaudio_chan_matrix_swap_2_0); 1534193640Sariff 1535193640Sariff return (feeder_matrix_format_map(format)); 1536193640Sariff} 1537193640Sariff 1538184610Salfredint 1539184610Salfreduaudio_chan_set_param_format(struct uaudio_chan *ch, uint32_t format) 1540184610Salfred{ 1541184610Salfred ch->format = format; 1542184610Salfred return (0); 1543184610Salfred} 1544184610Salfred 1545184610Salfredint 1546184610Salfreduaudio_chan_start(struct uaudio_chan *ch) 1547184610Salfred{ 1548184610Salfred ch->cur = ch->start; 1549184610Salfred 1550184610Salfred#if (UAUDIO_NCHANBUFS != 2) 1551184610Salfred#error "please update code" 1552184610Salfred#endif 1553184610Salfred if (ch->xfer[0]) { 1554194228Sthompsa usbd_transfer_start(ch->xfer[0]); 1555184610Salfred } 1556184610Salfred if (ch->xfer[1]) { 1557194228Sthompsa usbd_transfer_start(ch->xfer[1]); 1558184610Salfred } 1559184610Salfred return (0); 1560184610Salfred} 1561184610Salfred 1562184610Salfredint 1563184610Salfreduaudio_chan_stop(struct uaudio_chan *ch) 1564184610Salfred{ 1565184610Salfred#if (UAUDIO_NCHANBUFS != 2) 1566184610Salfred#error "please update code" 1567184610Salfred#endif 1568194228Sthompsa usbd_transfer_stop(ch->xfer[0]); 1569194228Sthompsa usbd_transfer_stop(ch->xfer[1]); 1570184610Salfred return (0); 1571184610Salfred} 1572184610Salfred 1573184610Salfred/*========================================================================* 1574184610Salfred * AC - Audio Controller - routines 1575184610Salfred *========================================================================*/ 1576184610Salfred 1577184610Salfredstatic void 1578184610Salfreduaudio_mixer_add_ctl_sub(struct uaudio_softc *sc, struct uaudio_mixer_node *mc) 1579184610Salfred{ 1580184610Salfred struct uaudio_mixer_node *p_mc_new = 1581184610Salfred malloc(sizeof(*p_mc_new), M_USBDEV, M_WAITOK); 1582184610Salfred 1583184610Salfred if (p_mc_new) { 1584184610Salfred bcopy(mc, p_mc_new, sizeof(*p_mc_new)); 1585184610Salfred p_mc_new->next = sc->sc_mixer_root; 1586184610Salfred sc->sc_mixer_root = p_mc_new; 1587184610Salfred sc->sc_mixer_count++; 1588184610Salfred } else { 1589184610Salfred DPRINTF("out of memory\n"); 1590184610Salfred } 1591184610Salfred} 1592184610Salfred 1593184610Salfredstatic void 1594184610Salfreduaudio_mixer_add_ctl(struct uaudio_softc *sc, struct uaudio_mixer_node *mc) 1595184610Salfred{ 1596184610Salfred int32_t res; 1597184610Salfred 1598184610Salfred if (mc->class < UAC_NCLASSES) { 1599184610Salfred DPRINTF("adding %s.%d\n", 1600184610Salfred uac_names[mc->class], mc->ctl); 1601184610Salfred } else { 1602184610Salfred DPRINTF("adding %d\n", mc->ctl); 1603184610Salfred } 1604184610Salfred 1605184610Salfred if (mc->type == MIX_ON_OFF) { 1606184610Salfred mc->minval = 0; 1607184610Salfred mc->maxval = 1; 1608184610Salfred } else if (mc->type == MIX_SELECTOR) { 1609184610Salfred } else { 1610184610Salfred 1611184610Salfred /* determine min and max values */ 1612184610Salfred 1613184610Salfred mc->minval = uaudio_mixer_get(sc->sc_udev, GET_MIN, mc); 1614184610Salfred 1615184610Salfred mc->minval = uaudio_mixer_signext(mc->type, mc->minval); 1616184610Salfred 1617184610Salfred mc->maxval = uaudio_mixer_get(sc->sc_udev, GET_MAX, mc); 1618184610Salfred 1619199060Sthompsa mc->maxval = uaudio_mixer_signext(mc->type, mc->maxval); 1620184610Salfred 1621199060Sthompsa /* check if max and min was swapped */ 1622199060Sthompsa 1623199060Sthompsa if (mc->maxval < mc->minval) { 1624199060Sthompsa res = mc->maxval; 1625199060Sthompsa mc->maxval = mc->minval; 1626199060Sthompsa mc->minval = res; 1627199060Sthompsa } 1628199060Sthompsa 1629199060Sthompsa /* compute value range */ 1630184610Salfred mc->mul = mc->maxval - mc->minval; 1631199060Sthompsa if (mc->mul == 0) 1632184610Salfred mc->mul = 1; 1633199060Sthompsa 1634199060Sthompsa /* compute value alignment */ 1635184610Salfred res = uaudio_mixer_get(sc->sc_udev, GET_RES, mc); 1636199576Sthompsa 1637199576Sthompsa DPRINTF("Resolution = %d\n", (int)res); 1638184610Salfred } 1639184610Salfred 1640184610Salfred uaudio_mixer_add_ctl_sub(sc, mc); 1641184610Salfred 1642207077Sthompsa#ifdef USB_DEBUG 1643184610Salfred if (uaudio_debug > 2) { 1644184610Salfred uint8_t i; 1645184610Salfred 1646184610Salfred for (i = 0; i < mc->nchan; i++) { 1647184610Salfred DPRINTF("[mix] wValue=%04x\n", mc->wValue[0]); 1648184610Salfred } 1649184610Salfred DPRINTF("[mix] wIndex=%04x type=%d ctl='%d' " 1650184610Salfred "min=%d max=%d\n", 1651184610Salfred mc->wIndex, mc->type, mc->ctl, 1652184610Salfred mc->minval, mc->maxval); 1653184610Salfred } 1654184610Salfred#endif 1655184610Salfred} 1656184610Salfred 1657184610Salfredstatic void 1658184610Salfreduaudio_mixer_add_input(struct uaudio_softc *sc, 1659184610Salfred const struct uaudio_terminal_node *iot, int id) 1660184610Salfred{ 1661207077Sthompsa#ifdef USB_DEBUG 1662203678Sbrucec const struct usb_audio_input_terminal *d = iot[id].u.it; 1663184610Salfred 1664184610Salfred DPRINTFN(3, "bTerminalId=%d wTerminalType=0x%04x " 1665184610Salfred "bAssocTerminal=%d bNrChannels=%d wChannelConfig=%d " 1666184610Salfred "iChannelNames=%d\n", 1667184610Salfred d->bTerminalId, UGETW(d->wTerminalType), d->bAssocTerminal, 1668184610Salfred d->bNrChannels, UGETW(d->wChannelConfig), 1669184610Salfred d->iChannelNames); 1670184610Salfred#endif 1671184610Salfred} 1672184610Salfred 1673184610Salfredstatic void 1674184610Salfreduaudio_mixer_add_output(struct uaudio_softc *sc, 1675184610Salfred const struct uaudio_terminal_node *iot, int id) 1676184610Salfred{ 1677207077Sthompsa#ifdef USB_DEBUG 1678203678Sbrucec const struct usb_audio_output_terminal *d = iot[id].u.ot; 1679184610Salfred 1680184610Salfred DPRINTFN(3, "bTerminalId=%d wTerminalType=0x%04x " 1681184610Salfred "bAssocTerminal=%d bSourceId=%d iTerminal=%d\n", 1682184610Salfred d->bTerminalId, UGETW(d->wTerminalType), d->bAssocTerminal, 1683184610Salfred d->bSourceId, d->iTerminal); 1684184610Salfred#endif 1685184610Salfred} 1686184610Salfred 1687184610Salfredstatic void 1688184610Salfreduaudio_mixer_add_mixer(struct uaudio_softc *sc, 1689184610Salfred const struct uaudio_terminal_node *iot, int id) 1690184610Salfred{ 1691184610Salfred struct uaudio_mixer_node mix; 1692184610Salfred 1693203678Sbrucec const struct usb_audio_mixer_unit_0 *d0 = iot[id].u.mu; 1694203678Sbrucec const struct usb_audio_mixer_unit_1 *d1; 1695184610Salfred 1696184610Salfred uint32_t bno; /* bit number */ 1697184610Salfred uint32_t p; /* bit number accumulator */ 1698184610Salfred uint32_t mo; /* matching outputs */ 1699184610Salfred uint32_t mc; /* matching channels */ 1700184610Salfred uint32_t ichs; /* input channels */ 1701184610Salfred uint32_t ochs; /* output channels */ 1702184610Salfred uint32_t c; 1703184610Salfred uint32_t chs; /* channels */ 1704184610Salfred uint32_t i; 1705184610Salfred uint32_t o; 1706184610Salfred 1707184610Salfred DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n", 1708184610Salfred d0->bUnitId, d0->bNrInPins); 1709184610Salfred 1710184610Salfred /* compute the number of input channels */ 1711184610Salfred 1712184610Salfred ichs = 0; 1713184610Salfred for (i = 0; i < d0->bNrInPins; i++) { 1714184610Salfred ichs += (uaudio_mixer_get_cluster(d0->baSourceId[i], iot) 1715184610Salfred .bNrChannels); 1716184610Salfred } 1717184610Salfred 1718184610Salfred d1 = (const void *)(d0->baSourceId + d0->bNrInPins); 1719184610Salfred 1720184610Salfred /* and the number of output channels */ 1721184610Salfred 1722184610Salfred ochs = d1->bNrChannels; 1723184610Salfred 1724184610Salfred DPRINTFN(3, "ichs=%d ochs=%d\n", ichs, ochs); 1725184610Salfred 1726184610Salfred bzero(&mix, sizeof(mix)); 1727184610Salfred 1728184610Salfred mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 1729184610Salfred uaudio_mixer_determine_class(&iot[id], &mix); 1730184610Salfred mix.type = MIX_SIGNED_16; 1731184610Salfred 1732184610Salfred if (uaudio_mixer_verify_desc(d0, ((ichs * ochs) + 7) / 8) == NULL) { 1733184610Salfred return; 1734184610Salfred } 1735184610Salfred for (p = i = 0; i < d0->bNrInPins; i++) { 1736184610Salfred chs = uaudio_mixer_get_cluster(d0->baSourceId[i], iot).bNrChannels; 1737184610Salfred mc = 0; 1738184610Salfred for (c = 0; c < chs; c++) { 1739184610Salfred mo = 0; 1740184610Salfred for (o = 0; o < ochs; o++) { 1741184610Salfred bno = ((p + c) * ochs) + o; 1742184610Salfred if (BIT_TEST(d1->bmControls, bno)) { 1743184610Salfred mo++; 1744184610Salfred } 1745184610Salfred } 1746184610Salfred if (mo == 1) { 1747184610Salfred mc++; 1748184610Salfred } 1749184610Salfred } 1750184610Salfred if ((mc == chs) && (chs <= MIX_MAX_CHAN)) { 1751184610Salfred 1752184610Salfred /* repeat bit-scan */ 1753184610Salfred 1754184610Salfred mc = 0; 1755184610Salfred for (c = 0; c < chs; c++) { 1756184610Salfred for (o = 0; o < ochs; o++) { 1757184610Salfred bno = ((p + c) * ochs) + o; 1758184610Salfred if (BIT_TEST(d1->bmControls, bno)) { 1759184610Salfred mix.wValue[mc++] = MAKE_WORD(p + c + 1, o + 1); 1760184610Salfred } 1761184610Salfred } 1762184610Salfred } 1763184610Salfred mix.nchan = chs; 1764184610Salfred uaudio_mixer_add_ctl(sc, &mix); 1765184610Salfred } else { 1766184610Salfred /* XXX */ 1767184610Salfred } 1768184610Salfred p += chs; 1769184610Salfred } 1770184610Salfred} 1771184610Salfred 1772184610Salfredstatic void 1773184610Salfreduaudio_mixer_add_selector(struct uaudio_softc *sc, 1774184610Salfred const struct uaudio_terminal_node *iot, int id) 1775184610Salfred{ 1776203678Sbrucec const struct usb_audio_selector_unit *d = iot[id].u.su; 1777184610Salfred struct uaudio_mixer_node mix; 1778184610Salfred uint16_t i; 1779184610Salfred 1780184610Salfred DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n", 1781184610Salfred d->bUnitId, d->bNrInPins); 1782184610Salfred 1783184610Salfred if (d->bNrInPins == 0) { 1784184610Salfred return; 1785184610Salfred } 1786184610Salfred bzero(&mix, sizeof(mix)); 1787184610Salfred 1788184610Salfred mix.wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no); 1789184610Salfred mix.wValue[0] = MAKE_WORD(0, 0); 1790184610Salfred uaudio_mixer_determine_class(&iot[id], &mix); 1791184610Salfred mix.nchan = 1; 1792184610Salfred mix.type = MIX_SELECTOR; 1793184610Salfred 1794184610Salfred mix.ctl = SOUND_MIXER_NRDEVICES; 1795184610Salfred mix.minval = 1; 1796184610Salfred mix.maxval = d->bNrInPins; 1797184610Salfred 1798184610Salfred if (mix.maxval > MAX_SELECTOR_INPUT_PIN) { 1799184610Salfred mix.maxval = MAX_SELECTOR_INPUT_PIN; 1800184610Salfred } 1801184610Salfred mix.mul = (mix.maxval - mix.minval); 1802184610Salfred for (i = 0; i < MAX_SELECTOR_INPUT_PIN; i++) { 1803184610Salfred mix.slctrtype[i] = SOUND_MIXER_NRDEVICES; 1804184610Salfred } 1805184610Salfred 1806184610Salfred for (i = 0; i < mix.maxval; i++) { 1807184610Salfred mix.slctrtype[i] = uaudio_mixer_feature_name 1808184610Salfred (&iot[d->baSourceId[i]], &mix); 1809184610Salfred } 1810184610Salfred 1811184610Salfred mix.class = 0; /* not used */ 1812184610Salfred 1813184610Salfred uaudio_mixer_add_ctl(sc, &mix); 1814184610Salfred} 1815184610Salfred 1816184610Salfredstatic uint32_t 1817203678Sbrucecuaudio_mixer_feature_get_bmaControls(const struct usb_audio_feature_unit *d, 1818184610Salfred uint8_t index) 1819184610Salfred{ 1820184610Salfred uint32_t temp = 0; 1821184610Salfred uint32_t offset = (index * d->bControlSize); 1822184610Salfred 1823184610Salfred if (d->bControlSize > 0) { 1824184610Salfred temp |= d->bmaControls[offset]; 1825184610Salfred if (d->bControlSize > 1) { 1826184610Salfred temp |= d->bmaControls[offset + 1] << 8; 1827184610Salfred if (d->bControlSize > 2) { 1828184610Salfred temp |= d->bmaControls[offset + 2] << 16; 1829184610Salfred if (d->bControlSize > 3) { 1830184610Salfred temp |= d->bmaControls[offset + 3] << 24; 1831184610Salfred } 1832184610Salfred } 1833184610Salfred } 1834184610Salfred } 1835184610Salfred return (temp); 1836184610Salfred} 1837184610Salfred 1838184610Salfredstatic void 1839184610Salfreduaudio_mixer_add_feature(struct uaudio_softc *sc, 1840184610Salfred const struct uaudio_terminal_node *iot, int id) 1841184610Salfred{ 1842203678Sbrucec const struct usb_audio_feature_unit *d = iot[id].u.fu; 1843184610Salfred struct uaudio_mixer_node mix; 1844184610Salfred uint32_t fumask; 1845184610Salfred uint32_t mmask; 1846184610Salfred uint32_t cmask; 1847184610Salfred uint16_t mixernumber; 1848184610Salfred uint8_t nchan; 1849184610Salfred uint8_t chan; 1850184610Salfred uint8_t ctl; 1851184610Salfred uint8_t i; 1852184610Salfred 1853184610Salfred if (d->bControlSize == 0) { 1854184610Salfred return; 1855184610Salfred } 1856184610Salfred bzero(&mix, sizeof(mix)); 1857184610Salfred 1858184610Salfred nchan = (d->bLength - 7) / d->bControlSize; 1859184610Salfred mmask = uaudio_mixer_feature_get_bmaControls(d, 0); 1860184610Salfred cmask = 0; 1861184610Salfred 1862184610Salfred if (nchan == 0) { 1863184610Salfred return; 1864184610Salfred } 1865184610Salfred /* figure out what we can control */ 1866184610Salfred 1867184610Salfred for (chan = 1; chan < nchan; chan++) { 1868184610Salfred DPRINTFN(10, "chan=%d mask=%x\n", 1869184610Salfred chan, uaudio_mixer_feature_get_bmaControls(d, chan)); 1870184610Salfred 1871184610Salfred cmask |= uaudio_mixer_feature_get_bmaControls(d, chan); 1872184610Salfred } 1873184610Salfred 1874184610Salfred if (nchan > MIX_MAX_CHAN) { 1875184610Salfred nchan = MIX_MAX_CHAN; 1876184610Salfred } 1877184610Salfred mix.wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no); 1878184610Salfred 1879184610Salfred for (ctl = 1; ctl <= LOUDNESS_CONTROL; ctl++) { 1880184610Salfred 1881184610Salfred fumask = FU_MASK(ctl); 1882184610Salfred 1883184610Salfred DPRINTFN(5, "ctl=%d fumask=0x%04x\n", 1884184610Salfred ctl, fumask); 1885184610Salfred 1886184610Salfred if (mmask & fumask) { 1887184610Salfred mix.nchan = 1; 1888184610Salfred mix.wValue[0] = MAKE_WORD(ctl, 0); 1889184610Salfred } else if (cmask & fumask) { 1890184610Salfred mix.nchan = nchan - 1; 1891184610Salfred for (i = 1; i < nchan; i++) { 1892184610Salfred if (uaudio_mixer_feature_get_bmaControls(d, i) & fumask) 1893184610Salfred mix.wValue[i - 1] = MAKE_WORD(ctl, i); 1894184610Salfred else 1895184610Salfred mix.wValue[i - 1] = -1; 1896184610Salfred } 1897184610Salfred } else { 1898184610Salfred continue; 1899184610Salfred } 1900184610Salfred 1901184610Salfred mixernumber = uaudio_mixer_feature_name(&iot[id], &mix); 1902184610Salfred 1903184610Salfred switch (ctl) { 1904184610Salfred case MUTE_CONTROL: 1905184610Salfred mix.type = MIX_ON_OFF; 1906184610Salfred mix.ctl = SOUND_MIXER_NRDEVICES; 1907184610Salfred break; 1908184610Salfred 1909184610Salfred case VOLUME_CONTROL: 1910184610Salfred mix.type = MIX_SIGNED_16; 1911184610Salfred mix.ctl = mixernumber; 1912184610Salfred break; 1913184610Salfred 1914184610Salfred case BASS_CONTROL: 1915184610Salfred mix.type = MIX_SIGNED_8; 1916184610Salfred mix.ctl = SOUND_MIXER_BASS; 1917184610Salfred break; 1918184610Salfred 1919184610Salfred case MID_CONTROL: 1920184610Salfred mix.type = MIX_SIGNED_8; 1921184610Salfred mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 1922184610Salfred break; 1923184610Salfred 1924184610Salfred case TREBLE_CONTROL: 1925184610Salfred mix.type = MIX_SIGNED_8; 1926184610Salfred mix.ctl = SOUND_MIXER_TREBLE; 1927184610Salfred break; 1928184610Salfred 1929184610Salfred case GRAPHIC_EQUALIZER_CONTROL: 1930184610Salfred continue; /* XXX don't add anything */ 1931184610Salfred break; 1932184610Salfred 1933184610Salfred case AGC_CONTROL: 1934184610Salfred mix.type = MIX_ON_OFF; 1935184610Salfred mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 1936184610Salfred break; 1937184610Salfred 1938184610Salfred case DELAY_CONTROL: 1939184610Salfred mix.type = MIX_UNSIGNED_16; 1940184610Salfred mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 1941184610Salfred break; 1942184610Salfred 1943184610Salfred case BASS_BOOST_CONTROL: 1944184610Salfred mix.type = MIX_ON_OFF; 1945184610Salfred mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 1946184610Salfred break; 1947184610Salfred 1948184610Salfred case LOUDNESS_CONTROL: 1949184610Salfred mix.type = MIX_ON_OFF; 1950184610Salfred mix.ctl = SOUND_MIXER_LOUD; /* Is this correct ? */ 1951184610Salfred break; 1952184610Salfred 1953184610Salfred default: 1954184610Salfred mix.type = MIX_UNKNOWN; 1955184610Salfred break; 1956184610Salfred } 1957184610Salfred 1958184610Salfred if (mix.type != MIX_UNKNOWN) { 1959184610Salfred uaudio_mixer_add_ctl(sc, &mix); 1960184610Salfred } 1961184610Salfred } 1962184610Salfred} 1963184610Salfred 1964184610Salfredstatic void 1965184610Salfreduaudio_mixer_add_processing_updown(struct uaudio_softc *sc, 1966184610Salfred const struct uaudio_terminal_node *iot, int id) 1967184610Salfred{ 1968203678Sbrucec const struct usb_audio_processing_unit_0 *d0 = iot[id].u.pu; 1969203678Sbrucec const struct usb_audio_processing_unit_1 *d1 = 1970184610Salfred (const void *)(d0->baSourceId + d0->bNrInPins); 1971203678Sbrucec const struct usb_audio_processing_unit_updown *ud = 1972184610Salfred (const void *)(d1->bmControls + d1->bControlSize); 1973184610Salfred struct uaudio_mixer_node mix; 1974184610Salfred uint8_t i; 1975184610Salfred 1976184610Salfred if (uaudio_mixer_verify_desc(d0, sizeof(*ud)) == NULL) { 1977184610Salfred return; 1978184610Salfred } 1979184610Salfred if (uaudio_mixer_verify_desc(d0, sizeof(*ud) + (2 * ud->bNrModes)) 1980184610Salfred == NULL) { 1981184610Salfred return; 1982184610Salfred } 1983184610Salfred DPRINTFN(3, "bUnitId=%d bNrModes=%d\n", 1984184610Salfred d0->bUnitId, ud->bNrModes); 1985184610Salfred 1986184610Salfred if (!(d1->bmControls[0] & UA_PROC_MASK(UD_MODE_SELECT_CONTROL))) { 1987184610Salfred DPRINTF("no mode select\n"); 1988184610Salfred return; 1989184610Salfred } 1990184610Salfred bzero(&mix, sizeof(mix)); 1991184610Salfred 1992184610Salfred mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 1993184610Salfred mix.nchan = 1; 1994184610Salfred mix.wValue[0] = MAKE_WORD(UD_MODE_SELECT_CONTROL, 0); 1995184610Salfred uaudio_mixer_determine_class(&iot[id], &mix); 1996184610Salfred mix.type = MIX_ON_OFF; /* XXX */ 1997184610Salfred 1998184610Salfred for (i = 0; i < ud->bNrModes; i++) { 1999184610Salfred DPRINTFN(3, "i=%d bm=0x%x\n", i, UGETW(ud->waModes[i])); 2000184610Salfred /* XXX */ 2001184610Salfred } 2002184610Salfred 2003184610Salfred uaudio_mixer_add_ctl(sc, &mix); 2004184610Salfred} 2005184610Salfred 2006184610Salfredstatic void 2007184610Salfreduaudio_mixer_add_processing(struct uaudio_softc *sc, 2008184610Salfred const struct uaudio_terminal_node *iot, int id) 2009184610Salfred{ 2010203678Sbrucec const struct usb_audio_processing_unit_0 *d0 = iot[id].u.pu; 2011203678Sbrucec const struct usb_audio_processing_unit_1 *d1 = 2012184610Salfred (const void *)(d0->baSourceId + d0->bNrInPins); 2013184610Salfred struct uaudio_mixer_node mix; 2014184610Salfred uint16_t ptype; 2015184610Salfred 2016184610Salfred bzero(&mix, sizeof(mix)); 2017184610Salfred 2018184610Salfred ptype = UGETW(d0->wProcessType); 2019184610Salfred 2020184610Salfred DPRINTFN(3, "wProcessType=%d bUnitId=%d " 2021184610Salfred "bNrInPins=%d\n", ptype, d0->bUnitId, d0->bNrInPins); 2022184610Salfred 2023184610Salfred if (d1->bControlSize == 0) { 2024184610Salfred return; 2025184610Salfred } 2026184610Salfred if (d1->bmControls[0] & UA_PROC_ENABLE_MASK) { 2027184610Salfred mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 2028184610Salfred mix.nchan = 1; 2029184610Salfred mix.wValue[0] = MAKE_WORD(XX_ENABLE_CONTROL, 0); 2030184610Salfred uaudio_mixer_determine_class(&iot[id], &mix); 2031184610Salfred mix.type = MIX_ON_OFF; 2032184610Salfred uaudio_mixer_add_ctl(sc, &mix); 2033184610Salfred } 2034184610Salfred switch (ptype) { 2035184610Salfred case UPDOWNMIX_PROCESS: 2036184610Salfred uaudio_mixer_add_processing_updown(sc, iot, id); 2037184610Salfred break; 2038184610Salfred 2039184610Salfred case DOLBY_PROLOGIC_PROCESS: 2040184610Salfred case P3D_STEREO_EXTENDER_PROCESS: 2041184610Salfred case REVERBATION_PROCESS: 2042184610Salfred case CHORUS_PROCESS: 2043184610Salfred case DYN_RANGE_COMP_PROCESS: 2044184610Salfred default: 2045184610Salfred DPRINTF("unit %d, type=%d is not implemented\n", 2046184610Salfred d0->bUnitId, ptype); 2047184610Salfred break; 2048184610Salfred } 2049184610Salfred} 2050184610Salfred 2051184610Salfredstatic void 2052184610Salfreduaudio_mixer_add_extension(struct uaudio_softc *sc, 2053184610Salfred const struct uaudio_terminal_node *iot, int id) 2054184610Salfred{ 2055203678Sbrucec const struct usb_audio_extension_unit_0 *d0 = iot[id].u.eu; 2056203678Sbrucec const struct usb_audio_extension_unit_1 *d1 = 2057184610Salfred (const void *)(d0->baSourceId + d0->bNrInPins); 2058184610Salfred struct uaudio_mixer_node mix; 2059184610Salfred 2060184610Salfred DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n", 2061184610Salfred d0->bUnitId, d0->bNrInPins); 2062184610Salfred 2063184610Salfred if (sc->sc_uq_au_no_xu) { 2064184610Salfred return; 2065184610Salfred } 2066184610Salfred if (d1->bControlSize == 0) { 2067184610Salfred return; 2068184610Salfred } 2069184610Salfred if (d1->bmControls[0] & UA_EXT_ENABLE_MASK) { 2070184610Salfred 2071184610Salfred bzero(&mix, sizeof(mix)); 2072184610Salfred 2073184610Salfred mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 2074184610Salfred mix.nchan = 1; 2075184610Salfred mix.wValue[0] = MAKE_WORD(UA_EXT_ENABLE, 0); 2076184610Salfred uaudio_mixer_determine_class(&iot[id], &mix); 2077184610Salfred mix.type = MIX_ON_OFF; 2078184610Salfred 2079184610Salfred uaudio_mixer_add_ctl(sc, &mix); 2080184610Salfred } 2081184610Salfred} 2082184610Salfred 2083184610Salfredstatic const void * 2084184610Salfreduaudio_mixer_verify_desc(const void *arg, uint32_t len) 2085184610Salfred{ 2086203678Sbrucec const struct usb_audio_mixer_unit_1 *d1; 2087203678Sbrucec const struct usb_audio_extension_unit_1 *e1; 2088203678Sbrucec const struct usb_audio_processing_unit_1 *u1; 2089184610Salfred 2090184610Salfred union { 2091192984Sthompsa const struct usb_descriptor *desc; 2092203678Sbrucec const struct usb_audio_input_terminal *it; 2093203678Sbrucec const struct usb_audio_output_terminal *ot; 2094203678Sbrucec const struct usb_audio_mixer_unit_0 *mu; 2095203678Sbrucec const struct usb_audio_selector_unit *su; 2096203678Sbrucec const struct usb_audio_feature_unit *fu; 2097203678Sbrucec const struct usb_audio_processing_unit_0 *pu; 2098203678Sbrucec const struct usb_audio_extension_unit_0 *eu; 2099184610Salfred } u; 2100184610Salfred 2101184610Salfred u.desc = arg; 2102184610Salfred 2103184610Salfred if (u.desc == NULL) { 2104184610Salfred goto error; 2105184610Salfred } 2106184610Salfred if (u.desc->bDescriptorType != UDESC_CS_INTERFACE) { 2107184610Salfred goto error; 2108184610Salfred } 2109184610Salfred switch (u.desc->bDescriptorSubtype) { 2110184610Salfred case UDESCSUB_AC_INPUT: 2111184610Salfred len += sizeof(*u.it); 2112184610Salfred break; 2113184610Salfred 2114184610Salfred case UDESCSUB_AC_OUTPUT: 2115184610Salfred len += sizeof(*u.ot); 2116184610Salfred break; 2117184610Salfred 2118184610Salfred case UDESCSUB_AC_MIXER: 2119184610Salfred len += sizeof(*u.mu); 2120184610Salfred 2121184610Salfred if (u.desc->bLength < len) { 2122184610Salfred goto error; 2123184610Salfred } 2124184610Salfred len += u.mu->bNrInPins; 2125184610Salfred 2126184610Salfred if (u.desc->bLength < len) { 2127184610Salfred goto error; 2128184610Salfred } 2129184610Salfred d1 = (const void *)(u.mu->baSourceId + u.mu->bNrInPins); 2130184610Salfred 2131184610Salfred len += sizeof(*d1); 2132184610Salfred break; 2133184610Salfred 2134184610Salfred case UDESCSUB_AC_SELECTOR: 2135184610Salfred len += sizeof(*u.su); 2136184610Salfred 2137184610Salfred if (u.desc->bLength < len) { 2138184610Salfred goto error; 2139184610Salfred } 2140184610Salfred len += u.su->bNrInPins; 2141184610Salfred break; 2142184610Salfred 2143184610Salfred case UDESCSUB_AC_FEATURE: 2144184610Salfred len += (sizeof(*u.fu) + 1); 2145184610Salfred break; 2146184610Salfred 2147184610Salfred case UDESCSUB_AC_PROCESSING: 2148184610Salfred len += sizeof(*u.pu); 2149184610Salfred 2150184610Salfred if (u.desc->bLength < len) { 2151184610Salfred goto error; 2152184610Salfred } 2153184610Salfred len += u.pu->bNrInPins; 2154184610Salfred 2155184610Salfred if (u.desc->bLength < len) { 2156184610Salfred goto error; 2157184610Salfred } 2158184610Salfred u1 = (const void *)(u.pu->baSourceId + u.pu->bNrInPins); 2159184610Salfred 2160184610Salfred len += sizeof(*u1); 2161184610Salfred 2162184610Salfred if (u.desc->bLength < len) { 2163184610Salfred goto error; 2164184610Salfred } 2165184610Salfred len += u1->bControlSize; 2166184610Salfred 2167184610Salfred break; 2168184610Salfred 2169184610Salfred case UDESCSUB_AC_EXTENSION: 2170184610Salfred len += sizeof(*u.eu); 2171184610Salfred 2172184610Salfred if (u.desc->bLength < len) { 2173184610Salfred goto error; 2174184610Salfred } 2175184610Salfred len += u.eu->bNrInPins; 2176184610Salfred 2177184610Salfred if (u.desc->bLength < len) { 2178184610Salfred goto error; 2179184610Salfred } 2180184610Salfred e1 = (const void *)(u.eu->baSourceId + u.eu->bNrInPins); 2181184610Salfred 2182184610Salfred len += sizeof(*e1); 2183184610Salfred 2184184610Salfred if (u.desc->bLength < len) { 2185184610Salfred goto error; 2186184610Salfred } 2187184610Salfred len += e1->bControlSize; 2188184610Salfred break; 2189184610Salfred 2190184610Salfred default: 2191184610Salfred goto error; 2192184610Salfred } 2193184610Salfred 2194184610Salfred if (u.desc->bLength < len) { 2195184610Salfred goto error; 2196184610Salfred } 2197184610Salfred return (u.desc); 2198184610Salfred 2199184610Salfrederror: 2200184610Salfred if (u.desc) { 2201184610Salfred DPRINTF("invalid descriptor, type=%d, " 2202184610Salfred "sub_type=%d, len=%d of %d bytes\n", 2203184610Salfred u.desc->bDescriptorType, 2204184610Salfred u.desc->bDescriptorSubtype, 2205184610Salfred u.desc->bLength, len); 2206184610Salfred } 2207184610Salfred return (NULL); 2208184610Salfred} 2209184610Salfred 2210207077Sthompsa#ifdef USB_DEBUG 2211184610Salfredstatic void 2212184610Salfreduaudio_mixer_dump_cluster(uint8_t id, const struct uaudio_terminal_node *iot) 2213184610Salfred{ 2214184610Salfred static const char *channel_names[16] = { 2215184610Salfred "LEFT", "RIGHT", "CENTER", "LFE", 2216184610Salfred "LEFT_SURROUND", "RIGHT_SURROUND", "LEFT_CENTER", "RIGHT_CENTER", 2217184610Salfred "SURROUND", "LEFT_SIDE", "RIGHT_SIDE", "TOP", 2218184610Salfred "RESERVED12", "RESERVED13", "RESERVED14", "RESERVED15", 2219184610Salfred }; 2220184610Salfred uint16_t cc; 2221184610Salfred uint8_t i; 2222203678Sbrucec const struct usb_audio_cluster cl = uaudio_mixer_get_cluster(id, iot); 2223184610Salfred 2224184610Salfred cc = UGETW(cl.wChannelConfig); 2225184610Salfred 2226184610Salfred DPRINTF("cluster: bNrChannels=%u iChannelNames=%u wChannelConfig=" 2227184610Salfred "0x%04x:\n", cl.iChannelNames, cl.bNrChannels, cc); 2228184610Salfred 2229184610Salfred for (i = 0; cc; i++) { 2230184610Salfred if (cc & 1) { 2231184610Salfred DPRINTF(" - %s\n", channel_names[i]); 2232184610Salfred } 2233184610Salfred cc >>= 1; 2234184610Salfred } 2235184610Salfred} 2236184610Salfred 2237184610Salfred#endif 2238184610Salfred 2239203678Sbrucecstatic struct usb_audio_cluster 2240184610Salfreduaudio_mixer_get_cluster(uint8_t id, const struct uaudio_terminal_node *iot) 2241184610Salfred{ 2242203678Sbrucec struct usb_audio_cluster r; 2243192984Sthompsa const struct usb_descriptor *dp; 2244184610Salfred uint8_t i; 2245184610Salfred 2246184610Salfred for (i = 0; i < UAUDIO_RECURSE_LIMIT; i++) { /* avoid infinite loops */ 2247184610Salfred dp = iot[id].u.desc; 2248184610Salfred if (dp == NULL) { 2249184610Salfred goto error; 2250184610Salfred } 2251184610Salfred switch (dp->bDescriptorSubtype) { 2252184610Salfred case UDESCSUB_AC_INPUT: 2253184610Salfred r.bNrChannels = iot[id].u.it->bNrChannels; 2254184610Salfred r.wChannelConfig[0] = iot[id].u.it->wChannelConfig[0]; 2255184610Salfred r.wChannelConfig[1] = iot[id].u.it->wChannelConfig[1]; 2256184610Salfred r.iChannelNames = iot[id].u.it->iChannelNames; 2257184610Salfred goto done; 2258184610Salfred 2259184610Salfred case UDESCSUB_AC_OUTPUT: 2260184610Salfred id = iot[id].u.ot->bSourceId; 2261184610Salfred break; 2262184610Salfred 2263184610Salfred case UDESCSUB_AC_MIXER: 2264203678Sbrucec r = *(const struct usb_audio_cluster *) 2265184610Salfred &iot[id].u.mu->baSourceId[iot[id].u.mu-> 2266184610Salfred bNrInPins]; 2267184610Salfred goto done; 2268184610Salfred 2269184610Salfred case UDESCSUB_AC_SELECTOR: 2270184610Salfred if (iot[id].u.su->bNrInPins > 0) { 2271184610Salfred /* XXX This is not really right */ 2272184610Salfred id = iot[id].u.su->baSourceId[0]; 2273184610Salfred } 2274184610Salfred break; 2275184610Salfred 2276184610Salfred case UDESCSUB_AC_FEATURE: 2277184610Salfred id = iot[id].u.fu->bSourceId; 2278184610Salfred break; 2279184610Salfred 2280184610Salfred case UDESCSUB_AC_PROCESSING: 2281203678Sbrucec r = *((const struct usb_audio_cluster *) 2282184610Salfred &iot[id].u.pu->baSourceId[iot[id].u.pu-> 2283184610Salfred bNrInPins]); 2284184610Salfred goto done; 2285184610Salfred 2286184610Salfred case UDESCSUB_AC_EXTENSION: 2287203678Sbrucec r = *((const struct usb_audio_cluster *) 2288184610Salfred &iot[id].u.eu->baSourceId[iot[id].u.eu-> 2289184610Salfred bNrInPins]); 2290184610Salfred goto done; 2291184610Salfred 2292184610Salfred default: 2293184610Salfred goto error; 2294184610Salfred } 2295184610Salfred } 2296184610Salfrederror: 2297184610Salfred DPRINTF("bad data\n"); 2298184610Salfred bzero(&r, sizeof(r)); 2299184610Salfreddone: 2300184610Salfred return (r); 2301184610Salfred} 2302184610Salfred 2303207077Sthompsa#ifdef USB_DEBUG 2304184610Salfred 2305184610Salfredstruct uaudio_tt_to_string { 2306184610Salfred uint16_t terminal_type; 2307184610Salfred const char *desc; 2308184610Salfred}; 2309184610Salfred 2310184610Salfredstatic const struct uaudio_tt_to_string uaudio_tt_to_string[] = { 2311184610Salfred 2312184610Salfred /* USB terminal types */ 2313184610Salfred {UAT_UNDEFINED, "UAT_UNDEFINED"}, 2314184610Salfred {UAT_STREAM, "UAT_STREAM"}, 2315184610Salfred {UAT_VENDOR, "UAT_VENDOR"}, 2316184610Salfred 2317184610Salfred /* input terminal types */ 2318184610Salfred {UATI_UNDEFINED, "UATI_UNDEFINED"}, 2319184610Salfred {UATI_MICROPHONE, "UATI_MICROPHONE"}, 2320184610Salfred {UATI_DESKMICROPHONE, "UATI_DESKMICROPHONE"}, 2321184610Salfred {UATI_PERSONALMICROPHONE, "UATI_PERSONALMICROPHONE"}, 2322184610Salfred {UATI_OMNIMICROPHONE, "UATI_OMNIMICROPHONE"}, 2323184610Salfred {UATI_MICROPHONEARRAY, "UATI_MICROPHONEARRAY"}, 2324184610Salfred {UATI_PROCMICROPHONEARR, "UATI_PROCMICROPHONEARR"}, 2325184610Salfred 2326184610Salfred /* output terminal types */ 2327184610Salfred {UATO_UNDEFINED, "UATO_UNDEFINED"}, 2328184610Salfred {UATO_SPEAKER, "UATO_SPEAKER"}, 2329184610Salfred {UATO_HEADPHONES, "UATO_HEADPHONES"}, 2330184610Salfred {UATO_DISPLAYAUDIO, "UATO_DISPLAYAUDIO"}, 2331184610Salfred {UATO_DESKTOPSPEAKER, "UATO_DESKTOPSPEAKER"}, 2332184610Salfred {UATO_ROOMSPEAKER, "UATO_ROOMSPEAKER"}, 2333184610Salfred {UATO_COMMSPEAKER, "UATO_COMMSPEAKER"}, 2334184610Salfred {UATO_SUBWOOFER, "UATO_SUBWOOFER"}, 2335184610Salfred 2336184610Salfred /* bidir terminal types */ 2337184610Salfred {UATB_UNDEFINED, "UATB_UNDEFINED"}, 2338184610Salfred {UATB_HANDSET, "UATB_HANDSET"}, 2339184610Salfred {UATB_HEADSET, "UATB_HEADSET"}, 2340184610Salfred {UATB_SPEAKERPHONE, "UATB_SPEAKERPHONE"}, 2341184610Salfred {UATB_SPEAKERPHONEESUP, "UATB_SPEAKERPHONEESUP"}, 2342184610Salfred {UATB_SPEAKERPHONEECANC, "UATB_SPEAKERPHONEECANC"}, 2343184610Salfred 2344184610Salfred /* telephony terminal types */ 2345184610Salfred {UATT_UNDEFINED, "UATT_UNDEFINED"}, 2346184610Salfred {UATT_PHONELINE, "UATT_PHONELINE"}, 2347184610Salfred {UATT_TELEPHONE, "UATT_TELEPHONE"}, 2348184610Salfred {UATT_DOWNLINEPHONE, "UATT_DOWNLINEPHONE"}, 2349184610Salfred 2350184610Salfred /* external terminal types */ 2351184610Salfred {UATE_UNDEFINED, "UATE_UNDEFINED"}, 2352184610Salfred {UATE_ANALOGCONN, "UATE_ANALOGCONN"}, 2353184610Salfred {UATE_LINECONN, "UATE_LINECONN"}, 2354184610Salfred {UATE_LEGACYCONN, "UATE_LEGACYCONN"}, 2355184610Salfred {UATE_DIGITALAUIFC, "UATE_DIGITALAUIFC"}, 2356184610Salfred {UATE_SPDIF, "UATE_SPDIF"}, 2357184610Salfred {UATE_1394DA, "UATE_1394DA"}, 2358184610Salfred {UATE_1394DV, "UATE_1394DV"}, 2359184610Salfred 2360184610Salfred /* embedded function terminal types */ 2361184610Salfred {UATF_UNDEFINED, "UATF_UNDEFINED"}, 2362184610Salfred {UATF_CALIBNOISE, "UATF_CALIBNOISE"}, 2363184610Salfred {UATF_EQUNOISE, "UATF_EQUNOISE"}, 2364184610Salfred {UATF_CDPLAYER, "UATF_CDPLAYER"}, 2365184610Salfred {UATF_DAT, "UATF_DAT"}, 2366184610Salfred {UATF_DCC, "UATF_DCC"}, 2367184610Salfred {UATF_MINIDISK, "UATF_MINIDISK"}, 2368184610Salfred {UATF_ANALOGTAPE, "UATF_ANALOGTAPE"}, 2369184610Salfred {UATF_PHONOGRAPH, "UATF_PHONOGRAPH"}, 2370184610Salfred {UATF_VCRAUDIO, "UATF_VCRAUDIO"}, 2371184610Salfred {UATF_VIDEODISCAUDIO, "UATF_VIDEODISCAUDIO"}, 2372184610Salfred {UATF_DVDAUDIO, "UATF_DVDAUDIO"}, 2373184610Salfred {UATF_TVTUNERAUDIO, "UATF_TVTUNERAUDIO"}, 2374184610Salfred {UATF_SATELLITE, "UATF_SATELLITE"}, 2375184610Salfred {UATF_CABLETUNER, "UATF_CABLETUNER"}, 2376184610Salfred {UATF_DSS, "UATF_DSS"}, 2377184610Salfred {UATF_RADIORECV, "UATF_RADIORECV"}, 2378184610Salfred {UATF_RADIOXMIT, "UATF_RADIOXMIT"}, 2379184610Salfred {UATF_MULTITRACK, "UATF_MULTITRACK"}, 2380184610Salfred {UATF_SYNTHESIZER, "UATF_SYNTHESIZER"}, 2381184610Salfred 2382184610Salfred /* unknown */ 2383184610Salfred {0x0000, "UNKNOWN"}, 2384184610Salfred}; 2385184610Salfred 2386184610Salfredstatic const char * 2387184610Salfreduaudio_mixer_get_terminal_name(uint16_t terminal_type) 2388184610Salfred{ 2389184610Salfred const struct uaudio_tt_to_string *uat = uaudio_tt_to_string; 2390184610Salfred 2391184610Salfred while (uat->terminal_type) { 2392184610Salfred if (uat->terminal_type == terminal_type) { 2393184610Salfred break; 2394184610Salfred } 2395184610Salfred uat++; 2396184610Salfred } 2397184610Salfred if (uat->terminal_type == 0) { 2398184610Salfred DPRINTF("unknown terminal type (0x%04x)", terminal_type); 2399184610Salfred } 2400184610Salfred return (uat->desc); 2401184610Salfred} 2402184610Salfred 2403184610Salfred#endif 2404184610Salfred 2405184610Salfredstatic uint16_t 2406184610Salfreduaudio_mixer_determine_class(const struct uaudio_terminal_node *iot, 2407184610Salfred struct uaudio_mixer_node *mix) 2408184610Salfred{ 2409184610Salfred uint16_t terminal_type = 0x0000; 2410184610Salfred const struct uaudio_terminal_node *input[2]; 2411184610Salfred const struct uaudio_terminal_node *output[2]; 2412184610Salfred 2413184610Salfred input[0] = uaudio_mixer_get_input(iot, 0); 2414184610Salfred input[1] = uaudio_mixer_get_input(iot, 1); 2415184610Salfred 2416184610Salfred output[0] = uaudio_mixer_get_output(iot, 0); 2417184610Salfred output[1] = uaudio_mixer_get_output(iot, 1); 2418184610Salfred 2419184610Salfred /* 2420184610Salfred * check if there is only 2421184610Salfred * one output terminal: 2422184610Salfred */ 2423184610Salfred if (output[0] && (!output[1])) { 2424184610Salfred terminal_type = UGETW(output[0]->u.ot->wTerminalType); 2425184610Salfred } 2426184610Salfred /* 2427184610Salfred * If the only output terminal is USB, 2428184610Salfred * the class is UAC_RECORD. 2429184610Salfred */ 2430184610Salfred if ((terminal_type & 0xff00) == (UAT_UNDEFINED & 0xff00)) { 2431184610Salfred 2432184610Salfred mix->class = UAC_RECORD; 2433184610Salfred if (input[0] && (!input[1])) { 2434184610Salfred terminal_type = UGETW(input[0]->u.it->wTerminalType); 2435184610Salfred } else { 2436184610Salfred terminal_type = 0; 2437184610Salfred } 2438184610Salfred goto done; 2439184610Salfred } 2440184610Salfred /* 2441184610Salfred * if the unit is connected to just 2442184610Salfred * one input terminal, the 2443184610Salfred * class is UAC_INPUT: 2444184610Salfred */ 2445184610Salfred if (input[0] && (!input[1])) { 2446184610Salfred mix->class = UAC_INPUT; 2447184610Salfred terminal_type = UGETW(input[0]->u.it->wTerminalType); 2448184610Salfred goto done; 2449184610Salfred } 2450184610Salfred /* 2451184610Salfred * Otherwise, the class is UAC_OUTPUT. 2452184610Salfred */ 2453184610Salfred mix->class = UAC_OUTPUT; 2454184610Salfreddone: 2455184610Salfred return (terminal_type); 2456184610Salfred} 2457184610Salfred 2458184610Salfredstruct uaudio_tt_to_feature { 2459184610Salfred uint16_t terminal_type; 2460184610Salfred uint16_t feature; 2461184610Salfred}; 2462184610Salfred 2463184610Salfredstatic const struct uaudio_tt_to_feature uaudio_tt_to_feature[] = { 2464184610Salfred 2465184610Salfred {UAT_STREAM, SOUND_MIXER_PCM}, 2466184610Salfred 2467184610Salfred {UATI_MICROPHONE, SOUND_MIXER_MIC}, 2468184610Salfred {UATI_DESKMICROPHONE, SOUND_MIXER_MIC}, 2469184610Salfred {UATI_PERSONALMICROPHONE, SOUND_MIXER_MIC}, 2470184610Salfred {UATI_OMNIMICROPHONE, SOUND_MIXER_MIC}, 2471184610Salfred {UATI_MICROPHONEARRAY, SOUND_MIXER_MIC}, 2472184610Salfred {UATI_PROCMICROPHONEARR, SOUND_MIXER_MIC}, 2473184610Salfred 2474184610Salfred {UATO_SPEAKER, SOUND_MIXER_SPEAKER}, 2475184610Salfred {UATO_DESKTOPSPEAKER, SOUND_MIXER_SPEAKER}, 2476184610Salfred {UATO_ROOMSPEAKER, SOUND_MIXER_SPEAKER}, 2477184610Salfred {UATO_COMMSPEAKER, SOUND_MIXER_SPEAKER}, 2478184610Salfred 2479184610Salfred {UATE_ANALOGCONN, SOUND_MIXER_LINE}, 2480184610Salfred {UATE_LINECONN, SOUND_MIXER_LINE}, 2481184610Salfred {UATE_LEGACYCONN, SOUND_MIXER_LINE}, 2482184610Salfred 2483184610Salfred {UATE_DIGITALAUIFC, SOUND_MIXER_ALTPCM}, 2484184610Salfred {UATE_SPDIF, SOUND_MIXER_ALTPCM}, 2485184610Salfred {UATE_1394DA, SOUND_MIXER_ALTPCM}, 2486184610Salfred {UATE_1394DV, SOUND_MIXER_ALTPCM}, 2487184610Salfred 2488184610Salfred {UATF_CDPLAYER, SOUND_MIXER_CD}, 2489184610Salfred 2490184610Salfred {UATF_SYNTHESIZER, SOUND_MIXER_SYNTH}, 2491184610Salfred 2492184610Salfred {UATF_VIDEODISCAUDIO, SOUND_MIXER_VIDEO}, 2493184610Salfred {UATF_DVDAUDIO, SOUND_MIXER_VIDEO}, 2494184610Salfred {UATF_TVTUNERAUDIO, SOUND_MIXER_VIDEO}, 2495184610Salfred 2496184610Salfred /* telephony terminal types */ 2497184610Salfred {UATT_UNDEFINED, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 2498184610Salfred {UATT_PHONELINE, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 2499184610Salfred {UATT_TELEPHONE, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 2500184610Salfred {UATT_DOWNLINEPHONE, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 2501184610Salfred 2502184610Salfred {UATF_RADIORECV, SOUND_MIXER_RADIO}, 2503184610Salfred {UATF_RADIOXMIT, SOUND_MIXER_RADIO}, 2504184610Salfred 2505184610Salfred {UAT_UNDEFINED, SOUND_MIXER_VOLUME}, 2506184610Salfred {UAT_VENDOR, SOUND_MIXER_VOLUME}, 2507184610Salfred {UATI_UNDEFINED, SOUND_MIXER_VOLUME}, 2508184610Salfred 2509184610Salfred /* output terminal types */ 2510184610Salfred {UATO_UNDEFINED, SOUND_MIXER_VOLUME}, 2511184610Salfred {UATO_DISPLAYAUDIO, SOUND_MIXER_VOLUME}, 2512184610Salfred {UATO_SUBWOOFER, SOUND_MIXER_VOLUME}, 2513184610Salfred {UATO_HEADPHONES, SOUND_MIXER_VOLUME}, 2514184610Salfred 2515184610Salfred /* bidir terminal types */ 2516184610Salfred {UATB_UNDEFINED, SOUND_MIXER_VOLUME}, 2517184610Salfred {UATB_HANDSET, SOUND_MIXER_VOLUME}, 2518184610Salfred {UATB_HEADSET, SOUND_MIXER_VOLUME}, 2519184610Salfred {UATB_SPEAKERPHONE, SOUND_MIXER_VOLUME}, 2520184610Salfred {UATB_SPEAKERPHONEESUP, SOUND_MIXER_VOLUME}, 2521184610Salfred {UATB_SPEAKERPHONEECANC, SOUND_MIXER_VOLUME}, 2522184610Salfred 2523184610Salfred /* external terminal types */ 2524184610Salfred {UATE_UNDEFINED, SOUND_MIXER_VOLUME}, 2525184610Salfred 2526184610Salfred /* embedded function terminal types */ 2527184610Salfred {UATF_UNDEFINED, SOUND_MIXER_VOLUME}, 2528184610Salfred {UATF_CALIBNOISE, SOUND_MIXER_VOLUME}, 2529184610Salfred {UATF_EQUNOISE, SOUND_MIXER_VOLUME}, 2530184610Salfred {UATF_DAT, SOUND_MIXER_VOLUME}, 2531184610Salfred {UATF_DCC, SOUND_MIXER_VOLUME}, 2532184610Salfred {UATF_MINIDISK, SOUND_MIXER_VOLUME}, 2533184610Salfred {UATF_ANALOGTAPE, SOUND_MIXER_VOLUME}, 2534184610Salfred {UATF_PHONOGRAPH, SOUND_MIXER_VOLUME}, 2535184610Salfred {UATF_VCRAUDIO, SOUND_MIXER_VOLUME}, 2536184610Salfred {UATF_SATELLITE, SOUND_MIXER_VOLUME}, 2537184610Salfred {UATF_CABLETUNER, SOUND_MIXER_VOLUME}, 2538184610Salfred {UATF_DSS, SOUND_MIXER_VOLUME}, 2539184610Salfred {UATF_MULTITRACK, SOUND_MIXER_VOLUME}, 2540184610Salfred {0xffff, SOUND_MIXER_VOLUME}, 2541184610Salfred 2542184610Salfred /* default */ 2543184610Salfred {0x0000, SOUND_MIXER_VOLUME}, 2544184610Salfred}; 2545184610Salfred 2546184610Salfredstatic uint16_t 2547184610Salfreduaudio_mixer_feature_name(const struct uaudio_terminal_node *iot, 2548184610Salfred struct uaudio_mixer_node *mix) 2549184610Salfred{ 2550184610Salfred const struct uaudio_tt_to_feature *uat = uaudio_tt_to_feature; 2551184610Salfred uint16_t terminal_type = uaudio_mixer_determine_class(iot, mix); 2552184610Salfred 2553184610Salfred if ((mix->class == UAC_RECORD) && (terminal_type == 0)) { 2554184610Salfred return (SOUND_MIXER_IMIX); 2555184610Salfred } 2556184610Salfred while (uat->terminal_type) { 2557184610Salfred if (uat->terminal_type == terminal_type) { 2558184610Salfred break; 2559184610Salfred } 2560184610Salfred uat++; 2561184610Salfred } 2562184610Salfred 2563184610Salfred DPRINTF("terminal_type=%s (0x%04x) -> %d\n", 2564184610Salfred uaudio_mixer_get_terminal_name(terminal_type), 2565184610Salfred terminal_type, uat->feature); 2566184610Salfred 2567184610Salfred return (uat->feature); 2568184610Salfred} 2569184610Salfred 2570184610Salfredconst static struct uaudio_terminal_node * 2571184610Salfreduaudio_mixer_get_input(const struct uaudio_terminal_node *iot, uint8_t index) 2572184610Salfred{ 2573184610Salfred struct uaudio_terminal_node *root = iot->root; 2574184610Salfred uint8_t n; 2575184610Salfred 2576184610Salfred n = iot->usr.id_max; 2577184610Salfred do { 2578184610Salfred if (iot->usr.bit_input[n / 8] & (1 << (n % 8))) { 2579184610Salfred if (!index--) { 2580184610Salfred return (root + n); 2581184610Salfred } 2582184610Salfred } 2583184610Salfred } while (n--); 2584184610Salfred 2585184610Salfred return (NULL); 2586184610Salfred} 2587184610Salfred 2588184610Salfredconst static struct uaudio_terminal_node * 2589184610Salfreduaudio_mixer_get_output(const struct uaudio_terminal_node *iot, uint8_t index) 2590184610Salfred{ 2591184610Salfred struct uaudio_terminal_node *root = iot->root; 2592184610Salfred uint8_t n; 2593184610Salfred 2594184610Salfred n = iot->usr.id_max; 2595184610Salfred do { 2596184610Salfred if (iot->usr.bit_output[n / 8] & (1 << (n % 8))) { 2597184610Salfred if (!index--) { 2598184610Salfred return (root + n); 2599184610Salfred } 2600184610Salfred } 2601184610Salfred } while (n--); 2602184610Salfred 2603184610Salfred return (NULL); 2604184610Salfred} 2605184610Salfred 2606184610Salfredstatic void 2607184610Salfreduaudio_mixer_find_inputs_sub(struct uaudio_terminal_node *root, 2608184610Salfred const uint8_t *p_id, uint8_t n_id, 2609184610Salfred struct uaudio_search_result *info) 2610184610Salfred{ 2611184610Salfred struct uaudio_terminal_node *iot; 2612184610Salfred uint8_t n; 2613184610Salfred uint8_t i; 2614184610Salfred 2615184610Salfred if (info->recurse_level >= UAUDIO_RECURSE_LIMIT) { 2616184610Salfred return; 2617184610Salfred } 2618184610Salfred info->recurse_level++; 2619184610Salfred 2620184610Salfred for (n = 0; n < n_id; n++) { 2621184610Salfred 2622184610Salfred i = p_id[n]; 2623184610Salfred 2624184610Salfred if (info->bit_visited[i / 8] & (1 << (i % 8))) { 2625184610Salfred /* don't go into a circle */ 2626184610Salfred DPRINTF("avoided going into a circle at id=%d!\n", i); 2627184610Salfred continue; 2628184610Salfred } else { 2629184610Salfred info->bit_visited[i / 8] |= (1 << (i % 8)); 2630184610Salfred } 2631184610Salfred 2632184610Salfred iot = (root + i); 2633184610Salfred 2634184610Salfred if (iot->u.desc == NULL) { 2635184610Salfred continue; 2636184610Salfred } 2637184610Salfred switch (iot->u.desc->bDescriptorSubtype) { 2638184610Salfred case UDESCSUB_AC_INPUT: 2639184610Salfred info->bit_input[i / 8] |= (1 << (i % 8)); 2640184610Salfred break; 2641184610Salfred 2642184610Salfred case UDESCSUB_AC_FEATURE: 2643184610Salfred uaudio_mixer_find_inputs_sub 2644184610Salfred (root, &iot->u.fu->bSourceId, 1, info); 2645184610Salfred break; 2646184610Salfred 2647184610Salfred case UDESCSUB_AC_OUTPUT: 2648184610Salfred uaudio_mixer_find_inputs_sub 2649184610Salfred (root, &iot->u.ot->bSourceId, 1, info); 2650184610Salfred break; 2651184610Salfred 2652184610Salfred case UDESCSUB_AC_MIXER: 2653184610Salfred uaudio_mixer_find_inputs_sub 2654184610Salfred (root, iot->u.mu->baSourceId, 2655184610Salfred iot->u.mu->bNrInPins, info); 2656184610Salfred break; 2657184610Salfred 2658184610Salfred case UDESCSUB_AC_SELECTOR: 2659184610Salfred uaudio_mixer_find_inputs_sub 2660184610Salfred (root, iot->u.su->baSourceId, 2661184610Salfred iot->u.su->bNrInPins, info); 2662184610Salfred break; 2663184610Salfred 2664184610Salfred case UDESCSUB_AC_PROCESSING: 2665184610Salfred uaudio_mixer_find_inputs_sub 2666184610Salfred (root, iot->u.pu->baSourceId, 2667184610Salfred iot->u.pu->bNrInPins, info); 2668184610Salfred break; 2669184610Salfred 2670184610Salfred case UDESCSUB_AC_EXTENSION: 2671184610Salfred uaudio_mixer_find_inputs_sub 2672184610Salfred (root, iot->u.eu->baSourceId, 2673184610Salfred iot->u.eu->bNrInPins, info); 2674184610Salfred break; 2675184610Salfred 2676184610Salfred case UDESCSUB_AC_HEADER: 2677184610Salfred default: 2678184610Salfred break; 2679184610Salfred } 2680184610Salfred } 2681184610Salfred info->recurse_level--; 2682184610Salfred} 2683184610Salfred 2684184610Salfredstatic void 2685184610Salfreduaudio_mixer_find_outputs_sub(struct uaudio_terminal_node *root, uint8_t id, 2686184610Salfred uint8_t n_id, struct uaudio_search_result *info) 2687184610Salfred{ 2688184610Salfred struct uaudio_terminal_node *iot = (root + id); 2689184610Salfred uint8_t j; 2690184610Salfred 2691184610Salfred j = n_id; 2692184610Salfred do { 2693184610Salfred if ((j != id) && ((root + j)->u.desc) && 2694184610Salfred ((root + j)->u.desc->bDescriptorSubtype == UDESCSUB_AC_OUTPUT)) { 2695184610Salfred 2696184610Salfred /* 2697184610Salfred * "j" (output) <--- virtual wire <--- "id" (input) 2698184610Salfred * 2699184610Salfred * if "j" has "id" on the input, then "id" have "j" on 2700184610Salfred * the output, because they are connected: 2701184610Salfred */ 2702184610Salfred if ((root + j)->usr.bit_input[id / 8] & (1 << (id % 8))) { 2703184610Salfred iot->usr.bit_output[j / 8] |= (1 << (j % 8)); 2704184610Salfred } 2705184610Salfred } 2706184610Salfred } while (j--); 2707184610Salfred} 2708184610Salfred 2709184610Salfredstatic void 2710192984Sthompsauaudio_mixer_fill_info(struct uaudio_softc *sc, struct usb_device *udev, 2711184610Salfred void *desc) 2712184610Salfred{ 2713203678Sbrucec const struct usb_audio_control_descriptor *acdp; 2714194228Sthompsa struct usb_config_descriptor *cd = usbd_get_config_descriptor(udev); 2715192984Sthompsa const struct usb_descriptor *dp; 2716203678Sbrucec const struct usb_audio_unit *au; 2717184610Salfred struct uaudio_terminal_node *iot = NULL; 2718184610Salfred uint16_t wTotalLen; 2719184610Salfred uint8_t ID_max = 0; /* inclusive */ 2720184610Salfred uint8_t i; 2721184610Salfred 2722194228Sthompsa desc = usb_desc_foreach(cd, desc); 2723184610Salfred 2724184610Salfred if (desc == NULL) { 2725184610Salfred DPRINTF("no Audio Control header\n"); 2726184610Salfred goto done; 2727184610Salfred } 2728184610Salfred acdp = desc; 2729184610Salfred 2730184610Salfred if ((acdp->bLength < sizeof(*acdp)) || 2731184610Salfred (acdp->bDescriptorType != UDESC_CS_INTERFACE) || 2732184610Salfred (acdp->bDescriptorSubtype != UDESCSUB_AC_HEADER)) { 2733184610Salfred DPRINTF("invalid Audio Control header\n"); 2734184610Salfred goto done; 2735184610Salfred } 2736186730Salfred /* "wTotalLen" is allowed to be corrupt */ 2737186730Salfred wTotalLen = UGETW(acdp->wTotalLength) - acdp->bLength; 2738186730Salfred 2739186730Salfred /* get USB audio revision */ 2740184610Salfred sc->sc_audio_rev = UGETW(acdp->bcdADC); 2741184610Salfred 2742184610Salfred DPRINTFN(3, "found AC header, vers=%03x, len=%d\n", 2743184610Salfred sc->sc_audio_rev, wTotalLen); 2744184610Salfred 2745184610Salfred if (sc->sc_audio_rev != UAUDIO_VERSION) { 2746184610Salfred 2747184610Salfred if (sc->sc_uq_bad_adc) { 2748184610Salfred 2749184610Salfred } else { 2750184610Salfred DPRINTF("invalid audio version\n"); 2751184610Salfred goto done; 2752184610Salfred } 2753184610Salfred } 2754184610Salfred iot = malloc(sizeof(struct uaudio_terminal_node) * 256, M_TEMP, 2755184610Salfred M_WAITOK | M_ZERO); 2756184610Salfred 2757184610Salfred if (iot == NULL) { 2758184610Salfred DPRINTF("no memory!\n"); 2759184610Salfred goto done; 2760184610Salfred } 2761194228Sthompsa while ((desc = usb_desc_foreach(cd, desc))) { 2762184610Salfred 2763184610Salfred dp = desc; 2764184610Salfred 2765184610Salfred if (dp->bLength > wTotalLen) { 2766184610Salfred break; 2767184610Salfred } else { 2768184610Salfred wTotalLen -= dp->bLength; 2769184610Salfred } 2770184610Salfred 2771184610Salfred au = uaudio_mixer_verify_desc(dp, 0); 2772184610Salfred 2773184610Salfred if (au) { 2774184610Salfred iot[au->bUnitId].u.desc = (const void *)au; 2775184610Salfred if (au->bUnitId > ID_max) { 2776184610Salfred ID_max = au->bUnitId; 2777184610Salfred } 2778184610Salfred } 2779184610Salfred } 2780184610Salfred 2781184610Salfred DPRINTF("Maximum ID=%d\n", ID_max); 2782184610Salfred 2783184610Salfred /* 2784184610Salfred * determine sourcing inputs for 2785184610Salfred * all nodes in the tree: 2786184610Salfred */ 2787184610Salfred i = ID_max; 2788184610Salfred do { 2789184610Salfred uaudio_mixer_find_inputs_sub(iot, &i, 1, &((iot + i)->usr)); 2790184610Salfred } while (i--); 2791184610Salfred 2792184610Salfred /* 2793184610Salfred * determine outputs for 2794184610Salfred * all nodes in the tree: 2795184610Salfred */ 2796184610Salfred i = ID_max; 2797184610Salfred do { 2798184610Salfred uaudio_mixer_find_outputs_sub(iot, i, ID_max, &((iot + i)->usr)); 2799184610Salfred } while (i--); 2800184610Salfred 2801184610Salfred /* set "id_max" and "root" */ 2802184610Salfred 2803184610Salfred i = ID_max; 2804184610Salfred do { 2805184610Salfred (iot + i)->usr.id_max = ID_max; 2806184610Salfred (iot + i)->root = iot; 2807184610Salfred } while (i--); 2808184610Salfred 2809207077Sthompsa#ifdef USB_DEBUG 2810184610Salfred i = ID_max; 2811184610Salfred do { 2812184610Salfred uint8_t j; 2813184610Salfred 2814184610Salfred if (iot[i].u.desc == NULL) { 2815184610Salfred continue; 2816184610Salfred } 2817184610Salfred DPRINTF("id %d:\n", i); 2818184610Salfred 2819184610Salfred switch (iot[i].u.desc->bDescriptorSubtype) { 2820184610Salfred case UDESCSUB_AC_INPUT: 2821184610Salfred DPRINTF(" - AC_INPUT type=%s\n", 2822184610Salfred uaudio_mixer_get_terminal_name 2823184610Salfred (UGETW(iot[i].u.it->wTerminalType))); 2824184610Salfred uaudio_mixer_dump_cluster(i, iot); 2825184610Salfred break; 2826184610Salfred 2827184610Salfred case UDESCSUB_AC_OUTPUT: 2828184610Salfred DPRINTF(" - AC_OUTPUT type=%s " 2829184610Salfred "src=%d\n", uaudio_mixer_get_terminal_name 2830184610Salfred (UGETW(iot[i].u.ot->wTerminalType)), 2831184610Salfred iot[i].u.ot->bSourceId); 2832184610Salfred break; 2833184610Salfred 2834184610Salfred case UDESCSUB_AC_MIXER: 2835184610Salfred DPRINTF(" - AC_MIXER src:\n"); 2836184610Salfred for (j = 0; j < iot[i].u.mu->bNrInPins; j++) { 2837184610Salfred DPRINTF(" - %d\n", iot[i].u.mu->baSourceId[j]); 2838184610Salfred } 2839184610Salfred uaudio_mixer_dump_cluster(i, iot); 2840184610Salfred break; 2841184610Salfred 2842184610Salfred case UDESCSUB_AC_SELECTOR: 2843184610Salfred DPRINTF(" - AC_SELECTOR src:\n"); 2844184610Salfred for (j = 0; j < iot[i].u.su->bNrInPins; j++) { 2845184610Salfred DPRINTF(" - %d\n", iot[i].u.su->baSourceId[j]); 2846184610Salfred } 2847184610Salfred break; 2848184610Salfred 2849184610Salfred case UDESCSUB_AC_FEATURE: 2850184610Salfred DPRINTF(" - AC_FEATURE src=%d\n", iot[i].u.fu->bSourceId); 2851184610Salfred break; 2852184610Salfred 2853184610Salfred case UDESCSUB_AC_PROCESSING: 2854184610Salfred DPRINTF(" - AC_PROCESSING src:\n"); 2855184610Salfred for (j = 0; j < iot[i].u.pu->bNrInPins; j++) { 2856184610Salfred DPRINTF(" - %d\n", iot[i].u.pu->baSourceId[j]); 2857184610Salfred } 2858184610Salfred uaudio_mixer_dump_cluster(i, iot); 2859184610Salfred break; 2860184610Salfred 2861184610Salfred case UDESCSUB_AC_EXTENSION: 2862184610Salfred DPRINTF(" - AC_EXTENSION src:\n"); 2863184610Salfred for (j = 0; j < iot[i].u.eu->bNrInPins; j++) { 2864184610Salfred DPRINTF("%d ", iot[i].u.eu->baSourceId[j]); 2865184610Salfred } 2866184610Salfred uaudio_mixer_dump_cluster(i, iot); 2867184610Salfred break; 2868184610Salfred 2869184610Salfred default: 2870184610Salfred DPRINTF("unknown audio control (subtype=%d)\n", 2871184610Salfred iot[i].u.desc->bDescriptorSubtype); 2872184610Salfred } 2873184610Salfred 2874184610Salfred DPRINTF("Inputs to this ID are:\n"); 2875184610Salfred 2876184610Salfred j = ID_max; 2877184610Salfred do { 2878184610Salfred if (iot[i].usr.bit_input[j / 8] & (1 << (j % 8))) { 2879184610Salfred DPRINTF(" -- ID=%d\n", j); 2880184610Salfred } 2881184610Salfred } while (j--); 2882184610Salfred 2883184610Salfred DPRINTF("Outputs from this ID are:\n"); 2884184610Salfred 2885184610Salfred j = ID_max; 2886184610Salfred do { 2887184610Salfred if (iot[i].usr.bit_output[j / 8] & (1 << (j % 8))) { 2888184610Salfred DPRINTF(" -- ID=%d\n", j); 2889184610Salfred } 2890184610Salfred } while (j--); 2891184610Salfred 2892184610Salfred } while (i--); 2893184610Salfred#endif 2894184610Salfred 2895184610Salfred /* 2896184610Salfred * scan the config to create a linked 2897184610Salfred * list of "mixer" nodes: 2898184610Salfred */ 2899184610Salfred 2900184610Salfred i = ID_max; 2901184610Salfred do { 2902184610Salfred dp = iot[i].u.desc; 2903184610Salfred 2904184610Salfred if (dp == NULL) { 2905184610Salfred continue; 2906184610Salfred } 2907184610Salfred DPRINTFN(11, "id=%d subtype=%d\n", 2908184610Salfred i, dp->bDescriptorSubtype); 2909184610Salfred 2910184610Salfred switch (dp->bDescriptorSubtype) { 2911184610Salfred case UDESCSUB_AC_HEADER: 2912184610Salfred DPRINTF("unexpected AC header\n"); 2913184610Salfred break; 2914184610Salfred 2915184610Salfred case UDESCSUB_AC_INPUT: 2916184610Salfred uaudio_mixer_add_input(sc, iot, i); 2917184610Salfred break; 2918184610Salfred 2919184610Salfred case UDESCSUB_AC_OUTPUT: 2920184610Salfred uaudio_mixer_add_output(sc, iot, i); 2921184610Salfred break; 2922184610Salfred 2923184610Salfred case UDESCSUB_AC_MIXER: 2924184610Salfred uaudio_mixer_add_mixer(sc, iot, i); 2925184610Salfred break; 2926184610Salfred 2927184610Salfred case UDESCSUB_AC_SELECTOR: 2928184610Salfred uaudio_mixer_add_selector(sc, iot, i); 2929184610Salfred break; 2930184610Salfred 2931184610Salfred case UDESCSUB_AC_FEATURE: 2932184610Salfred uaudio_mixer_add_feature(sc, iot, i); 2933184610Salfred break; 2934184610Salfred 2935184610Salfred case UDESCSUB_AC_PROCESSING: 2936184610Salfred uaudio_mixer_add_processing(sc, iot, i); 2937184610Salfred break; 2938184610Salfred 2939184610Salfred case UDESCSUB_AC_EXTENSION: 2940184610Salfred uaudio_mixer_add_extension(sc, iot, i); 2941184610Salfred break; 2942184610Salfred 2943184610Salfred default: 2944184610Salfred DPRINTF("bad AC desc subtype=0x%02x\n", 2945184610Salfred dp->bDescriptorSubtype); 2946184610Salfred break; 2947184610Salfred } 2948184610Salfred 2949184610Salfred } while (i--); 2950184610Salfred 2951184610Salfreddone: 2952184610Salfred if (iot) { 2953184610Salfred free(iot, M_TEMP); 2954184610Salfred } 2955184610Salfred} 2956184610Salfred 2957184610Salfredstatic uint16_t 2958192984Sthompsauaudio_mixer_get(struct usb_device *udev, uint8_t what, 2959184610Salfred struct uaudio_mixer_node *mc) 2960184610Salfred{ 2961192984Sthompsa struct usb_device_request req; 2962184610Salfred uint16_t val; 2963184610Salfred uint16_t len = MIX_SIZE(mc->type); 2964184610Salfred uint8_t data[4]; 2965193045Sthompsa usb_error_t err; 2966184610Salfred 2967184610Salfred if (mc->wValue[0] == -1) { 2968184610Salfred return (0); 2969184610Salfred } 2970184610Salfred req.bmRequestType = UT_READ_CLASS_INTERFACE; 2971184610Salfred req.bRequest = what; 2972184610Salfred USETW(req.wValue, mc->wValue[0]); 2973184610Salfred USETW(req.wIndex, mc->wIndex); 2974184610Salfred USETW(req.wLength, len); 2975184610Salfred 2976196487Salfred err = usbd_do_request(udev, NULL, &req, data); 2977184610Salfred if (err) { 2978194228Sthompsa DPRINTF("err=%s\n", usbd_errstr(err)); 2979184610Salfred return (0); 2980184610Salfred } 2981184610Salfred if (len < 1) { 2982184610Salfred data[0] = 0; 2983184610Salfred } 2984184610Salfred if (len < 2) { 2985184610Salfred data[1] = 0; 2986184610Salfred } 2987184610Salfred val = (data[0] | (data[1] << 8)); 2988184610Salfred 2989184610Salfred DPRINTFN(3, "val=%d\n", val); 2990184610Salfred 2991184610Salfred return (val); 2992184610Salfred} 2993184610Salfred 2994184610Salfredstatic void 2995194677Sthompsauaudio_mixer_write_cfg_callback(struct usb_xfer *xfer, usb_error_t error) 2996184610Salfred{ 2997192984Sthompsa struct usb_device_request req; 2998194677Sthompsa struct uaudio_softc *sc = usbd_xfer_softc(xfer); 2999184610Salfred struct uaudio_mixer_node *mc = sc->sc_mixer_curr; 3000194677Sthompsa struct usb_page_cache *pc; 3001184610Salfred uint16_t len; 3002184610Salfred uint8_t repeat = 1; 3003184610Salfred uint8_t update; 3004184610Salfred uint8_t chan; 3005184610Salfred uint8_t buf[2]; 3006184610Salfred 3007187165Sthompsa DPRINTF("\n"); 3008187165Sthompsa 3009184610Salfred switch (USB_GET_STATE(xfer)) { 3010184610Salfred case USB_ST_TRANSFERRED: 3011184610Salfredtr_transferred: 3012184610Salfred case USB_ST_SETUP: 3013184610Salfredtr_setup: 3014184610Salfred 3015184610Salfred if (mc == NULL) { 3016184610Salfred mc = sc->sc_mixer_root; 3017184610Salfred sc->sc_mixer_curr = mc; 3018184610Salfred sc->sc_mixer_chan = 0; 3019184610Salfred repeat = 0; 3020184610Salfred } 3021184610Salfred while (mc) { 3022184610Salfred while (sc->sc_mixer_chan < mc->nchan) { 3023184610Salfred 3024184610Salfred len = MIX_SIZE(mc->type); 3025184610Salfred 3026184610Salfred chan = sc->sc_mixer_chan; 3027184610Salfred 3028184610Salfred sc->sc_mixer_chan++; 3029184610Salfred 3030184610Salfred update = ((mc->update[chan / 8] & (1 << (chan % 8))) && 3031184610Salfred (mc->wValue[chan] != -1)); 3032184610Salfred 3033184610Salfred mc->update[chan / 8] &= ~(1 << (chan % 8)); 3034184610Salfred 3035184610Salfred if (update) { 3036184610Salfred 3037184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 3038184610Salfred req.bRequest = SET_CUR; 3039184610Salfred USETW(req.wValue, mc->wValue[chan]); 3040184610Salfred USETW(req.wIndex, mc->wIndex); 3041184610Salfred USETW(req.wLength, len); 3042184610Salfred 3043184610Salfred if (len > 0) { 3044184610Salfred buf[0] = (mc->wData[chan] & 0xFF); 3045184610Salfred } 3046184610Salfred if (len > 1) { 3047184610Salfred buf[1] = (mc->wData[chan] >> 8) & 0xFF; 3048184610Salfred } 3049194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 3050194677Sthompsa usbd_copy_in(pc, 0, &req, sizeof(req)); 3051194677Sthompsa pc = usbd_xfer_get_frame(xfer, 1); 3052194677Sthompsa usbd_copy_in(pc, 0, buf, len); 3053184610Salfred 3054194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 3055194677Sthompsa usbd_xfer_set_frame_len(xfer, 1, len); 3056194677Sthompsa usbd_xfer_set_frames(xfer, len ? 2 : 1); 3057194228Sthompsa usbd_transfer_submit(xfer); 3058184610Salfred return; 3059184610Salfred } 3060184610Salfred } 3061184610Salfred 3062184610Salfred mc = mc->next; 3063184610Salfred sc->sc_mixer_curr = mc; 3064184610Salfred sc->sc_mixer_chan = 0; 3065184610Salfred } 3066184610Salfred 3067184610Salfred if (repeat) { 3068184610Salfred goto tr_setup; 3069184610Salfred } 3070187165Sthompsa break; 3071184610Salfred 3072184610Salfred default: /* Error */ 3073194677Sthompsa DPRINTF("error=%s\n", usbd_errstr(error)); 3074194677Sthompsa if (error == USB_ERR_CANCELLED) { 3075187165Sthompsa /* do nothing - we are detaching */ 3076187165Sthompsa break; 3077187165Sthompsa } 3078184610Salfred goto tr_transferred; 3079184610Salfred } 3080184610Salfred} 3081184610Salfred 3082193045Sthompsastatic usb_error_t 3083192984Sthompsauaudio_set_speed(struct usb_device *udev, uint8_t endpt, uint32_t speed) 3084184610Salfred{ 3085192984Sthompsa struct usb_device_request req; 3086184610Salfred uint8_t data[3]; 3087184610Salfred 3088184610Salfred DPRINTFN(6, "endpt=%d speed=%u\n", endpt, speed); 3089184610Salfred 3090184610Salfred req.bmRequestType = UT_WRITE_CLASS_ENDPOINT; 3091184610Salfred req.bRequest = SET_CUR; 3092184610Salfred USETW2(req.wValue, SAMPLING_FREQ_CONTROL, 0); 3093184610Salfred USETW(req.wIndex, endpt); 3094184610Salfred USETW(req.wLength, 3); 3095184610Salfred data[0] = speed; 3096184610Salfred data[1] = speed >> 8; 3097184610Salfred data[2] = speed >> 16; 3098184610Salfred 3099196487Salfred return (usbd_do_request(udev, NULL, &req, data)); 3100184610Salfred} 3101184610Salfred 3102184610Salfredstatic int 3103184610Salfreduaudio_mixer_signext(uint8_t type, int val) 3104184610Salfred{ 3105184610Salfred if (!MIX_UNSIGNED(type)) { 3106184610Salfred if (MIX_SIZE(type) == 2) { 3107184610Salfred val = (int16_t)val; 3108184610Salfred } else { 3109184610Salfred val = (int8_t)val; 3110184610Salfred } 3111184610Salfred } 3112184610Salfred return (val); 3113184610Salfred} 3114184610Salfred 3115184610Salfredstatic int 3116184610Salfreduaudio_mixer_bsd2value(struct uaudio_mixer_node *mc, int32_t val) 3117184610Salfred{ 3118184610Salfred if (mc->type == MIX_ON_OFF) { 3119184610Salfred val = (val != 0); 3120184610Salfred } else if (mc->type == MIX_SELECTOR) { 3121184610Salfred if ((val < mc->minval) || 3122184610Salfred (val > mc->maxval)) { 3123184610Salfred val = mc->minval; 3124184610Salfred } 3125184610Salfred } else { 3126199060Sthompsa 3127199060Sthompsa /* compute actual volume */ 3128199060Sthompsa val = (val * mc->mul) / 255; 3129199060Sthompsa 3130199060Sthompsa /* add lower offset */ 3131199060Sthompsa val = val + mc->minval; 3132199060Sthompsa 3133199060Sthompsa /* make sure we don't write a value out of range */ 3134199060Sthompsa if (val > mc->maxval) 3135199060Sthompsa val = mc->maxval; 3136199060Sthompsa else if (val < mc->minval) 3137199060Sthompsa val = mc->minval; 3138184610Salfred } 3139184610Salfred 3140185087Salfred DPRINTFN(6, "type=0x%03x val=%d min=%d max=%d val=%d\n", 3141185087Salfred mc->type, val, mc->minval, mc->maxval, val); 3142184610Salfred return (val); 3143184610Salfred} 3144184610Salfred 3145184610Salfredstatic void 3146184610Salfreduaudio_mixer_ctl_set(struct uaudio_softc *sc, struct uaudio_mixer_node *mc, 3147184610Salfred uint8_t chan, int32_t val) 3148184610Salfred{ 3149184610Salfred val = uaudio_mixer_bsd2value(mc, val); 3150184610Salfred 3151184610Salfred mc->update[chan / 8] |= (1 << (chan % 8)); 3152184610Salfred mc->wData[chan] = val; 3153184610Salfred 3154184610Salfred /* start the transfer, if not already started */ 3155184610Salfred 3156194228Sthompsa usbd_transfer_start(sc->sc_mixer_xfer[0]); 3157184610Salfred} 3158184610Salfred 3159184610Salfredstatic void 3160184610Salfreduaudio_mixer_init(struct uaudio_softc *sc) 3161184610Salfred{ 3162184610Salfred struct uaudio_mixer_node *mc; 3163184610Salfred int32_t i; 3164184610Salfred 3165184610Salfred for (mc = sc->sc_mixer_root; mc; 3166184610Salfred mc = mc->next) { 3167184610Salfred 3168184610Salfred if (mc->ctl != SOUND_MIXER_NRDEVICES) { 3169184610Salfred /* 3170184610Salfred * Set device mask bits. See 3171184610Salfred * /usr/include/machine/soundcard.h 3172184610Salfred */ 3173184610Salfred sc->sc_mix_info |= (1 << mc->ctl); 3174184610Salfred } 3175184610Salfred if ((mc->ctl == SOUND_MIXER_NRDEVICES) && 3176184610Salfred (mc->type == MIX_SELECTOR)) { 3177184610Salfred 3178184610Salfred for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { 3179184610Salfred if (mc->slctrtype[i - 1] == SOUND_MIXER_NRDEVICES) { 3180184610Salfred continue; 3181184610Salfred } 3182184610Salfred sc->sc_recsrc_info |= 1 << mc->slctrtype[i - 1]; 3183184610Salfred } 3184184610Salfred } 3185184610Salfred } 3186184610Salfred} 3187184610Salfred 3188184610Salfredint 3189184610Salfreduaudio_mixer_init_sub(struct uaudio_softc *sc, struct snd_mixer *m) 3190184610Salfred{ 3191184610Salfred DPRINTF("\n"); 3192184610Salfred 3193194228Sthompsa if (usbd_transfer_setup(sc->sc_udev, &sc->sc_mixer_iface_index, 3194184610Salfred sc->sc_mixer_xfer, uaudio_mixer_config, 1, sc, 3195184610Salfred mixer_get_lock(m))) { 3196184610Salfred DPRINTFN(0, "could not allocate USB " 3197184610Salfred "transfer for audio mixer!\n"); 3198184610Salfred return (ENOMEM); 3199184610Salfred } 3200184610Salfred if (!(sc->sc_mix_info & SOUND_MASK_VOLUME)) { 3201184610Salfred mix_setparentchild(m, SOUND_MIXER_VOLUME, SOUND_MASK_PCM); 3202184610Salfred mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE); 3203184610Salfred } 3204184610Salfred mix_setdevs(m, sc->sc_mix_info); 3205184610Salfred mix_setrecdevs(m, sc->sc_recsrc_info); 3206184610Salfred return (0); 3207184610Salfred} 3208184610Salfred 3209184610Salfredint 3210184610Salfreduaudio_mixer_uninit_sub(struct uaudio_softc *sc) 3211184610Salfred{ 3212184610Salfred DPRINTF("\n"); 3213184610Salfred 3214194228Sthompsa usbd_transfer_unsetup(sc->sc_mixer_xfer, 1); 3215184610Salfred 3216184610Salfred return (0); 3217184610Salfred} 3218184610Salfred 3219184610Salfredvoid 3220184610Salfreduaudio_mixer_set(struct uaudio_softc *sc, unsigned type, 3221184610Salfred unsigned left, unsigned right) 3222184610Salfred{ 3223184610Salfred struct uaudio_mixer_node *mc; 3224184610Salfred 3225184610Salfred for (mc = sc->sc_mixer_root; mc; 3226184610Salfred mc = mc->next) { 3227184610Salfred 3228184610Salfred if (mc->ctl == type) { 3229184610Salfred if (mc->nchan == 2) { 3230184610Salfred /* set Right */ 3231184610Salfred uaudio_mixer_ctl_set(sc, mc, 1, (int)(right * 255) / 100); 3232184610Salfred } 3233184610Salfred /* set Left or Mono */ 3234184610Salfred uaudio_mixer_ctl_set(sc, mc, 0, (int)(left * 255) / 100); 3235184610Salfred } 3236184610Salfred } 3237184610Salfred} 3238184610Salfred 3239184610Salfreduint32_t 3240184610Salfreduaudio_mixer_setrecsrc(struct uaudio_softc *sc, uint32_t src) 3241184610Salfred{ 3242184610Salfred struct uaudio_mixer_node *mc; 3243184610Salfred uint32_t mask; 3244184610Salfred uint32_t temp; 3245184610Salfred int32_t i; 3246184610Salfred 3247184610Salfred for (mc = sc->sc_mixer_root; mc; 3248184610Salfred mc = mc->next) { 3249184610Salfred 3250184610Salfred if ((mc->ctl == SOUND_MIXER_NRDEVICES) && 3251184610Salfred (mc->type == MIX_SELECTOR)) { 3252184610Salfred 3253184610Salfred /* compute selector mask */ 3254184610Salfred 3255184610Salfred mask = 0; 3256184610Salfred for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { 3257184610Salfred mask |= (1 << mc->slctrtype[i - 1]); 3258184610Salfred } 3259184610Salfred 3260184610Salfred temp = mask & src; 3261184610Salfred if (temp == 0) { 3262184610Salfred continue; 3263184610Salfred } 3264184610Salfred /* find the first set bit */ 3265184610Salfred temp = (-temp) & temp; 3266184610Salfred 3267184610Salfred /* update "src" */ 3268184610Salfred src &= ~mask; 3269184610Salfred src |= temp; 3270184610Salfred 3271184610Salfred for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { 3272184610Salfred if (temp != (1 << mc->slctrtype[i - 1])) { 3273184610Salfred continue; 3274184610Salfred } 3275184610Salfred uaudio_mixer_ctl_set(sc, mc, 0, i); 3276184610Salfred break; 3277184610Salfred } 3278184610Salfred } 3279184610Salfred } 3280184610Salfred return (src); 3281184610Salfred} 3282184610Salfred 3283184610Salfred/*========================================================================* 3284184610Salfred * MIDI support routines 3285184610Salfred *========================================================================*/ 3286184610Salfred 3287184610Salfredstatic void 3288194677Sthompsaumidi_read_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error) 3289184610Salfred{ 3290194677Sthompsa struct umidi_chan *chan = usbd_xfer_softc(xfer); 3291192984Sthompsa struct usb_xfer *xfer_other = chan->xfer[1]; 3292184610Salfred 3293194228Sthompsa if (usbd_clear_stall_callback(xfer, xfer_other)) { 3294184610Salfred DPRINTF("stall cleared\n"); 3295184610Salfred chan->flags &= ~UMIDI_FLAG_READ_STALL; 3296194228Sthompsa usbd_transfer_start(xfer_other); 3297184610Salfred } 3298184610Salfred} 3299184610Salfred 3300184610Salfredstatic void 3301194677Sthompsaumidi_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 3302184610Salfred{ 3303194677Sthompsa struct umidi_chan *chan = usbd_xfer_softc(xfer); 3304184610Salfred struct umidi_sub_chan *sub; 3305194677Sthompsa struct usb_page_cache *pc; 3306184610Salfred uint8_t buf[1]; 3307184610Salfred uint8_t cmd_len; 3308184610Salfred uint8_t cn; 3309184610Salfred uint16_t pos; 3310194677Sthompsa int actlen; 3311184610Salfred 3312194677Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 3313194677Sthompsa 3314184610Salfred switch (USB_GET_STATE(xfer)) { 3315184610Salfred case USB_ST_TRANSFERRED: 3316184610Salfred 3317194677Sthompsa DPRINTF("actlen=%d bytes\n", actlen); 3318184610Salfred 3319184610Salfred pos = 0; 3320194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 3321184610Salfred 3322194677Sthompsa while (actlen >= 4) { 3323184610Salfred 3324194677Sthompsa usbd_copy_out(pc, pos, buf, 1); 3325184610Salfred 3326184610Salfred cmd_len = umidi_cmd_to_len[buf[0] & 0xF]; /* command length */ 3327184610Salfred cn = buf[0] >> 4; /* cable number */ 3328184610Salfred sub = &chan->sub[cn]; 3329184610Salfred 3330184610Salfred if (cmd_len && (cn < chan->max_cable) && sub->read_open) { 3331194677Sthompsa usb_fifo_put_data(sub->fifo.fp[USB_FIFO_RX], pc, 3332184610Salfred pos + 1, cmd_len, 1); 3333184610Salfred } else { 3334184610Salfred /* ignore the command */ 3335184610Salfred } 3336184610Salfred 3337194677Sthompsa actlen -= 4; 3338184610Salfred pos += 4; 3339184610Salfred } 3340184610Salfred 3341184610Salfred case USB_ST_SETUP: 3342184610Salfred DPRINTF("start\n"); 3343184610Salfred 3344184610Salfred if (chan->flags & UMIDI_FLAG_READ_STALL) { 3345194228Sthompsa usbd_transfer_start(chan->xfer[3]); 3346184610Salfred return; 3347184610Salfred } 3348194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 3349194228Sthompsa usbd_transfer_submit(xfer); 3350184610Salfred return; 3351184610Salfred 3352184610Salfred default: 3353194677Sthompsa DPRINTF("error=%s\n", usbd_errstr(error)); 3354184610Salfred 3355194677Sthompsa if (error != USB_ERR_CANCELLED) { 3356184610Salfred /* try to clear stall first */ 3357184610Salfred chan->flags |= UMIDI_FLAG_READ_STALL; 3358194228Sthompsa usbd_transfer_start(chan->xfer[3]); 3359184610Salfred } 3360184610Salfred return; 3361184610Salfred 3362184610Salfred } 3363184610Salfred} 3364184610Salfred 3365184610Salfredstatic void 3366194677Sthompsaumidi_write_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error) 3367184610Salfred{ 3368194677Sthompsa struct umidi_chan *chan = usbd_xfer_softc(xfer); 3369192984Sthompsa struct usb_xfer *xfer_other = chan->xfer[0]; 3370184610Salfred 3371194228Sthompsa if (usbd_clear_stall_callback(xfer, xfer_other)) { 3372184610Salfred DPRINTF("stall cleared\n"); 3373184610Salfred chan->flags &= ~UMIDI_FLAG_WRITE_STALL; 3374194228Sthompsa usbd_transfer_start(xfer_other); 3375184610Salfred } 3376184610Salfred} 3377184610Salfred 3378184610Salfred/* 3379184610Salfred * The following statemachine, that converts MIDI commands to 3380184610Salfred * USB MIDI packets, derives from Linux's usbmidi.c, which 3381184610Salfred * was written by "Clemens Ladisch": 3382184610Salfred * 3383184610Salfred * Returns: 3384184610Salfred * 0: No command 3385184610Salfred * Else: Command is complete 3386184610Salfred */ 3387184610Salfredstatic uint8_t 3388184610Salfredumidi_convert_to_usb(struct umidi_sub_chan *sub, uint8_t cn, uint8_t b) 3389184610Salfred{ 3390184610Salfred uint8_t p0 = (cn << 4); 3391184610Salfred 3392184610Salfred if (b >= 0xf8) { 3393184610Salfred sub->temp_0[0] = p0 | 0x0f; 3394184610Salfred sub->temp_0[1] = b; 3395184610Salfred sub->temp_0[2] = 0; 3396184610Salfred sub->temp_0[3] = 0; 3397184610Salfred sub->temp_cmd = sub->temp_0; 3398184610Salfred return (1); 3399184610Salfred 3400184610Salfred } else if (b >= 0xf0) { 3401184610Salfred switch (b) { 3402184610Salfred case 0xf0: /* system exclusive begin */ 3403184610Salfred sub->temp_1[1] = b; 3404184610Salfred sub->state = UMIDI_ST_SYSEX_1; 3405184610Salfred break; 3406184610Salfred case 0xf1: /* MIDI time code */ 3407184610Salfred case 0xf3: /* song select */ 3408184610Salfred sub->temp_1[1] = b; 3409184610Salfred sub->state = UMIDI_ST_1PARAM; 3410184610Salfred break; 3411184610Salfred case 0xf2: /* song position pointer */ 3412184610Salfred sub->temp_1[1] = b; 3413184610Salfred sub->state = UMIDI_ST_2PARAM_1; 3414184610Salfred break; 3415184610Salfred case 0xf4: /* unknown */ 3416184610Salfred case 0xf5: /* unknown */ 3417184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3418184610Salfred break; 3419184610Salfred case 0xf6: /* tune request */ 3420184610Salfred sub->temp_1[0] = p0 | 0x05; 3421184610Salfred sub->temp_1[1] = 0xf6; 3422184610Salfred sub->temp_1[2] = 0; 3423184610Salfred sub->temp_1[3] = 0; 3424184610Salfred sub->temp_cmd = sub->temp_1; 3425184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3426184610Salfred return (1); 3427184610Salfred 3428184610Salfred case 0xf7: /* system exclusive end */ 3429184610Salfred switch (sub->state) { 3430184610Salfred case UMIDI_ST_SYSEX_0: 3431184610Salfred sub->temp_1[0] = p0 | 0x05; 3432184610Salfred sub->temp_1[1] = 0xf7; 3433184610Salfred sub->temp_1[2] = 0; 3434184610Salfred sub->temp_1[3] = 0; 3435184610Salfred sub->temp_cmd = sub->temp_1; 3436184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3437184610Salfred return (1); 3438184610Salfred case UMIDI_ST_SYSEX_1: 3439184610Salfred sub->temp_1[0] = p0 | 0x06; 3440184610Salfred sub->temp_1[2] = 0xf7; 3441184610Salfred sub->temp_1[3] = 0; 3442184610Salfred sub->temp_cmd = sub->temp_1; 3443184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3444184610Salfred return (1); 3445184610Salfred case UMIDI_ST_SYSEX_2: 3446184610Salfred sub->temp_1[0] = p0 | 0x07; 3447184610Salfred sub->temp_1[3] = 0xf7; 3448184610Salfred sub->temp_cmd = sub->temp_1; 3449184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3450184610Salfred return (1); 3451184610Salfred } 3452184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3453184610Salfred break; 3454184610Salfred } 3455184610Salfred } else if (b >= 0x80) { 3456184610Salfred sub->temp_1[1] = b; 3457184610Salfred if ((b >= 0xc0) && (b <= 0xdf)) { 3458184610Salfred sub->state = UMIDI_ST_1PARAM; 3459184610Salfred } else { 3460184610Salfred sub->state = UMIDI_ST_2PARAM_1; 3461184610Salfred } 3462184610Salfred } else { /* b < 0x80 */ 3463184610Salfred switch (sub->state) { 3464184610Salfred case UMIDI_ST_1PARAM: 3465184610Salfred if (sub->temp_1[1] < 0xf0) { 3466184610Salfred p0 |= sub->temp_1[1] >> 4; 3467184610Salfred } else { 3468184610Salfred p0 |= 0x02; 3469184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3470184610Salfred } 3471184610Salfred sub->temp_1[0] = p0; 3472184610Salfred sub->temp_1[2] = b; 3473184610Salfred sub->temp_1[3] = 0; 3474184610Salfred sub->temp_cmd = sub->temp_1; 3475184610Salfred return (1); 3476184610Salfred case UMIDI_ST_2PARAM_1: 3477184610Salfred sub->temp_1[2] = b; 3478184610Salfred sub->state = UMIDI_ST_2PARAM_2; 3479184610Salfred break; 3480184610Salfred case UMIDI_ST_2PARAM_2: 3481184610Salfred if (sub->temp_1[1] < 0xf0) { 3482184610Salfred p0 |= sub->temp_1[1] >> 4; 3483184610Salfred sub->state = UMIDI_ST_2PARAM_1; 3484184610Salfred } else { 3485184610Salfred p0 |= 0x03; 3486184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3487184610Salfred } 3488184610Salfred sub->temp_1[0] = p0; 3489184610Salfred sub->temp_1[3] = b; 3490184610Salfred sub->temp_cmd = sub->temp_1; 3491184610Salfred return (1); 3492184610Salfred case UMIDI_ST_SYSEX_0: 3493184610Salfred sub->temp_1[1] = b; 3494184610Salfred sub->state = UMIDI_ST_SYSEX_1; 3495184610Salfred break; 3496184610Salfred case UMIDI_ST_SYSEX_1: 3497184610Salfred sub->temp_1[2] = b; 3498184610Salfred sub->state = UMIDI_ST_SYSEX_2; 3499184610Salfred break; 3500184610Salfred case UMIDI_ST_SYSEX_2: 3501184610Salfred sub->temp_1[0] = p0 | 0x04; 3502184610Salfred sub->temp_1[3] = b; 3503184610Salfred sub->temp_cmd = sub->temp_1; 3504184610Salfred sub->state = UMIDI_ST_SYSEX_0; 3505184610Salfred return (1); 3506184610Salfred } 3507184610Salfred } 3508184610Salfred return (0); 3509184610Salfred} 3510184610Salfred 3511184610Salfredstatic void 3512194677Sthompsaumidi_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 3513184610Salfred{ 3514194677Sthompsa struct umidi_chan *chan = usbd_xfer_softc(xfer); 3515184610Salfred struct umidi_sub_chan *sub; 3516194677Sthompsa struct usb_page_cache *pc; 3517184610Salfred uint32_t actlen; 3518184610Salfred uint16_t total_length; 3519184610Salfred uint8_t buf; 3520184610Salfred uint8_t start_cable; 3521184610Salfred uint8_t tr_any; 3522194677Sthompsa int len; 3523184610Salfred 3524194677Sthompsa usbd_xfer_status(xfer, &len, NULL, NULL, NULL); 3525194677Sthompsa 3526184610Salfred switch (USB_GET_STATE(xfer)) { 3527184610Salfred case USB_ST_TRANSFERRED: 3528194677Sthompsa DPRINTF("actlen=%d bytes\n", len); 3529184610Salfred 3530184610Salfred case USB_ST_SETUP: 3531184610Salfred 3532184610Salfred DPRINTF("start\n"); 3533184610Salfred 3534184610Salfred if (chan->flags & UMIDI_FLAG_WRITE_STALL) { 3535194228Sthompsa usbd_transfer_start(chan->xfer[2]); 3536184610Salfred return; 3537184610Salfred } 3538184610Salfred total_length = 0; /* reset */ 3539184610Salfred start_cable = chan->curr_cable; 3540184610Salfred tr_any = 0; 3541194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 3542184610Salfred 3543184610Salfred while (1) { 3544184610Salfred 3545184610Salfred /* round robin de-queueing */ 3546184610Salfred 3547184610Salfred sub = &chan->sub[chan->curr_cable]; 3548184610Salfred 3549184610Salfred if (sub->write_open) { 3550194228Sthompsa usb_fifo_get_data(sub->fifo.fp[USB_FIFO_TX], 3551194677Sthompsa pc, total_length, 1, &actlen, 0); 3552184610Salfred } else { 3553184610Salfred actlen = 0; 3554184610Salfred } 3555184610Salfred 3556184610Salfred if (actlen) { 3557194677Sthompsa usbd_copy_out(pc, total_length, &buf, 1); 3558184610Salfred 3559184610Salfred tr_any = 1; 3560184610Salfred 3561184610Salfred DPRINTF("byte=0x%02x\n", buf); 3562184610Salfred 3563184610Salfred if (umidi_convert_to_usb(sub, chan->curr_cable, buf)) { 3564184610Salfred 3565184610Salfred DPRINTF("sub= %02x %02x %02x %02x\n", 3566184610Salfred sub->temp_cmd[0], sub->temp_cmd[1], 3567184610Salfred sub->temp_cmd[2], sub->temp_cmd[3]); 3568184610Salfred 3569194677Sthompsa usbd_copy_in(pc, total_length, 3570184610Salfred sub->temp_cmd, 4); 3571184610Salfred 3572184610Salfred total_length += 4; 3573184610Salfred 3574184610Salfred if (total_length >= UMIDI_BULK_SIZE) { 3575184610Salfred break; 3576184610Salfred } 3577184610Salfred } else { 3578184610Salfred continue; 3579184610Salfred } 3580184610Salfred } 3581184610Salfred chan->curr_cable++; 3582184610Salfred if (chan->curr_cable >= chan->max_cable) { 3583184610Salfred chan->curr_cable = 0; 3584184610Salfred } 3585184610Salfred if (chan->curr_cable == start_cable) { 3586184610Salfred if (tr_any == 0) { 3587184610Salfred break; 3588184610Salfred } 3589184610Salfred tr_any = 0; 3590184610Salfred } 3591184610Salfred } 3592184610Salfred 3593184610Salfred if (total_length) { 3594194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, total_length); 3595194228Sthompsa usbd_transfer_submit(xfer); 3596184610Salfred } 3597184610Salfred return; 3598184610Salfred 3599184610Salfred default: /* Error */ 3600184610Salfred 3601194677Sthompsa DPRINTF("error=%s\n", usbd_errstr(error)); 3602184610Salfred 3603194677Sthompsa if (error != USB_ERR_CANCELLED) { 3604184610Salfred /* try to clear stall first */ 3605184610Salfred chan->flags |= UMIDI_FLAG_WRITE_STALL; 3606194228Sthompsa usbd_transfer_start(chan->xfer[2]); 3607184610Salfred } 3608184610Salfred return; 3609184610Salfred 3610184610Salfred } 3611184610Salfred} 3612184610Salfred 3613184610Salfredstatic struct umidi_sub_chan * 3614192984Sthompsaumidi_sub_by_fifo(struct usb_fifo *fifo) 3615184610Salfred{ 3616194677Sthompsa struct umidi_chan *chan = usb_fifo_softc(fifo); 3617184610Salfred struct umidi_sub_chan *sub; 3618184610Salfred uint32_t n; 3619184610Salfred 3620184610Salfred for (n = 0; n < UMIDI_CABLES_MAX; n++) { 3621184610Salfred sub = &chan->sub[n]; 3622184610Salfred if ((sub->fifo.fp[USB_FIFO_RX] == fifo) || 3623184610Salfred (sub->fifo.fp[USB_FIFO_TX] == fifo)) { 3624184610Salfred return (sub); 3625184610Salfred } 3626184610Salfred } 3627184610Salfred 3628192984Sthompsa panic("%s:%d cannot find usb_fifo!\n", 3629184610Salfred __FILE__, __LINE__); 3630184610Salfred 3631184610Salfred return (NULL); 3632184610Salfred} 3633184610Salfred 3634184610Salfredstatic void 3635192984Sthompsaumidi_start_read(struct usb_fifo *fifo) 3636184610Salfred{ 3637194677Sthompsa struct umidi_chan *chan = usb_fifo_softc(fifo); 3638184610Salfred 3639194228Sthompsa usbd_transfer_start(chan->xfer[1]); 3640184610Salfred} 3641184610Salfred 3642184610Salfredstatic void 3643192984Sthompsaumidi_stop_read(struct usb_fifo *fifo) 3644184610Salfred{ 3645194677Sthompsa struct umidi_chan *chan = usb_fifo_softc(fifo); 3646184610Salfred struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo); 3647184610Salfred 3648184610Salfred DPRINTF("\n"); 3649184610Salfred 3650184610Salfred sub->read_open = 0; 3651184610Salfred 3652184610Salfred if (--(chan->read_open_refcount) == 0) { 3653184610Salfred /* 3654184610Salfred * XXX don't stop the read transfer here, hence that causes 3655184610Salfred * problems with some MIDI adapters 3656184610Salfred */ 3657184610Salfred DPRINTF("(stopping read transfer)\n"); 3658184610Salfred } 3659184610Salfred} 3660184610Salfred 3661184610Salfredstatic void 3662192984Sthompsaumidi_start_write(struct usb_fifo *fifo) 3663184610Salfred{ 3664194677Sthompsa struct umidi_chan *chan = usb_fifo_softc(fifo); 3665184610Salfred 3666194228Sthompsa usbd_transfer_start(chan->xfer[0]); 3667184610Salfred} 3668184610Salfred 3669184610Salfredstatic void 3670192984Sthompsaumidi_stop_write(struct usb_fifo *fifo) 3671184610Salfred{ 3672194677Sthompsa struct umidi_chan *chan = usb_fifo_softc(fifo); 3673184610Salfred struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo); 3674184610Salfred 3675184610Salfred DPRINTF("\n"); 3676184610Salfred 3677184610Salfred sub->write_open = 0; 3678184610Salfred 3679184610Salfred if (--(chan->write_open_refcount) == 0) { 3680184610Salfred DPRINTF("(stopping write transfer)\n"); 3681194228Sthompsa usbd_transfer_stop(chan->xfer[2]); 3682194228Sthompsa usbd_transfer_stop(chan->xfer[0]); 3683184610Salfred } 3684184610Salfred} 3685184610Salfred 3686184610Salfredstatic int 3687192984Sthompsaumidi_open(struct usb_fifo *fifo, int fflags) 3688184610Salfred{ 3689194677Sthompsa struct umidi_chan *chan = usb_fifo_softc(fifo); 3690184610Salfred struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo); 3691184610Salfred 3692184610Salfred if (fflags & FREAD) { 3693194228Sthompsa if (usb_fifo_alloc_buffer(fifo, 4, (1024 / 4))) { 3694184610Salfred return (ENOMEM); 3695184610Salfred } 3696195120Sthompsa mtx_lock(&chan->mtx); 3697184610Salfred chan->read_open_refcount++; 3698184610Salfred sub->read_open = 1; 3699195120Sthompsa mtx_unlock(&chan->mtx); 3700184610Salfred } 3701184610Salfred if (fflags & FWRITE) { 3702194228Sthompsa if (usb_fifo_alloc_buffer(fifo, 32, (1024 / 32))) { 3703184610Salfred return (ENOMEM); 3704184610Salfred } 3705184610Salfred /* clear stall first */ 3706195120Sthompsa mtx_lock(&chan->mtx); 3707184610Salfred chan->flags |= UMIDI_FLAG_WRITE_STALL; 3708184610Salfred chan->write_open_refcount++; 3709184610Salfred sub->write_open = 1; 3710184610Salfred 3711184610Salfred /* reset */ 3712184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3713195120Sthompsa mtx_unlock(&chan->mtx); 3714184610Salfred } 3715184610Salfred return (0); /* success */ 3716184610Salfred} 3717184610Salfred 3718184610Salfredstatic void 3719192984Sthompsaumidi_close(struct usb_fifo *fifo, int fflags) 3720184610Salfred{ 3721184610Salfred if (fflags & FREAD) { 3722194228Sthompsa usb_fifo_free_buffer(fifo); 3723184610Salfred } 3724184610Salfred if (fflags & FWRITE) { 3725194228Sthompsa usb_fifo_free_buffer(fifo); 3726184610Salfred } 3727184610Salfred} 3728184610Salfred 3729184610Salfred 3730184610Salfredstatic int 3731192984Sthompsaumidi_ioctl(struct usb_fifo *fifo, u_long cmd, void *data, 3732189110Sthompsa int fflags) 3733184610Salfred{ 3734184610Salfred return (ENODEV); 3735184610Salfred} 3736184610Salfred 3737184610Salfredstatic void 3738184610Salfredumidi_init(device_t dev) 3739184610Salfred{ 3740184610Salfred struct uaudio_softc *sc = device_get_softc(dev); 3741184610Salfred struct umidi_chan *chan = &sc->sc_midi_chan; 3742184610Salfred 3743184610Salfred mtx_init(&chan->mtx, "umidi lock", NULL, MTX_DEF | MTX_RECURSE); 3744184610Salfred} 3745184610Salfred 3746192984Sthompsastatic struct usb_fifo_methods umidi_fifo_methods = { 3747184610Salfred .f_start_read = &umidi_start_read, 3748184610Salfred .f_start_write = &umidi_start_write, 3749184610Salfred .f_stop_read = &umidi_stop_read, 3750184610Salfred .f_stop_write = &umidi_stop_write, 3751184610Salfred .f_open = &umidi_open, 3752184610Salfred .f_close = &umidi_close, 3753184610Salfred .f_ioctl = &umidi_ioctl, 3754184610Salfred .basename[0] = "umidi", 3755184610Salfred}; 3756184610Salfred 3757184610Salfredstatic int32_t 3758184610Salfredumidi_probe(device_t dev) 3759184610Salfred{ 3760184610Salfred struct uaudio_softc *sc = device_get_softc(dev); 3761192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 3762184610Salfred struct umidi_chan *chan = &sc->sc_midi_chan; 3763184610Salfred struct umidi_sub_chan *sub; 3764184610Salfred int unit = device_get_unit(dev); 3765184610Salfred int error; 3766184610Salfred uint32_t n; 3767184610Salfred 3768194228Sthompsa if (usbd_set_alt_interface_index(sc->sc_udev, chan->iface_index, 3769184610Salfred chan->iface_alt_index)) { 3770184610Salfred DPRINTF("setting of alternate index failed!\n"); 3771184610Salfred goto detach; 3772184610Salfred } 3773194228Sthompsa usbd_set_parent_iface(sc->sc_udev, chan->iface_index, sc->sc_mixer_iface_index); 3774184610Salfred 3775194228Sthompsa error = usbd_transfer_setup(uaa->device, &chan->iface_index, 3776184610Salfred chan->xfer, umidi_config, UMIDI_N_TRANSFER, 3777184610Salfred chan, &chan->mtx); 3778184610Salfred if (error) { 3779194228Sthompsa DPRINTF("error=%s\n", usbd_errstr(error)); 3780184610Salfred goto detach; 3781184610Salfred } 3782184610Salfred if ((chan->max_cable > UMIDI_CABLES_MAX) || 3783184610Salfred (chan->max_cable == 0)) { 3784184610Salfred chan->max_cable = UMIDI_CABLES_MAX; 3785184610Salfred } 3786184610Salfred 3787184610Salfred for (n = 0; n < chan->max_cable; n++) { 3788184610Salfred 3789184610Salfred sub = &chan->sub[n]; 3790184610Salfred 3791194228Sthompsa error = usb_fifo_attach(sc->sc_udev, chan, &chan->mtx, 3792184610Salfred &umidi_fifo_methods, &sub->fifo, unit, n, 3793189110Sthompsa chan->iface_index, 3794189110Sthompsa UID_ROOT, GID_OPERATOR, 0644); 3795184610Salfred if (error) { 3796184610Salfred goto detach; 3797184610Salfred } 3798184610Salfred } 3799184610Salfred 3800184610Salfred mtx_lock(&chan->mtx); 3801184610Salfred 3802184610Salfred /* clear stall first */ 3803184610Salfred chan->flags |= UMIDI_FLAG_READ_STALL; 3804184610Salfred 3805184610Salfred /* 3806184610Salfred * NOTE: at least one device will not work properly unless 3807184610Salfred * the BULK pipe is open all the time. 3808184610Salfred */ 3809194228Sthompsa usbd_transfer_start(chan->xfer[1]); 3810184610Salfred 3811184610Salfred mtx_unlock(&chan->mtx); 3812184610Salfred 3813184610Salfred return (0); /* success */ 3814184610Salfred 3815184610Salfreddetach: 3816184610Salfred return (ENXIO); /* failure */ 3817184610Salfred} 3818184610Salfred 3819184610Salfredstatic int32_t 3820184610Salfredumidi_detach(device_t dev) 3821184610Salfred{ 3822184610Salfred struct uaudio_softc *sc = device_get_softc(dev); 3823184610Salfred struct umidi_chan *chan = &sc->sc_midi_chan; 3824184610Salfred uint32_t n; 3825184610Salfred 3826184610Salfred for (n = 0; n < UMIDI_CABLES_MAX; n++) { 3827194228Sthompsa usb_fifo_detach(&chan->sub[n].fifo); 3828184610Salfred } 3829184610Salfred 3830184610Salfred mtx_lock(&chan->mtx); 3831184610Salfred 3832194228Sthompsa usbd_transfer_stop(chan->xfer[3]); 3833194228Sthompsa usbd_transfer_stop(chan->xfer[1]); 3834184610Salfred 3835184610Salfred mtx_unlock(&chan->mtx); 3836184610Salfred 3837194228Sthompsa usbd_transfer_unsetup(chan->xfer, UMIDI_N_TRANSFER); 3838184610Salfred 3839184610Salfred mtx_destroy(&chan->mtx); 3840184610Salfred 3841184610Salfred return (0); 3842184610Salfred} 3843184610Salfred 3844189275SthompsaDRIVER_MODULE(uaudio, uhub, uaudio_driver, uaudio_devclass, NULL, 0); 3845188942SthompsaMODULE_DEPEND(uaudio, usb, 1, 1, 1); 3846184610SalfredMODULE_DEPEND(uaudio, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 3847184610SalfredMODULE_VERSION(uaudio, 1); 3848