uaudio.c revision 242223
1181641Skmacy/* $NetBSD: uaudio.c,v 1.91 2004/11/05 17:46:14 kent Exp $ */ 2181641Skmacy/* $FreeBSD: head/sys/dev/sound/usb/uaudio.c 242223 2012-10-28 14:37:17Z hselasky $ */ 3181641Skmacy 4181641Skmacy/*- 5181641Skmacy * Copyright (c) 1999 The NetBSD Foundation, Inc. 6181641Skmacy * All rights reserved. 7181641Skmacy * 8181641Skmacy * This code is derived from software contributed to The NetBSD Foundation 9181641Skmacy * by Lennart Augustsson (lennart@augustsson.net) at 10181641Skmacy * Carlstedt Research & Technology. 11181641Skmacy * 12181641Skmacy * Redistribution and use in source and binary forms, with or without 13181641Skmacy * modification, are permitted provided that the following conditions 14181641Skmacy * are met: 15181641Skmacy * 1. Redistributions of source code must retain the above copyright 16181641Skmacy * notice, this list of conditions and the following disclaimer. 17181641Skmacy * 2. Redistributions in binary form must reproduce the above copyright 18181641Skmacy * notice, this list of conditions and the following disclaimer in the 19181641Skmacy * documentation and/or other materials provided with the distribution. 20181641Skmacy * 21181641Skmacy * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22181641Skmacy * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23181641Skmacy * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24181641Skmacy * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25181641Skmacy * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26181641Skmacy * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27181641Skmacy * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28181641Skmacy * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29181641Skmacy * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30181641Skmacy * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31181641Skmacy * POSSIBILITY OF SUCH DAMAGE. 32181641Skmacy */ 33181641Skmacy 34181641Skmacy#include <sys/cdefs.h> 35181641Skmacy__FBSDID("$FreeBSD: head/sys/dev/sound/usb/uaudio.c 242223 2012-10-28 14:37:17Z hselasky $"); 36181641Skmacy 37181641Skmacy/* 38181641Skmacy * USB audio specs: http://www.usb.org/developers/devclass_docs/audio10.pdf 39181641Skmacy * http://www.usb.org/developers/devclass_docs/frmts10.pdf 40181641Skmacy * http://www.usb.org/developers/devclass_docs/termt10.pdf 41181641Skmacy */ 42181641Skmacy 43181641Skmacy/* 44181641Skmacy * Also merged: 45181641Skmacy * $NetBSD: uaudio.c,v 1.94 2005/01/15 15:19:53 kent Exp $ 46181641Skmacy * $NetBSD: uaudio.c,v 1.95 2005/01/16 06:02:19 dsainty Exp $ 47181641Skmacy * $NetBSD: uaudio.c,v 1.96 2005/01/16 12:46:00 kent Exp $ 48181641Skmacy * $NetBSD: uaudio.c,v 1.97 2005/02/24 08:19:38 martin Exp $ 49181641Skmacy */ 50181641Skmacy 51181641Skmacy#include <sys/stdint.h> 52181641Skmacy#include <sys/stddef.h> 53181641Skmacy#include <sys/param.h> 54181641Skmacy#include <sys/queue.h> 55181641Skmacy#include <sys/types.h> 56181641Skmacy#include <sys/systm.h> 57181641Skmacy#include <sys/kernel.h> 58181641Skmacy#include <sys/bus.h> 59181641Skmacy#include <sys/module.h> 60181641Skmacy#include <sys/lock.h> 61181641Skmacy#include <sys/mutex.h> 62181641Skmacy#include <sys/condvar.h> 63181641Skmacy#include <sys/sysctl.h> 64181641Skmacy#include <sys/sx.h> 65181641Skmacy#include <sys/unistd.h> 66181641Skmacy#include <sys/callout.h> 67181641Skmacy#include <sys/malloc.h> 68181641Skmacy#include <sys/priv.h> 69181641Skmacy 70181641Skmacy#include "usbdevs.h" 71181641Skmacy#include <dev/usb/usb.h> 72181641Skmacy#include <dev/usb/usbdi.h> 73181641Skmacy#include <dev/usb/usbdi_util.h> 74181641Skmacy 75181641Skmacy#define USB_DEBUG_VAR uaudio_debug 76181641Skmacy#include <dev/usb/usb_debug.h> 77181641Skmacy 78181641Skmacy#include <dev/usb/quirk/usb_quirk.h> 79181641Skmacy 80181641Skmacy#include <sys/reboot.h> /* for bootverbose */ 81181641Skmacy 82181641Skmacy#ifdef HAVE_KERNEL_OPTION_HEADERS 83181641Skmacy#include "opt_snd.h" 84181641Skmacy#endif 85181641Skmacy 86181641Skmacy#include <dev/sound/pcm/sound.h> 87181641Skmacy#include <dev/sound/usb/uaudioreg.h> 88181641Skmacy#include <dev/sound/usb/uaudio.h> 89181641Skmacy#include <dev/sound/chip.h> 90181641Skmacy#include "feeder_if.h" 91181641Skmacy 92181641Skmacystatic int uaudio_default_rate = 0; /* use rate list */ 93181641Skmacystatic int uaudio_default_bits = 32; 94181641Skmacystatic int uaudio_default_channels = 0; /* use default */ 95181641Skmacy 96181641Skmacy#ifdef USB_DEBUG 97181641Skmacystatic int uaudio_debug = 0; 98181641Skmacy 99181641Skmacystatic SYSCTL_NODE(_hw_usb, OID_AUTO, uaudio, CTLFLAG_RW, 0, "USB uaudio"); 100181641Skmacy 101181641SkmacySYSCTL_INT(_hw_usb_uaudio, OID_AUTO, debug, CTLFLAG_RW, 102181641Skmacy &uaudio_debug, 0, "uaudio debug level"); 103181641Skmacy 104181641SkmacyTUNABLE_INT("hw.usb.uaudio.default_rate", &uaudio_default_rate); 105181641SkmacySYSCTL_INT(_hw_usb_uaudio, OID_AUTO, default_rate, CTLFLAG_RW, 106181641Skmacy &uaudio_default_rate, 0, "uaudio default sample rate"); 107181641Skmacy 108181641SkmacyTUNABLE_INT("hw.usb.uaudio.default_bits", &uaudio_default_bits); 109181641SkmacySYSCTL_INT(_hw_usb_uaudio, OID_AUTO, default_bits, CTLFLAG_RW, 110181641Skmacy &uaudio_default_bits, 0, "uaudio default sample bits"); 111181641Skmacy 112181641SkmacyTUNABLE_INT("hw.usb.uaudio.default_channels", &uaudio_default_channels); 113181641SkmacySYSCTL_INT(_hw_usb_uaudio, OID_AUTO, default_channels, CTLFLAG_RW, 114181641Skmacy &uaudio_default_channels, 0, "uaudio default sample channels"); 115181641Skmacy#endif 116181641Skmacy 117181641Skmacy#define UAUDIO_NFRAMES 64 /* must be factor of 8 due HS-USB */ 118181641Skmacy#define UAUDIO_NCHANBUFS 2 /* number of outstanding request */ 119181641Skmacy#define UAUDIO_RECURSE_LIMIT 255 /* rounds */ 120181641Skmacy 121181641Skmacy#define MAKE_WORD(h,l) (((h) << 8) | (l)) 122181641Skmacy#define BIT_TEST(bm,bno) (((bm)[(bno) / 8] >> (7 - ((bno) % 8))) & 1) 123181641Skmacy#define UAUDIO_MAX_CHAN(x) (x) 124195949Skib 125181641Skmacyunion uaudio_asid { 126181641Skmacy const struct usb_audio_streaming_interface_descriptor *v1; 127181641Skmacy const struct usb_audio20_streaming_interface_descriptor *v2; 128181641Skmacy}; 129181641Skmacy 130181641Skmacyunion uaudio_asf1d { 131181641Skmacy const struct usb_audio_streaming_type1_descriptor *v1; 132181641Skmacy const struct usb_audio20_streaming_type1_descriptor *v2; 133181641Skmacy}; 134181641Skmacy 135181641Skmacyunion uaudio_sed { 136181641Skmacy const struct usb_audio_streaming_endpoint_descriptor *v1; 137181641Skmacy const struct usb_audio20_streaming_endpoint_descriptor *v2; 138181641Skmacy}; 139181641Skmacy 140181641Skmacystruct uaudio_mixer_node { 141181641Skmacy int32_t minval; 142181641Skmacy int32_t maxval; 143181641Skmacy#define MIX_MAX_CHAN 8 144181641Skmacy int32_t wValue[MIX_MAX_CHAN]; /* using nchan */ 145181641Skmacy uint32_t mul; 146181641Skmacy uint32_t ctl; 147181641Skmacy 148181641Skmacy uint16_t wData[MIX_MAX_CHAN]; /* using nchan */ 149181641Skmacy uint16_t wIndex; 150181641Skmacy 151181641Skmacy uint8_t update[(MIX_MAX_CHAN + 7) / 8]; 152181641Skmacy uint8_t nchan; 153181641Skmacy uint8_t type; 154181641Skmacy#define MIX_ON_OFF 1 155181641Skmacy#define MIX_SIGNED_16 2 156181641Skmacy#define MIX_UNSIGNED_16 3 157181641Skmacy#define MIX_SIGNED_8 4 158186557Skmacy#define MIX_SELECTOR 5 159181641Skmacy#define MIX_UNKNOWN 6 160181641Skmacy#define MIX_SIZE(n) ((((n) == MIX_SIGNED_16) || \ 161181641Skmacy ((n) == MIX_UNSIGNED_16)) ? 2 : 1) 162181641Skmacy#define MIX_UNSIGNED(n) ((n) == MIX_UNSIGNED_16) 163181641Skmacy 164181641Skmacy#define MAX_SELECTOR_INPUT_PIN 256 165181641Skmacy uint8_t slctrtype[MAX_SELECTOR_INPUT_PIN]; 166181641Skmacy uint8_t class; 167181641Skmacy 168181641Skmacy struct uaudio_mixer_node *next; 169181641Skmacy}; 170181641Skmacy 171181641Skmacystruct uaudio_chan { 172181641Skmacy struct pcmchan_caps pcm_cap; /* capabilities */ 173181641Skmacy 174181641Skmacy struct snd_dbuf *pcm_buf; 175181641Skmacy const struct usb_config *usb_cfg; 176204041Sed struct mtx *pcm_mtx; /* lock protecting this structure */ 177204041Sed struct uaudio_softc *priv_sc; 178204041Sed struct pcm_channel *pcm_ch; 179202628Sed struct usb_xfer *xfer[UAUDIO_NCHANBUFS + 1]; 180204041Sed union uaudio_asf1d p_asf1d; 181181641Skmacy union uaudio_sed p_sed; 182181641Skmacy const usb_endpoint_descriptor_audio_t *p_ed1; 183181641Skmacy const struct uaudio_format *p_fmt; 184181641Skmacy 185181641Skmacy uint8_t *buf; /* pointer to buffer */ 186181641Skmacy uint8_t *start; /* upper layer buffer start */ 187181641Skmacy uint8_t *end; /* upper layer buffer end */ 188181641Skmacy uint8_t *cur; /* current position in upper layer 189181641Skmacy * buffer */ 190181641Skmacy 191181641Skmacy uint32_t intr_size; /* in bytes */ 192181747Skmacy uint32_t intr_frames; /* in units */ 193181747Skmacy uint32_t sample_rate; 194181747Skmacy uint32_t frames_per_second; 195181641Skmacy uint32_t sample_rem; 196181641Skmacy uint32_t sample_curr; 197181641Skmacy 198181641Skmacy uint32_t format; 199181641Skmacy uint32_t pcm_format[2]; 200181641Skmacy 201181641Skmacy uint16_t bytes_per_frame[2]; 202181641Skmacy 203181641Skmacy uint16_t sample_size; 204181641Skmacy 205181641Skmacy uint8_t valid; 206181641Skmacy uint8_t iface_index; 207181641Skmacy uint8_t iface_alt_index; 208181641Skmacy uint8_t channels; 209181641Skmacy 210181641Skmacy uint8_t last_sync_time; 211181641Skmacy uint8_t last_sync_state; 212181641Skmacy#define UAUDIO_SYNC_NONE 0 213181641Skmacy#define UAUDIO_SYNC_MORE 1 214181641Skmacy#define UAUDIO_SYNC_LESS 2 215181641Skmacy}; 216181641Skmacy 217181641Skmacy#define UMIDI_CABLES_MAX 16 /* units */ 218181641Skmacy#define UMIDI_TX_FRAMES 256 /* units */ 219182902Skmacy#define UMIDI_TX_BUFFER (UMIDI_TX_FRAMES * 4) /* bytes */ 220181641Skmacy 221181641Skmacyenum { 222181641Skmacy UMIDI_TX_TRANSFER, 223181641Skmacy UMIDI_RX_TRANSFER, 224181641Skmacy UMIDI_N_TRANSFER, 225181641Skmacy}; 226181641Skmacy 227181641Skmacystruct umidi_sub_chan { 228181641Skmacy struct usb_fifo_sc fifo; 229181641Skmacy uint8_t *temp_cmd; 230196726Sadrian uint8_t temp_0[4]; 231196726Sadrian uint8_t temp_1[4]; 232181641Skmacy uint8_t state; 233181641Skmacy#define UMIDI_ST_UNKNOWN 0 /* scan for command */ 234181641Skmacy#define UMIDI_ST_1PARAM 1 235181641Skmacy#define UMIDI_ST_2PARAM_1 2 236181747Skmacy#define UMIDI_ST_2PARAM_2 3 237181641Skmacy#define UMIDI_ST_SYSEX_0 4 238181641Skmacy#define UMIDI_ST_SYSEX_1 5 239181641Skmacy#define UMIDI_ST_SYSEX_2 6 240181641Skmacy 241181641Skmacy uint8_t read_open:1; 242181641Skmacy uint8_t write_open:1; 243181641Skmacy uint8_t unused:6; 244181641Skmacy}; 245181641Skmacy 246181641Skmacystruct umidi_chan { 247181641Skmacy 248181641Skmacy struct umidi_sub_chan sub[UMIDI_CABLES_MAX]; 249181641Skmacy struct mtx mtx; 250181641Skmacy 251181641Skmacy struct usb_xfer *xfer[UMIDI_N_TRANSFER]; 252181641Skmacy 253181641Skmacy uint8_t iface_index; 254181641Skmacy uint8_t iface_alt_index; 255204160Skmacy 256181641Skmacy uint8_t read_open_refcount; 257181641Skmacy uint8_t write_open_refcount; 258181641Skmacy 259181641Skmacy uint8_t curr_cable; 260181641Skmacy uint8_t max_cable; 261181641Skmacy uint8_t valid; 262181641Skmacy uint8_t single_command; 263181641Skmacy}; 264181641Skmacy 265181641Skmacystruct uaudio_search_result { 266181641Skmacy uint8_t bit_input[(256 + 7) / 8]; 267181641Skmacy uint8_t bit_output[(256 + 7) / 8]; 268181641Skmacy uint8_t recurse_level; 269181641Skmacy uint8_t id_max; 270181641Skmacy uint8_t is_input; 271181641Skmacy}; 272181641Skmacy 273181641Skmacystruct uaudio_softc { 274181641Skmacy struct sbuf sc_sndstat; 275181641Skmacy struct sndcard_func sc_sndcard_func; 276181641Skmacy struct uaudio_chan sc_rec_chan; 277181641Skmacy struct uaudio_chan sc_play_chan; 278181641Skmacy struct umidi_chan sc_midi_chan; 279181641Skmacy struct uaudio_search_result sc_mixer_clocks; 280181641Skmacy 281181641Skmacy struct usb_device *sc_udev; 282181641Skmacy struct usb_xfer *sc_mixer_xfer[1]; 283181747Skmacy struct uaudio_mixer_node *sc_mixer_root; 284181747Skmacy struct uaudio_mixer_node *sc_mixer_curr; 285199184Savg 286181747Skmacy uint32_t sc_mix_info; 287181747Skmacy uint32_t sc_recsrc_info; 288181747Skmacy 289181747Skmacy uint16_t sc_audio_rev; 290181747Skmacy uint16_t sc_mixer_count; 291181747Skmacy 292207419Skmacy uint8_t sc_sndstat_valid; 293207419Skmacy uint8_t sc_mixer_iface_index; 294181747Skmacy uint8_t sc_mixer_iface_no; 295207419Skmacy uint8_t sc_mixer_chan; 296207419Skmacy uint8_t sc_pcm_registered:1; 297207419Skmacy uint8_t sc_mixer_init:1; 298207419Skmacy uint8_t sc_uq_audio_swap_lr:1; 299181641Skmacy uint8_t sc_uq_au_inp_async:1; 300181641Skmacy uint8_t sc_uq_au_no_xu:1; 301181641Skmacy uint8_t sc_uq_bad_adc:1; 302181641Skmacy uint8_t sc_uq_au_vendor_class:1; 303181641Skmacy}; 304181641Skmacy 305181641Skmacystruct uaudio_terminal_node { 306181641Skmacy union { 307181641Skmacy const struct usb_descriptor *desc; 308181641Skmacy const struct usb_audio_input_terminal *it_v1; 309181641Skmacy const struct usb_audio_output_terminal *ot_v1; 310181641Skmacy const struct usb_audio_mixer_unit_0 *mu_v1; 311181641Skmacy const struct usb_audio_selector_unit *su_v1; 312181641Skmacy const struct usb_audio_feature_unit *fu_v1; 313181641Skmacy const struct usb_audio_processing_unit_0 *pu_v1; 314181641Skmacy const struct usb_audio_extension_unit_0 *eu_v1; 315181641Skmacy const struct usb_audio20_clock_source_unit *csrc_v2; 316181641Skmacy const struct usb_audio20_clock_selector_unit_0 *csel_v2; 317181641Skmacy const struct usb_audio20_clock_multiplier_unit *cmul_v2; 318181641Skmacy const struct usb_audio20_input_terminal *it_v2; 319181641Skmacy const struct usb_audio20_output_terminal *ot_v2; 320181641Skmacy const struct usb_audio20_mixer_unit_0 *mu_v2; 321181641Skmacy const struct usb_audio20_selector_unit *su_v2; 322181641Skmacy const struct usb_audio20_feature_unit *fu_v2; 323181747Skmacy const struct usb_audio20_sample_rate_unit *ru_v2; 324181641Skmacy const struct usb_audio20_processing_unit_0 *pu_v2; 325196725Sadrian const struct usb_audio20_extension_unit_0 *eu_v2; 326181747Skmacy const struct usb_audio20_effect_unit *ef_v2; 327181641Skmacy } u; 328181641Skmacy struct uaudio_search_result usr; 329181641Skmacy struct uaudio_terminal_node *root; 330201804Sbz}; 331201751Salc 332201804Sbzstruct uaudio_format { 333181641Skmacy uint16_t wFormat; 334181641Skmacy uint8_t bPrecision; 335181641Skmacy uint32_t freebsd_fmt; 336181641Skmacy const char *description; 337181641Skmacy}; 338181641Skmacy 339181641Skmacystatic const struct uaudio_format uaudio10_formats[] = { 340181641Skmacy 341181641Skmacy {UA_FMT_PCM8, 8, AFMT_U8, "8-bit U-LE PCM"}, 342181641Skmacy {UA_FMT_PCM8, 16, AFMT_U16_LE, "16-bit U-LE PCM"}, 343181641Skmacy {UA_FMT_PCM8, 24, AFMT_U24_LE, "24-bit U-LE PCM"}, 344181641Skmacy {UA_FMT_PCM8, 32, AFMT_U32_LE, "32-bit U-LE PCM"}, 345181641Skmacy 346181641Skmacy {UA_FMT_PCM, 8, AFMT_S8, "8-bit S-LE PCM"}, 347181641Skmacy {UA_FMT_PCM, 16, AFMT_S16_LE, "16-bit S-LE PCM"}, 348181641Skmacy {UA_FMT_PCM, 24, AFMT_S24_LE, "24-bit S-LE PCM"}, 349181641Skmacy {UA_FMT_PCM, 32, AFMT_S32_LE, "32-bit S-LE PCM"}, 350181641Skmacy 351181641Skmacy {UA_FMT_ALAW, 8, AFMT_A_LAW, "8-bit A-Law"}, 352181641Skmacy {UA_FMT_MULAW, 8, AFMT_MU_LAW, "8-bit mu-Law"}, 353181641Skmacy 354181641Skmacy {0, 0, 0, NULL} 355181641Skmacy}; 356181641Skmacy 357181641Skmacystatic const struct uaudio_format uaudio20_formats[] = { 358181641Skmacy 359181641Skmacy {UA20_FMT_PCM, 8, AFMT_S8, "8-bit S-LE PCM"}, 360181641Skmacy {UA20_FMT_PCM, 16, AFMT_S16_LE, "16-bit S-LE PCM"}, 361181641Skmacy {UA20_FMT_PCM, 24, AFMT_S24_LE, "24-bit S-LE PCM"}, 362181641Skmacy {UA20_FMT_PCM, 32, AFMT_S32_LE, "32-bit S-LE PCM"}, 363181641Skmacy 364181641Skmacy {UA20_FMT_PCM8, 8, AFMT_U8, "8-bit U-LE PCM"}, 365181641Skmacy {UA20_FMT_PCM8, 16, AFMT_U16_LE, "16-bit U-LE PCM"}, 366181641Skmacy {UA20_FMT_PCM8, 24, AFMT_U24_LE, "24-bit U-LE PCM"}, 367181641Skmacy {UA20_FMT_PCM8, 32, AFMT_U32_LE, "32-bit U-LE PCM"}, 368181641Skmacy 369181641Skmacy {UA20_FMT_ALAW, 8, AFMT_A_LAW, "8-bit A-Law"}, 370181641Skmacy {UA20_FMT_MULAW, 8, AFMT_MU_LAW, "8-bit mu-Law"}, 371181641Skmacy 372181641Skmacy {0, 0, 0, NULL} 373181641Skmacy}; 374181641Skmacy 375181641Skmacy#define UAC_OUTPUT 0 376181641Skmacy#define UAC_INPUT 1 377181641Skmacy#define UAC_EQUAL 2 378181641Skmacy#define UAC_RECORD 3 379181641Skmacy#define UAC_NCLASSES 4 380181641Skmacy 381181641Skmacy#ifdef USB_DEBUG 382181641Skmacystatic const char *uac_names[] = { 383181641Skmacy "outputs", "inputs", "equalization", "record" 384181641Skmacy}; 385181641Skmacy 386181641Skmacy#endif 387181641Skmacy 388181641Skmacy/* prototypes */ 389181641Skmacy 390181641Skmacystatic device_probe_t uaudio_probe; 391181641Skmacystatic device_attach_t uaudio_attach; 392181641Skmacystatic device_detach_t uaudio_detach; 393181641Skmacy 394181641Skmacystatic usb_callback_t uaudio_chan_play_callback; 395181641Skmacystatic usb_callback_t uaudio_chan_play_sync_callback; 396181641Skmacystatic usb_callback_t uaudio_chan_record_callback; 397181641Skmacystatic usb_callback_t uaudio_chan_record_sync_callback; 398181641Skmacystatic usb_callback_t uaudio_mixer_write_cfg_callback; 399181641Skmacystatic usb_callback_t umidi_bulk_read_callback; 400181641Skmacystatic usb_callback_t umidi_bulk_write_callback; 401181641Skmacy 402181641Skmacy/* ==== USB audio v1.0 ==== */ 403181641Skmacy 404181641Skmacystatic void uaudio_mixer_add_mixer(struct uaudio_softc *, 405181641Skmacy const struct uaudio_terminal_node *, int); 406181641Skmacystatic void uaudio_mixer_add_selector(struct uaudio_softc *, 407181641Skmacy const struct uaudio_terminal_node *, int); 408181641Skmacystatic uint32_t uaudio_mixer_feature_get_bmaControls( 409181641Skmacy const struct usb_audio_feature_unit *, uint8_t); 410181641Skmacystatic void uaudio_mixer_add_feature(struct uaudio_softc *, 411181641Skmacy const struct uaudio_terminal_node *, int); 412181641Skmacystatic void uaudio_mixer_add_processing_updown(struct uaudio_softc *, 413181641Skmacy const struct uaudio_terminal_node *, int); 414181641Skmacystatic void uaudio_mixer_add_processing(struct uaudio_softc *, 415181641Skmacy const struct uaudio_terminal_node *, int); 416181641Skmacystatic void uaudio_mixer_add_extension(struct uaudio_softc *, 417181641Skmacy const struct uaudio_terminal_node *, int); 418181641Skmacystatic struct usb_audio_cluster uaudio_mixer_get_cluster(uint8_t, 419181641Skmacy const struct uaudio_terminal_node *); 420181641Skmacystatic uint16_t uaudio_mixer_determine_class(const struct uaudio_terminal_node *, 421181641Skmacy struct uaudio_mixer_node *); 422181641Skmacystatic uint16_t uaudio_mixer_feature_name(const struct uaudio_terminal_node *, 423181641Skmacy struct uaudio_mixer_node *); 424181641Skmacystatic void uaudio_mixer_find_inputs_sub(struct uaudio_terminal_node *, 425181641Skmacy const uint8_t *, uint8_t, struct uaudio_search_result *); 426181641Skmacystatic const void *uaudio_mixer_verify_desc(const void *, uint32_t); 427181641Skmacystatic usb_error_t uaudio_set_speed(struct usb_device *, uint8_t, uint32_t); 428181641Skmacystatic int uaudio_mixer_get(struct usb_device *, uint16_t, uint8_t, 429181641Skmacy struct uaudio_mixer_node *); 430181641Skmacy 431181641Skmacy/* ==== USB audio v2.0 ==== */ 432181641Skmacy 433181641Skmacystatic void uaudio20_mixer_add_mixer(struct uaudio_softc *, 434181641Skmacy const struct uaudio_terminal_node *, int); 435181641Skmacystatic void uaudio20_mixer_add_selector(struct uaudio_softc *, 436181641Skmacy const struct uaudio_terminal_node *, int); 437181641Skmacystatic void uaudio20_mixer_add_feature(struct uaudio_softc *, 438181641Skmacy const struct uaudio_terminal_node *, int); 439181641Skmacystatic struct usb_audio20_cluster uaudio20_mixer_get_cluster(uint8_t, 440183342Skmacy const struct uaudio_terminal_node *); 441183342Skmacystatic uint16_t uaudio20_mixer_determine_class(const struct uaudio_terminal_node *, 442181641Skmacy struct uaudio_mixer_node *); 443181641Skmacystatic uint16_t uaudio20_mixer_feature_name(const struct uaudio_terminal_node *, 444181641Skmacy struct uaudio_mixer_node *); 445181641Skmacystatic void uaudio20_mixer_find_inputs_sub(struct uaudio_terminal_node *, 446181641Skmacy const uint8_t *, uint8_t, struct uaudio_search_result *); 447181641Skmacystatic const void *uaudio20_mixer_verify_desc(const void *, uint32_t); 448181641Skmacystatic usb_error_t uaudio20_set_speed(struct usb_device *, uint8_t, 449181641Skmacy uint8_t, uint32_t); 450181641Skmacy 451181641Skmacy/* USB audio v1.0 and v2.0 */ 452181641Skmacy 453181641Skmacystatic void uaudio_chan_fill_info_sub(struct uaudio_softc *, 454181641Skmacy struct usb_device *, uint32_t, uint8_t, uint8_t); 455181641Skmacystatic void uaudio_chan_fill_info(struct uaudio_softc *, 456181641Skmacy struct usb_device *); 457181641Skmacystatic void uaudio_mixer_add_ctl_sub(struct uaudio_softc *, 458181641Skmacy struct uaudio_mixer_node *); 459181641Skmacystatic void uaudio_mixer_add_ctl(struct uaudio_softc *, 460181641Skmacy struct uaudio_mixer_node *); 461181641Skmacystatic void uaudio_mixer_fill_info(struct uaudio_softc *, 462204160Skmacy struct usb_device *, void *); 463204160Skmacystatic void uaudio_mixer_ctl_set(struct uaudio_softc *, 464181641Skmacy struct uaudio_mixer_node *, uint8_t, int32_t val); 465181641Skmacystatic int uaudio_mixer_signext(uint8_t, int); 466181641Skmacystatic int uaudio_mixer_bsd2value(struct uaudio_mixer_node *, int32_t val); 467181641Skmacystatic void uaudio_mixer_init(struct uaudio_softc *); 468181641Skmacystatic const struct uaudio_terminal_node *uaudio_mixer_get_input( 469181641Skmacy const struct uaudio_terminal_node *, uint8_t); 470181641Skmacystatic const struct uaudio_terminal_node *uaudio_mixer_get_output( 471181641Skmacy const struct uaudio_terminal_node *, uint8_t); 472181641Skmacystatic void uaudio_mixer_find_outputs_sub(struct uaudio_terminal_node *, 473181641Skmacy uint8_t, uint8_t, struct uaudio_search_result *); 474181641Skmacystatic uint8_t umidi_convert_to_usb(struct umidi_sub_chan *, uint8_t, uint8_t); 475181641Skmacystatic struct umidi_sub_chan *umidi_sub_by_fifo(struct usb_fifo *); 476181641Skmacystatic void umidi_start_read(struct usb_fifo *); 477181641Skmacystatic void umidi_stop_read(struct usb_fifo *); 478181641Skmacystatic void umidi_start_write(struct usb_fifo *); 479181641Skmacystatic void umidi_stop_write(struct usb_fifo *); 480181641Skmacystatic int umidi_open(struct usb_fifo *, int); 481181641Skmacystatic int umidi_ioctl(struct usb_fifo *, u_long cmd, void *, int); 482181641Skmacystatic void umidi_close(struct usb_fifo *, int); 483181641Skmacystatic void umidi_init(device_t dev); 484181641Skmacystatic int umidi_probe(device_t dev); 485181641Skmacystatic int umidi_detach(device_t dev); 486181641Skmacy 487181641Skmacy#ifdef USB_DEBUG 488181641Skmacystatic void uaudio_chan_dump_ep_desc( 489181641Skmacy const usb_endpoint_descriptor_audio_t *); 490181641Skmacy#endif 491181641Skmacy 492181641Skmacystatic const struct usb_config 493181641Skmacy uaudio_cfg_record[UAUDIO_NCHANBUFS + 1] = { 494181641Skmacy [0] = { 495181641Skmacy .type = UE_ISOCHRONOUS, 496181641Skmacy .endpoint = UE_ADDR_ANY, 497181641Skmacy .direction = UE_DIR_IN, 498181641Skmacy .bufsize = 0, /* use "wMaxPacketSize * frames" */ 499181641Skmacy .frames = UAUDIO_NFRAMES, 500181641Skmacy .flags = {.short_xfer_ok = 1,}, 501181641Skmacy .callback = &uaudio_chan_record_callback, 502181641Skmacy }, 503181641Skmacy 504181641Skmacy [1] = { 505181641Skmacy .type = UE_ISOCHRONOUS, 506181641Skmacy .endpoint = UE_ADDR_ANY, 507181641Skmacy .direction = UE_DIR_IN, 508181641Skmacy .bufsize = 0, /* use "wMaxPacketSize * frames" */ 509181641Skmacy .frames = UAUDIO_NFRAMES, 510181641Skmacy .flags = {.short_xfer_ok = 1,}, 511181641Skmacy .callback = &uaudio_chan_record_callback, 512181641Skmacy }, 513181641Skmacy 514181641Skmacy [2] = { 515181641Skmacy .type = UE_ISOCHRONOUS, 516181641Skmacy .endpoint = UE_ADDR_ANY, 517181641Skmacy .direction = UE_DIR_OUT, 518181641Skmacy .bufsize = 0, /* use "wMaxPacketSize * frames" */ 519181641Skmacy .frames = 1, 520181641Skmacy .flags = {.no_pipe_ok = 1,.short_xfer_ok = 1,}, 521181641Skmacy .callback = &uaudio_chan_record_sync_callback, 522181641Skmacy }, 523181641Skmacy}; 524181641Skmacy 525181641Skmacystatic const struct usb_config 526181641Skmacy uaudio_cfg_play[UAUDIO_NCHANBUFS + 1] = { 527181641Skmacy [0] = { 528181641Skmacy .type = UE_ISOCHRONOUS, 529181641Skmacy .endpoint = UE_ADDR_ANY, 530181641Skmacy .direction = UE_DIR_OUT, 531196726Sadrian .bufsize = 0, /* use "wMaxPacketSize * frames" */ 532197070Sjkim .frames = UAUDIO_NFRAMES, 533196726Sadrian .flags = {.short_xfer_ok = 1,}, 534196726Sadrian .callback = &uaudio_chan_play_callback, 535196726Sadrian }, 536196726Sadrian 537196726Sadrian [1] = { 538196726Sadrian .type = UE_ISOCHRONOUS, 539196726Sadrian .endpoint = UE_ADDR_ANY, 540196726Sadrian .direction = UE_DIR_OUT, 541196726Sadrian .bufsize = 0, /* use "wMaxPacketSize * frames" */ 542196726Sadrian .frames = UAUDIO_NFRAMES, 543196726Sadrian .flags = {.short_xfer_ok = 1,}, 544196726Sadrian .callback = &uaudio_chan_play_callback, 545196726Sadrian }, 546196726Sadrian 547196726Sadrian [2] = { 548196726Sadrian .type = UE_ISOCHRONOUS, 549196726Sadrian .endpoint = UE_ADDR_ANY, 550196726Sadrian .direction = UE_DIR_IN, 551196726Sadrian .bufsize = 0, /* use "wMaxPacketSize * frames" */ 552196726Sadrian .frames = 1, 553196726Sadrian .flags = {.no_pipe_ok = 1,.short_xfer_ok = 1,}, 554196726Sadrian .callback = &uaudio_chan_play_sync_callback, 555196726Sadrian }, 556196726Sadrian}; 557196726Sadrian 558196726Sadrianstatic const struct usb_config 559196726Sadrian uaudio_mixer_config[1] = { 560196726Sadrian [0] = { 561181641Skmacy .type = UE_CONTROL, 562181641Skmacy .endpoint = 0x00, /* Control pipe */ 563181641Skmacy .direction = UE_DIR_ANY, 564201804Sbz .bufsize = (sizeof(struct usb_device_request) + 4), 565181641Skmacy .callback = &uaudio_mixer_write_cfg_callback, 566181641Skmacy .timeout = 1000, /* 1 second */ 567181641Skmacy }, 568201751Salc}; 569181641Skmacy 570181641Skmacystatic const 571181641Skmacyuint8_t umidi_cmd_to_len[16] = { 572181641Skmacy [0x0] = 0, /* reserved */ 573181641Skmacy [0x1] = 0, /* reserved */ 574181641Skmacy [0x2] = 2, /* bytes */ 575181641Skmacy [0x3] = 3, /* bytes */ 576181641Skmacy [0x4] = 3, /* bytes */ 577181641Skmacy [0x5] = 1, /* bytes */ 578181641Skmacy [0x6] = 2, /* bytes */ 579181641Skmacy [0x7] = 3, /* bytes */ 580181641Skmacy [0x8] = 3, /* bytes */ 581181641Skmacy [0x9] = 3, /* bytes */ 582181641Skmacy [0xA] = 3, /* bytes */ 583181641Skmacy [0xB] = 3, /* bytes */ 584181641Skmacy [0xC] = 2, /* bytes */ 585181641Skmacy [0xD] = 2, /* bytes */ 586181641Skmacy [0xE] = 3, /* bytes */ 587181641Skmacy [0xF] = 1, /* bytes */ 588181641Skmacy}; 589181641Skmacy 590181641Skmacystatic const struct usb_config 591181641Skmacy umidi_config[UMIDI_N_TRANSFER] = { 592181641Skmacy [UMIDI_TX_TRANSFER] = { 593181641Skmacy .type = UE_BULK, 594181641Skmacy .endpoint = UE_ADDR_ANY, 595181641Skmacy .direction = UE_DIR_OUT, 596181641Skmacy .bufsize = UMIDI_TX_BUFFER, 597181641Skmacy .callback = &umidi_bulk_write_callback, 598181641Skmacy }, 599181641Skmacy 600181641Skmacy [UMIDI_RX_TRANSFER] = { 601181641Skmacy .type = UE_BULK, 602181641Skmacy .endpoint = UE_ADDR_ANY, 603201804Sbz .direction = UE_DIR_IN, 604181641Skmacy .bufsize = 4, /* bytes */ 605181641Skmacy .flags = {.short_xfer_ok = 1,.proxy_buffer = 1,}, 606181641Skmacy .callback = &umidi_bulk_read_callback, 607181641Skmacy }, 608181641Skmacy}; 609181641Skmacy 610181641Skmacystatic devclass_t uaudio_devclass; 611181641Skmacy 612181641Skmacystatic device_method_t uaudio_methods[] = { 613195649Salc DEVMETHOD(device_probe, uaudio_probe), 614181641Skmacy DEVMETHOD(device_attach, uaudio_attach), 615181641Skmacy DEVMETHOD(device_detach, uaudio_detach), 616181641Skmacy DEVMETHOD(device_suspend, bus_generic_suspend), 617181641Skmacy DEVMETHOD(device_resume, bus_generic_resume), 618181641Skmacy DEVMETHOD(device_shutdown, bus_generic_shutdown), 619181641Skmacy 620195385Salc DEVMETHOD_END 621195385Salc}; 622195385Salc 623195385Salcstatic driver_t uaudio_driver = { 624195649Salc .name = "uaudio", 625181641Skmacy .methods = uaudio_methods, 626181641Skmacy .size = sizeof(struct uaudio_softc), 627181641Skmacy}; 628181641Skmacy 629181641Skmacystatic const STRUCT_USB_HOST_ID __used uaudio_devs[] = { 630181641Skmacy /* Generic USB audio class match */ 631181641Skmacy {USB_IFACE_CLASS(UICLASS_AUDIO), 632181641Skmacy USB_IFACE_SUBCLASS(UISUBCLASS_AUDIOCONTROL),}, 633181641Skmacy /* Generic USB MIDI class match */ 634181641Skmacy {USB_IFACE_CLASS(UICLASS_AUDIO), 635181641Skmacy USB_IFACE_SUBCLASS(UISUBCLASS_MIDISTREAM),}, 636181641Skmacy}; 637181641Skmacy 638181641Skmacystatic int 639181641Skmacyuaudio_probe(device_t dev) 640181641Skmacy{ 641181641Skmacy struct usb_attach_arg *uaa = device_get_ivars(dev); 642181641Skmacy 643181641Skmacy if (uaa->usb_mode != USB_MODE_HOST) 644181641Skmacy return (ENXIO); 645181641Skmacy 646181641Skmacy /* lookup non-standard device */ 647181641Skmacy 648181641Skmacy if (uaa->info.bInterfaceClass != UICLASS_AUDIO) { 649181641Skmacy if (uaa->info.bInterfaceClass != UICLASS_VENDOR || 650181641Skmacy usb_test_quirk(uaa, UQ_AU_VENDOR_CLASS) == 0) 651181641Skmacy return (ENXIO); 652181641Skmacy } 653181641Skmacy 654181641Skmacy /* check for AUDIO control interface */ 655181641Skmacy 656181641Skmacy if (uaa->info.bInterfaceSubClass == UISUBCLASS_AUDIOCONTROL) { 657181641Skmacy if (usb_test_quirk(uaa, UQ_BAD_AUDIO)) 658181641Skmacy return (ENXIO); 659181641Skmacy else 660181641Skmacy return (BUS_PROBE_GENERIC); 661181641Skmacy } 662181641Skmacy 663181641Skmacy /* check for MIDI stream */ 664181641Skmacy 665181641Skmacy if (uaa->info.bInterfaceSubClass == UISUBCLASS_MIDISTREAM) { 666181641Skmacy if (usb_test_quirk(uaa, UQ_BAD_MIDI)) 667181641Skmacy return (ENXIO); 668181641Skmacy else 669181641Skmacy return (BUS_PROBE_GENERIC); 670181641Skmacy } 671181641Skmacy return (ENXIO); 672181641Skmacy} 673181641Skmacy 674181641Skmacystatic int 675181641Skmacyuaudio_attach(device_t dev) 676181641Skmacy{ 677181641Skmacy struct usb_attach_arg *uaa = device_get_ivars(dev); 678181641Skmacy struct uaudio_softc *sc = device_get_softc(dev); 679181641Skmacy struct usb_interface_descriptor *id; 680181641Skmacy device_t child; 681181641Skmacy 682181641Skmacy sc->sc_play_chan.priv_sc = sc; 683181641Skmacy sc->sc_rec_chan.priv_sc = sc; 684181641Skmacy sc->sc_udev = uaa->device; 685181641Skmacy sc->sc_mixer_iface_index = uaa->info.bIfaceIndex; 686181641Skmacy sc->sc_mixer_iface_no = uaa->info.bIfaceNum; 687181641Skmacy 688181641Skmacy if (usb_test_quirk(uaa, UQ_AUDIO_SWAP_LR)) 689181641Skmacy sc->sc_uq_audio_swap_lr = 1; 690181641Skmacy 691181641Skmacy if (usb_test_quirk(uaa, UQ_AU_INP_ASYNC)) 692181641Skmacy sc->sc_uq_au_inp_async = 1; 693181641Skmacy 694181641Skmacy if (usb_test_quirk(uaa, UQ_AU_NO_XU)) 695181641Skmacy sc->sc_uq_au_no_xu = 1; 696181747Skmacy 697181747Skmacy if (usb_test_quirk(uaa, UQ_BAD_ADC)) 698181747Skmacy sc->sc_uq_bad_adc = 1; 699181641Skmacy 700181641Skmacy if (usb_test_quirk(uaa, UQ_AU_VENDOR_CLASS)) 701181747Skmacy sc->sc_uq_au_vendor_class = 1; 702181747Skmacy 703181747Skmacy umidi_init(dev); 704181747Skmacy 705181808Skmacy device_set_usb_desc(dev); 706181747Skmacy 707181747Skmacy id = usbd_get_interface_descriptor(uaa->iface); 708181747Skmacy 709181747Skmacy /* must fill mixer info before channel info */ 710181808Skmacy uaudio_mixer_fill_info(sc, uaa->device, id); 711181747Skmacy 712181747Skmacy /* fill channel info */ 713181747Skmacy uaudio_chan_fill_info(sc, uaa->device); 714181641Skmacy 715181641Skmacy DPRINTF("audio rev %d.%02x\n", 716181641Skmacy sc->sc_audio_rev >> 8, 717181641Skmacy sc->sc_audio_rev & 0xff); 718181641Skmacy 719181641Skmacy DPRINTF("%d mixer controls\n", 720181641Skmacy sc->sc_mixer_count); 721181641Skmacy 722181641Skmacy if (sc->sc_play_chan.valid) { 723181641Skmacy device_printf(dev, "Play: %d Hz, %d ch, %s format.\n", 724181747Skmacy sc->sc_play_chan.sample_rate, 725181747Skmacy sc->sc_play_chan.channels, 726181747Skmacy sc->sc_play_chan.p_fmt->description); 727181747Skmacy } else { 728181747Skmacy device_printf(dev, "No playback.\n"); 729181747Skmacy } 730181747Skmacy 731181747Skmacy if (sc->sc_rec_chan.valid) { 732181747Skmacy device_printf(dev, "Record: %d Hz, %d ch, %s format.\n", 733181747Skmacy sc->sc_rec_chan.sample_rate, 734181747Skmacy sc->sc_play_chan.channels, 735181747Skmacy sc->sc_rec_chan.p_fmt->description); 736181747Skmacy } else { 737181747Skmacy device_printf(dev, "No recording.\n"); 738181747Skmacy } 739181747Skmacy 740181747Skmacy if (sc->sc_midi_chan.valid) { 741181747Skmacy 742181747Skmacy if (umidi_probe(dev)) { 743181747Skmacy goto detach; 744181641Skmacy } 745181641Skmacy device_printf(dev, "MIDI sequencer.\n"); 746181641Skmacy } else { 747181641Skmacy device_printf(dev, "No midi sequencer.\n"); 748181641Skmacy } 749181641Skmacy 750181641Skmacy DPRINTF("doing child attach\n"); 751181641Skmacy 752181641Skmacy /* attach the children */ 753181641Skmacy 754181641Skmacy sc->sc_sndcard_func.func = SCF_PCM; 755181641Skmacy 756181641Skmacy /* 757181641Skmacy * Only attach a PCM device if we have a playback, recording 758181641Skmacy * or mixer device present: 759181641Skmacy */ 760181641Skmacy if (sc->sc_play_chan.valid || 761181641Skmacy sc->sc_rec_chan.valid || 762181641Skmacy sc->sc_mix_info) { 763181641Skmacy child = device_add_child(dev, "pcm", -1); 764181641Skmacy 765181641Skmacy if (child == NULL) { 766181641Skmacy DPRINTF("out of memory\n"); 767195949Skib goto detach; 768181641Skmacy } 769181641Skmacy device_set_ivars(child, &sc->sc_sndcard_func); 770181641Skmacy } 771181641Skmacy 772181641Skmacy if (bus_generic_attach(dev)) { 773181641Skmacy DPRINTF("child attach failed\n"); 774181641Skmacy goto detach; 775181641Skmacy } 776181641Skmacy return (0); /* success */ 777181641Skmacy 778181641Skmacydetach: 779181641Skmacy uaudio_detach(dev); 780181641Skmacy return (ENXIO); 781181641Skmacy} 782181641Skmacy 783181641Skmacystatic void 784181641Skmacyuaudio_pcm_setflags(device_t dev, uint32_t flags) 785181641Skmacy{ 786181641Skmacy pcm_setflags(dev, pcm_getflags(dev) | flags); 787181641Skmacy} 788181641Skmacy 789181641Skmacyint 790181641Skmacyuaudio_attach_sub(device_t dev, kobj_class_t mixer_class, kobj_class_t chan_class) 791196726Sadrian{ 792196726Sadrian struct uaudio_softc *sc = device_get_softc(device_get_parent(dev)); 793196726Sadrian char status[SND_STATUSLEN]; 794196726Sadrian 795196726Sadrian uaudio_mixer_init(sc); 796196726Sadrian 797196726Sadrian if (sc->sc_uq_audio_swap_lr) { 798196726Sadrian DPRINTF("hardware has swapped left and right\n"); 799196726Sadrian /* uaudio_pcm_setflags(dev, SD_F_PSWAPLR); */ 800196726Sadrian } 801196726Sadrian if (!(sc->sc_mix_info & SOUND_MASK_PCM)) { 802196726Sadrian 803196726Sadrian DPRINTF("emulating master volume\n"); 804196726Sadrian 805196726Sadrian /* 806196726Sadrian * Emulate missing pcm mixer controller 807196726Sadrian * through FEEDER_VOLUME 808196726Sadrian */ 809196726Sadrian uaudio_pcm_setflags(dev, SD_F_SOFTPCMVOL); 810196726Sadrian } 811196726Sadrian if (mixer_init(dev, mixer_class, sc)) { 812196726Sadrian goto detach; 813196726Sadrian } 814196726Sadrian sc->sc_mixer_init = 1; 815196726Sadrian 816196726Sadrian snprintf(status, sizeof(status), "at ? %s", PCM_KLDSTRING(snd_uaudio)); 817196726Sadrian 818196726Sadrian if (pcm_register(dev, sc, 819196726Sadrian sc->sc_play_chan.valid ? 1 : 0, 820196726Sadrian sc->sc_rec_chan.valid ? 1 : 0)) { 821196726Sadrian goto detach; 822196726Sadrian } 823196726Sadrian 824196726Sadrian uaudio_pcm_setflags(dev, SD_F_MPSAFE); 825196726Sadrian sc->sc_pcm_registered = 1; 826196726Sadrian 827196726Sadrian if (sc->sc_play_chan.valid) { 828196726Sadrian pcm_addchan(dev, PCMDIR_PLAY, chan_class, sc); 829196726Sadrian } 830196726Sadrian if (sc->sc_rec_chan.valid) { 831196726Sadrian pcm_addchan(dev, PCMDIR_REC, chan_class, sc); 832196726Sadrian } 833181641Skmacy pcm_setstatus(dev, status); 834181641Skmacy 835181641Skmacy return (0); /* success */ 836181641Skmacy 837181641Skmacydetach: 838181641Skmacy uaudio_detach_sub(dev); 839181641Skmacy return (ENXIO); 840181641Skmacy} 841181641Skmacy 842181641Skmacyint 843181641Skmacyuaudio_detach_sub(device_t dev) 844181641Skmacy{ 845181641Skmacy struct uaudio_softc *sc = device_get_softc(device_get_parent(dev)); 846181641Skmacy int error = 0; 847181641Skmacy 848181641Skmacyrepeat: 849181641Skmacy if (sc->sc_pcm_registered) { 850181641Skmacy error = pcm_unregister(dev); 851181641Skmacy } else { 852181641Skmacy if (sc->sc_mixer_init) { 853181641Skmacy error = mixer_uninit(dev); 854181641Skmacy } 855181641Skmacy } 856181641Skmacy 857181641Skmacy if (error) { 858181641Skmacy device_printf(dev, "Waiting for sound application to exit!\n"); 859181641Skmacy usb_pause_mtx(NULL, 2 * hz); 860181641Skmacy goto repeat; /* try again */ 861181641Skmacy } 862181641Skmacy return (0); /* success */ 863181641Skmacy} 864181641Skmacy 865181641Skmacystatic int 866181641Skmacyuaudio_detach(device_t dev) 867181641Skmacy{ 868181641Skmacy struct uaudio_softc *sc = device_get_softc(dev); 869181641Skmacy 870181641Skmacy /* 871181641Skmacy * Stop USB transfers early so that any audio applications 872181641Skmacy * will time out and close opened /dev/dspX.Y device(s), if 873181641Skmacy * any. 874181641Skmacy */ 875181641Skmacy if (sc->sc_play_chan.valid) 876181641Skmacy usbd_transfer_unsetup(sc->sc_play_chan.xfer, UAUDIO_NCHANBUFS + 1); 877181641Skmacy if (sc->sc_rec_chan.valid) 878181641Skmacy usbd_transfer_unsetup(sc->sc_rec_chan.xfer, UAUDIO_NCHANBUFS + 1); 879181641Skmacy 880181641Skmacy if (bus_generic_detach(dev) != 0) { 881181641Skmacy DPRINTF("detach failed!\n"); 882181641Skmacy } 883181641Skmacy sbuf_delete(&sc->sc_sndstat); 884181641Skmacy sc->sc_sndstat_valid = 0; 885181641Skmacy 886181641Skmacy umidi_detach(dev); 887181641Skmacy 888181641Skmacy return (0); 889181641Skmacy} 890181641Skmacy 891181641Skmacy/*========================================================================* 892181641Skmacy * AS - Audio Stream - routines 893181641Skmacy *========================================================================*/ 894181641Skmacy 895181641Skmacy#ifdef USB_DEBUG 896181641Skmacystatic void 897181641Skmacyuaudio_chan_dump_ep_desc(const usb_endpoint_descriptor_audio_t *ed) 898181641Skmacy{ 899181641Skmacy if (ed) { 900181641Skmacy DPRINTF("endpoint=%p bLength=%d bDescriptorType=%d \n" 901181641Skmacy "bEndpointAddress=%d bmAttributes=0x%x \n" 902181641Skmacy "wMaxPacketSize=%d bInterval=%d \n" 903181641Skmacy "bRefresh=%d bSynchAddress=%d\n", 904181641Skmacy ed, ed->bLength, ed->bDescriptorType, 905181641Skmacy ed->bEndpointAddress, ed->bmAttributes, 906181641Skmacy UGETW(ed->wMaxPacketSize), ed->bInterval, 907181641Skmacy UEP_HAS_REFRESH(ed) ? ed->bRefresh : 0, 908181641Skmacy UEP_HAS_SYNCADDR(ed) ? ed->bSynchAddress : 0); 909181641Skmacy } 910181641Skmacy} 911181641Skmacy 912181641Skmacy#endif 913181641Skmacy 914181641Skmacy/* 915181641Skmacy * The following is a workaround for broken no-name USB audio devices 916181641Skmacy * sold by dealextreme called "3D sound". The problem is that the 917181641Skmacy * manufacturer computed wMaxPacketSize is too small to hold the 918181641Skmacy * actual data sent. In other words the device sometimes sends more 919181641Skmacy * data than it actually reports it can send in a single isochronous 920181641Skmacy * packet. 921181641Skmacy */ 922181641Skmacystatic void 923181641Skmacyuaudio_record_fix_fs(usb_endpoint_descriptor_audio_t *ep, 924181641Skmacy uint32_t xps, uint32_t add) 925181641Skmacy{ 926181641Skmacy uint32_t mps; 927181641Skmacy 928181641Skmacy mps = UGETW(ep->wMaxPacketSize); 929181641Skmacy 930181641Skmacy /* 931181641Skmacy * If the device indicates it can send more data than what the 932181641Skmacy * sample rate indicates, we apply the workaround. 933181641Skmacy */ 934181641Skmacy if (mps > xps) { 935181641Skmacy 936181641Skmacy /* allow additional data */ 937181641Skmacy xps += add; 938181641Skmacy 939181641Skmacy /* check against the maximum USB 1.x length */ 940181641Skmacy if (xps > 1023) 941181641Skmacy xps = 1023; 942181641Skmacy 943181641Skmacy /* check if we should do an update */ 944181641Skmacy if (mps < xps) { 945181641Skmacy /* simply update the wMaxPacketSize field */ 946181641Skmacy USETW(ep->wMaxPacketSize, xps); 947181641Skmacy DPRINTF("Workaround: Updated wMaxPacketSize " 948181641Skmacy "from %d to %d bytes.\n", 949181641Skmacy (int)mps, (int)xps); 950181641Skmacy } 951181641Skmacy } 952181641Skmacy} 953181641Skmacy 954181641Skmacystatic usb_error_t 955181641Skmacyuaudio20_check_rate(struct usb_device *udev, uint8_t iface_no, 956181641Skmacy uint8_t clockid, uint32_t rate) 957181641Skmacy{ 958181641Skmacy struct usb_device_request req; 959181641Skmacy usb_error_t error; 960181641Skmacy uint8_t data[255]; 961181641Skmacy uint16_t actlen; 962181641Skmacy uint16_t rates; 963181641Skmacy uint16_t x; 964181641Skmacy 965181641Skmacy DPRINTFN(6, "ifaceno=%d clockid=%d rate=%u\n", 966181641Skmacy iface_no, clockid, rate); 967181641Skmacy 968181641Skmacy req.bmRequestType = UT_READ_CLASS_INTERFACE; 969181641Skmacy req.bRequest = UA20_CS_RANGE; 970181641Skmacy USETW2(req.wValue, UA20_CS_SAM_FREQ_CONTROL, 0); 971181641Skmacy USETW2(req.wIndex, clockid, iface_no); 972181641Skmacy USETW(req.wLength, 255); 973181641Skmacy 974181641Skmacy error = usbd_do_request_flags(udev, NULL, &req, data, 975181641Skmacy USB_SHORT_XFER_OK, &actlen, USB_DEFAULT_TIMEOUT); 976181641Skmacy 977181641Skmacy if (error != 0 || actlen < 2) 978181641Skmacy return (USB_ERR_INVAL); 979181641Skmacy 980181641Skmacy rates = data[0] | (data[1] << 8); 981181641Skmacy actlen = (actlen - 2) / 12; 982181641Skmacy 983181641Skmacy if (rates > actlen) { 984181641Skmacy DPRINTF("Too many rates\n"); 985181641Skmacy rates = actlen; 986181641Skmacy } 987181641Skmacy 988181641Skmacy for (x = 0; x != rates; x++) { 989181641Skmacy uint32_t min = UGETDW(data + 2 + (12 * x)); 990181641Skmacy uint32_t max = UGETDW(data + 6 + (12 * x)); 991181641Skmacy uint32_t res = UGETDW(data + 10 + (12 * x)); 992181641Skmacy 993181641Skmacy if (res == 0) { 994181641Skmacy DPRINTF("Zero residue\n"); 995181641Skmacy res = 1; 996181641Skmacy } 997181641Skmacy 998181641Skmacy if (min > max) { 999181641Skmacy DPRINTF("Swapped max and min\n"); 1000195949Skib uint32_t temp; 1001195949Skib temp = min; 1002195949Skib min = max; 1003195949Skib max = temp; 1004195949Skib } 1005195949Skib 1006195949Skib if (rate >= min && rate <= max && 1007195949Skib (((rate - min) % res) == 0)) { 1008195949Skib return (0); 1009195949Skib } 1010195949Skib } 1011195949Skib return (USB_ERR_INVAL); 1012195949Skib} 1013195949Skib 1014195949Skibstatic void 1015195949Skibuaudio_chan_fill_info_sub(struct uaudio_softc *sc, struct usb_device *udev, 1016195949Skib uint32_t rate, uint8_t channels, uint8_t bit_resolution) 1017195949Skib{ 1018195949Skib struct usb_descriptor *desc = NULL; 1019195949Skib union uaudio_asid asid = { NULL }; 1020195949Skib union uaudio_asf1d asf1d = { NULL }; 1021197046Skib union uaudio_sed sed = { NULL }; 1022197046Skib usb_endpoint_descriptor_audio_t *ed1 = NULL; 1023195949Skib const struct usb_audio_control_descriptor *acdp = NULL; 1024195949Skib struct usb_config_descriptor *cd = usbd_get_config_descriptor(udev); 1025195949Skib struct usb_interface_descriptor *id; 1026195949Skib const struct uaudio_format *p_fmt = NULL; 1027195949Skib struct uaudio_chan *chan; 1028195949Skib uint16_t curidx = 0xFFFF; 1029195949Skib uint16_t lastidx = 0xFFFF; 1030195949Skib uint16_t alt_index = 0; 1031195949Skib uint16_t audio_rev = 0; 1032195949Skib uint16_t x; 1033195949Skib uint8_t ep_dir; 1034181641Skmacy uint8_t bChannels; 1035181641Skmacy uint8_t bBitResolution; 1036181641Skmacy uint8_t audio_if = 0; 1037181641Skmacy uint8_t uma_if_class; 1038181641Skmacy 1039181641Skmacy while ((desc = usb_desc_foreach(cd, desc))) { 1040181641Skmacy 1041181641Skmacy if ((desc->bDescriptorType == UDESC_INTERFACE) && 1042181641Skmacy (desc->bLength >= sizeof(*id))) { 1043181641Skmacy 1044181641Skmacy id = (void *)desc; 1045181641Skmacy 1046181641Skmacy if (id->bInterfaceNumber != lastidx) { 1047181641Skmacy lastidx = id->bInterfaceNumber; 1048181641Skmacy curidx++; 1049181641Skmacy alt_index = 0; 1050181641Skmacy 1051181641Skmacy } else { 1052181641Skmacy alt_index++; 1053181641Skmacy } 1054181641Skmacy 1055181641Skmacy uma_if_class = 1056181641Skmacy ((id->bInterfaceClass == UICLASS_AUDIO) || 1057181641Skmacy ((id->bInterfaceClass == UICLASS_VENDOR) && 1058181641Skmacy (sc->sc_uq_au_vendor_class != 0))); 1059181641Skmacy 1060181641Skmacy if ((uma_if_class != 0) && (id->bInterfaceSubClass == UISUBCLASS_AUDIOSTREAM)) { 1061181641Skmacy audio_if = 1; 1062181641Skmacy } else { 1063181641Skmacy audio_if = 0; 1064181641Skmacy } 1065181641Skmacy 1066181641Skmacy if ((uma_if_class != 0) && 1067181641Skmacy (id->bInterfaceSubClass == UISUBCLASS_MIDISTREAM)) { 1068181641Skmacy 1069204160Skmacy /* 1070181641Skmacy * XXX could allow multiple MIDI interfaces 1071204160Skmacy */ 1072181641Skmacy 1073181641Skmacy if ((sc->sc_midi_chan.valid == 0) && 1074181641Skmacy usbd_get_iface(udev, curidx)) { 1075181641Skmacy sc->sc_midi_chan.iface_index = curidx; 1076181641Skmacy sc->sc_midi_chan.iface_alt_index = alt_index; 1077181641Skmacy sc->sc_midi_chan.valid = 1; 1078181641Skmacy } 1079181641Skmacy } 1080181641Skmacy asid.v1 = NULL; 1081181641Skmacy asf1d.v1 = NULL; 1082181641Skmacy ed1 = NULL; 1083181641Skmacy sed.v1 = NULL; 1084181641Skmacy } 1085181641Skmacy 1086181641Skmacy if (audio_if == 0) { 1087181641Skmacy if ((acdp == NULL) && 1088181641Skmacy (desc->bDescriptorType == UDESC_CS_INTERFACE) && 1089181641Skmacy (desc->bDescriptorSubtype == UDESCSUB_AC_HEADER) && 1090181641Skmacy (desc->bLength >= sizeof(*acdp))) { 1091181641Skmacy acdp = (void *)desc; 1092181641Skmacy audio_rev = UGETW(acdp->bcdADC); 1093181641Skmacy } 1094181641Skmacy 1095181641Skmacy /* 1096181641Skmacy * Don't collect any USB audio descriptors if 1097181641Skmacy * this is not an USB audio stream interface. 1098181641Skmacy */ 1099181641Skmacy continue; 1100181641Skmacy } 1101181641Skmacy 1102181641Skmacy if ((acdp != NULL) && 1103181641Skmacy (desc->bDescriptorType == UDESC_CS_INTERFACE) && 1104181641Skmacy (desc->bDescriptorSubtype == AS_GENERAL) && 1105181641Skmacy (asid.v1 == NULL)) { 1106181641Skmacy if (audio_rev >= UAUDIO_VERSION_30) { 1107181641Skmacy /* FALLTHROUGH */ 1108181641Skmacy } else if (audio_rev >= UAUDIO_VERSION_20) { 1109181641Skmacy if (desc->bLength >= sizeof(*asid.v2)) { 1110181641Skmacy asid.v2 = (void *)desc; 1111181641Skmacy } 1112181641Skmacy } else { 1113181641Skmacy if (desc->bLength >= sizeof(*asid.v1)) { 1114181641Skmacy asid.v1 = (void *)desc; 1115181641Skmacy } 1116181641Skmacy } 1117181641Skmacy } 1118181641Skmacy if ((acdp != NULL) && 1119181641Skmacy (desc->bDescriptorType == UDESC_CS_INTERFACE) && 1120181641Skmacy (desc->bDescriptorSubtype == FORMAT_TYPE) && 1121181641Skmacy (asf1d.v1 == NULL)) { 1122181641Skmacy if (audio_rev >= UAUDIO_VERSION_30) { 1123181641Skmacy /* FALLTHROUGH */ 1124181641Skmacy } else if (audio_rev >= UAUDIO_VERSION_20) { 1125181641Skmacy if (desc->bLength >= sizeof(*asf1d.v2)) 1126181641Skmacy asf1d.v2 = (void *)desc; 1127181641Skmacy } else { 1128181641Skmacy if (desc->bLength >= sizeof(*asf1d.v1)) { 1129181641Skmacy asf1d.v1 = (void *)desc; 1130181641Skmacy 1131181641Skmacy if (asf1d.v1->bFormatType != FORMAT_TYPE_I) { 1132181641Skmacy DPRINTFN(11, "ignored bFormatType = %d\n", 1133181641Skmacy asf1d.v1->bFormatType); 1134181641Skmacy asf1d.v1 = NULL; 1135181641Skmacy continue; 1136181641Skmacy } 1137181641Skmacy if (desc->bLength < (sizeof(*asf1d.v1) + 1138181641Skmacy ((asf1d.v1->bSamFreqType == 0) ? 6 : 1139181641Skmacy (asf1d.v1->bSamFreqType * 3)))) { 1140181641Skmacy DPRINTFN(11, "invalid descriptor, " 1141181641Skmacy "too short\n"); 1142181641Skmacy asf1d.v1 = NULL; 1143181641Skmacy continue; 1144181641Skmacy } 1145181641Skmacy } 1146181641Skmacy } 1147181641Skmacy } 1148181641Skmacy if ((desc->bDescriptorType == UDESC_ENDPOINT) && 1149181641Skmacy (desc->bLength >= UEP_MINSIZE) && 1150181641Skmacy (ed1 == NULL)) { 1151181641Skmacy ed1 = (void *)desc; 1152181641Skmacy if (UE_GET_XFERTYPE(ed1->bmAttributes) != UE_ISOCHRONOUS) { 1153181641Skmacy ed1 = NULL; 1154181641Skmacy continue; 1155181641Skmacy } 1156181641Skmacy } 1157181641Skmacy if ((acdp != NULL) && 1158181641Skmacy (desc->bDescriptorType == UDESC_CS_ENDPOINT) && 1159181641Skmacy (desc->bDescriptorSubtype == AS_GENERAL) && 1160181641Skmacy (sed.v1 == NULL)) { 1161181641Skmacy if (audio_rev >= UAUDIO_VERSION_30) { 1162181641Skmacy /* FALLTHROUGH */ 1163181641Skmacy } else if (audio_rev >= UAUDIO_VERSION_20) { 1164181641Skmacy if (desc->bLength >= sizeof(*sed.v2)) 1165181641Skmacy sed.v2 = (void *)desc; 1166181641Skmacy } else { 1167181641Skmacy if (desc->bLength >= sizeof(*sed.v1)) 1168181641Skmacy sed.v1 = (void *)desc; 1169181641Skmacy } 1170181641Skmacy } 1171181641Skmacy if (asid.v1 == NULL || asf1d.v1 == NULL || 1172181641Skmacy ed1 == NULL || sed.v1 == NULL) { 1173181641Skmacy /* need more descriptors */ 1174181641Skmacy continue; 1175181641Skmacy } 1176181641Skmacy 1177181641Skmacy ep_dir = UE_GET_DIR(ed1->bEndpointAddress); 1178181641Skmacy 1179181641Skmacy /* We ignore sync endpoint information until further. */ 1180181641Skmacy 1181181641Skmacy if (audio_rev >= UAUDIO_VERSION_30) { 1182181641Skmacy goto next_ep; 1183181641Skmacy } else if (audio_rev >= UAUDIO_VERSION_20) { 1184181641Skmacy 1185181641Skmacy uint32_t dwFormat; 1186181641Skmacy uint8_t bSubslotSize; 1187181641Skmacy 1188181641Skmacy dwFormat = UGETDW(asid.v2->bmFormats); 1189181641Skmacy bChannels = asid.v2->bNrChannels; 1190181641Skmacy bBitResolution = asf1d.v2->bBitResolution; 1191181641Skmacy bSubslotSize = asf1d.v2->bSubslotSize; 1192181641Skmacy 1193181641Skmacy if (bBitResolution != (bSubslotSize * 8)) { 1194181641Skmacy DPRINTF("Invalid bSubslotSize\n"); 1195181641Skmacy goto next_ep; 1196181641Skmacy } 1197181641Skmacy 1198181641Skmacy if ((bChannels != channels) || 1199181641Skmacy (bBitResolution != bit_resolution)) { 1200181641Skmacy DPRINTF("Wrong number of channels\n"); 1201181641Skmacy goto next_ep; 1202181641Skmacy } 1203181641Skmacy 1204181641Skmacy for (p_fmt = uaudio20_formats; 1205181641Skmacy p_fmt->wFormat != 0; p_fmt++) { 1206181641Skmacy if ((p_fmt->wFormat & dwFormat) && 1207181641Skmacy (p_fmt->bPrecision == bBitResolution)) 1208181641Skmacy break; 1209181641Skmacy } 1210181641Skmacy 1211181641Skmacy if (p_fmt->wFormat == 0) { 1212181641Skmacy DPRINTF("Unsupported audio format\n"); 1213181641Skmacy goto next_ep; 1214181641Skmacy } 1215181641Skmacy 1216181641Skmacy for (x = 0; x != 256; x++) { 1217181641Skmacy if (ep_dir == UE_DIR_OUT) { 1218181641Skmacy if (!(sc->sc_mixer_clocks.bit_output[x / 8] & 1219181641Skmacy (1 << (x % 8)))) { 1220181641Skmacy continue; 1221181641Skmacy } 1222181641Skmacy } else { 1223181641Skmacy if (!(sc->sc_mixer_clocks.bit_input[x / 8] & 1224181641Skmacy (1 << (x % 8)))) { 1225181641Skmacy continue; 1226181641Skmacy } 1227181641Skmacy } 1228207410Skmacy 1229181641Skmacy DPRINTF("Checking clock ID=%d\n", x); 1230207410Skmacy 1231181641Skmacy if (uaudio20_check_rate(udev, 1232181641Skmacy sc->sc_mixer_iface_no, x, rate)) { 1233207410Skmacy DPRINTF("Unsupported sampling " 1234181641Skmacy "rate, id=%d\n", x); 1235181641Skmacy goto next_ep; 1236181641Skmacy } 1237181641Skmacy } 1238207410Skmacy } else { 1239207410Skmacy uint16_t wFormat; 1240207410Skmacy 1241181641Skmacy wFormat = UGETW(asid.v1->wFormatTag); 1242181641Skmacy bChannels = UAUDIO_MAX_CHAN(asf1d.v1->bNrChannels); 1243181641Skmacy bBitResolution = asf1d.v1->bBitResolution; 1244181641Skmacy 1245181641Skmacy if (asf1d.v1->bSamFreqType == 0) { 1246181641Skmacy DPRINTFN(16, "Sample rate: %d-%dHz\n", 1247181641Skmacy UA_SAMP_LO(asf1d.v1), 1248181641Skmacy UA_SAMP_HI(asf1d.v1)); 1249181641Skmacy 1250181641Skmacy if ((rate >= UA_SAMP_LO(asf1d.v1)) && 1251181641Skmacy (rate <= UA_SAMP_HI(asf1d.v1))) 1252207410Skmacy goto found_rate; 1253207410Skmacy } else { 1254181641Skmacy 1255181641Skmacy for (x = 0; x < asf1d.v1->bSamFreqType; x++) { 1256181641Skmacy DPRINTFN(16, "Sample rate = %dHz\n", 1257181641Skmacy UA_GETSAMP(asf1d.v1, x)); 1258181641Skmacy 1259181641Skmacy if (rate == UA_GETSAMP(asf1d.v1, x)) 1260207410Skmacy goto found_rate; 1261181641Skmacy } 1262181641Skmacy } 1263181641Skmacy goto next_ep; 1264181641Skmacy 1265181641Skmacy found_rate: 1266181641Skmacy for (p_fmt = uaudio10_formats; 1267181641Skmacy p_fmt->wFormat != 0; p_fmt++) { 1268181641Skmacy if ((p_fmt->wFormat == wFormat) && 1269181641Skmacy (p_fmt->bPrecision == bBitResolution)) 1270181641Skmacy break; 1271181641Skmacy } 1272181641Skmacy if (p_fmt->wFormat == 0) { 1273181747Skmacy DPRINTF("Unsupported audio format\n"); 1274181641Skmacy goto next_ep; 1275181641Skmacy } 1276181641Skmacy 1277181641Skmacy if ((bChannels != channels) || 1278181641Skmacy (bBitResolution != bit_resolution)) { 1279181747Skmacy DPRINTF("Wrong number of channels\n"); 1280181641Skmacy goto next_ep; 1281181641Skmacy } 1282181641Skmacy } 1283181641Skmacy 1284181641Skmacy chan = (ep_dir == UE_DIR_IN) ? 1285181641Skmacy &sc->sc_rec_chan : &sc->sc_play_chan; 1286181641Skmacy 1287181641Skmacy if (chan->valid != 0 || 1288181641Skmacy usbd_get_iface(udev, curidx) == NULL) { 1289181747Skmacy DPRINTF("Channel already exists or " 1290181641Skmacy "interface is not valid\n"); 1291181641Skmacy goto next_ep; 1292181641Skmacy } 1293181641Skmacy 1294181641Skmacy chan->valid = 1; 1295181641Skmacy#ifdef USB_DEBUG 1296181641Skmacy uaudio_chan_dump_ep_desc(ed1); 1297181641Skmacy#endif 1298181641Skmacy DPRINTF("Sample rate = %dHz, channels = %d, " 1299181641Skmacy "bits = %d, format = %s\n", rate, channels, 1300181641Skmacy bit_resolution, p_fmt->description); 1301181641Skmacy 1302181641Skmacy chan->sample_rate = rate; 1303181641Skmacy chan->p_asf1d = asf1d; 1304181641Skmacy chan->p_ed1 = ed1; 1305181641Skmacy chan->p_fmt = p_fmt; 1306181641Skmacy chan->p_sed = sed; 1307181641Skmacy chan->iface_index = curidx; 1308181641Skmacy chan->iface_alt_index = alt_index; 1309181641Skmacy 1310181641Skmacy if (ep_dir == UE_DIR_IN) 1311181641Skmacy chan->usb_cfg = uaudio_cfg_record; 1312181641Skmacy else 1313181641Skmacy chan->usb_cfg = uaudio_cfg_play; 1314181641Skmacy 1315181641Skmacy chan->sample_size = (UAUDIO_MAX_CHAN(channels) * 1316181641Skmacy p_fmt->bPrecision) / 8; 1317181641Skmacy chan->channels = channels; 1318181641Skmacy 1319181641Skmacy if (ep_dir == UE_DIR_IN && 1320181641Skmacy usbd_get_speed(udev) == USB_SPEED_FULL) { 1321181641Skmacy uaudio_record_fix_fs(ed1, 1322181641Skmacy chan->sample_size * (rate / 1000), 1323181641Skmacy chan->sample_size * (rate / 4000)); 1324181641Skmacy } 1325181641Skmacy 1326181641Skmacy if (sc->sc_sndstat_valid != 0) { 1327181641Skmacy sbuf_printf(&sc->sc_sndstat, "\n\t" 1328181641Skmacy "mode %d.%d:(%s) %dch, %dbit, %s, %dHz", 1329181641Skmacy curidx, alt_index, 1330181641Skmacy (ep_dir == UE_DIR_IN) ? "input" : "output", 1331181641Skmacy channels, p_fmt->bPrecision, 1332181641Skmacy p_fmt->description, rate); 1333181641Skmacy } 1334181641Skmacy 1335181641Skmacy next_ep: 1336181641Skmacy sed.v1 = NULL; 1337181641Skmacy ed1 = NULL; 1338181641Skmacy } 1339181641Skmacy} 1340181641Skmacy 1341181641Skmacy/* This structure defines all the supported rates. */ 1342181641Skmacy 1343181641Skmacystatic const uint32_t uaudio_rate_list[] = { 1344181641Skmacy 96000, 1345181641Skmacy 88000, 1346181641Skmacy 80000, 1347181641Skmacy 72000, 1348181641Skmacy 64000, 1349181641Skmacy 56000, 1350181641Skmacy 48000, 1351181641Skmacy 44100, 1352181641Skmacy 40000, 1353181641Skmacy 32000, 1354181641Skmacy 24000, 1355181641Skmacy 22050, 1356181641Skmacy 16000, 1357181641Skmacy 11025, 1358181641Skmacy 8000, 1359181641Skmacy 0 1360181641Skmacy}; 1361181641Skmacy 1362181641Skmacystatic void 1363181641Skmacyuaudio_chan_fill_info(struct uaudio_softc *sc, struct usb_device *udev) 1364181641Skmacy{ 1365181641Skmacy uint32_t rate = uaudio_default_rate; 1366181641Skmacy uint8_t z; 1367181641Skmacy uint8_t bits = uaudio_default_bits; 1368181641Skmacy uint8_t y; 1369181641Skmacy uint8_t channels = uaudio_default_channels; 1370181641Skmacy uint8_t x; 1371181641Skmacy 1372181641Skmacy bits -= (bits % 8); 1373181641Skmacy if ((bits == 0) || (bits > 32)) { 1374181641Skmacy /* set a valid value */ 1375181641Skmacy bits = 32; 1376181641Skmacy } 1377181641Skmacy if (channels == 0) { 1378181641Skmacy switch (usbd_get_speed(udev)) { 1379181641Skmacy case USB_SPEED_LOW: 1380181641Skmacy case USB_SPEED_FULL: 1381181641Skmacy /* 1382181641Skmacy * Due to high bandwidth usage and problems 1383181641Skmacy * with HIGH-speed split transactions we 1384181641Skmacy * disable surround setups on FULL-speed USB 1385181641Skmacy * by default 1386181641Skmacy */ 1387181641Skmacy channels = 4; 1388181641Skmacy break; 1389181641Skmacy default: 1390181641Skmacy channels = 16; 1391181641Skmacy break; 1392181641Skmacy } 1393181641Skmacy } else if (channels > 16) { 1394181641Skmacy channels = 16; 1395181641Skmacy } 1396181641Skmacy if (sbuf_new(&sc->sc_sndstat, NULL, 4096, SBUF_AUTOEXTEND)) { 1397181641Skmacy sc->sc_sndstat_valid = 1; 1398181641Skmacy } 1399181641Skmacy /* try to search for a valid config */ 1400181641Skmacy 1401181641Skmacy for (x = channels; x; x--) { 1402181641Skmacy for (y = bits; y; y -= 8) { 1403181641Skmacy 1404181641Skmacy /* try user defined rate, if any */ 1405181641Skmacy if (rate != 0) 1406181641Skmacy uaudio_chan_fill_info_sub(sc, udev, rate, x, y); 1407181641Skmacy 1408181641Skmacy /* try find a matching rate, if any */ 1409181641Skmacy for (z = 0; uaudio_rate_list[z]; z++) { 1410181641Skmacy uaudio_chan_fill_info_sub(sc, udev, uaudio_rate_list[z], x, y); 1411181641Skmacy 1412181641Skmacy if (sc->sc_rec_chan.valid && 1413181641Skmacy sc->sc_play_chan.valid) { 1414181641Skmacy goto done; 1415181641Skmacy } 1416181641Skmacy } 1417181641Skmacy } 1418181641Skmacy } 1419181641Skmacy 1420181641Skmacydone: 1421181641Skmacy if (sc->sc_sndstat_valid) { 1422181641Skmacy sbuf_finish(&sc->sc_sndstat); 1423181641Skmacy } 1424181641Skmacy} 1425181641Skmacy 1426181641Skmacystatic void 1427181641Skmacyuaudio_chan_play_sync_callback(struct usb_xfer *xfer, usb_error_t error) 1428181641Skmacy{ 1429181641Skmacy struct uaudio_chan *ch = usbd_xfer_softc(xfer); 1430181641Skmacy struct usb_page_cache *pc; 1431181641Skmacy uint8_t buf[4]; 1432181641Skmacy uint64_t temp; 1433181641Skmacy int len; 1434181641Skmacy int actlen; 1435181641Skmacy int nframes; 1436181641Skmacy 1437181641Skmacy usbd_xfer_status(xfer, &actlen, NULL, NULL, &nframes); 1438181641Skmacy 1439181641Skmacy switch (USB_GET_STATE(xfer)) { 1440181641Skmacy case USB_ST_TRANSFERRED: 1441181641Skmacy 1442181641Skmacy DPRINTFN(6, "transferred %d bytes\n", actlen); 1443181641Skmacy 1444181641Skmacy if (nframes == 0) 1445181641Skmacy break; 1446181641Skmacy len = usbd_xfer_frame_len(xfer, 0); 1447181641Skmacy if (len == 0) 1448181641Skmacy break; 1449181641Skmacy if (len > sizeof(buf)) 1450181641Skmacy len = sizeof(buf); 1451181641Skmacy 1452181641Skmacy memset(buf, 0, sizeof(buf)); 1453181641Skmacy 1454181641Skmacy pc = usbd_xfer_get_frame(xfer, 0); 1455181641Skmacy usbd_copy_out(pc, 0, buf, len); 1456181641Skmacy 1457181641Skmacy temp = UGETDW(buf); 1458181641Skmacy 1459181641Skmacy DPRINTF("Value = 0x%08x\n", (int)temp); 1460181641Skmacy 1461181641Skmacy /* auto-detect SYNC format */ 1462181641Skmacy 1463181641Skmacy if (len == 4) 1464181641Skmacy temp &= 0x0fffffff; 1465181641Skmacy 1466181641Skmacy /* check for no data */ 1467181641Skmacy 1468181641Skmacy if (temp == 0) 1469181641Skmacy break; 1470181641Skmacy 1471181641Skmacy /* correctly scale value */ 1472181641Skmacy 1473181641Skmacy temp = (temp * 125ULL) - 64; 1474181641Skmacy 1475181641Skmacy /* auto adjust */ 1476181641Skmacy 1477181641Skmacy while (temp < (ch->sample_rate - (ch->sample_rate / 4))) 1478181641Skmacy temp *= 2; 1479181641Skmacy 1480181641Skmacy while (temp > (ch->sample_rate + (ch->sample_rate / 2))) 1481181641Skmacy temp /= 2; 1482181641Skmacy 1483181641Skmacy /* bias */ 1484181641Skmacy 1485181641Skmacy temp += (ch->sample_rate + 1999) / 2000; 1486181641Skmacy 1487181641Skmacy /* compare */ 1488181641Skmacy 1489181641Skmacy DPRINTF("Comparing %d < %d\n", 1490181641Skmacy (int)temp, (int)ch->sample_rate); 1491181641Skmacy 1492181641Skmacy if (temp == ch->sample_rate) 1493181641Skmacy ch->last_sync_state = UAUDIO_SYNC_NONE; 1494181641Skmacy else if (temp > ch->sample_rate) 1495181641Skmacy ch->last_sync_state = UAUDIO_SYNC_MORE; 1496181641Skmacy else 1497181641Skmacy ch->last_sync_state = UAUDIO_SYNC_LESS; 1498181641Skmacy break; 1499181641Skmacy 1500181641Skmacy case USB_ST_SETUP: 1501181641Skmacy usbd_xfer_set_frames(xfer, 1); 1502181641Skmacy usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_framelen(xfer)); 1503181641Skmacy usbd_transfer_submit(xfer); 1504181641Skmacy break; 1505181641Skmacy 1506181641Skmacy default: /* Error */ 1507181641Skmacy break; 1508181641Skmacy } 1509181641Skmacy} 1510181641Skmacy 1511181641Skmacystatic void 1512181641Skmacyuaudio_chan_play_callback(struct usb_xfer *xfer, usb_error_t error) 1513181641Skmacy{ 1514181641Skmacy struct uaudio_chan *ch = usbd_xfer_softc(xfer); 1515181641Skmacy struct usb_page_cache *pc; 1516181641Skmacy uint32_t mfl; 1517181641Skmacy uint32_t total; 1518181641Skmacy uint32_t blockcount; 1519181641Skmacy uint32_t n; 1520181641Skmacy uint32_t offset; 1521181641Skmacy int actlen; 1522181641Skmacy int sumlen; 1523181641Skmacy 1524181641Skmacy usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 1525181641Skmacy 1526181641Skmacy if (ch->end == ch->start) { 1527181641Skmacy DPRINTF("no buffer!\n"); 1528181641Skmacy return; 1529181641Skmacy } 1530181641Skmacy 1531181641Skmacy switch (USB_GET_STATE(xfer)) { 1532181641Skmacy case USB_ST_TRANSFERRED: 1533181641Skmacytr_transferred: 1534181641Skmacy if (actlen < sumlen) { 1535181641Skmacy DPRINTF("short transfer, " 1536181641Skmacy "%d of %d bytes\n", actlen, sumlen); 1537181641Skmacy } 1538181641Skmacy chn_intr(ch->pcm_ch); 1539181641Skmacy 1540181641Skmacy /* start SYNC transfer, if any */ 1541181641Skmacy if ((ch->last_sync_time++ & 7) == 0) 1542181641Skmacy usbd_transfer_start(ch->xfer[UAUDIO_NCHANBUFS]); 1543181641Skmacy 1544181641Skmacy case USB_ST_SETUP: 1545181641Skmacy mfl = usbd_xfer_max_framelen(xfer); 1546181641Skmacy 1547181641Skmacy if (ch->bytes_per_frame[1] > mfl) { 1548181641Skmacy DPRINTF("bytes per transfer, %d, " 1549181641Skmacy "exceeds maximum, %d!\n", 1550181641Skmacy ch->bytes_per_frame[1], 1551181641Skmacy mfl); 1552181641Skmacy break; 1553181641Skmacy } 1554181641Skmacy 1555181641Skmacy blockcount = ch->intr_frames; 1556181641Skmacy 1557181641Skmacy /* setup number of frames */ 1558181641Skmacy usbd_xfer_set_frames(xfer, blockcount); 1559181641Skmacy 1560181641Skmacy /* reset total length */ 1561181641Skmacy total = 0; 1562181641Skmacy 1563181641Skmacy /* setup frame lengths */ 1564181641Skmacy for (n = 0; n != blockcount; n++) { 1565181641Skmacy uint32_t frame_len; 1566181641Skmacy 1567181641Skmacy ch->sample_curr += ch->sample_rem; 1568181641Skmacy if (ch->sample_curr >= ch->frames_per_second) { 1569181641Skmacy ch->sample_curr -= ch->frames_per_second; 1570181641Skmacy frame_len = ch->bytes_per_frame[1]; 1571181641Skmacy } else { 1572181641Skmacy frame_len = ch->bytes_per_frame[0]; 1573181641Skmacy } 1574181641Skmacy 1575181641Skmacy if (n == (blockcount - 1)) { 1576181641Skmacy switch (ch->last_sync_state) { 1577181641Skmacy case UAUDIO_SYNC_MORE: 1578181641Skmacy DPRINTFN(6, "sending one sample more\n"); 1579181641Skmacy if ((frame_len + ch->sample_size) <= mfl) 1580181641Skmacy frame_len += ch->sample_size; 1581181641Skmacy ch->last_sync_state = UAUDIO_SYNC_NONE; 1582181641Skmacy break; 1583181641Skmacy case UAUDIO_SYNC_LESS: 1584181641Skmacy DPRINTFN(6, "sending one sample less\n"); 1585181641Skmacy if (frame_len >= ch->sample_size) 1586181641Skmacy frame_len -= ch->sample_size; 1587181641Skmacy ch->last_sync_state = UAUDIO_SYNC_NONE; 1588181641Skmacy break; 1589181641Skmacy default: 1590181641Skmacy break; 1591181641Skmacy } 1592181641Skmacy } 1593181641Skmacy 1594181641Skmacy usbd_xfer_set_frame_len(xfer, n, frame_len); 1595181641Skmacy total += frame_len; 1596181641Skmacy } 1597181641Skmacy 1598181641Skmacy DPRINTFN(6, "transfer %d bytes\n", total); 1599181641Skmacy 1600181641Skmacy offset = 0; 1601181641Skmacy 1602181641Skmacy pc = usbd_xfer_get_frame(xfer, 0); 1603181641Skmacy while (total > 0) { 1604181641Skmacy 1605181641Skmacy n = (ch->end - ch->cur); 1606181641Skmacy if (n > total) { 1607181641Skmacy n = total; 1608181641Skmacy } 1609181641Skmacy usbd_copy_in(pc, offset, ch->cur, n); 1610181641Skmacy 1611181641Skmacy total -= n; 1612181641Skmacy ch->cur += n; 1613181641Skmacy offset += n; 1614181641Skmacy 1615181641Skmacy if (ch->cur >= ch->end) { 1616181641Skmacy ch->cur = ch->start; 1617181641Skmacy } 1618181641Skmacy } 1619181641Skmacy 1620181641Skmacy usbd_transfer_submit(xfer); 1621181641Skmacy break; 1622181641Skmacy 1623181641Skmacy default: /* Error */ 1624181641Skmacy if (error == USB_ERR_CANCELLED) { 1625181641Skmacy break; 1626181641Skmacy } 1627181641Skmacy goto tr_transferred; 1628181641Skmacy } 1629181641Skmacy} 1630181641Skmacy 1631181641Skmacystatic void 1632181641Skmacyuaudio_chan_record_sync_callback(struct usb_xfer *xfer, usb_error_t error) 1633181641Skmacy{ 1634181641Skmacy /* TODO */ 1635181641Skmacy} 1636181641Skmacy 1637181641Skmacystatic void 1638181641Skmacyuaudio_chan_record_callback(struct usb_xfer *xfer, usb_error_t error) 1639181641Skmacy{ 1640181641Skmacy struct uaudio_chan *ch = usbd_xfer_softc(xfer); 1641181641Skmacy struct usb_page_cache *pc; 1642181641Skmacy uint32_t offset0; 1643181641Skmacy uint32_t offset1; 1644181641Skmacy uint32_t mfl; 1645181641Skmacy int m; 1646181641Skmacy int n; 1647181641Skmacy int len; 1648181641Skmacy int actlen; 1649181641Skmacy int nframes; 1650181641Skmacy int blockcount; 1651181641Skmacy 1652181641Skmacy usbd_xfer_status(xfer, &actlen, NULL, NULL, &nframes); 1653181641Skmacy mfl = usbd_xfer_max_framelen(xfer); 1654181641Skmacy 1655181641Skmacy if (ch->end == ch->start) { 1656181641Skmacy DPRINTF("no buffer!\n"); 1657181641Skmacy return; 1658181641Skmacy } 1659181641Skmacy 1660181641Skmacy switch (USB_GET_STATE(xfer)) { 1661181641Skmacy case USB_ST_TRANSFERRED: 1662181641Skmacy 1663181641Skmacy DPRINTFN(6, "transferred %d bytes\n", actlen); 1664181641Skmacy 1665181641Skmacy offset0 = 0; 1666181641Skmacy pc = usbd_xfer_get_frame(xfer, 0); 1667181641Skmacy 1668181641Skmacy for (n = 0; n != nframes; n++) { 1669181641Skmacy 1670181641Skmacy offset1 = offset0; 1671181641Skmacy len = usbd_xfer_frame_len(xfer, n); 1672181641Skmacy 1673181641Skmacy while (len > 0) { 1674181641Skmacy 1675181641Skmacy m = (ch->end - ch->cur); 1676181641Skmacy 1677181641Skmacy if (m > len) 1678181641Skmacy m = len; 1679181641Skmacy 1680181641Skmacy usbd_copy_out(pc, offset1, ch->cur, m); 1681181641Skmacy 1682181641Skmacy len -= m; 1683181641Skmacy offset1 += m; 1684181641Skmacy ch->cur += m; 1685181641Skmacy 1686181641Skmacy if (ch->cur >= ch->end) { 1687181641Skmacy ch->cur = ch->start; 1688181641Skmacy } 1689181641Skmacy } 1690181641Skmacy 1691181641Skmacy offset0 += mfl; 1692181641Skmacy } 1693181641Skmacy 1694181641Skmacy chn_intr(ch->pcm_ch); 1695181641Skmacy 1696181641Skmacy case USB_ST_SETUP: 1697181641Skmacytr_setup: 1698181641Skmacy blockcount = ch->intr_frames; 1699181641Skmacy 1700181641Skmacy usbd_xfer_set_frames(xfer, blockcount); 1701181641Skmacy for (n = 0; n < blockcount; n++) { 1702181641Skmacy usbd_xfer_set_frame_len(xfer, n, mfl); 1703181641Skmacy } 1704181641Skmacy 1705181641Skmacy usbd_transfer_submit(xfer); 1706181641Skmacy break; 1707181641Skmacy 1708181641Skmacy default: /* Error */ 1709181641Skmacy if (error == USB_ERR_CANCELLED) { 1710181641Skmacy break; 1711181641Skmacy } 1712181641Skmacy goto tr_setup; 1713181641Skmacy } 1714181641Skmacy} 1715181641Skmacy 1716181641Skmacyvoid * 1717181641Skmacyuaudio_chan_init(struct uaudio_softc *sc, struct snd_dbuf *b, 1718181641Skmacy struct pcm_channel *c, int dir) 1719181641Skmacy{ 1720181641Skmacy struct uaudio_chan *ch = ((dir == PCMDIR_PLAY) ? 1721181641Skmacy &sc->sc_play_chan : &sc->sc_rec_chan); 1722181641Skmacy uint32_t buf_size; 1723181641Skmacy uint32_t frames; 1724181641Skmacy uint32_t format; 1725181641Skmacy uint16_t fps; 1726181641Skmacy uint8_t endpoint; 1727181641Skmacy uint8_t blocks; 1728181641Skmacy uint8_t iface_index; 1729181641Skmacy uint8_t alt_index; 1730181641Skmacy uint8_t fps_shift; 1731181641Skmacy usb_error_t err; 1732181641Skmacy 1733181641Skmacy fps = usbd_get_isoc_fps(sc->sc_udev); 1734181641Skmacy 1735181641Skmacy if (fps < 8000) { 1736181641Skmacy /* FULL speed USB */ 1737181641Skmacy frames = 8; 1738181641Skmacy } else { 1739181641Skmacy /* HIGH speed USB */ 1740181641Skmacy frames = UAUDIO_NFRAMES; 1741181641Skmacy } 1742181641Skmacy 1743181641Skmacy /* setup play/record format */ 1744181641Skmacy 1745181641Skmacy ch->pcm_cap.fmtlist = ch->pcm_format; 1746181641Skmacy 1747181641Skmacy ch->pcm_format[0] = 0; 1748181641Skmacy ch->pcm_format[1] = 0; 1749181641Skmacy 1750181641Skmacy ch->pcm_cap.minspeed = ch->sample_rate; 1751181641Skmacy ch->pcm_cap.maxspeed = ch->sample_rate; 1752181641Skmacy 1753181641Skmacy /* setup mutex and PCM channel */ 1754181641Skmacy 1755196728Sadrian ch->pcm_ch = c; 1756181641Skmacy ch->pcm_mtx = c->lock; 1757181641Skmacy 1758181641Skmacy format = ch->p_fmt->freebsd_fmt; 1759181641Skmacy 1760181641Skmacy switch (ch->channels) { 1761181641Skmacy case 2: 1762181641Skmacy /* stereo */ 1763181641Skmacy format = SND_FORMAT(format, 2, 0); 1764196728Sadrian break; 1765181641Skmacy case 1: 1766181641Skmacy /* mono */ 1767181641Skmacy format = SND_FORMAT(format, 1, 0); 1768181641Skmacy break; 1769181641Skmacy default: 1770181641Skmacy /* surround and more */ 1771181641Skmacy format = feeder_matrix_default_format( 1772181641Skmacy SND_FORMAT(format, ch->channels, 0)); 1773181641Skmacy break; 1774181641Skmacy } 1775181641Skmacy 1776196728Sadrian ch->pcm_cap.fmtlist[0] = format; 1777181641Skmacy ch->pcm_cap.fmtlist[1] = 0; 1778181641Skmacy 1779181641Skmacy /* check if format is not supported */ 1780181641Skmacy 1781181641Skmacy if (format == 0) { 1782181641Skmacy DPRINTF("The selected audio format is not supported\n"); 1783181641Skmacy goto error; 1784181641Skmacy } 1785181641Skmacy 1786181641Skmacy /* set alternate interface corresponding to the mode */ 1787181641Skmacy 1788196728Sadrian endpoint = ch->p_ed1->bEndpointAddress; 1789181641Skmacy iface_index = ch->iface_index; 1790181641Skmacy alt_index = ch->iface_alt_index; 1791181641Skmacy 1792181641Skmacy DPRINTF("endpoint=0x%02x, speed=%d, iface=%d alt=%d\n", 1793181641Skmacy endpoint, ch->sample_rate, iface_index, alt_index); 1794181641Skmacy 1795181641Skmacy err = usbd_set_alt_interface_index(sc->sc_udev, iface_index, alt_index); 1796181641Skmacy if (err) { 1797181641Skmacy DPRINTF("setting of alternate index failed: %s!\n", 1798181641Skmacy usbd_errstr(err)); 1799181641Skmacy goto error; 1800181641Skmacy } 1801181641Skmacy usbd_set_parent_iface(sc->sc_udev, iface_index, 1802181641Skmacy sc->sc_mixer_iface_index); 1803181641Skmacy 1804181641Skmacy /* 1805181641Skmacy * Only set the sample rate if the channel reports that it 1806181641Skmacy * supports the frequency control. 1807181641Skmacy */ 1808181641Skmacy 1809181641Skmacy if (sc->sc_audio_rev >= UAUDIO_VERSION_30) { 1810181641Skmacy /* FALLTHROUGH */ 1811181641Skmacy } else if (sc->sc_audio_rev >= UAUDIO_VERSION_20) { 1812181641Skmacy unsigned int x; 1813181641Skmacy 1814181641Skmacy for (x = 0; x != 256; x++) { 1815181641Skmacy if (dir == PCMDIR_PLAY) { 1816181641Skmacy if (!(sc->sc_mixer_clocks.bit_output[x / 8] & 1817181641Skmacy (1 << (x % 8)))) { 1818181641Skmacy continue; 1819181641Skmacy } 1820181641Skmacy } else { 1821181641Skmacy if (!(sc->sc_mixer_clocks.bit_input[x / 8] & 1822181641Skmacy (1 << (x % 8)))) { 1823181641Skmacy continue; 1824181641Skmacy } 1825181641Skmacy } 1826181641Skmacy 1827181641Skmacy if (uaudio20_set_speed(sc->sc_udev, 1828181641Skmacy sc->sc_mixer_iface_no, x, ch->sample_rate)) { 1829181641Skmacy /* 1830181641Skmacy * If the endpoint is adaptive setting 1831181641Skmacy * the speed may fail. 1832181641Skmacy */ 1833181641Skmacy DPRINTF("setting of sample rate failed! " 1834181641Skmacy "(continuing anyway)\n"); 1835181641Skmacy } 1836181641Skmacy } 1837181641Skmacy } else if (ch->p_sed.v1->bmAttributes & UA_SED_FREQ_CONTROL) { 1838181641Skmacy if (uaudio_set_speed(sc->sc_udev, endpoint, ch->sample_rate)) { 1839181641Skmacy /* 1840181641Skmacy * If the endpoint is adaptive setting the 1841181641Skmacy * speed may fail. 1842181641Skmacy */ 1843181641Skmacy DPRINTF("setting of sample rate failed! " 1844181641Skmacy "(continuing anyway)\n"); 1845181641Skmacy } 1846181641Skmacy } 1847181641Skmacy if (usbd_transfer_setup(sc->sc_udev, &iface_index, ch->xfer, 1848181641Skmacy ch->usb_cfg, UAUDIO_NCHANBUFS + 1, ch, ch->pcm_mtx)) { 1849181641Skmacy DPRINTF("could not allocate USB transfers!\n"); 1850181641Skmacy goto error; 1851181641Skmacy } 1852181641Skmacy 1853181641Skmacy fps_shift = usbd_xfer_get_fps_shift(ch->xfer[0]); 1854181641Skmacy 1855181641Skmacy /* down shift number of frames per second, if any */ 1856181641Skmacy fps >>= fps_shift; 1857181641Skmacy frames >>= fps_shift; 1858181641Skmacy 1859181641Skmacy /* bytes per frame should not be zero */ 1860181641Skmacy ch->bytes_per_frame[0] = ((ch->sample_rate / fps) * ch->sample_size); 1861181641Skmacy ch->bytes_per_frame[1] = (((ch->sample_rate + fps - 1) / fps) * ch->sample_size); 1862181641Skmacy 1863181641Skmacy /* setup data rate dithering, if any */ 1864181641Skmacy ch->frames_per_second = fps; 1865181641Skmacy ch->sample_rem = ch->sample_rate % fps; 1866181641Skmacy ch->sample_curr = 0; 1867181641Skmacy ch->frames_per_second = fps; 1868181641Skmacy 1869181641Skmacy /* compute required buffer size */ 1870181641Skmacy buf_size = (ch->bytes_per_frame[1] * frames); 1871181641Skmacy 1872181641Skmacy ch->intr_size = buf_size; 1873181641Skmacy ch->intr_frames = frames; 1874181641Skmacy 1875181641Skmacy DPRINTF("fps=%d sample_rem=%d\n", fps, ch->sample_rem); 1876181641Skmacy 1877181641Skmacy if (ch->intr_frames == 0) { 1878181641Skmacy DPRINTF("frame shift is too high!\n"); 1879181641Skmacy goto error; 1880181641Skmacy } 1881181641Skmacy 1882181641Skmacy /* setup double buffering */ 1883181641Skmacy buf_size *= 2; 1884181641Skmacy blocks = 2; 1885181641Skmacy 1886181641Skmacy ch->buf = malloc(buf_size, M_DEVBUF, M_WAITOK | M_ZERO); 1887181641Skmacy if (ch->buf == NULL) 1888181641Skmacy goto error; 1889181641Skmacy if (sndbuf_setup(b, ch->buf, buf_size) != 0) 1890181641Skmacy goto error; 1891181641Skmacy if (sndbuf_resize(b, blocks, ch->intr_size)) 1892181641Skmacy goto error; 1893181641Skmacy 1894181641Skmacy ch->start = ch->buf; 1895181641Skmacy ch->end = ch->buf + buf_size; 1896181641Skmacy ch->cur = ch->buf; 1897181641Skmacy ch->pcm_buf = b; 1898181641Skmacy 1899181641Skmacy if (ch->pcm_mtx == NULL) { 1900181641Skmacy DPRINTF("ERROR: PCM channels does not have a mutex!\n"); 1901181641Skmacy goto error; 1902181641Skmacy } 1903181641Skmacy 1904181641Skmacy return (ch); 1905181641Skmacy 1906181641Skmacyerror: 1907181641Skmacy uaudio_chan_free(ch); 1908181641Skmacy return (NULL); 1909181641Skmacy} 1910181641Skmacy 1911181641Skmacyint 1912181641Skmacyuaudio_chan_free(struct uaudio_chan *ch) 1913181641Skmacy{ 1914181641Skmacy if (ch->buf != NULL) { 1915181641Skmacy free(ch->buf, M_DEVBUF); 1916181641Skmacy ch->buf = NULL; 1917181641Skmacy } 1918181641Skmacy usbd_transfer_unsetup(ch->xfer, UAUDIO_NCHANBUFS + 1); 1919181641Skmacy 1920181641Skmacy ch->valid = 0; 1921181641Skmacy 1922181641Skmacy return (0); 1923181641Skmacy} 1924181641Skmacy 1925181641Skmacyint 1926181641Skmacyuaudio_chan_set_param_blocksize(struct uaudio_chan *ch, uint32_t blocksize) 1927181641Skmacy{ 1928181641Skmacy return (ch->intr_size); 1929181641Skmacy} 1930181641Skmacy 1931181641Skmacyint 1932181641Skmacyuaudio_chan_set_param_fragments(struct uaudio_chan *ch, uint32_t blocksize, 1933181641Skmacy uint32_t blockcount) 1934181641Skmacy{ 1935181641Skmacy return (1); 1936181641Skmacy} 1937181641Skmacy 1938181641Skmacyint 1939181641Skmacyuaudio_chan_set_param_speed(struct uaudio_chan *ch, uint32_t speed) 1940181641Skmacy{ 1941181641Skmacy if (speed != ch->sample_rate) { 1942181641Skmacy DPRINTF("rate conversion required\n"); 1943181641Skmacy } 1944181641Skmacy return (ch->sample_rate); 1945181641Skmacy} 1946181641Skmacy 1947181641Skmacyint 1948181641Skmacyuaudio_chan_getptr(struct uaudio_chan *ch) 1949181641Skmacy{ 1950181641Skmacy return (ch->cur - ch->start); 1951181641Skmacy} 1952181641Skmacy 1953181641Skmacystruct pcmchan_caps * 1954181641Skmacyuaudio_chan_getcaps(struct uaudio_chan *ch) 1955181641Skmacy{ 1956181641Skmacy return (&ch->pcm_cap); 1957181641Skmacy} 1958181641Skmacy 1959181641Skmacystatic struct pcmchan_matrix uaudio_chan_matrix_swap_2_0 = { 1960181641Skmacy .id = SND_CHN_MATRIX_DRV, 1961181641Skmacy .channels = 2, 1962181641Skmacy .ext = 0, 1963181641Skmacy .map = { 1964181641Skmacy /* Right */ 1965181946Skmacy [0] = { 1966181641Skmacy .type = SND_CHN_T_FR, 1967181641Skmacy .members = 1968181641Skmacy SND_CHN_T_MASK_FR | SND_CHN_T_MASK_FC | 1969181641Skmacy SND_CHN_T_MASK_LF | SND_CHN_T_MASK_BR | 1970181641Skmacy SND_CHN_T_MASK_BC | SND_CHN_T_MASK_SR 1971181641Skmacy }, 1972181946Skmacy /* Left */ 1973181946Skmacy [1] = { 1974181641Skmacy .type = SND_CHN_T_FL, 1975181641Skmacy .members = 1976181641Skmacy SND_CHN_T_MASK_FL | SND_CHN_T_MASK_FC | 1977181641Skmacy SND_CHN_T_MASK_LF | SND_CHN_T_MASK_BL | 1978181641Skmacy SND_CHN_T_MASK_BC | SND_CHN_T_MASK_SL 1979181641Skmacy }, 1980181641Skmacy [2] = { 1981181641Skmacy .type = SND_CHN_T_MAX, 1982181641Skmacy .members = 0 1983181641Skmacy } 1984181641Skmacy }, 1985181641Skmacy .mask = SND_CHN_T_MASK_FR | SND_CHN_T_MASK_FL, 1986181641Skmacy .offset = { 1, 0, -1, -1, -1, -1, -1, -1, -1, 1987181641Skmacy -1, -1, -1, -1, -1, -1, -1, -1, -1 } 1988181641Skmacy}; 1989181641Skmacy 1990181641Skmacystruct pcmchan_matrix * 1991181641Skmacyuaudio_chan_getmatrix(struct uaudio_chan *ch, uint32_t format) 1992181641Skmacy{ 1993181641Skmacy struct uaudio_softc *sc; 1994181641Skmacy 1995181641Skmacy sc = ch->priv_sc; 1996181641Skmacy 1997181641Skmacy if (sc != NULL && sc->sc_uq_audio_swap_lr != 0 && 1998181641Skmacy AFMT_CHANNEL(format) == 2) 1999181641Skmacy return (&uaudio_chan_matrix_swap_2_0); 2000181641Skmacy 2001181641Skmacy return (feeder_matrix_format_map(format)); 2002181641Skmacy} 2003181641Skmacy 2004181641Skmacyint 2005181641Skmacyuaudio_chan_set_param_format(struct uaudio_chan *ch, uint32_t format) 2006181641Skmacy{ 2007181641Skmacy ch->format = format; 2008181641Skmacy return (0); 2009181641Skmacy} 2010181641Skmacy 2011181641Skmacyint 2012181641Skmacyuaudio_chan_start(struct uaudio_chan *ch) 2013181641Skmacy{ 2014181641Skmacy ch->cur = ch->start; 2015181641Skmacy 2016181641Skmacy#if (UAUDIO_NCHANBUFS != 2) 2017181641Skmacy#error "please update code" 2018181641Skmacy#endif 2019181641Skmacy usbd_transfer_start(ch->xfer[0]); 2020181641Skmacy usbd_transfer_start(ch->xfer[1]); 2021181641Skmacy return (0); 2022181641Skmacy} 2023181641Skmacy 2024181641Skmacyint 2025181641Skmacyuaudio_chan_stop(struct uaudio_chan *ch) 2026181641Skmacy{ 2027181641Skmacy#if (UAUDIO_NCHANBUFS != 2) 2028181641Skmacy#error "please update code" 2029181641Skmacy#endif 2030181641Skmacy usbd_transfer_stop(ch->xfer[0]); 2031181641Skmacy usbd_transfer_stop(ch->xfer[1]); 2032181641Skmacy return (0); 2033181641Skmacy} 2034181641Skmacy 2035181641Skmacy/*========================================================================* 2036181641Skmacy * AC - Audio Controller - routines 2037181641Skmacy *========================================================================*/ 2038181641Skmacy 2039181641Skmacystatic void 2040181641Skmacyuaudio_mixer_add_ctl_sub(struct uaudio_softc *sc, struct uaudio_mixer_node *mc) 2041181641Skmacy{ 2042181641Skmacy struct uaudio_mixer_node *p_mc_new = 2043181641Skmacy malloc(sizeof(*p_mc_new), M_USBDEV, M_WAITOK); 2044181641Skmacy 2045181641Skmacy if (p_mc_new != NULL) { 2046181641Skmacy memcpy(p_mc_new, mc, sizeof(*p_mc_new)); 2047181641Skmacy p_mc_new->next = sc->sc_mixer_root; 2048181641Skmacy sc->sc_mixer_root = p_mc_new; 2049181641Skmacy sc->sc_mixer_count++; 2050181641Skmacy } else { 2051181641Skmacy DPRINTF("out of memory\n"); 2052181641Skmacy } 2053181641Skmacy} 2054181641Skmacy 2055181641Skmacystatic void 2056181641Skmacyuaudio_mixer_add_ctl(struct uaudio_softc *sc, struct uaudio_mixer_node *mc) 2057181641Skmacy{ 2058181641Skmacy int32_t res; 2059181641Skmacy 2060181641Skmacy if (mc->class < UAC_NCLASSES) { 2061181641Skmacy DPRINTF("adding %s.%d\n", 2062181641Skmacy uac_names[mc->class], mc->ctl); 2063181641Skmacy } else { 2064181641Skmacy DPRINTF("adding %d\n", mc->ctl); 2065181641Skmacy } 2066181641Skmacy 2067181641Skmacy if (mc->type == MIX_ON_OFF) { 2068181641Skmacy mc->minval = 0; 2069181641Skmacy mc->maxval = 1; 2070181641Skmacy } else if (mc->type == MIX_SELECTOR) { 2071181641Skmacy } else { 2072181641Skmacy 2073181641Skmacy /* determine min and max values */ 2074181641Skmacy 2075181641Skmacy mc->minval = uaudio_mixer_get(sc->sc_udev, 2076181641Skmacy sc->sc_audio_rev, GET_MIN, mc); 2077181641Skmacy mc->maxval = uaudio_mixer_get(sc->sc_udev, 2078181641Skmacy sc->sc_audio_rev, GET_MAX, mc); 2079181641Skmacy 2080181641Skmacy /* check if max and min was swapped */ 2081181641Skmacy 2082181641Skmacy if (mc->maxval < mc->minval) { 2083181641Skmacy res = mc->maxval; 2084181641Skmacy mc->maxval = mc->minval; 2085181641Skmacy mc->minval = res; 2086181641Skmacy } 2087181641Skmacy 2088181641Skmacy /* compute value range */ 2089181641Skmacy mc->mul = mc->maxval - mc->minval; 2090181641Skmacy if (mc->mul == 0) 2091181641Skmacy mc->mul = 1; 2092181641Skmacy 2093181641Skmacy /* compute value alignment */ 2094181641Skmacy res = uaudio_mixer_get(sc->sc_udev, 2095181641Skmacy sc->sc_audio_rev, GET_RES, mc); 2096181641Skmacy 2097181641Skmacy DPRINTF("Resolution = %d\n", (int)res); 2098181641Skmacy } 2099181641Skmacy 2100181641Skmacy uaudio_mixer_add_ctl_sub(sc, mc); 2101181641Skmacy 2102181641Skmacy#ifdef USB_DEBUG 2103181641Skmacy if (uaudio_debug > 2) { 2104181641Skmacy uint8_t i; 2105181641Skmacy 2106181641Skmacy for (i = 0; i < mc->nchan; i++) { 2107181641Skmacy DPRINTF("[mix] wValue=%04x\n", mc->wValue[0]); 2108181641Skmacy } 2109181641Skmacy DPRINTF("[mix] wIndex=%04x type=%d ctl='%d' " 2110181641Skmacy "min=%d max=%d\n", 2111181641Skmacy mc->wIndex, mc->type, mc->ctl, 2112181641Skmacy mc->minval, mc->maxval); 2113181641Skmacy } 2114181641Skmacy#endif 2115181641Skmacy} 2116181641Skmacy 2117181641Skmacystatic void 2118181641Skmacyuaudio_mixer_add_mixer(struct uaudio_softc *sc, 2119181641Skmacy const struct uaudio_terminal_node *iot, int id) 2120181641Skmacy{ 2121181641Skmacy struct uaudio_mixer_node mix; 2122181641Skmacy 2123181641Skmacy const struct usb_audio_mixer_unit_0 *d0 = iot[id].u.mu_v1; 2124181641Skmacy const struct usb_audio_mixer_unit_1 *d1; 2125181641Skmacy 2126181641Skmacy uint32_t bno; /* bit number */ 2127181641Skmacy uint32_t p; /* bit number accumulator */ 2128181641Skmacy uint32_t mo; /* matching outputs */ 2129181641Skmacy uint32_t mc; /* matching channels */ 2130181641Skmacy uint32_t ichs; /* input channels */ 2131181641Skmacy uint32_t ochs; /* output channels */ 2132181641Skmacy uint32_t c; 2133181641Skmacy uint32_t chs; /* channels */ 2134181641Skmacy uint32_t i; 2135181641Skmacy uint32_t o; 2136181641Skmacy 2137181641Skmacy DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n", 2138181641Skmacy d0->bUnitId, d0->bNrInPins); 2139181641Skmacy 2140181641Skmacy /* compute the number of input channels */ 2141181641Skmacy 2142181641Skmacy ichs = 0; 2143181641Skmacy for (i = 0; i < d0->bNrInPins; i++) { 2144181641Skmacy ichs += uaudio_mixer_get_cluster( 2145181641Skmacy d0->baSourceId[i], iot).bNrChannels; 2146181641Skmacy } 2147181641Skmacy 2148181641Skmacy d1 = (const void *)(d0->baSourceId + d0->bNrInPins); 2149181641Skmacy 2150181641Skmacy /* and the number of output channels */ 2151181641Skmacy 2152181641Skmacy ochs = d1->bNrChannels; 2153181641Skmacy 2154181641Skmacy DPRINTFN(3, "ichs=%d ochs=%d\n", ichs, ochs); 2155181641Skmacy 2156181641Skmacy memset(&mix, 0, sizeof(mix)); 2157181641Skmacy 2158181641Skmacy mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 2159181641Skmacy uaudio_mixer_determine_class(&iot[id], &mix); 2160181641Skmacy mix.type = MIX_SIGNED_16; 2161181641Skmacy 2162181641Skmacy if (uaudio_mixer_verify_desc(d0, ((ichs * ochs) + 7) / 8) == NULL) 2163181641Skmacy return; 2164181641Skmacy 2165181641Skmacy for (p = i = 0; i < d0->bNrInPins; i++) { 2166181641Skmacy chs = uaudio_mixer_get_cluster( 2167181641Skmacy d0->baSourceId[i], iot).bNrChannels; 2168181641Skmacy mc = 0; 2169181641Skmacy for (c = 0; c < chs; c++) { 2170181641Skmacy mo = 0; 2171181641Skmacy for (o = 0; o < ochs; o++) { 2172181641Skmacy bno = ((p + c) * ochs) + o; 2173181641Skmacy if (BIT_TEST(d1->bmControls, bno)) 2174181641Skmacy mo++; 2175181641Skmacy } 2176181641Skmacy if (mo == 1) 2177181641Skmacy mc++; 2178181641Skmacy } 2179181641Skmacy if ((mc == chs) && (chs <= MIX_MAX_CHAN)) { 2180181641Skmacy 2181181641Skmacy /* repeat bit-scan */ 2182181641Skmacy 2183181641Skmacy mc = 0; 2184181641Skmacy for (c = 0; c < chs; c++) { 2185181641Skmacy for (o = 0; o < ochs; o++) { 2186181641Skmacy bno = ((p + c) * ochs) + o; 2187181641Skmacy if (BIT_TEST(d1->bmControls, bno)) 2188181641Skmacy mix.wValue[mc++] = MAKE_WORD(p + c + 1, o + 1); 2189181641Skmacy } 2190181641Skmacy } 2191181641Skmacy mix.nchan = chs; 2192181641Skmacy uaudio_mixer_add_ctl(sc, &mix); 2193181641Skmacy } 2194181641Skmacy p += chs; 2195181641Skmacy } 2196181641Skmacy} 2197181641Skmacy 2198181641Skmacystatic void 2199181641Skmacyuaudio20_mixer_add_mixer(struct uaudio_softc *sc, 2200181641Skmacy const struct uaudio_terminal_node *iot, int id) 2201181641Skmacy{ 2202181641Skmacy struct uaudio_mixer_node mix; 2203181641Skmacy 2204181641Skmacy const struct usb_audio20_mixer_unit_0 *d0 = iot[id].u.mu_v2; 2205181641Skmacy const struct usb_audio20_mixer_unit_1 *d1; 2206181641Skmacy 2207181641Skmacy uint32_t bno; /* bit number */ 2208181641Skmacy uint32_t p; /* bit number accumulator */ 2209181641Skmacy uint32_t mo; /* matching outputs */ 2210181641Skmacy uint32_t mc; /* matching channels */ 2211181641Skmacy uint32_t ichs; /* input channels */ 2212181641Skmacy uint32_t ochs; /* output channels */ 2213181641Skmacy uint32_t c; 2214181641Skmacy uint32_t chs; /* channels */ 2215181641Skmacy uint32_t i; 2216181641Skmacy uint32_t o; 2217181641Skmacy 2218181641Skmacy DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n", 2219181641Skmacy d0->bUnitId, d0->bNrInPins); 2220181641Skmacy 2221181641Skmacy /* compute the number of input channels */ 2222181641Skmacy 2223181641Skmacy ichs = 0; 2224181641Skmacy for (i = 0; i < d0->bNrInPins; i++) { 2225181641Skmacy ichs += uaudio20_mixer_get_cluster( 2226181641Skmacy d0->baSourceId[i], iot).bNrChannels; 2227181641Skmacy } 2228181641Skmacy 2229181641Skmacy d1 = (const void *)(d0->baSourceId + d0->bNrInPins); 2230181641Skmacy 2231181641Skmacy /* and the number of output channels */ 2232181641Skmacy 2233181641Skmacy ochs = d1->bNrChannels; 2234181641Skmacy 2235181641Skmacy DPRINTFN(3, "ichs=%d ochs=%d\n", ichs, ochs); 2236181641Skmacy 2237181641Skmacy memset(&mix, 0, sizeof(mix)); 2238181641Skmacy 2239181641Skmacy mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 2240181641Skmacy uaudio20_mixer_determine_class(&iot[id], &mix); 2241181641Skmacy mix.type = MIX_SIGNED_16; 2242181641Skmacy 2243181641Skmacy if (uaudio20_mixer_verify_desc(d0, ((ichs * ochs) + 7) / 8) == NULL) 2244181641Skmacy return; 2245181641Skmacy 2246181641Skmacy for (p = i = 0; i < d0->bNrInPins; i++) { 2247181641Skmacy chs = uaudio20_mixer_get_cluster( 2248181641Skmacy d0->baSourceId[i], iot).bNrChannels; 2249181641Skmacy mc = 0; 2250181641Skmacy for (c = 0; c < chs; c++) { 2251181641Skmacy mo = 0; 2252181641Skmacy for (o = 0; o < ochs; o++) { 2253181641Skmacy bno = ((p + c) * ochs) + o; 2254181641Skmacy if (BIT_TEST(d1->bmControls, bno)) 2255181641Skmacy mo++; 2256181641Skmacy } 2257181641Skmacy if (mo == 1) 2258181641Skmacy mc++; 2259181641Skmacy } 2260181641Skmacy if ((mc == chs) && (chs <= MIX_MAX_CHAN)) { 2261181641Skmacy 2262181641Skmacy /* repeat bit-scan */ 2263181641Skmacy 2264181641Skmacy mc = 0; 2265181641Skmacy for (c = 0; c < chs; c++) { 2266181641Skmacy for (o = 0; o < ochs; o++) { 2267181641Skmacy bno = ((p + c) * ochs) + o; 2268181641Skmacy if (BIT_TEST(d1->bmControls, bno)) 2269181641Skmacy mix.wValue[mc++] = MAKE_WORD(p + c + 1, o + 1); 2270181641Skmacy } 2271181641Skmacy } 2272181641Skmacy mix.nchan = chs; 2273181641Skmacy uaudio_mixer_add_ctl(sc, &mix); 2274181641Skmacy } 2275181641Skmacy p += chs; 2276181641Skmacy } 2277181641Skmacy} 2278181641Skmacy 2279181641Skmacystatic void 2280181641Skmacyuaudio_mixer_add_selector(struct uaudio_softc *sc, 2281181641Skmacy const struct uaudio_terminal_node *iot, int id) 2282181641Skmacy{ 2283181641Skmacy const struct usb_audio_selector_unit *d = iot[id].u.su_v1; 2284181641Skmacy struct uaudio_mixer_node mix; 2285181641Skmacy uint16_t i; 2286181641Skmacy 2287181641Skmacy DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n", 2288181641Skmacy d->bUnitId, d->bNrInPins); 2289181641Skmacy 2290181641Skmacy if (d->bNrInPins == 0) { 2291181641Skmacy return; 2292181641Skmacy } 2293181641Skmacy memset(&mix, 0, sizeof(mix)); 2294181641Skmacy 2295181641Skmacy mix.wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no); 2296181641Skmacy mix.wValue[0] = MAKE_WORD(0, 0); 2297181641Skmacy uaudio_mixer_determine_class(&iot[id], &mix); 2298181641Skmacy mix.nchan = 1; 2299181641Skmacy mix.type = MIX_SELECTOR; 2300181641Skmacy 2301181641Skmacy mix.ctl = SOUND_MIXER_NRDEVICES; 2302181641Skmacy mix.minval = 1; 2303181641Skmacy mix.maxval = d->bNrInPins; 2304181641Skmacy 2305181641Skmacy if (mix.maxval > MAX_SELECTOR_INPUT_PIN) { 2306181641Skmacy mix.maxval = MAX_SELECTOR_INPUT_PIN; 2307181641Skmacy } 2308181641Skmacy mix.mul = (mix.maxval - mix.minval); 2309181641Skmacy for (i = 0; i < MAX_SELECTOR_INPUT_PIN; i++) { 2310181641Skmacy mix.slctrtype[i] = SOUND_MIXER_NRDEVICES; 2311181641Skmacy } 2312181641Skmacy 2313181641Skmacy for (i = 0; i < mix.maxval; i++) { 2314181641Skmacy mix.slctrtype[i] = uaudio_mixer_feature_name( 2315181641Skmacy &iot[d->baSourceId[i]], &mix); 2316181641Skmacy } 2317181641Skmacy 2318181641Skmacy mix.class = 0; /* not used */ 2319181641Skmacy 2320181641Skmacy uaudio_mixer_add_ctl(sc, &mix); 2321181641Skmacy} 2322181641Skmacy 2323181641Skmacystatic void 2324181641Skmacyuaudio20_mixer_add_selector(struct uaudio_softc *sc, 2325181641Skmacy const struct uaudio_terminal_node *iot, int id) 2326181641Skmacy{ 2327181641Skmacy const struct usb_audio20_selector_unit *d = iot[id].u.su_v2; 2328181641Skmacy struct uaudio_mixer_node mix; 2329181641Skmacy uint16_t i; 2330181641Skmacy 2331181641Skmacy DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n", 2332181641Skmacy d->bUnitId, d->bNrInPins); 2333181641Skmacy 2334181641Skmacy if (d->bNrInPins == 0) 2335181641Skmacy return; 2336181641Skmacy 2337181641Skmacy memset(&mix, 0, sizeof(mix)); 2338181641Skmacy 2339181641Skmacy mix.wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no); 2340181641Skmacy mix.wValue[0] = MAKE_WORD(0, 0); 2341181641Skmacy uaudio20_mixer_determine_class(&iot[id], &mix); 2342181641Skmacy mix.nchan = 1; 2343181641Skmacy mix.type = MIX_SELECTOR; 2344181641Skmacy 2345181641Skmacy mix.ctl = SOUND_MIXER_NRDEVICES; 2346181641Skmacy mix.minval = 1; 2347181641Skmacy mix.maxval = d->bNrInPins; 2348181641Skmacy 2349181641Skmacy if (mix.maxval > MAX_SELECTOR_INPUT_PIN) 2350181641Skmacy mix.maxval = MAX_SELECTOR_INPUT_PIN; 2351181641Skmacy 2352181641Skmacy mix.mul = (mix.maxval - mix.minval); 2353181641Skmacy for (i = 0; i < MAX_SELECTOR_INPUT_PIN; i++) 2354181641Skmacy mix.slctrtype[i] = SOUND_MIXER_NRDEVICES; 2355181641Skmacy 2356181641Skmacy for (i = 0; i < mix.maxval; i++) { 2357181641Skmacy mix.slctrtype[i] = uaudio20_mixer_feature_name( 2358181641Skmacy &iot[d->baSourceId[i]], &mix); 2359181641Skmacy } 2360181641Skmacy 2361181641Skmacy mix.class = 0; /* not used */ 2362181641Skmacy 2363181641Skmacy uaudio_mixer_add_ctl(sc, &mix); 2364181641Skmacy} 2365181641Skmacy 2366181641Skmacystatic uint32_t 2367181641Skmacyuaudio_mixer_feature_get_bmaControls(const struct usb_audio_feature_unit *d, 2368181641Skmacy uint8_t i) 2369181641Skmacy{ 2370181641Skmacy uint32_t temp = 0; 2371181641Skmacy uint32_t offset = (i * d->bControlSize); 2372181641Skmacy 2373181641Skmacy if (d->bControlSize > 0) { 2374181641Skmacy temp |= d->bmaControls[offset]; 2375181641Skmacy if (d->bControlSize > 1) { 2376181641Skmacy temp |= d->bmaControls[offset + 1] << 8; 2377181641Skmacy if (d->bControlSize > 2) { 2378181641Skmacy temp |= d->bmaControls[offset + 2] << 16; 2379181641Skmacy if (d->bControlSize > 3) { 2380181641Skmacy temp |= d->bmaControls[offset + 3] << 24; 2381181641Skmacy } 2382181641Skmacy } 2383181641Skmacy } 2384181641Skmacy } 2385181641Skmacy return (temp); 2386181641Skmacy} 2387181641Skmacy 2388181641Skmacystatic void 2389181641Skmacyuaudio_mixer_add_feature(struct uaudio_softc *sc, 2390181641Skmacy const struct uaudio_terminal_node *iot, int id) 2391181641Skmacy{ 2392181641Skmacy const struct usb_audio_feature_unit *d = iot[id].u.fu_v1; 2393181641Skmacy struct uaudio_mixer_node mix; 2394181641Skmacy uint32_t fumask; 2395181641Skmacy uint32_t mmask; 2396181641Skmacy uint32_t cmask; 2397181641Skmacy uint16_t mixernumber; 2398181641Skmacy uint8_t nchan; 2399181641Skmacy uint8_t chan; 2400181641Skmacy uint8_t ctl; 2401181641Skmacy uint8_t i; 2402181641Skmacy 2403181641Skmacy if (d->bControlSize == 0) { 2404181641Skmacy return; 2405181641Skmacy } 2406181641Skmacy memset(&mix, 0, sizeof(mix)); 2407181641Skmacy 2408181641Skmacy nchan = (d->bLength - 7) / d->bControlSize; 2409181641Skmacy mmask = uaudio_mixer_feature_get_bmaControls(d, 0); 2410181641Skmacy cmask = 0; 2411181641Skmacy 2412181641Skmacy if (nchan == 0) { 2413181641Skmacy return; 2414181641Skmacy } 2415181641Skmacy /* figure out what we can control */ 2416181641Skmacy 2417181641Skmacy for (chan = 1; chan < nchan; chan++) { 2418181641Skmacy DPRINTFN(10, "chan=%d mask=%x\n", 2419181641Skmacy chan, uaudio_mixer_feature_get_bmaControls(d, chan)); 2420181641Skmacy 2421181641Skmacy cmask |= uaudio_mixer_feature_get_bmaControls(d, chan); 2422181641Skmacy } 2423181641Skmacy 2424181641Skmacy if (nchan > MIX_MAX_CHAN) { 2425181641Skmacy nchan = MIX_MAX_CHAN; 2426181641Skmacy } 2427181641Skmacy mix.wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no); 2428181641Skmacy 2429181641Skmacy for (ctl = 1; ctl <= LOUDNESS_CONTROL; ctl++) { 2430181641Skmacy 2431181641Skmacy fumask = FU_MASK(ctl); 2432181641Skmacy 2433181641Skmacy DPRINTFN(5, "ctl=%d fumask=0x%04x\n", 2434181641Skmacy ctl, fumask); 2435181641Skmacy 2436181641Skmacy if (mmask & fumask) { 2437181641Skmacy mix.nchan = 1; 2438181641Skmacy mix.wValue[0] = MAKE_WORD(ctl, 0); 2439181641Skmacy } else if (cmask & fumask) { 2440181641Skmacy mix.nchan = nchan - 1; 2441181641Skmacy for (i = 1; i < nchan; i++) { 2442181641Skmacy if (uaudio_mixer_feature_get_bmaControls(d, i) & fumask) 2443181641Skmacy mix.wValue[i - 1] = MAKE_WORD(ctl, i); 2444181641Skmacy else 2445181641Skmacy mix.wValue[i - 1] = -1; 2446181641Skmacy } 2447181641Skmacy } else { 2448181641Skmacy continue; 2449181641Skmacy } 2450181641Skmacy 2451181641Skmacy mixernumber = uaudio_mixer_feature_name(&iot[id], &mix); 2452181641Skmacy 2453181641Skmacy switch (ctl) { 2454181641Skmacy case MUTE_CONTROL: 2455181641Skmacy mix.type = MIX_ON_OFF; 2456181641Skmacy mix.ctl = SOUND_MIXER_NRDEVICES; 2457181641Skmacy break; 2458181641Skmacy 2459181641Skmacy case VOLUME_CONTROL: 2460181641Skmacy mix.type = MIX_SIGNED_16; 2461181641Skmacy mix.ctl = mixernumber; 2462181641Skmacy break; 2463181641Skmacy 2464181641Skmacy case BASS_CONTROL: 2465181641Skmacy mix.type = MIX_SIGNED_8; 2466181641Skmacy mix.ctl = SOUND_MIXER_BASS; 2467181641Skmacy break; 2468181641Skmacy 2469181641Skmacy case MID_CONTROL: 2470181641Skmacy mix.type = MIX_SIGNED_8; 2471181641Skmacy mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 2472181641Skmacy break; 2473181641Skmacy 2474181641Skmacy case TREBLE_CONTROL: 2475181641Skmacy mix.type = MIX_SIGNED_8; 2476181641Skmacy mix.ctl = SOUND_MIXER_TREBLE; 2477181641Skmacy break; 2478181641Skmacy 2479181641Skmacy case GRAPHIC_EQUALIZER_CONTROL: 2480181641Skmacy continue; /* XXX don't add anything */ 2481181641Skmacy break; 2482181641Skmacy 2483181641Skmacy case AGC_CONTROL: 2484181641Skmacy mix.type = MIX_ON_OFF; 2485181641Skmacy mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 2486181641Skmacy break; 2487181641Skmacy 2488207796Salc case DELAY_CONTROL: 2489207796Salc mix.type = MIX_UNSIGNED_16; 2490207796Salc mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 2491181641Skmacy break; 2492181641Skmacy 2493181641Skmacy case BASS_BOOST_CONTROL: 2494181641Skmacy mix.type = MIX_ON_OFF; 2495181641Skmacy mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 2496181641Skmacy break; 2497181641Skmacy 2498181641Skmacy case LOUDNESS_CONTROL: 2499181641Skmacy mix.type = MIX_ON_OFF; 2500181641Skmacy mix.ctl = SOUND_MIXER_LOUD; /* Is this correct ? */ 2501181641Skmacy break; 2502181641Skmacy 2503181641Skmacy default: 2504181641Skmacy mix.type = MIX_UNKNOWN; 2505181641Skmacy break; 2506181641Skmacy } 2507181641Skmacy 2508181641Skmacy if (mix.type != MIX_UNKNOWN) 2509181641Skmacy uaudio_mixer_add_ctl(sc, &mix); 2510181641Skmacy } 2511181641Skmacy} 2512181641Skmacy 2513181641Skmacystatic void 2514181641Skmacyuaudio20_mixer_add_feature(struct uaudio_softc *sc, 2515181641Skmacy const struct uaudio_terminal_node *iot, int id) 2516181641Skmacy{ 2517181641Skmacy const struct usb_audio20_feature_unit *d = iot[id].u.fu_v2; 2518181641Skmacy struct uaudio_mixer_node mix; 2519181641Skmacy uint32_t ctl; 2520181641Skmacy uint32_t mmask; 2521181641Skmacy uint32_t cmask; 2522181641Skmacy uint16_t mixernumber; 2523181641Skmacy uint8_t nchan; 2524181641Skmacy uint8_t chan; 2525181641Skmacy uint8_t i; 2526181641Skmacy uint8_t what; 2527207796Salc 2528181641Skmacy if (UGETDW(d->bmaControls[0]) == 0) 2529181641Skmacy return; 2530181641Skmacy 2531181641Skmacy memset(&mix, 0, sizeof(mix)); 2532181641Skmacy 2533181641Skmacy nchan = (d->bLength - 6) / 4; 2534181641Skmacy mmask = UGETDW(d->bmaControls[0]); 2535181641Skmacy cmask = 0; 2536181641Skmacy 2537181641Skmacy if (nchan == 0) 2538181641Skmacy return; 2539181641Skmacy 2540181641Skmacy /* figure out what we can control */ 2541181641Skmacy 2542181641Skmacy for (chan = 1; chan < nchan; chan++) 2543181641Skmacy cmask |= UGETDW(d->bmaControls[chan]); 2544181641Skmacy 2545181641Skmacy if (nchan > MIX_MAX_CHAN) 2546181641Skmacy nchan = MIX_MAX_CHAN; 2547181641Skmacy 2548181641Skmacy mix.wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no); 2549181641Skmacy 2550181641Skmacy for (ctl = 3; ctl != 0; ctl <<= 2) { 2551181641Skmacy 2552181641Skmacy mixernumber = uaudio20_mixer_feature_name(&iot[id], &mix); 2553181641Skmacy 2554181641Skmacy switch (ctl) { 2555181641Skmacy case (3 << 0): 2556181641Skmacy mix.type = MIX_ON_OFF; 2557181641Skmacy mix.ctl = SOUND_MIXER_NRDEVICES; 2558181641Skmacy what = MUTE_CONTROL; 2559181641Skmacy break; 2560181641Skmacy case (3 << 2): 2561181641Skmacy mix.type = MIX_SIGNED_16; 2562181641Skmacy mix.ctl = mixernumber; 2563181641Skmacy what = VOLUME_CONTROL; 2564181641Skmacy break; 2565181641Skmacy case (3 << 4): 2566181641Skmacy mix.type = MIX_SIGNED_8; 2567181641Skmacy mix.ctl = SOUND_MIXER_BASS; 2568181641Skmacy what = BASS_CONTROL; 2569181641Skmacy break; 2570181641Skmacy case (3 << 6): 2571181641Skmacy mix.type = MIX_SIGNED_8; 2572181641Skmacy mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 2573181641Skmacy what = MID_CONTROL; 2574181641Skmacy break; 2575181641Skmacy case (3 << 8): 2576181641Skmacy mix.type = MIX_SIGNED_8; 2577181641Skmacy mix.ctl = SOUND_MIXER_TREBLE; 2578181641Skmacy what = TREBLE_CONTROL; 2579181641Skmacy break; 2580181641Skmacy case (3 << 12): 2581181641Skmacy mix.type = MIX_ON_OFF; 2582181641Skmacy mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 2583181641Skmacy what = AGC_CONTROL; 2584181641Skmacy break; 2585181641Skmacy case (3 << 14): 2586181641Skmacy mix.type = MIX_UNSIGNED_16; 2587181641Skmacy mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 2588181641Skmacy what = DELAY_CONTROL; 2589181641Skmacy break; 2590181641Skmacy case (3 << 16): 2591181641Skmacy mix.type = MIX_ON_OFF; 2592181641Skmacy mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 2593181641Skmacy what = BASS_BOOST_CONTROL; 2594181641Skmacy break; 2595181641Skmacy case (3 << 18): 2596181641Skmacy mix.type = MIX_ON_OFF; 2597181641Skmacy mix.ctl = SOUND_MIXER_LOUD; /* Is this correct ? */ 2598181641Skmacy what = LOUDNESS_CONTROL; 2599181641Skmacy break; 2600181641Skmacy case (3 << 20): 2601181641Skmacy mix.type = MIX_SIGNED_16; 2602181641Skmacy mix.ctl = mixernumber; 2603181641Skmacy what = INPUT_GAIN_CONTROL; 2604181641Skmacy break; 2605181641Skmacy case (3 << 22): 2606181641Skmacy mix.type = MIX_SIGNED_16; 2607181641Skmacy mix.ctl = mixernumber; 2608181641Skmacy what = INPUT_GAIN_PAD_CONTROL; 2609181641Skmacy break; 2610207262Salc default: 2611207262Salc continue; 2612207262Salc } 2613207262Salc 2614207262Salc if ((mmask & ctl) == ctl) { 2615207262Salc mix.nchan = 1; 2616181641Skmacy mix.wValue[0] = MAKE_WORD(what, 0); 2617181641Skmacy } else if ((cmask & ctl) == ctl) { 2618207262Salc mix.nchan = nchan - 1; 2619181641Skmacy for (i = 1; i < nchan; i++) { 2620181641Skmacy if ((UGETDW(d->bmaControls[i]) & ctl) == ctl) 2621181641Skmacy mix.wValue[i - 1] = MAKE_WORD(what, i); 2622181641Skmacy else 2623181641Skmacy mix.wValue[i - 1] = -1; 2624181641Skmacy } 2625181641Skmacy } else { 2626181641Skmacy continue; 2627181641Skmacy } 2628181641Skmacy 2629181641Skmacy if (mix.type != MIX_UNKNOWN) 2630181641Skmacy uaudio_mixer_add_ctl(sc, &mix); 2631181641Skmacy } 2632181641Skmacy} 2633181641Skmacy 2634181641Skmacystatic void 2635181641Skmacyuaudio_mixer_add_processing_updown(struct uaudio_softc *sc, 2636181641Skmacy const struct uaudio_terminal_node *iot, int id) 2637181641Skmacy{ 2638181641Skmacy const struct usb_audio_processing_unit_0 *d0 = iot[id].u.pu_v1; 2639181641Skmacy const struct usb_audio_processing_unit_1 *d1 = 2640181641Skmacy (const void *)(d0->baSourceId + d0->bNrInPins); 2641181641Skmacy const struct usb_audio_processing_unit_updown *ud = 2642181641Skmacy (const void *)(d1->bmControls + d1->bControlSize); 2643181641Skmacy struct uaudio_mixer_node mix; 2644181641Skmacy uint8_t i; 2645181641Skmacy 2646181641Skmacy if (uaudio_mixer_verify_desc(d0, sizeof(*ud)) == NULL) { 2647181641Skmacy return; 2648181641Skmacy } 2649181641Skmacy if (uaudio_mixer_verify_desc(d0, sizeof(*ud) + (2 * ud->bNrModes)) 2650181641Skmacy == NULL) { 2651181641Skmacy return; 2652181641Skmacy } 2653181641Skmacy DPRINTFN(3, "bUnitId=%d bNrModes=%d\n", 2654181641Skmacy d0->bUnitId, ud->bNrModes); 2655181641Skmacy 2656181641Skmacy if (!(d1->bmControls[0] & UA_PROC_MASK(UD_MODE_SELECT_CONTROL))) { 2657181641Skmacy DPRINTF("no mode select\n"); 2658181641Skmacy return; 2659181641Skmacy } 2660181641Skmacy memset(&mix, 0, sizeof(mix)); 2661181641Skmacy 2662181641Skmacy mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 2663181641Skmacy mix.nchan = 1; 2664181641Skmacy mix.wValue[0] = MAKE_WORD(UD_MODE_SELECT_CONTROL, 0); 2665181641Skmacy uaudio_mixer_determine_class(&iot[id], &mix); 2666181641Skmacy mix.type = MIX_ON_OFF; /* XXX */ 2667181641Skmacy 2668181641Skmacy for (i = 0; i < ud->bNrModes; i++) { 2669181641Skmacy DPRINTFN(3, "i=%d bm=0x%x\n", i, UGETW(ud->waModes[i])); 2670181641Skmacy /* XXX */ 2671181641Skmacy } 2672181641Skmacy 2673181641Skmacy uaudio_mixer_add_ctl(sc, &mix); 2674181641Skmacy} 2675181641Skmacy 2676181641Skmacystatic void 2677181641Skmacyuaudio_mixer_add_processing(struct uaudio_softc *sc, 2678181641Skmacy const struct uaudio_terminal_node *iot, int id) 2679181641Skmacy{ 2680181641Skmacy const struct usb_audio_processing_unit_0 *d0 = iot[id].u.pu_v1; 2681181641Skmacy const struct usb_audio_processing_unit_1 *d1 = 2682181641Skmacy (const void *)(d0->baSourceId + d0->bNrInPins); 2683181641Skmacy struct uaudio_mixer_node mix; 2684181641Skmacy uint16_t ptype; 2685208175Salc 2686208175Salc memset(&mix, 0, sizeof(mix)); 2687208175Salc 2688208175Salc ptype = UGETW(d0->wProcessType); 2689208175Salc 2690208175Salc DPRINTFN(3, "wProcessType=%d bUnitId=%d " 2691181641Skmacy "bNrInPins=%d\n", ptype, d0->bUnitId, d0->bNrInPins); 2692181641Skmacy 2693181641Skmacy if (d1->bControlSize == 0) { 2694181641Skmacy return; 2695181641Skmacy } 2696181641Skmacy if (d1->bmControls[0] & UA_PROC_ENABLE_MASK) { 2697181641Skmacy mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 2698181641Skmacy mix.nchan = 1; 2699181641Skmacy mix.wValue[0] = MAKE_WORD(XX_ENABLE_CONTROL, 0); 2700181641Skmacy uaudio_mixer_determine_class(&iot[id], &mix); 2701181641Skmacy mix.type = MIX_ON_OFF; 2702181641Skmacy uaudio_mixer_add_ctl(sc, &mix); 2703181641Skmacy } 2704181641Skmacy switch (ptype) { 2705181641Skmacy case UPDOWNMIX_PROCESS: 2706181641Skmacy uaudio_mixer_add_processing_updown(sc, iot, id); 2707181641Skmacy break; 2708181641Skmacy 2709181641Skmacy case DOLBY_PROLOGIC_PROCESS: 2710181641Skmacy case P3D_STEREO_EXTENDER_PROCESS: 2711181641Skmacy case REVERBATION_PROCESS: 2712181641Skmacy case CHORUS_PROCESS: 2713181641Skmacy case DYN_RANGE_COMP_PROCESS: 2714181641Skmacy default: 2715181641Skmacy DPRINTF("unit %d, type=%d is not implemented\n", 2716181641Skmacy d0->bUnitId, ptype); 2717181641Skmacy break; 2718181641Skmacy } 2719181641Skmacy} 2720181641Skmacy 2721181641Skmacystatic void 2722181641Skmacyuaudio_mixer_add_extension(struct uaudio_softc *sc, 2723181641Skmacy const struct uaudio_terminal_node *iot, int id) 2724181641Skmacy{ 2725181641Skmacy const struct usb_audio_extension_unit_0 *d0 = iot[id].u.eu_v1; 2726181641Skmacy const struct usb_audio_extension_unit_1 *d1 = 2727181641Skmacy (const void *)(d0->baSourceId + d0->bNrInPins); 2728181641Skmacy struct uaudio_mixer_node mix; 2729181641Skmacy 2730181641Skmacy DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n", 2731181641Skmacy d0->bUnitId, d0->bNrInPins); 2732181641Skmacy 2733181641Skmacy if (sc->sc_uq_au_no_xu) { 2734181641Skmacy return; 2735181641Skmacy } 2736181641Skmacy if (d1->bControlSize == 0) { 2737181641Skmacy return; 2738181641Skmacy } 2739181641Skmacy if (d1->bmControls[0] & UA_EXT_ENABLE_MASK) { 2740181641Skmacy 2741181641Skmacy memset(&mix, 0, sizeof(mix)); 2742181641Skmacy 2743181641Skmacy mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 2744181641Skmacy mix.nchan = 1; 2745181641Skmacy mix.wValue[0] = MAKE_WORD(UA_EXT_ENABLE, 0); 2746181641Skmacy uaudio_mixer_determine_class(&iot[id], &mix); 2747181641Skmacy mix.type = MIX_ON_OFF; 2748181641Skmacy 2749181641Skmacy uaudio_mixer_add_ctl(sc, &mix); 2750181641Skmacy } 2751181641Skmacy} 2752181641Skmacy 2753181641Skmacystatic const void * 2754181641Skmacyuaudio_mixer_verify_desc(const void *arg, uint32_t len) 2755181641Skmacy{ 2756181641Skmacy const struct usb_audio_mixer_unit_1 *d1; 2757181641Skmacy const struct usb_audio_extension_unit_1 *e1; 2758181641Skmacy const struct usb_audio_processing_unit_1 *u1; 2759181641Skmacy 2760181641Skmacy union { 2761181641Skmacy const struct usb_descriptor *desc; 2762181641Skmacy const struct usb_audio_input_terminal *it; 2763181641Skmacy const struct usb_audio_output_terminal *ot; 2764181641Skmacy const struct usb_audio_mixer_unit_0 *mu; 2765181641Skmacy const struct usb_audio_selector_unit *su; 2766181641Skmacy const struct usb_audio_feature_unit *fu; 2767181641Skmacy const struct usb_audio_processing_unit_0 *pu; 2768181641Skmacy const struct usb_audio_extension_unit_0 *eu; 2769181641Skmacy } u; 2770181641Skmacy 2771181641Skmacy u.desc = arg; 2772181641Skmacy 2773181641Skmacy if (u.desc == NULL) { 2774181641Skmacy goto error; 2775181641Skmacy } 2776181641Skmacy if (u.desc->bDescriptorType != UDESC_CS_INTERFACE) { 2777181641Skmacy goto error; 2778181641Skmacy } 2779181641Skmacy switch (u.desc->bDescriptorSubtype) { 2780181641Skmacy case UDESCSUB_AC_INPUT: 2781181641Skmacy len += sizeof(*u.it); 2782181641Skmacy break; 2783181641Skmacy 2784181641Skmacy case UDESCSUB_AC_OUTPUT: 2785181641Skmacy len += sizeof(*u.ot); 2786181641Skmacy break; 2787181641Skmacy 2788181641Skmacy case UDESCSUB_AC_MIXER: 2789181641Skmacy len += sizeof(*u.mu); 2790181641Skmacy 2791181641Skmacy if (u.desc->bLength < len) { 2792181641Skmacy goto error; 2793181641Skmacy } 2794181641Skmacy len += u.mu->bNrInPins; 2795181641Skmacy 2796181641Skmacy if (u.desc->bLength < len) { 2797181641Skmacy goto error; 2798181641Skmacy } 2799181641Skmacy d1 = (const void *)(u.mu->baSourceId + u.mu->bNrInPins); 2800181641Skmacy 2801181641Skmacy len += sizeof(*d1); 2802181641Skmacy break; 2803181641Skmacy 2804181641Skmacy case UDESCSUB_AC_SELECTOR: 2805181641Skmacy len += sizeof(*u.su); 2806181641Skmacy 2807181641Skmacy if (u.desc->bLength < len) { 2808181641Skmacy goto error; 2809181641Skmacy } 2810181641Skmacy len += u.su->bNrInPins; 2811181641Skmacy break; 2812181641Skmacy 2813181641Skmacy case UDESCSUB_AC_FEATURE: 2814181641Skmacy len += (sizeof(*u.fu) + 1); 2815181641Skmacy break; 2816181641Skmacy 2817181641Skmacy case UDESCSUB_AC_PROCESSING: 2818181641Skmacy len += sizeof(*u.pu); 2819181641Skmacy 2820181641Skmacy if (u.desc->bLength < len) { 2821181641Skmacy goto error; 2822181641Skmacy } 2823181641Skmacy len += u.pu->bNrInPins; 2824181641Skmacy 2825181641Skmacy if (u.desc->bLength < len) { 2826181641Skmacy goto error; 2827181641Skmacy } 2828181641Skmacy u1 = (const void *)(u.pu->baSourceId + u.pu->bNrInPins); 2829181641Skmacy 2830181641Skmacy len += sizeof(*u1); 2831181641Skmacy 2832181641Skmacy if (u.desc->bLength < len) { 2833181641Skmacy goto error; 2834181641Skmacy } 2835181641Skmacy len += u1->bControlSize; 2836181641Skmacy 2837181641Skmacy break; 2838181641Skmacy 2839181641Skmacy case UDESCSUB_AC_EXTENSION: 2840181641Skmacy len += sizeof(*u.eu); 2841181641Skmacy 2842181641Skmacy if (u.desc->bLength < len) { 2843181641Skmacy goto error; 2844181641Skmacy } 2845181641Skmacy len += u.eu->bNrInPins; 2846181641Skmacy 2847181641Skmacy if (u.desc->bLength < len) { 2848181641Skmacy goto error; 2849181641Skmacy } 2850181641Skmacy e1 = (const void *)(u.eu->baSourceId + u.eu->bNrInPins); 2851181641Skmacy 2852181641Skmacy len += sizeof(*e1); 2853181641Skmacy 2854181641Skmacy if (u.desc->bLength < len) { 2855181641Skmacy goto error; 2856181641Skmacy } 2857181641Skmacy len += e1->bControlSize; 2858181641Skmacy break; 2859181641Skmacy 2860181641Skmacy default: 2861181641Skmacy goto error; 2862181641Skmacy } 2863181641Skmacy 2864181641Skmacy if (u.desc->bLength < len) { 2865181641Skmacy goto error; 2866181641Skmacy } 2867181641Skmacy return (u.desc); 2868181641Skmacy 2869181641Skmacyerror: 2870181641Skmacy if (u.desc) { 2871181641Skmacy DPRINTF("invalid descriptor, type=%d, " 2872181641Skmacy "sub_type=%d, len=%d of %d bytes\n", 2873181641Skmacy u.desc->bDescriptorType, 2874181641Skmacy u.desc->bDescriptorSubtype, 2875181641Skmacy u.desc->bLength, len); 2876181641Skmacy } 2877181641Skmacy return (NULL); 2878181641Skmacy} 2879181641Skmacy 2880181641Skmacystatic const void * 2881181641Skmacyuaudio20_mixer_verify_desc(const void *arg, uint32_t len) 2882181641Skmacy{ 2883181641Skmacy const struct usb_audio20_mixer_unit_1 *d1; 2884181641Skmacy const struct usb_audio20_extension_unit_1 *e1; 2885181641Skmacy const struct usb_audio20_processing_unit_1 *u1; 2886181641Skmacy const struct usb_audio20_clock_selector_unit_1 *c1; 2887181641Skmacy 2888181641Skmacy union { 2889181641Skmacy const struct usb_descriptor *desc; 2890181641Skmacy const struct usb_audio20_clock_source_unit *csrc; 2891181641Skmacy const struct usb_audio20_clock_selector_unit_0 *csel; 2892181641Skmacy const struct usb_audio20_clock_multiplier_unit *cmul; 2893181641Skmacy const struct usb_audio20_input_terminal *it; 2894181641Skmacy const struct usb_audio20_output_terminal *ot; 2895181641Skmacy const struct usb_audio20_mixer_unit_0 *mu; 2896181641Skmacy const struct usb_audio20_selector_unit *su; 2897181641Skmacy const struct usb_audio20_feature_unit *fu; 2898181641Skmacy const struct usb_audio20_sample_rate_unit *ru; 2899181641Skmacy const struct usb_audio20_processing_unit_0 *pu; 2900181641Skmacy const struct usb_audio20_extension_unit_0 *eu; 2901181641Skmacy const struct usb_audio20_effect_unit *ef; 2902181641Skmacy } u; 2903181641Skmacy 2904181641Skmacy u.desc = arg; 2905181641Skmacy 2906181641Skmacy if (u.desc == NULL) 2907181641Skmacy goto error; 2908181641Skmacy 2909181641Skmacy if (u.desc->bDescriptorType != UDESC_CS_INTERFACE) 2910181641Skmacy goto error; 2911181641Skmacy 2912181641Skmacy switch (u.desc->bDescriptorSubtype) { 2913181641Skmacy case UDESCSUB_AC_INPUT: 2914181641Skmacy len += sizeof(*u.it); 2915181641Skmacy break; 2916181641Skmacy 2917181641Skmacy case UDESCSUB_AC_OUTPUT: 2918181641Skmacy len += sizeof(*u.ot); 2919181641Skmacy break; 2920181641Skmacy 2921181641Skmacy case UDESCSUB_AC_MIXER: 2922181641Skmacy len += sizeof(*u.mu); 2923181641Skmacy 2924181641Skmacy if (u.desc->bLength < len) 2925181641Skmacy goto error; 2926181641Skmacy len += u.mu->bNrInPins; 2927181641Skmacy 2928181641Skmacy if (u.desc->bLength < len) 2929181641Skmacy goto error; 2930181641Skmacy 2931181641Skmacy d1 = (const void *)(u.mu->baSourceId + u.mu->bNrInPins); 2932181641Skmacy 2933181641Skmacy len += sizeof(*d1) + d1->bNrChannels; 2934181641Skmacy break; 2935181641Skmacy 2936181641Skmacy case UDESCSUB_AC_SELECTOR: 2937181641Skmacy len += sizeof(*u.su); 2938181641Skmacy 2939181641Skmacy if (u.desc->bLength < len) 2940181641Skmacy goto error; 2941181641Skmacy 2942181641Skmacy len += u.su->bNrInPins; 2943207796Salc break; 2944181641Skmacy 2945207796Salc case UDESCSUB_AC_FEATURE: 2946181641Skmacy len += sizeof(*u.fu) + 1; 2947181641Skmacy 2948207796Salc if (u.desc->bLength < len) 2949181641Skmacy goto error; 2950181641Skmacy break; 2951181641Skmacy 2952181747Skmacy case UDESCSUB_AC_EFFECT: 2953181641Skmacy len += sizeof(*u.ef) + 4; 2954181641Skmacy break; 2955181641Skmacy 2956181641Skmacy case UDESCSUB_AC_PROCESSING_V2: 2957181641Skmacy len += sizeof(*u.pu); 2958181641Skmacy 2959181641Skmacy if (u.desc->bLength < len) 2960181641Skmacy goto error; 2961181641Skmacy 2962181641Skmacy len += u.pu->bNrInPins; 2963181641Skmacy 2964181641Skmacy if (u.desc->bLength < len) 2965181641Skmacy goto error; 2966181641Skmacy 2967181641Skmacy u1 = (const void *)(u.pu->baSourceId + u.pu->bNrInPins); 2968181641Skmacy 2969181641Skmacy len += sizeof(*u1); 2970181641Skmacy break; 2971181641Skmacy 2972181641Skmacy case UDESCSUB_AC_EXTENSION_V2: 2973181641Skmacy len += sizeof(*u.eu); 2974181641Skmacy 2975181641Skmacy if (u.desc->bLength < len) 2976181641Skmacy goto error; 2977181641Skmacy 2978181641Skmacy len += u.eu->bNrInPins; 2979181641Skmacy 2980181747Skmacy if (u.desc->bLength < len) 2981181641Skmacy goto error; 2982181641Skmacy 2983181641Skmacy e1 = (const void *)(u.eu->baSourceId + u.eu->bNrInPins); 2984181641Skmacy 2985181641Skmacy len += sizeof(*e1); 2986181641Skmacy break; 2987181641Skmacy 2988181641Skmacy case UDESCSUB_AC_CLOCK_SRC: 2989181641Skmacy len += sizeof(*u.csrc); 2990181641Skmacy break; 2991181641Skmacy 2992181641Skmacy case UDESCSUB_AC_CLOCK_SEL: 2993181641Skmacy len += sizeof(*u.csel); 2994181641Skmacy 2995181641Skmacy if (u.desc->bLength < len) 2996181641Skmacy goto error; 2997181641Skmacy 2998181641Skmacy len += u.csel->bNrInPins; 2999181641Skmacy 3000181641Skmacy if (u.desc->bLength < len) 3001181641Skmacy goto error; 3002181641Skmacy 3003181641Skmacy c1 = (const void *)(u.csel->baCSourceId + u.csel->bNrInPins); 3004181641Skmacy 3005181641Skmacy len += sizeof(*c1); 3006181641Skmacy break; 3007181641Skmacy 3008181641Skmacy case UDESCSUB_AC_CLOCK_MUL: 3009181641Skmacy len += sizeof(*u.cmul); 3010181641Skmacy break; 3011181641Skmacy 3012181641Skmacy case UDESCSUB_AC_SAMPLE_RT: 3013181641Skmacy len += sizeof(*u.ru); 3014181641Skmacy break; 3015181641Skmacy 3016181641Skmacy default: 3017181641Skmacy goto error; 3018181641Skmacy } 3019181641Skmacy 3020181641Skmacy if (u.desc->bLength < len) 3021181641Skmacy goto error; 3022181641Skmacy 3023181641Skmacy return (u.desc); 3024181641Skmacy 3025181641Skmacyerror: 3026181641Skmacy if (u.desc) { 3027181641Skmacy DPRINTF("invalid descriptor, type=%d, " 3028181641Skmacy "sub_type=%d, len=%d of %d bytes\n", 3029181641Skmacy u.desc->bDescriptorType, 3030181641Skmacy u.desc->bDescriptorSubtype, 3031181641Skmacy u.desc->bLength, len); 3032181641Skmacy } 3033181641Skmacy return (NULL); 3034181641Skmacy} 3035181641Skmacy 3036181641Skmacystatic struct usb_audio_cluster 3037181641Skmacyuaudio_mixer_get_cluster(uint8_t id, const struct uaudio_terminal_node *iot) 3038181641Skmacy{ 3039181641Skmacy struct usb_audio_cluster r; 3040181641Skmacy const struct usb_descriptor *dp; 3041181641Skmacy uint8_t i; 3042181641Skmacy 3043181641Skmacy for (i = 0; i < UAUDIO_RECURSE_LIMIT; i++) { /* avoid infinite loops */ 3044181641Skmacy dp = iot[id].u.desc; 3045181641Skmacy if (dp == NULL) { 3046181641Skmacy goto error; 3047181641Skmacy } 3048181641Skmacy switch (dp->bDescriptorSubtype) { 3049181641Skmacy case UDESCSUB_AC_INPUT: 3050181641Skmacy r.bNrChannels = iot[id].u.it_v1->bNrChannels; 3051181641Skmacy r.wChannelConfig[0] = iot[id].u.it_v1->wChannelConfig[0]; 3052181641Skmacy r.wChannelConfig[1] = iot[id].u.it_v1->wChannelConfig[1]; 3053181641Skmacy r.iChannelNames = iot[id].u.it_v1->iChannelNames; 3054181641Skmacy goto done; 3055181641Skmacy 3056181641Skmacy case UDESCSUB_AC_OUTPUT: 3057181641Skmacy id = iot[id].u.ot_v1->bSourceId; 3058181641Skmacy break; 3059181641Skmacy 3060181641Skmacy case UDESCSUB_AC_MIXER: 3061181641Skmacy r = *(const struct usb_audio_cluster *) 3062181641Skmacy &iot[id].u.mu_v1->baSourceId[ 3063181641Skmacy iot[id].u.mu_v1->bNrInPins]; 3064181641Skmacy goto done; 3065181641Skmacy 3066181641Skmacy case UDESCSUB_AC_SELECTOR: 3067181641Skmacy if (iot[id].u.su_v1->bNrInPins > 0) { 3068181641Skmacy /* XXX This is not really right */ 3069181641Skmacy id = iot[id].u.su_v1->baSourceId[0]; 3070181641Skmacy } 3071181641Skmacy break; 3072181641Skmacy 3073181641Skmacy case UDESCSUB_AC_FEATURE: 3074181641Skmacy id = iot[id].u.fu_v1->bSourceId; 3075181641Skmacy break; 3076181641Skmacy 3077181641Skmacy case UDESCSUB_AC_PROCESSING: 3078181641Skmacy r = *((const struct usb_audio_cluster *) 3079181641Skmacy &iot[id].u.pu_v1->baSourceId[ 3080181641Skmacy iot[id].u.pu_v1->bNrInPins]); 3081181641Skmacy goto done; 3082181641Skmacy 3083181641Skmacy case UDESCSUB_AC_EXTENSION: 3084181641Skmacy r = *((const struct usb_audio_cluster *) 3085181641Skmacy &iot[id].u.eu_v1->baSourceId[ 3086181641Skmacy iot[id].u.eu_v1->bNrInPins]); 3087181641Skmacy goto done; 3088181641Skmacy 3089181641Skmacy default: 3090181641Skmacy goto error; 3091181641Skmacy } 3092181641Skmacy } 3093181641Skmacyerror: 3094181641Skmacy DPRINTF("bad data\n"); 3095181641Skmacy memset(&r, 0, sizeof(r)); 3096181641Skmacydone: 3097181641Skmacy return (r); 3098181641Skmacy} 3099181641Skmacy 3100181641Skmacystatic struct usb_audio20_cluster 3101181641Skmacyuaudio20_mixer_get_cluster(uint8_t id, const struct uaudio_terminal_node *iot) 3102181641Skmacy{ 3103181641Skmacy struct usb_audio20_cluster r; 3104181641Skmacy const struct usb_descriptor *dp; 3105181641Skmacy uint8_t i; 3106181641Skmacy 3107181641Skmacy for (i = 0; i < UAUDIO_RECURSE_LIMIT; i++) { /* avoid infinite loops */ 3108181641Skmacy dp = iot[id].u.desc; 3109181641Skmacy if (dp == NULL) 3110181641Skmacy goto error; 3111181641Skmacy 3112181641Skmacy switch (dp->bDescriptorSubtype) { 3113181641Skmacy case UDESCSUB_AC_INPUT: 3114181641Skmacy r.bNrChannels = iot[id].u.it_v2->bNrChannels; 3115181641Skmacy r.bmChannelConfig[0] = iot[id].u.it_v2->bmChannelConfig[0]; 3116181641Skmacy r.bmChannelConfig[1] = iot[id].u.it_v2->bmChannelConfig[1]; 3117200346Skmacy r.bmChannelConfig[2] = iot[id].u.it_v2->bmChannelConfig[2]; 3118181641Skmacy r.bmChannelConfig[3] = iot[id].u.it_v2->bmChannelConfig[3]; 3119181641Skmacy r.iChannelNames = iot[id].u.it_v2->iTerminal; 3120200346Skmacy goto done; 3121181641Skmacy 3122181641Skmacy case UDESCSUB_AC_OUTPUT: 3123181641Skmacy id = iot[id].u.ot_v2->bSourceId; 3124181641Skmacy break; 3125181641Skmacy 3126181641Skmacy case UDESCSUB_AC_MIXER: 3127181641Skmacy r = *(const struct usb_audio20_cluster *) 3128181641Skmacy &iot[id].u.mu_v2->baSourceId[ 3129181641Skmacy iot[id].u.mu_v2->bNrInPins]; 3130181641Skmacy goto done; 3131181641Skmacy 3132181641Skmacy case UDESCSUB_AC_SELECTOR: 3133181641Skmacy if (iot[id].u.su_v2->bNrInPins > 0) { 3134181641Skmacy /* XXX This is not really right */ 3135207419Skmacy id = iot[id].u.su_v2->baSourceId[0]; 3136207419Skmacy } 3137181641Skmacy break; 3138207419Skmacy 3139181641Skmacy case UDESCSUB_AC_SAMPLE_RT: 3140181641Skmacy id = iot[id].u.ru_v2->bSourceId; 3141195840Sjhb break; 3142181641Skmacy 3143181641Skmacy case UDESCSUB_AC_EFFECT: 3144207419Skmacy id = iot[id].u.ef_v2->bSourceId; 3145207419Skmacy break; 3146207419Skmacy 3147181641Skmacy case UDESCSUB_AC_FEATURE: 3148207419Skmacy id = iot[id].u.fu_v2->bSourceId; 3149207419Skmacy break; 3150207419Skmacy 3151207419Skmacy case UDESCSUB_AC_PROCESSING_V2: 3152207419Skmacy r = *((const struct usb_audio20_cluster *) 3153207419Skmacy &iot[id].u.pu_v2->baSourceId[ 3154207419Skmacy iot[id].u.pu_v2->bNrInPins]); 3155181641Skmacy goto done; 3156181641Skmacy 3157181641Skmacy case UDESCSUB_AC_EXTENSION_V2: 3158207419Skmacy r = *((const struct usb_audio20_cluster *) 3159207419Skmacy &iot[id].u.eu_v2->baSourceId[ 3160207419Skmacy iot[id].u.eu_v2->bNrInPins]); 3161207419Skmacy goto done; 3162207419Skmacy 3163207419Skmacy default: 3164207419Skmacy goto error; 3165207419Skmacy } 3166207419Skmacy } 3167207419Skmacyerror: 3168207419Skmacy DPRINTF("Bad data!\n"); 3169207419Skmacy memset(&r, 0, sizeof(r)); 3170207419Skmacydone: 3171207419Skmacy return (r); 3172207419Skmacy} 3173207419Skmacy 3174181641Skmacystatic uint16_t 3175207419Skmacyuaudio_mixer_determine_class(const struct uaudio_terminal_node *iot, 3176207419Skmacy struct uaudio_mixer_node *mix) 3177207419Skmacy{ 3178207419Skmacy uint16_t terminal_type = 0x0000; 3179207419Skmacy const struct uaudio_terminal_node *input[2]; 3180207419Skmacy const struct uaudio_terminal_node *output[2]; 3181207419Skmacy 3182207419Skmacy input[0] = uaudio_mixer_get_input(iot, 0); 3183207419Skmacy input[1] = uaudio_mixer_get_input(iot, 1); 3184207419Skmacy 3185207419Skmacy output[0] = uaudio_mixer_get_output(iot, 0); 3186207419Skmacy output[1] = uaudio_mixer_get_output(iot, 1); 3187181641Skmacy 3188181641Skmacy /* 3189181641Skmacy * check if there is only 3190181641Skmacy * one output terminal: 3191181641Skmacy */ 3192181641Skmacy if (output[0] && (!output[1])) { 3193181641Skmacy terminal_type = 3194181641Skmacy UGETW(output[0]->u.ot_v1->wTerminalType); 3195181641Skmacy } 3196181641Skmacy /* 3197181641Skmacy * If the only output terminal is USB, 3198181641Skmacy * the class is UAC_RECORD. 3199181641Skmacy */ 3200181641Skmacy if ((terminal_type & 0xff00) == (UAT_UNDEFINED & 0xff00)) { 3201181641Skmacy 3202181641Skmacy mix->class = UAC_RECORD; 3203181641Skmacy if (input[0] && (!input[1])) { 3204181641Skmacy terminal_type = 3205181641Skmacy UGETW(input[0]->u.it_v1->wTerminalType); 3206181641Skmacy } else { 3207181641Skmacy terminal_type = 0; 3208181641Skmacy } 3209181641Skmacy goto done; 3210181641Skmacy } 3211181641Skmacy /* 3212181641Skmacy * if the unit is connected to just 3213181641Skmacy * one input terminal, the 3214181641Skmacy * class is UAC_INPUT: 3215181641Skmacy */ 3216181641Skmacy if (input[0] && (!input[1])) { 3217181641Skmacy mix->class = UAC_INPUT; 3218181641Skmacy terminal_type = 3219181641Skmacy UGETW(input[0]->u.it_v1->wTerminalType); 3220181641Skmacy goto done; 3221181641Skmacy } 3222181641Skmacy /* 3223181641Skmacy * Otherwise, the class is UAC_OUTPUT. 3224181641Skmacy */ 3225181641Skmacy mix->class = UAC_OUTPUT; 3226181641Skmacydone: 3227181641Skmacy return (terminal_type); 3228181641Skmacy} 3229181641Skmacy 3230181641Skmacystatic uint16_t 3231181641Skmacyuaudio20_mixer_determine_class(const struct uaudio_terminal_node *iot, 3232181641Skmacy struct uaudio_mixer_node *mix) 3233181641Skmacy{ 3234181641Skmacy uint16_t terminal_type = 0x0000; 3235181641Skmacy const struct uaudio_terminal_node *input[2]; 3236181641Skmacy const struct uaudio_terminal_node *output[2]; 3237181641Skmacy 3238181641Skmacy input[0] = uaudio_mixer_get_input(iot, 0); 3239181641Skmacy input[1] = uaudio_mixer_get_input(iot, 1); 3240181641Skmacy 3241181641Skmacy output[0] = uaudio_mixer_get_output(iot, 0); 3242181641Skmacy output[1] = uaudio_mixer_get_output(iot, 1); 3243181641Skmacy 3244181641Skmacy /* 3245181641Skmacy * check if there is only 3246181641Skmacy * one output terminal: 3247181641Skmacy */ 3248181641Skmacy if (output[0] && (!output[1])) 3249181641Skmacy terminal_type = UGETW(output[0]->u.ot_v2->wTerminalType); 3250181641Skmacy /* 3251181641Skmacy * If the only output terminal is USB, 3252181641Skmacy * the class is UAC_RECORD. 3253181641Skmacy */ 3254181641Skmacy if ((terminal_type & 0xff00) == (UAT_UNDEFINED & 0xff00)) { 3255181641Skmacy 3256181641Skmacy mix->class = UAC_RECORD; 3257181641Skmacy if (input[0] && (!input[1])) { 3258181641Skmacy terminal_type = 3259181641Skmacy UGETW(input[0]->u.it_v2->wTerminalType); 3260181641Skmacy } else { 3261181641Skmacy terminal_type = 0; 3262181641Skmacy } 3263181641Skmacy goto done; 3264181641Skmacy } 3265181641Skmacy /* 3266181641Skmacy * if the unit is connected to just 3267181641Skmacy * one input terminal, the 3268181641Skmacy * class is UAC_INPUT: 3269181641Skmacy */ 3270181641Skmacy if (input[0] && (!input[1])) { 3271181641Skmacy mix->class = UAC_INPUT; 3272181641Skmacy terminal_type = 3273181641Skmacy UGETW(input[0]->u.it_v2->wTerminalType); 3274181641Skmacy goto done; 3275181641Skmacy } 3276181641Skmacy /* 3277181641Skmacy * Otherwise, the class is UAC_OUTPUT. 3278181641Skmacy */ 3279181641Skmacy mix->class = UAC_OUTPUT; 3280181641Skmacydone: 3281181641Skmacy return (terminal_type); 3282181641Skmacy} 3283181641Skmacy 3284181641Skmacystruct uaudio_tt_to_feature { 3285181641Skmacy uint16_t terminal_type; 3286181641Skmacy uint16_t feature; 3287181641Skmacy}; 3288181641Skmacy 3289181641Skmacystatic const struct uaudio_tt_to_feature uaudio_tt_to_feature[] = { 3290181641Skmacy 3291181641Skmacy {UAT_STREAM, SOUND_MIXER_PCM}, 3292181641Skmacy 3293181641Skmacy {UATI_MICROPHONE, SOUND_MIXER_MIC}, 3294181641Skmacy {UATI_DESKMICROPHONE, SOUND_MIXER_MIC}, 3295181641Skmacy {UATI_PERSONALMICROPHONE, SOUND_MIXER_MIC}, 3296181641Skmacy {UATI_OMNIMICROPHONE, SOUND_MIXER_MIC}, 3297181641Skmacy {UATI_MICROPHONEARRAY, SOUND_MIXER_MIC}, 3298181641Skmacy {UATI_PROCMICROPHONEARR, SOUND_MIXER_MIC}, 3299181641Skmacy 3300181641Skmacy {UATO_SPEAKER, SOUND_MIXER_SPEAKER}, 3301181641Skmacy {UATO_DESKTOPSPEAKER, SOUND_MIXER_SPEAKER}, 3302181641Skmacy {UATO_ROOMSPEAKER, SOUND_MIXER_SPEAKER}, 3303181641Skmacy {UATO_COMMSPEAKER, SOUND_MIXER_SPEAKER}, 3304181641Skmacy 3305181641Skmacy {UATE_ANALOGCONN, SOUND_MIXER_LINE}, 3306181641Skmacy {UATE_LINECONN, SOUND_MIXER_LINE}, 3307181641Skmacy {UATE_LEGACYCONN, SOUND_MIXER_LINE}, 3308181641Skmacy 3309181641Skmacy {UATE_DIGITALAUIFC, SOUND_MIXER_ALTPCM}, 3310181641Skmacy {UATE_SPDIF, SOUND_MIXER_ALTPCM}, 3311181641Skmacy {UATE_1394DA, SOUND_MIXER_ALTPCM}, 3312181641Skmacy {UATE_1394DV, SOUND_MIXER_ALTPCM}, 3313181641Skmacy 3314181641Skmacy {UATF_CDPLAYER, SOUND_MIXER_CD}, 3315181641Skmacy 3316181641Skmacy {UATF_SYNTHESIZER, SOUND_MIXER_SYNTH}, 3317181641Skmacy 3318181641Skmacy {UATF_VIDEODISCAUDIO, SOUND_MIXER_VIDEO}, 3319181641Skmacy {UATF_DVDAUDIO, SOUND_MIXER_VIDEO}, 3320181641Skmacy {UATF_TVTUNERAUDIO, SOUND_MIXER_VIDEO}, 3321181641Skmacy 3322181641Skmacy /* telephony terminal types */ 3323181641Skmacy {UATT_UNDEFINED, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 3324181641Skmacy {UATT_PHONELINE, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 3325181641Skmacy {UATT_TELEPHONE, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 3326181641Skmacy {UATT_DOWNLINEPHONE, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 3327181641Skmacy 3328181641Skmacy {UATF_RADIORECV, SOUND_MIXER_RADIO}, 3329181641Skmacy {UATF_RADIOXMIT, SOUND_MIXER_RADIO}, 3330181641Skmacy 3331181641Skmacy {UAT_UNDEFINED, SOUND_MIXER_VOLUME}, 3332181641Skmacy {UAT_VENDOR, SOUND_MIXER_VOLUME}, 3333181641Skmacy {UATI_UNDEFINED, SOUND_MIXER_VOLUME}, 3334181641Skmacy 3335181641Skmacy /* output terminal types */ 3336181641Skmacy {UATO_UNDEFINED, SOUND_MIXER_VOLUME}, 3337181641Skmacy {UATO_DISPLAYAUDIO, SOUND_MIXER_VOLUME}, 3338181641Skmacy {UATO_SUBWOOFER, SOUND_MIXER_VOLUME}, 3339181641Skmacy {UATO_HEADPHONES, SOUND_MIXER_VOLUME}, 3340181641Skmacy 3341181641Skmacy /* bidir terminal types */ 3342181641Skmacy {UATB_UNDEFINED, SOUND_MIXER_VOLUME}, 3343181641Skmacy {UATB_HANDSET, SOUND_MIXER_VOLUME}, 3344181641Skmacy {UATB_HEADSET, SOUND_MIXER_VOLUME}, 3345181641Skmacy {UATB_SPEAKERPHONE, SOUND_MIXER_VOLUME}, 3346181641Skmacy {UATB_SPEAKERPHONEESUP, SOUND_MIXER_VOLUME}, 3347181641Skmacy {UATB_SPEAKERPHONEECANC, SOUND_MIXER_VOLUME}, 3348196723Sadrian 3349196723Sadrian /* external terminal types */ 3350196723Sadrian {UATE_UNDEFINED, SOUND_MIXER_VOLUME}, 3351196723Sadrian 3352196723Sadrian /* embedded function terminal types */ 3353196723Sadrian {UATF_UNDEFINED, SOUND_MIXER_VOLUME}, 3354196723Sadrian {UATF_CALIBNOISE, SOUND_MIXER_VOLUME}, 3355196723Sadrian {UATF_EQUNOISE, SOUND_MIXER_VOLUME}, 3356196723Sadrian {UATF_DAT, SOUND_MIXER_VOLUME}, 3357196723Sadrian {UATF_DCC, SOUND_MIXER_VOLUME}, 3358196723Sadrian {UATF_MINIDISK, SOUND_MIXER_VOLUME}, 3359196723Sadrian {UATF_ANALOGTAPE, SOUND_MIXER_VOLUME}, 3360196723Sadrian {UATF_PHONOGRAPH, SOUND_MIXER_VOLUME}, 3361196723Sadrian {UATF_VCRAUDIO, SOUND_MIXER_VOLUME}, 3362196723Sadrian {UATF_SATELLITE, SOUND_MIXER_VOLUME}, 3363196723Sadrian {UATF_CABLETUNER, SOUND_MIXER_VOLUME}, 3364181641Skmacy {UATF_DSS, SOUND_MIXER_VOLUME}, 3365181641Skmacy {UATF_MULTITRACK, SOUND_MIXER_VOLUME}, 3366181641Skmacy {0xffff, SOUND_MIXER_VOLUME}, 3367181641Skmacy 3368181641Skmacy /* default */ 3369181641Skmacy {0x0000, SOUND_MIXER_VOLUME}, 3370181641Skmacy}; 3371181641Skmacy 3372181641Skmacystatic uint16_t 3373181641Skmacyuaudio_mixer_feature_name(const struct uaudio_terminal_node *iot, 3374181641Skmacy struct uaudio_mixer_node *mix) 3375181641Skmacy{ 3376181641Skmacy const struct uaudio_tt_to_feature *uat = uaudio_tt_to_feature; 3377181641Skmacy uint16_t terminal_type = uaudio_mixer_determine_class(iot, mix); 3378181641Skmacy 3379181641Skmacy if ((mix->class == UAC_RECORD) && (terminal_type == 0)) { 3380181641Skmacy return (SOUND_MIXER_IMIX); 3381181641Skmacy } 3382181641Skmacy while (uat->terminal_type) { 3383181641Skmacy if (uat->terminal_type == terminal_type) { 3384181641Skmacy break; 3385181641Skmacy } 3386181641Skmacy uat++; 3387181641Skmacy } 3388181641Skmacy 3389181641Skmacy DPRINTF("terminal_type=0x%04x -> %d\n", 3390181641Skmacy terminal_type, uat->feature); 3391181641Skmacy 3392181641Skmacy return (uat->feature); 3393181641Skmacy} 3394181641Skmacy 3395181641Skmacystatic uint16_t 3396181641Skmacyuaudio20_mixer_feature_name(const struct uaudio_terminal_node *iot, 3397181641Skmacy struct uaudio_mixer_node *mix) 3398181641Skmacy{ 3399181641Skmacy const struct uaudio_tt_to_feature *uat; 3400181641Skmacy uint16_t terminal_type = uaudio20_mixer_determine_class(iot, mix); 3401181641Skmacy 3402181641Skmacy if ((mix->class == UAC_RECORD) && (terminal_type == 0)) 3403181641Skmacy return (SOUND_MIXER_IMIX); 3404181641Skmacy 3405181641Skmacy for (uat = uaudio_tt_to_feature; uat->terminal_type != 0; uat++) { 3406181641Skmacy if (uat->terminal_type == terminal_type) 3407181641Skmacy break; 3408181641Skmacy } 3409181641Skmacy 3410181641Skmacy DPRINTF("terminal_type=0x%04x -> %d\n", 3411181641Skmacy terminal_type, uat->feature); 3412181641Skmacy 3413181641Skmacy return (uat->feature); 3414181641Skmacy} 3415181641Skmacy 3416181641Skmacystatic const struct uaudio_terminal_node * 3417181641Skmacyuaudio_mixer_get_input(const struct uaudio_terminal_node *iot, uint8_t i) 3418181641Skmacy{ 3419181641Skmacy struct uaudio_terminal_node *root = iot->root; 3420181641Skmacy uint8_t n; 3421181641Skmacy 3422181641Skmacy n = iot->usr.id_max; 3423181641Skmacy do { 3424181641Skmacy if (iot->usr.bit_input[n / 8] & (1 << (n % 8))) { 3425181641Skmacy if (!i--) 3426181641Skmacy return (root + n); 3427181641Skmacy } 3428181641Skmacy } while (n--); 3429181641Skmacy 3430181641Skmacy return (NULL); 3431181641Skmacy} 3432181641Skmacy 3433181641Skmacystatic const struct uaudio_terminal_node * 3434181641Skmacyuaudio_mixer_get_output(const struct uaudio_terminal_node *iot, uint8_t i) 3435181641Skmacy{ 3436181641Skmacy struct uaudio_terminal_node *root = iot->root; 3437181641Skmacy uint8_t n; 3438181641Skmacy 3439181641Skmacy n = iot->usr.id_max; 3440181641Skmacy do { 3441181641Skmacy if (iot->usr.bit_output[n / 8] & (1 << (n % 8))) { 3442181641Skmacy if (!i--) 3443181641Skmacy return (root + n); 3444181641Skmacy } 3445181641Skmacy } while (n--); 3446181641Skmacy 3447181641Skmacy return (NULL); 3448181641Skmacy} 3449181641Skmacy 3450181641Skmacystatic void 3451181641Skmacyuaudio_mixer_find_inputs_sub(struct uaudio_terminal_node *root, 3452181641Skmacy const uint8_t *p_id, uint8_t n_id, 3453181641Skmacy struct uaudio_search_result *info) 3454181641Skmacy{ 3455181641Skmacy struct uaudio_terminal_node *iot; 3456181641Skmacy uint8_t n; 3457181641Skmacy uint8_t i; 3458181641Skmacy uint8_t is_last; 3459181641Skmacy 3460181641Skmacytop: 3461181641Skmacy for (n = 0; n < n_id; n++) { 3462181641Skmacy 3463181641Skmacy i = p_id[n]; 3464181641Skmacy 3465181641Skmacy if (info->recurse_level == UAUDIO_RECURSE_LIMIT) { 3466181641Skmacy DPRINTF("avoided going into a circle at id=%d!\n", i); 3467181641Skmacy return; 3468181641Skmacy } 3469181641Skmacy 3470181641Skmacy info->recurse_level++; 3471181641Skmacy 3472181641Skmacy iot = (root + i); 3473181641Skmacy 3474181641Skmacy if (iot->u.desc == NULL) 3475181641Skmacy continue; 3476181641Skmacy 3477181641Skmacy is_last = ((n + 1) == n_id); 3478181641Skmacy 3479181641Skmacy switch (iot->u.desc->bDescriptorSubtype) { 3480181641Skmacy case UDESCSUB_AC_INPUT: 3481181641Skmacy info->bit_input[i / 8] |= (1 << (i % 8)); 3482181641Skmacy break; 3483181641Skmacy 3484181641Skmacy case UDESCSUB_AC_FEATURE: 3485181641Skmacy if (is_last) { 3486181641Skmacy p_id = &iot->u.fu_v1->bSourceId; 3487181641Skmacy n_id = 1; 3488181641Skmacy goto top; 3489181641Skmacy } 3490181641Skmacy uaudio_mixer_find_inputs_sub( 3491181641Skmacy root, &iot->u.fu_v1->bSourceId, 1, info); 3492181641Skmacy break; 3493181641Skmacy 3494181641Skmacy case UDESCSUB_AC_OUTPUT: 3495181641Skmacy if (is_last) { 3496181641Skmacy p_id = &iot->u.ot_v1->bSourceId; 3497181641Skmacy n_id = 1; 3498181641Skmacy goto top; 3499181641Skmacy } 3500181641Skmacy uaudio_mixer_find_inputs_sub( 3501181641Skmacy root, &iot->u.ot_v1->bSourceId, 1, info); 3502181641Skmacy break; 3503207796Salc 3504181641Skmacy case UDESCSUB_AC_MIXER: 3505181641Skmacy if (is_last) { 3506181641Skmacy p_id = iot->u.mu_v1->baSourceId; 3507181641Skmacy n_id = iot->u.mu_v1->bNrInPins; 3508181641Skmacy goto top; 3509181641Skmacy } 3510181641Skmacy uaudio_mixer_find_inputs_sub( 3511181641Skmacy root, iot->u.mu_v1->baSourceId, 3512181641Skmacy iot->u.mu_v1->bNrInPins, info); 3513181641Skmacy break; 3514207796Salc 3515181641Skmacy case UDESCSUB_AC_SELECTOR: 3516181641Skmacy if (is_last) { 3517181641Skmacy p_id = iot->u.su_v1->baSourceId; 3518181641Skmacy n_id = iot->u.su_v1->bNrInPins; 3519181747Skmacy goto top; 3520181747Skmacy } 3521181747Skmacy uaudio_mixer_find_inputs_sub( 3522181747Skmacy root, iot->u.su_v1->baSourceId, 3523181747Skmacy iot->u.su_v1->bNrInPins, info); 3524181747Skmacy break; 3525207796Salc 3526181747Skmacy case UDESCSUB_AC_PROCESSING: 3527181747Skmacy if (is_last) { 3528181747Skmacy p_id = iot->u.pu_v1->baSourceId; 3529207796Salc n_id = iot->u.pu_v1->bNrInPins; 3530207796Salc goto top; 3531207796Salc } 3532207796Salc uaudio_mixer_find_inputs_sub( 3533207796Salc root, iot->u.pu_v1->baSourceId, 3534181747Skmacy iot->u.pu_v1->bNrInPins, info); 3535181747Skmacy break; 3536181747Skmacy 3537181641Skmacy case UDESCSUB_AC_EXTENSION: 3538181641Skmacy if (is_last) { 3539181641Skmacy p_id = iot->u.eu_v1->baSourceId; 3540181641Skmacy n_id = iot->u.eu_v1->bNrInPins; 3541181641Skmacy goto top; 3542181641Skmacy } 3543181641Skmacy uaudio_mixer_find_inputs_sub( 3544181641Skmacy root, iot->u.eu_v1->baSourceId, 3545181641Skmacy iot->u.eu_v1->bNrInPins, info); 3546181641Skmacy break; 3547181641Skmacy 3548181641Skmacy default: 3549181641Skmacy break; 3550181641Skmacy } 3551181641Skmacy } 3552181641Skmacy} 3553181641Skmacy 3554181641Skmacystatic void 3555181641Skmacyuaudio20_mixer_find_inputs_sub(struct uaudio_terminal_node *root, 3556181641Skmacy const uint8_t *p_id, uint8_t n_id, 3557181641Skmacy struct uaudio_search_result *info) 3558181641Skmacy{ 3559181641Skmacy struct uaudio_terminal_node *iot; 3560181641Skmacy uint8_t n; 3561181641Skmacy uint8_t i; 3562181641Skmacy uint8_t is_last; 3563181641Skmacy 3564181641Skmacytop: 3565181641Skmacy for (n = 0; n < n_id; n++) { 3566181641Skmacy 3567181641Skmacy i = p_id[n]; 3568181641Skmacy 3569181641Skmacy if (info->recurse_level == UAUDIO_RECURSE_LIMIT) { 3570181641Skmacy DPRINTF("avoided going into a circle at id=%d!\n", i); 3571181641Skmacy return; 3572181641Skmacy } 3573181641Skmacy 3574181641Skmacy info->recurse_level++; 3575181641Skmacy 3576181641Skmacy iot = (root + i); 3577181641Skmacy 3578181641Skmacy if (iot->u.desc == NULL) 3579181641Skmacy continue; 3580181641Skmacy 3581181641Skmacy is_last = ((n + 1) == n_id); 3582181641Skmacy 3583181641Skmacy switch (iot->u.desc->bDescriptorSubtype) { 3584181641Skmacy case UDESCSUB_AC_INPUT: 3585181641Skmacy info->bit_input[i / 8] |= (1 << (i % 8)); 3586181641Skmacy break; 3587181641Skmacy 3588181641Skmacy case UDESCSUB_AC_OUTPUT: 3589181641Skmacy if (is_last) { 3590181641Skmacy p_id = &iot->u.ot_v2->bSourceId; 3591181641Skmacy n_id = 1; 3592181641Skmacy goto top; 3593181641Skmacy } 3594181641Skmacy uaudio20_mixer_find_inputs_sub( 3595181641Skmacy root, &iot->u.ot_v2->bSourceId, 1, info); 3596181641Skmacy break; 3597181641Skmacy 3598181641Skmacy case UDESCSUB_AC_MIXER: 3599181641Skmacy if (is_last) { 3600181641Skmacy p_id = iot->u.mu_v2->baSourceId; 3601181641Skmacy n_id = iot->u.mu_v2->bNrInPins; 3602181641Skmacy goto top; 3603181641Skmacy } 3604181641Skmacy uaudio20_mixer_find_inputs_sub( 3605181641Skmacy root, iot->u.mu_v2->baSourceId, 3606181641Skmacy iot->u.mu_v2->bNrInPins, info); 3607181641Skmacy break; 3608181641Skmacy 3609181641Skmacy case UDESCSUB_AC_SELECTOR: 3610181641Skmacy if (is_last) { 3611181641Skmacy p_id = iot->u.su_v2->baSourceId; 3612181641Skmacy n_id = iot->u.su_v2->bNrInPins; 3613181641Skmacy goto top; 3614181641Skmacy } 3615181641Skmacy uaudio20_mixer_find_inputs_sub( 3616181641Skmacy root, iot->u.su_v2->baSourceId, 3617181641Skmacy iot->u.su_v2->bNrInPins, info); 3618181641Skmacy break; 3619181641Skmacy 3620181641Skmacy case UDESCSUB_AC_SAMPLE_RT: 3621181641Skmacy if (is_last) { 3622181641Skmacy p_id = &iot->u.ru_v2->bSourceId; 3623181641Skmacy n_id = 1; 3624181641Skmacy goto top; 3625181641Skmacy } 3626181641Skmacy uaudio20_mixer_find_inputs_sub( 3627181641Skmacy root, &iot->u.ru_v2->bSourceId, 3628181641Skmacy 1, info); 3629181641Skmacy break; 3630181641Skmacy 3631181641Skmacy case UDESCSUB_AC_EFFECT: 3632181641Skmacy if (is_last) { 3633181641Skmacy p_id = &iot->u.ef_v2->bSourceId; 3634181641Skmacy n_id = 1; 3635181641Skmacy goto top; 3636181641Skmacy } 3637181641Skmacy uaudio20_mixer_find_inputs_sub( 3638181641Skmacy root, &iot->u.ef_v2->bSourceId, 3639181641Skmacy 1, info); 3640181641Skmacy break; 3641181641Skmacy 3642181641Skmacy case UDESCSUB_AC_FEATURE: 3643181641Skmacy if (is_last) { 3644181641Skmacy p_id = &iot->u.fu_v2->bSourceId; 3645181641Skmacy n_id = 1; 3646181641Skmacy goto top; 3647181641Skmacy } 3648181641Skmacy uaudio20_mixer_find_inputs_sub( 3649181641Skmacy root, &iot->u.fu_v2->bSourceId, 1, info); 3650181641Skmacy break; 3651181641Skmacy 3652181641Skmacy case UDESCSUB_AC_PROCESSING_V2: 3653181641Skmacy if (is_last) { 3654181641Skmacy p_id = iot->u.pu_v2->baSourceId; 3655181641Skmacy n_id = iot->u.pu_v2->bNrInPins; 3656181641Skmacy goto top; 3657181641Skmacy } 3658181641Skmacy uaudio20_mixer_find_inputs_sub( 3659181641Skmacy root, iot->u.pu_v2->baSourceId, 3660181641Skmacy iot->u.pu_v2->bNrInPins, info); 3661181641Skmacy break; 3662181641Skmacy 3663181641Skmacy case UDESCSUB_AC_EXTENSION_V2: 3664181641Skmacy if (is_last) { 3665181641Skmacy p_id = iot->u.eu_v2->baSourceId; 3666208504Salc n_id = iot->u.eu_v2->bNrInPins; 3667208504Salc goto top; 3668181641Skmacy } 3669208504Salc uaudio20_mixer_find_inputs_sub( 3670208504Salc root, iot->u.eu_v2->baSourceId, 3671208504Salc iot->u.eu_v2->bNrInPins, info); 3672208504Salc break; 3673208504Salc default: 3674208504Salc break; 3675208504Salc } 3676208504Salc } 3677208504Salc} 3678181641Skmacy 3679208504Salcstatic void 3680181641Skmacyuaudio20_mixer_find_clocks_sub(struct uaudio_terminal_node *root, 3681181641Skmacy const uint8_t *p_id, uint8_t n_id, 3682181641Skmacy struct uaudio_search_result *info) 3683181641Skmacy{ 3684181641Skmacy struct uaudio_terminal_node *iot; 3685181641Skmacy uint8_t n; 3686181641Skmacy uint8_t i; 3687181641Skmacy uint8_t is_last; 3688181641Skmacy uint8_t id; 3689181641Skmacy 3690181641Skmacytop: 3691181641Skmacy for (n = 0; n < n_id; n++) { 3692181641Skmacy 3693208504Salc i = p_id[n]; 3694181641Skmacy 3695181641Skmacy if (info->recurse_level == UAUDIO_RECURSE_LIMIT) { 3696181641Skmacy DPRINTF("avoided going into a circle at id=%d!\n", i); 3697181641Skmacy return; 3698181641Skmacy } 3699181641Skmacy 3700181641Skmacy info->recurse_level++; 3701181641Skmacy 3702181641Skmacy iot = (root + i); 3703181641Skmacy 3704181641Skmacy if (iot->u.desc == NULL) 3705181641Skmacy continue; 3706181641Skmacy 3707181641Skmacy is_last = ((n + 1) == n_id); 3708181641Skmacy 3709181641Skmacy switch (iot->u.desc->bDescriptorSubtype) { 3710181641Skmacy case UDESCSUB_AC_INPUT: 3711181641Skmacy info->is_input = 1; 3712181641Skmacy if (is_last) { 3713181641Skmacy p_id = &iot->u.it_v2->bCSourceId; 3714181641Skmacy n_id = 1; 3715181641Skmacy goto top; 3716181641Skmacy } 3717181641Skmacy uaudio20_mixer_find_clocks_sub(root, 3718181641Skmacy &iot->u.it_v2->bCSourceId, 1, info); 3719181641Skmacy break; 3720181641Skmacy 3721181641Skmacy case UDESCSUB_AC_OUTPUT: 3722181641Skmacy info->is_input = 0; 3723181641Skmacy if (is_last) { 3724181641Skmacy p_id = &iot->u.ot_v2->bCSourceId; 3725181641Skmacy n_id = 1; 3726181641Skmacy goto top; 3727181641Skmacy } 3728181641Skmacy uaudio20_mixer_find_clocks_sub(root, 3729207155Salc &iot->u.ot_v2->bCSourceId, 1, info); 3730207155Salc break; 3731207155Salc 3732207155Salc case UDESCSUB_AC_CLOCK_SEL: 3733207155Salc if (is_last) { 3734207155Salc p_id = iot->u.csel_v2->baCSourceId; 3735207155Salc n_id = iot->u.csel_v2->bNrInPins; 3736207155Salc goto top; 3737207155Salc } 3738207155Salc uaudio20_mixer_find_clocks_sub(root, 3739207155Salc iot->u.csel_v2->baCSourceId, 3740207155Salc iot->u.csel_v2->bNrInPins, info); 3741207155Salc break; 3742207155Salc 3743207155Salc case UDESCSUB_AC_CLOCK_MUL: 3744207155Salc if (is_last) { 3745207155Salc p_id = &iot->u.cmul_v2->bCSourceId; 3746207155Salc n_id = 1; 3747207155Salc goto top; 3748207155Salc } 3749207155Salc uaudio20_mixer_find_clocks_sub(root, 3750207155Salc &iot->u.cmul_v2->bCSourceId, 3751207155Salc 1, info); 3752207155Salc break; 3753207155Salc 3754207155Salc case UDESCSUB_AC_CLOCK_SRC: 3755207155Salc 3756207155Salc id = iot->u.csrc_v2->bClockId; 3757181641Skmacy 3758181641Skmacy switch (info->is_input) { 3759181641Skmacy case 0: 3760181641Skmacy info->bit_output[id / 8] |= (1 << (id % 8)); 3761181641Skmacy break; 3762181641Skmacy case 1: 3763181641Skmacy info->bit_input[id / 8] |= (1 << (id % 8)); 3764181641Skmacy break; 3765181641Skmacy default: 3766181641Skmacy break; 3767181641Skmacy } 3768181641Skmacy break; 3769181641Skmacy 3770181641Skmacy default: 3771181641Skmacy break; 3772181641Skmacy } 3773181641Skmacy } 3774181641Skmacy} 3775181641Skmacy 3776181641Skmacystatic void 3777181641Skmacyuaudio_mixer_find_outputs_sub(struct uaudio_terminal_node *root, uint8_t id, 3778181641Skmacy uint8_t n_id, struct uaudio_search_result *info) 3779181641Skmacy{ 3780181641Skmacy struct uaudio_terminal_node *iot = (root + id); 3781181641Skmacy uint8_t j; 3782181641Skmacy 3783181641Skmacy j = n_id; 3784181641Skmacy do { 3785181641Skmacy if ((j != id) && ((root + j)->u.desc) && 3786181641Skmacy ((root + j)->u.desc->bDescriptorSubtype == UDESCSUB_AC_OUTPUT)) { 3787181641Skmacy 3788181641Skmacy /* 3789181641Skmacy * "j" (output) <--- virtual wire <--- "id" (input) 3790181641Skmacy * 3791181641Skmacy * if "j" has "id" on the input, then "id" have "j" on 3792181641Skmacy * the output, because they are connected: 3793208175Salc */ 3794208175Salc if ((root + j)->usr.bit_input[id / 8] & (1 << (id % 8))) { 3795208175Salc iot->usr.bit_output[j / 8] |= (1 << (j % 8)); 3796208175Salc } 3797208175Salc } 3798208175Salc } while (j--); 3799208175Salc} 3800208175Salc 3801208175Salcstatic void 3802208175Salcuaudio_mixer_fill_info(struct uaudio_softc *sc, 3803181641Skmacy struct usb_device *udev, void *desc) 3804181641Skmacy{ 3805207796Salc const struct usb_audio_control_descriptor *acdp; 3806181641Skmacy struct usb_config_descriptor *cd = usbd_get_config_descriptor(udev); 3807181641Skmacy const struct usb_descriptor *dp; 3808181641Skmacy const struct usb_audio_unit *au; 3809181641Skmacy struct uaudio_terminal_node *iot = NULL; 3810181641Skmacy uint16_t wTotalLen; 3811181641Skmacy uint8_t ID_max = 0; /* inclusive */ 3812181641Skmacy uint8_t i; 3813181641Skmacy 3814188341Skmacy desc = usb_desc_foreach(cd, desc); 3815188341Skmacy 3816181641Skmacy if (desc == NULL) { 3817181641Skmacy DPRINTF("no Audio Control header\n"); 3818181641Skmacy goto done; 3819181641Skmacy } 3820181641Skmacy acdp = desc; 3821188341Skmacy 3822188341Skmacy if ((acdp->bLength < sizeof(*acdp)) || 3823181641Skmacy (acdp->bDescriptorType != UDESC_CS_INTERFACE) || 3824188341Skmacy (acdp->bDescriptorSubtype != UDESCSUB_AC_HEADER)) { 3825181641Skmacy DPRINTF("invalid Audio Control header\n"); 3826181641Skmacy goto done; 3827181641Skmacy } 3828181641Skmacy /* "wTotalLen" is allowed to be corrupt */ 3829181641Skmacy wTotalLen = UGETW(acdp->wTotalLength) - acdp->bLength; 3830181641Skmacy 3831181641Skmacy /* get USB audio revision */ 3832181641Skmacy sc->sc_audio_rev = UGETW(acdp->bcdADC); 3833181641Skmacy 3834181641Skmacy DPRINTFN(3, "found AC header, vers=%03x, len=%d\n", 3835181641Skmacy sc->sc_audio_rev, wTotalLen); 3836207796Salc 3837181641Skmacy iot = malloc(sizeof(struct uaudio_terminal_node) * 256, M_TEMP, 3838181641Skmacy M_WAITOK | M_ZERO); 3839181641Skmacy 3840181641Skmacy if (iot == NULL) { 3841181641Skmacy DPRINTF("no memory!\n"); 3842181641Skmacy goto done; 3843181641Skmacy } 3844181641Skmacy while ((desc = usb_desc_foreach(cd, desc))) { 3845181641Skmacy 3846181641Skmacy dp = desc; 3847181641Skmacy 3848181641Skmacy if (dp->bLength > wTotalLen) { 3849181641Skmacy break; 3850181641Skmacy } else { 3851181641Skmacy wTotalLen -= dp->bLength; 3852181641Skmacy } 3853181641Skmacy 3854181641Skmacy if (sc->sc_audio_rev >= UAUDIO_VERSION_30) 3855181641Skmacy au = NULL; 3856181641Skmacy else if (sc->sc_audio_rev >= UAUDIO_VERSION_20) 3857181641Skmacy au = uaudio20_mixer_verify_desc(dp, 0); 3858181641Skmacy else 3859181641Skmacy au = uaudio_mixer_verify_desc(dp, 0); 3860181641Skmacy 3861181641Skmacy if (au) { 3862181641Skmacy iot[au->bUnitId].u.desc = (const void *)au; 3863181641Skmacy if (au->bUnitId > ID_max) 3864181641Skmacy ID_max = au->bUnitId; 3865181641Skmacy } 3866181641Skmacy } 3867181641Skmacy 3868181641Skmacy DPRINTF("Maximum ID=%d\n", ID_max); 3869181641Skmacy 3870181641Skmacy /* 3871181641Skmacy * determine sourcing inputs for 3872181641Skmacy * all nodes in the tree: 3873181641Skmacy */ 3874181641Skmacy i = ID_max; 3875181641Skmacy do { 3876181641Skmacy if (sc->sc_audio_rev >= UAUDIO_VERSION_30) { 3877181641Skmacy /* FALLTHROUGH */ 3878181641Skmacy } else if (sc->sc_audio_rev >= UAUDIO_VERSION_20) { 3879181641Skmacy uaudio20_mixer_find_inputs_sub(iot, 3880181641Skmacy &i, 1, &((iot + i)->usr)); 3881181641Skmacy 3882181641Skmacy sc->sc_mixer_clocks.is_input = 255; 3883181641Skmacy sc->sc_mixer_clocks.recurse_level = 0; 3884181641Skmacy 3885181641Skmacy uaudio20_mixer_find_clocks_sub(iot, 3886181641Skmacy &i, 1, &sc->sc_mixer_clocks); 3887181641Skmacy } else { 3888181641Skmacy uaudio_mixer_find_inputs_sub(iot, 3889181641Skmacy &i, 1, &((iot + i)->usr)); 3890181641Skmacy } 3891181641Skmacy } while (i--); 3892181641Skmacy 3893181641Skmacy /* 3894181641Skmacy * determine outputs for 3895181641Skmacy * all nodes in the tree: 3896181641Skmacy */ 3897181641Skmacy i = ID_max; 3898181641Skmacy do { 3899181641Skmacy uaudio_mixer_find_outputs_sub(iot, 3900208504Salc i, ID_max, &((iot + i)->usr)); 3901208504Salc } while (i--); 3902208504Salc 3903208504Salc /* set "id_max" and "root" */ 3904208504Salc 3905208504Salc i = ID_max; 3906208504Salc do { 3907208504Salc (iot + i)->usr.id_max = ID_max; 3908208504Salc (iot + i)->root = iot; 3909208504Salc } while (i--); 3910208504Salc 3911208504Salc /* 3912181641Skmacy * Scan the config to create a linked list of "mixer" nodes: 3913208504Salc */ 3914181641Skmacy 3915181641Skmacy i = ID_max; 3916181641Skmacy do { 3917181641Skmacy dp = iot[i].u.desc; 3918181641Skmacy 3919181641Skmacy if (dp == NULL) 3920181641Skmacy continue; 3921181641Skmacy 3922181641Skmacy DPRINTFN(11, "id=%d subtype=%d\n", 3923181641Skmacy i, dp->bDescriptorSubtype); 3924181641Skmacy 3925181641Skmacy if (sc->sc_audio_rev >= UAUDIO_VERSION_30) { 3926181641Skmacy continue; 3927181641Skmacy } else if (sc->sc_audio_rev >= UAUDIO_VERSION_20) { 3928181641Skmacy 3929181641Skmacy switch (dp->bDescriptorSubtype) { 3930181641Skmacy case UDESCSUB_AC_HEADER: 3931208504Salc DPRINTF("unexpected AC header\n"); 3932181641Skmacy break; 3933181641Skmacy 3934181641Skmacy case UDESCSUB_AC_INPUT: 3935181641Skmacy case UDESCSUB_AC_OUTPUT: 3936181641Skmacy case UDESCSUB_AC_PROCESSING_V2: 3937181641Skmacy case UDESCSUB_AC_EXTENSION_V2: 3938181641Skmacy case UDESCSUB_AC_EFFECT: 3939181641Skmacy case UDESCSUB_AC_CLOCK_SRC: 3940181641Skmacy case UDESCSUB_AC_CLOCK_SEL: 3941181641Skmacy case UDESCSUB_AC_CLOCK_MUL: 3942181641Skmacy case UDESCSUB_AC_SAMPLE_RT: 3943181641Skmacy break; 3944181641Skmacy 3945181641Skmacy case UDESCSUB_AC_MIXER: 3946208504Salc uaudio20_mixer_add_mixer(sc, iot, i); 3947208504Salc break; 3948208504Salc 3949181641Skmacy case UDESCSUB_AC_SELECTOR: 3950181641Skmacy uaudio20_mixer_add_selector(sc, iot, i); 3951181641Skmacy break; 3952181641Skmacy 3953181641Skmacy case UDESCSUB_AC_FEATURE: 3954181641Skmacy uaudio20_mixer_add_feature(sc, iot, i); 3955181641Skmacy break; 3956181641Skmacy 3957181641Skmacy default: 3958181641Skmacy DPRINTF("bad AC desc subtype=0x%02x\n", 3959181641Skmacy dp->bDescriptorSubtype); 3960181641Skmacy break; 3961181641Skmacy } 3962181641Skmacy continue; 3963181641Skmacy } 3964181641Skmacy 3965181641Skmacy switch (dp->bDescriptorSubtype) { 3966208504Salc case UDESCSUB_AC_HEADER: 3967181641Skmacy DPRINTF("unexpected AC header\n"); 3968181641Skmacy break; 3969181641Skmacy 3970181641Skmacy case UDESCSUB_AC_INPUT: 3971181641Skmacy case UDESCSUB_AC_OUTPUT: 3972181641Skmacy break; 3973181641Skmacy 3974181641Skmacy case UDESCSUB_AC_MIXER: 3975181641Skmacy uaudio_mixer_add_mixer(sc, iot, i); 3976181641Skmacy break; 3977181641Skmacy 3978181641Skmacy case UDESCSUB_AC_SELECTOR: 3979181641Skmacy uaudio_mixer_add_selector(sc, iot, i); 3980181641Skmacy break; 3981181641Skmacy 3982195949Skib case UDESCSUB_AC_FEATURE: 3983195949Skib uaudio_mixer_add_feature(sc, iot, i); 3984181641Skmacy break; 3985181641Skmacy 3986181641Skmacy case UDESCSUB_AC_PROCESSING: 3987181641Skmacy uaudio_mixer_add_processing(sc, iot, i); 3988181641Skmacy break; 3989181641Skmacy 3990181641Skmacy case UDESCSUB_AC_EXTENSION: 3991181641Skmacy uaudio_mixer_add_extension(sc, iot, i); 3992181641Skmacy break; 3993181641Skmacy 3994181641Skmacy default: 3995181641Skmacy DPRINTF("bad AC desc subtype=0x%02x\n", 3996195949Skib dp->bDescriptorSubtype); 3997195949Skib break; 3998195949Skib } 3999195949Skib 4000181641Skmacy } while (i--); 4001181641Skmacy 4002181641Skmacydone: 4003181641Skmacy free(iot, M_TEMP); 4004181641Skmacy} 4005181641Skmacy 4006181641Skmacystatic int 4007181641Skmacyuaudio_mixer_get(struct usb_device *udev, uint16_t audio_rev, 4008181641Skmacy uint8_t what, struct uaudio_mixer_node *mc) 4009181641Skmacy{ 4010181641Skmacy struct usb_device_request req; 4011181641Skmacy int val; 4012181641Skmacy uint8_t data[2 + (2 * 3)]; 4013181641Skmacy usb_error_t err; 4014181641Skmacy 4015181641Skmacy if (mc->wValue[0] == -1) 4016181641Skmacy return (0); 4017181641Skmacy 4018181641Skmacy if (audio_rev >= UAUDIO_VERSION_30) 4019181641Skmacy return (0); 4020181641Skmacy else if (audio_rev >= UAUDIO_VERSION_20) { 4021181641Skmacy if (what == GET_CUR) { 4022181641Skmacy req.bRequest = UA20_CS_CUR; 4023181641Skmacy USETW(req.wLength, 2); 4024181641Skmacy } else { 4025181641Skmacy req.bRequest = UA20_CS_RANGE; 4026181641Skmacy USETW(req.wLength, 8); 4027181641Skmacy } 4028181641Skmacy } else { 4029181641Skmacy uint16_t len = MIX_SIZE(mc->type); 4030181641Skmacy 4031181641Skmacy req.bRequest = what; 4032181641Skmacy USETW(req.wLength, len); 4033181641Skmacy } 4034181641Skmacy 4035195774Salc req.bmRequestType = UT_READ_CLASS_INTERFACE; 4036195774Salc USETW(req.wValue, mc->wValue[0]); 4037195774Salc USETW(req.wIndex, mc->wIndex); 4038195774Salc 4039195774Salc memset(data, 0, sizeof(data)); 4040195774Salc 4041195949Skib err = usbd_do_request(udev, NULL, &req, data); 4042195949Skib if (err) { 4043195774Salc DPRINTF("err=%s\n", usbd_errstr(err)); 4044195774Salc return (0); 4045195949Skib } 4046195949Skib 4047195774Salc if (audio_rev >= UAUDIO_VERSION_30) { 4048195774Salc val = 0; 4049195774Salc } else if (audio_rev >= UAUDIO_VERSION_20) { 4050195949Skib switch (what) { 4051195949Skib case GET_CUR: 4052195949Skib val = (data[0] | (data[1] << 8)); 4053195949Skib break; 4054195949Skib case GET_MIN: 4055195774Salc val = (data[2] | (data[3] << 8)); 4056195949Skib break; 4057195949Skib case GET_MAX: 4058195949Skib val = (data[4] | (data[5] << 8)); 4059195949Skib break; 4060195949Skib case GET_RES: 4061195949Skib val = (data[6] | (data[7] << 8)); 4062195949Skib break; 4063195949Skib default: 4064195949Skib val = 0; 4065195949Skib break; 4066195949Skib } 4067195949Skib } else { 4068195949Skib val = (data[0] | (data[1] << 8)); 4069195949Skib } 4070195949Skib 4071195949Skib if (what == GET_CUR || what == GET_MIN || what == GET_MAX) 4072195949Skib val = uaudio_mixer_signext(mc->type, val); 4073195949Skib 4074195949Skib DPRINTFN(3, "val=%d\n", val); 4075195949Skib 4076195949Skib return (val); 4077195949Skib} 4078195949Skib 4079195949Skibstatic void 4080195949Skibuaudio_mixer_write_cfg_callback(struct usb_xfer *xfer, usb_error_t error) 4081195949Skib{ 4082195949Skib struct usb_device_request req; 4083195949Skib struct uaudio_softc *sc = usbd_xfer_softc(xfer); 4084195774Salc struct uaudio_mixer_node *mc = sc->sc_mixer_curr; 4085195774Salc struct usb_page_cache *pc; 4086195774Salc uint16_t len; 4087181641Skmacy uint8_t repeat = 1; 4088181641Skmacy uint8_t update; 4089181641Skmacy uint8_t chan; 4090181641Skmacy uint8_t buf[2]; 4091181641Skmacy 4092181641Skmacy DPRINTF("\n"); 4093181641Skmacy 4094181641Skmacy switch (USB_GET_STATE(xfer)) { 4095181641Skmacy case USB_ST_TRANSFERRED: 4096181641Skmacytr_transferred: 4097195949Skib case USB_ST_SETUP: 4098181641Skmacytr_setup: 4099181641Skmacy 4100181641Skmacy if (mc == NULL) { 4101181641Skmacy mc = sc->sc_mixer_root; 4102181641Skmacy sc->sc_mixer_curr = mc; 4103181641Skmacy sc->sc_mixer_chan = 0; 4104181641Skmacy repeat = 0; 4105181641Skmacy } 4106181641Skmacy while (mc) { 4107181641Skmacy while (sc->sc_mixer_chan < mc->nchan) { 4108181641Skmacy 4109181641Skmacy chan = sc->sc_mixer_chan; 4110181641Skmacy 4111181641Skmacy sc->sc_mixer_chan++; 4112181641Skmacy 4113181641Skmacy update = ((mc->update[chan / 8] & (1 << (chan % 8))) && 4114181641Skmacy (mc->wValue[chan] != -1)); 4115181641Skmacy 4116181641Skmacy mc->update[chan / 8] &= ~(1 << (chan % 8)); 4117181641Skmacy 4118181641Skmacy if (update) { 4119195949Skib 4120195949Skib req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 4121181641Skmacy USETW(req.wValue, mc->wValue[chan]); 4122181641Skmacy USETW(req.wIndex, mc->wIndex); 4123181641Skmacy 4124181641Skmacy if (sc->sc_audio_rev >= UAUDIO_VERSION_30) { 4125181641Skmacy return; 4126181641Skmacy } else if (sc->sc_audio_rev >= UAUDIO_VERSION_20) { 4127181641Skmacy len = 2; 4128181641Skmacy req.bRequest = UA20_CS_CUR; 4129181641Skmacy USETW(req.wLength, len); 4130181641Skmacy } else { 4131181641Skmacy len = MIX_SIZE(mc->type); 4132181641Skmacy req.bRequest = SET_CUR; 4133181641Skmacy USETW(req.wLength, len); 4134181641Skmacy } 4135181641Skmacy 4136181641Skmacy buf[0] = (mc->wData[chan] & 0xFF); 4137181641Skmacy buf[1] = (mc->wData[chan] >> 8) & 0xFF; 4138195949Skib 4139195949Skib pc = usbd_xfer_get_frame(xfer, 0); 4140181641Skmacy usbd_copy_in(pc, 0, &req, sizeof(req)); 4141181641Skmacy pc = usbd_xfer_get_frame(xfer, 1); 4142181641Skmacy usbd_copy_in(pc, 0, buf, len); 4143181641Skmacy 4144181641Skmacy usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 4145181641Skmacy usbd_xfer_set_frame_len(xfer, 1, len); 4146181641Skmacy usbd_xfer_set_frames(xfer, len ? 2 : 1); 4147181641Skmacy usbd_transfer_submit(xfer); 4148195949Skib return; 4149195949Skib } 4150195949Skib } 4151195949Skib 4152181641Skmacy mc = mc->next; 4153181641Skmacy sc->sc_mixer_curr = mc; 4154181641Skmacy sc->sc_mixer_chan = 0; 4155181641Skmacy } 4156181641Skmacy 4157181641Skmacy if (repeat) { 4158181641Skmacy goto tr_setup; 4159208504Salc } 4160181641Skmacy break; 4161181641Skmacy 4162208504Salc default: /* Error */ 4163208504Salc DPRINTF("error=%s\n", usbd_errstr(error)); 4164181641Skmacy if (error == USB_ERR_CANCELLED) { 4165181641Skmacy /* do nothing - we are detaching */ 4166208504Salc break; 4167181641Skmacy } 4168181641Skmacy goto tr_transferred; 4169181641Skmacy } 4170208504Salc} 4171208504Salc 4172208504Salcstatic usb_error_t 4173208504Salcuaudio_set_speed(struct usb_device *udev, uint8_t endpt, uint32_t speed) 4174208504Salc{ 4175208504Salc struct usb_device_request req; 4176208504Salc uint8_t data[3]; 4177208504Salc 4178208504Salc DPRINTFN(6, "endpt=%d speed=%u\n", endpt, speed); 4179208504Salc 4180208504Salc req.bmRequestType = UT_WRITE_CLASS_ENDPOINT; 4181208504Salc req.bRequest = SET_CUR; 4182208504Salc USETW2(req.wValue, SAMPLING_FREQ_CONTROL, 0); 4183208504Salc USETW(req.wIndex, endpt); 4184208504Salc USETW(req.wLength, 3); 4185208504Salc data[0] = speed; 4186208504Salc data[1] = speed >> 8; 4187181641Skmacy data[2] = speed >> 16; 4188208504Salc 4189181641Skmacy return (usbd_do_request(udev, NULL, &req, data)); 4190181641Skmacy} 4191181641Skmacy 4192181641Skmacystatic usb_error_t 4193181641Skmacyuaudio20_set_speed(struct usb_device *udev, uint8_t iface_no, 4194181641Skmacy uint8_t clockid, uint32_t speed) 4195181641Skmacy{ 4196181641Skmacy struct usb_device_request req; 4197181641Skmacy uint8_t data[4]; 4198181641Skmacy 4199181641Skmacy DPRINTFN(6, "ifaceno=%d clockid=%d speed=%u\n", 4200181641Skmacy iface_no, clockid, speed); 4201181641Skmacy 4202181641Skmacy req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 4203181641Skmacy req.bRequest = UA20_CS_CUR; 4204181641Skmacy USETW2(req.wValue, UA20_CS_SAM_FREQ_CONTROL, 0); 4205181641Skmacy USETW2(req.wIndex, clockid, iface_no); 4206181641Skmacy USETW(req.wLength, 4); 4207181641Skmacy data[0] = speed; 4208181641Skmacy data[1] = speed >> 8; 4209181641Skmacy data[2] = speed >> 16; 4210181641Skmacy data[3] = speed >> 24; 4211181641Skmacy 4212181641Skmacy return (usbd_do_request(udev, NULL, &req, data)); 4213181641Skmacy} 4214181641Skmacy 4215181641Skmacystatic int 4216181641Skmacyuaudio_mixer_signext(uint8_t type, int val) 4217181641Skmacy{ 4218181641Skmacy if (!MIX_UNSIGNED(type)) { 4219181641Skmacy if (MIX_SIZE(type) == 2) { 4220181641Skmacy val = (int16_t)val; 4221181641Skmacy } else { 4222198341Smarcel val = (int8_t)val; 4223198341Smarcel } 4224198341Smarcel } 4225198341Smarcel return (val); 4226198341Smarcel} 4227181747Skmacy 4228181747Skmacystatic int 4229181747Skmacyuaudio_mixer_bsd2value(struct uaudio_mixer_node *mc, int32_t val) 4230181747Skmacy{ 4231181747Skmacy if (mc->type == MIX_ON_OFF) { 4232181747Skmacy val = (val != 0); 4233181747Skmacy } else if (mc->type == MIX_SELECTOR) { 4234181641Skmacy if ((val < mc->minval) || 4235181747Skmacy (val > mc->maxval)) { 4236181641Skmacy val = mc->minval; 4237181747Skmacy } 4238181747Skmacy } else { 4239181747Skmacy 4240181747Skmacy /* compute actual volume */ 4241181747Skmacy val = (val * mc->mul) / 255; 4242181747Skmacy 4243181747Skmacy /* add lower offset */ 4244181747Skmacy val = val + mc->minval; 4245181747Skmacy 4246181747Skmacy /* make sure we don't write a value out of range */ 4247181747Skmacy if (val > mc->maxval) 4248181747Skmacy val = mc->maxval; 4249181641Skmacy else if (val < mc->minval) 4250181641Skmacy val = mc->minval; 4251190627Sdfr } 4252190627Sdfr 4253190627Sdfr DPRINTFN(6, "type=0x%03x val=%d min=%d max=%d val=%d\n", 4254190627Sdfr mc->type, val, mc->minval, mc->maxval, val); 4255190627Sdfr return (val); 4256190627Sdfr} 4257190627Sdfr 4258190627Sdfrstatic void 4259190627Sdfruaudio_mixer_ctl_set(struct uaudio_softc *sc, struct uaudio_mixer_node *mc, 4260190627Sdfr uint8_t chan, int32_t val) 4261190627Sdfr{ 4262190627Sdfr val = uaudio_mixer_bsd2value(mc, val); 4263190627Sdfr 4264190627Sdfr mc->update[chan / 8] |= (1 << (chan % 8)); 4265190627Sdfr mc->wData[chan] = val; 4266190627Sdfr 4267190627Sdfr /* start the transfer, if not already started */ 4268190627Sdfr 4269190627Sdfr usbd_transfer_start(sc->sc_mixer_xfer[0]); 4270190627Sdfr} 4271190627Sdfr 4272190627Sdfrstatic void 4273190627Sdfruaudio_mixer_init(struct uaudio_softc *sc) 4274190627Sdfr{ 4275190627Sdfr struct uaudio_mixer_node *mc; 4276190627Sdfr int32_t i; 4277190627Sdfr 4278190627Sdfr for (mc = sc->sc_mixer_root; mc; 4279190627Sdfr mc = mc->next) { 4280190627Sdfr 4281190627Sdfr if (mc->ctl != SOUND_MIXER_NRDEVICES) { 4282190627Sdfr /* 4283190627Sdfr * Set device mask bits. See 4284190627Sdfr * /usr/include/machine/soundcard.h 4285190627Sdfr */ 4286190627Sdfr sc->sc_mix_info |= (1 << mc->ctl); 4287190627Sdfr } 4288190627Sdfr if ((mc->ctl == SOUND_MIXER_NRDEVICES) && 4289190627Sdfr (mc->type == MIX_SELECTOR)) { 4290190627Sdfr 4291190627Sdfr for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { 4292190627Sdfr if (mc->slctrtype[i - 1] == SOUND_MIXER_NRDEVICES) { 4293190627Sdfr continue; 4294190627Sdfr } 4295190627Sdfr sc->sc_recsrc_info |= 1 << mc->slctrtype[i - 1]; 4296190627Sdfr } 4297190627Sdfr } 4298190627Sdfr } 4299190627Sdfr} 4300190627Sdfr 4301190627Sdfrint 4302190627Sdfruaudio_mixer_init_sub(struct uaudio_softc *sc, struct snd_mixer *m) 4303190627Sdfr{ 4304190627Sdfr DPRINTF("\n"); 4305190627Sdfr 4306190627Sdfr if (usbd_transfer_setup(sc->sc_udev, &sc->sc_mixer_iface_index, 4307190627Sdfr sc->sc_mixer_xfer, uaudio_mixer_config, 1, sc, 4308190627Sdfr mixer_get_lock(m))) { 4309190627Sdfr DPRINTFN(0, "could not allocate USB " 4310190627Sdfr "transfer for audio mixer!\n"); 4311190627Sdfr return (ENOMEM); 4312190627Sdfr } 4313190627Sdfr if (!(sc->sc_mix_info & SOUND_MASK_VOLUME)) { 4314190627Sdfr mix_setparentchild(m, SOUND_MIXER_VOLUME, SOUND_MASK_PCM); 4315190627Sdfr mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE); 4316190627Sdfr } 4317181641Skmacy mix_setdevs(m, sc->sc_mix_info); 4318181641Skmacy mix_setrecdevs(m, sc->sc_recsrc_info); 4319181641Skmacy return (0); 4320181641Skmacy} 4321181641Skmacy 4322181641Skmacyint 4323181641Skmacyuaudio_mixer_uninit_sub(struct uaudio_softc *sc) 4324181641Skmacy{ 4325181641Skmacy DPRINTF("\n"); 4326181641Skmacy 4327181641Skmacy usbd_transfer_unsetup(sc->sc_mixer_xfer, 1); 4328181641Skmacy 4329181641Skmacy return (0); 4330181641Skmacy} 4331181641Skmacy 4332181641Skmacyvoid 4333181641Skmacyuaudio_mixer_set(struct uaudio_softc *sc, unsigned type, 4334181641Skmacy unsigned left, unsigned right) 4335181641Skmacy{ 4336181641Skmacy struct uaudio_mixer_node *mc; 4337181641Skmacy 4338181641Skmacy for (mc = sc->sc_mixer_root; mc; 4339181641Skmacy mc = mc->next) { 4340181641Skmacy 4341181641Skmacy if (mc->ctl == type) { 4342181641Skmacy if (mc->nchan == 2) { 4343181641Skmacy /* set Right */ 4344181641Skmacy uaudio_mixer_ctl_set(sc, mc, 1, (int)(right * 255) / 100); 4345181641Skmacy } 4346181641Skmacy /* set Left or Mono */ 4347181641Skmacy uaudio_mixer_ctl_set(sc, mc, 0, (int)(left * 255) / 100); 4348181641Skmacy } 4349181641Skmacy } 4350181641Skmacy} 4351181641Skmacy 4352181641Skmacyuint32_t 4353181641Skmacyuaudio_mixer_setrecsrc(struct uaudio_softc *sc, uint32_t src) 4354181641Skmacy{ 4355181641Skmacy struct uaudio_mixer_node *mc; 4356181641Skmacy uint32_t mask; 4357181641Skmacy uint32_t temp; 4358181641Skmacy int32_t i; 4359181641Skmacy 4360181641Skmacy for (mc = sc->sc_mixer_root; mc; 4361181641Skmacy mc = mc->next) { 4362181641Skmacy 4363181641Skmacy if ((mc->ctl == SOUND_MIXER_NRDEVICES) && 4364181641Skmacy (mc->type == MIX_SELECTOR)) { 4365181641Skmacy 4366181641Skmacy /* compute selector mask */ 4367181641Skmacy 4368181641Skmacy mask = 0; 4369181641Skmacy for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { 4370181641Skmacy mask |= (1 << mc->slctrtype[i - 1]); 4371181641Skmacy } 4372181641Skmacy 4373181641Skmacy temp = mask & src; 4374181641Skmacy if (temp == 0) { 4375181641Skmacy continue; 4376181641Skmacy } 4377181641Skmacy /* find the first set bit */ 4378181641Skmacy temp = (-temp) & temp; 4379181641Skmacy 4380181641Skmacy /* update "src" */ 4381181641Skmacy src &= ~mask; 4382181641Skmacy src |= temp; 4383181641Skmacy 4384181641Skmacy for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { 4385181641Skmacy if (temp != (1 << mc->slctrtype[i - 1])) { 4386181641Skmacy continue; 4387181641Skmacy } 4388181641Skmacy uaudio_mixer_ctl_set(sc, mc, 0, i); 4389181641Skmacy break; 4390181641Skmacy } 4391181641Skmacy } 4392181641Skmacy } 4393181641Skmacy return (src); 4394181641Skmacy} 4395181641Skmacy 4396181641Skmacy/*========================================================================* 4397181641Skmacy * MIDI support routines 4398181641Skmacy *========================================================================*/ 4399181641Skmacy 4400181641Skmacystatic void 4401181641Skmacyumidi_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 4402181641Skmacy{ 4403181641Skmacy struct umidi_chan *chan = usbd_xfer_softc(xfer); 4404181641Skmacy struct umidi_sub_chan *sub; 4405181641Skmacy struct usb_page_cache *pc; 4406181641Skmacy uint8_t buf[4]; 4407181641Skmacy uint8_t cmd_len; 4408181641Skmacy uint8_t cn; 4409181641Skmacy uint16_t pos; 4410181641Skmacy int actlen; 4411181641Skmacy 4412181641Skmacy usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 4413181641Skmacy 4414181641Skmacy switch (USB_GET_STATE(xfer)) { 4415181641Skmacy case USB_ST_TRANSFERRED: 4416181641Skmacy 4417181641Skmacy DPRINTF("actlen=%d bytes\n", actlen); 4418181641Skmacy 4419181641Skmacy pos = 0; 4420181641Skmacy pc = usbd_xfer_get_frame(xfer, 0); 4421181641Skmacy 4422181641Skmacy while (actlen >= 4) { 4423181641Skmacy 4424181641Skmacy /* copy out the MIDI data */ 4425 usbd_copy_out(pc, pos, buf, 4); 4426 /* command length */ 4427 cmd_len = umidi_cmd_to_len[buf[0] & 0xF]; 4428 /* cable number */ 4429 cn = buf[0] >> 4; 4430 /* 4431 * Lookup sub-channel. The index is range 4432 * checked below. 4433 */ 4434 sub = &chan->sub[cn]; 4435 4436 if ((cmd_len != 0) && 4437 (cn < chan->max_cable) && 4438 (sub->read_open != 0)) { 4439 4440 /* Send data to the application */ 4441 usb_fifo_put_data_linear( 4442 sub->fifo.fp[USB_FIFO_RX], 4443 buf + 1, cmd_len, 1); 4444 } 4445 actlen -= 4; 4446 pos += 4; 4447 } 4448 4449 case USB_ST_SETUP: 4450 DPRINTF("start\n"); 4451tr_setup: 4452 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 4453 usbd_transfer_submit(xfer); 4454 break; 4455 4456 default: 4457 DPRINTF("error=%s\n", usbd_errstr(error)); 4458 4459 if (error != USB_ERR_CANCELLED) { 4460 /* try to clear stall first */ 4461 usbd_xfer_set_stall(xfer); 4462 goto tr_setup; 4463 } 4464 break; 4465 } 4466} 4467 4468/* 4469 * The following statemachine, that converts MIDI commands to 4470 * USB MIDI packets, derives from Linux's usbmidi.c, which 4471 * was written by "Clemens Ladisch": 4472 * 4473 * Returns: 4474 * 0: No command 4475 * Else: Command is complete 4476 */ 4477static uint8_t 4478umidi_convert_to_usb(struct umidi_sub_chan *sub, uint8_t cn, uint8_t b) 4479{ 4480 uint8_t p0 = (cn << 4); 4481 4482 if (b >= 0xf8) { 4483 sub->temp_0[0] = p0 | 0x0f; 4484 sub->temp_0[1] = b; 4485 sub->temp_0[2] = 0; 4486 sub->temp_0[3] = 0; 4487 sub->temp_cmd = sub->temp_0; 4488 return (1); 4489 4490 } else if (b >= 0xf0) { 4491 switch (b) { 4492 case 0xf0: /* system exclusive begin */ 4493 sub->temp_1[1] = b; 4494 sub->state = UMIDI_ST_SYSEX_1; 4495 break; 4496 case 0xf1: /* MIDI time code */ 4497 case 0xf3: /* song select */ 4498 sub->temp_1[1] = b; 4499 sub->state = UMIDI_ST_1PARAM; 4500 break; 4501 case 0xf2: /* song position pointer */ 4502 sub->temp_1[1] = b; 4503 sub->state = UMIDI_ST_2PARAM_1; 4504 break; 4505 case 0xf4: /* unknown */ 4506 case 0xf5: /* unknown */ 4507 sub->state = UMIDI_ST_UNKNOWN; 4508 break; 4509 case 0xf6: /* tune request */ 4510 sub->temp_1[0] = p0 | 0x05; 4511 sub->temp_1[1] = 0xf6; 4512 sub->temp_1[2] = 0; 4513 sub->temp_1[3] = 0; 4514 sub->temp_cmd = sub->temp_1; 4515 sub->state = UMIDI_ST_UNKNOWN; 4516 return (1); 4517 4518 case 0xf7: /* system exclusive end */ 4519 switch (sub->state) { 4520 case UMIDI_ST_SYSEX_0: 4521 sub->temp_1[0] = p0 | 0x05; 4522 sub->temp_1[1] = 0xf7; 4523 sub->temp_1[2] = 0; 4524 sub->temp_1[3] = 0; 4525 sub->temp_cmd = sub->temp_1; 4526 sub->state = UMIDI_ST_UNKNOWN; 4527 return (1); 4528 case UMIDI_ST_SYSEX_1: 4529 sub->temp_1[0] = p0 | 0x06; 4530 sub->temp_1[2] = 0xf7; 4531 sub->temp_1[3] = 0; 4532 sub->temp_cmd = sub->temp_1; 4533 sub->state = UMIDI_ST_UNKNOWN; 4534 return (1); 4535 case UMIDI_ST_SYSEX_2: 4536 sub->temp_1[0] = p0 | 0x07; 4537 sub->temp_1[3] = 0xf7; 4538 sub->temp_cmd = sub->temp_1; 4539 sub->state = UMIDI_ST_UNKNOWN; 4540 return (1); 4541 } 4542 sub->state = UMIDI_ST_UNKNOWN; 4543 break; 4544 } 4545 } else if (b >= 0x80) { 4546 sub->temp_1[1] = b; 4547 if ((b >= 0xc0) && (b <= 0xdf)) { 4548 sub->state = UMIDI_ST_1PARAM; 4549 } else { 4550 sub->state = UMIDI_ST_2PARAM_1; 4551 } 4552 } else { /* b < 0x80 */ 4553 switch (sub->state) { 4554 case UMIDI_ST_1PARAM: 4555 if (sub->temp_1[1] < 0xf0) { 4556 p0 |= sub->temp_1[1] >> 4; 4557 } else { 4558 p0 |= 0x02; 4559 sub->state = UMIDI_ST_UNKNOWN; 4560 } 4561 sub->temp_1[0] = p0; 4562 sub->temp_1[2] = b; 4563 sub->temp_1[3] = 0; 4564 sub->temp_cmd = sub->temp_1; 4565 return (1); 4566 case UMIDI_ST_2PARAM_1: 4567 sub->temp_1[2] = b; 4568 sub->state = UMIDI_ST_2PARAM_2; 4569 break; 4570 case UMIDI_ST_2PARAM_2: 4571 if (sub->temp_1[1] < 0xf0) { 4572 p0 |= sub->temp_1[1] >> 4; 4573 sub->state = UMIDI_ST_2PARAM_1; 4574 } else { 4575 p0 |= 0x03; 4576 sub->state = UMIDI_ST_UNKNOWN; 4577 } 4578 sub->temp_1[0] = p0; 4579 sub->temp_1[3] = b; 4580 sub->temp_cmd = sub->temp_1; 4581 return (1); 4582 case UMIDI_ST_SYSEX_0: 4583 sub->temp_1[1] = b; 4584 sub->state = UMIDI_ST_SYSEX_1; 4585 break; 4586 case UMIDI_ST_SYSEX_1: 4587 sub->temp_1[2] = b; 4588 sub->state = UMIDI_ST_SYSEX_2; 4589 break; 4590 case UMIDI_ST_SYSEX_2: 4591 sub->temp_1[0] = p0 | 0x04; 4592 sub->temp_1[3] = b; 4593 sub->temp_cmd = sub->temp_1; 4594 sub->state = UMIDI_ST_SYSEX_0; 4595 return (1); 4596 default: 4597 break; 4598 } 4599 } 4600 return (0); 4601} 4602 4603static void 4604umidi_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 4605{ 4606 struct umidi_chan *chan = usbd_xfer_softc(xfer); 4607 struct umidi_sub_chan *sub; 4608 struct usb_page_cache *pc; 4609 uint32_t actlen; 4610 uint16_t nframes; 4611 uint8_t buf; 4612 uint8_t start_cable; 4613 uint8_t tr_any; 4614 int len; 4615 4616 usbd_xfer_status(xfer, &len, NULL, NULL, NULL); 4617 4618 /* 4619 * NOTE: Some MIDI devices only accept 4 bytes of data per 4620 * short terminated USB transfer. 4621 */ 4622 switch (USB_GET_STATE(xfer)) { 4623 case USB_ST_TRANSFERRED: 4624 DPRINTF("actlen=%d bytes\n", len); 4625 4626 case USB_ST_SETUP: 4627tr_setup: 4628 DPRINTF("start\n"); 4629 4630 nframes = 0; /* reset */ 4631 start_cable = chan->curr_cable; 4632 tr_any = 0; 4633 pc = usbd_xfer_get_frame(xfer, 0); 4634 4635 while (1) { 4636 4637 /* round robin de-queueing */ 4638 4639 sub = &chan->sub[chan->curr_cable]; 4640 4641 if (sub->write_open) { 4642 usb_fifo_get_data_linear(sub->fifo.fp[USB_FIFO_TX], 4643 &buf, 1, &actlen, 0); 4644 } else { 4645 actlen = 0; 4646 } 4647 4648 if (actlen) { 4649 4650 tr_any = 1; 4651 4652 DPRINTF("byte=0x%02x from FIFO %u\n", buf, 4653 (unsigned int)chan->curr_cable); 4654 4655 if (umidi_convert_to_usb(sub, chan->curr_cable, buf)) { 4656 4657 DPRINTF("sub=0x%02x 0x%02x 0x%02x 0x%02x\n", 4658 sub->temp_cmd[0], sub->temp_cmd[1], 4659 sub->temp_cmd[2], sub->temp_cmd[3]); 4660 4661 usbd_copy_in(pc, nframes * 4, sub->temp_cmd, 4); 4662 4663 nframes++; 4664 4665 if ((nframes >= UMIDI_TX_FRAMES) || (chan->single_command != 0)) 4666 break; 4667 } else { 4668 continue; 4669 } 4670 } 4671 4672 chan->curr_cable++; 4673 if (chan->curr_cable >= chan->max_cable) 4674 chan->curr_cable = 0; 4675 4676 if (chan->curr_cable == start_cable) { 4677 if (tr_any == 0) 4678 break; 4679 tr_any = 0; 4680 } 4681 } 4682 4683 if (nframes != 0) { 4684 DPRINTF("Transferring %d frames\n", (int)nframes); 4685 usbd_xfer_set_frame_len(xfer, 0, 4 * nframes); 4686 usbd_transfer_submit(xfer); 4687 } 4688 break; 4689 4690 default: /* Error */ 4691 4692 DPRINTF("error=%s\n", usbd_errstr(error)); 4693 4694 if (error != USB_ERR_CANCELLED) { 4695 /* try to clear stall first */ 4696 usbd_xfer_set_stall(xfer); 4697 goto tr_setup; 4698 } 4699 break; 4700 } 4701} 4702 4703static struct umidi_sub_chan * 4704umidi_sub_by_fifo(struct usb_fifo *fifo) 4705{ 4706 struct umidi_chan *chan = usb_fifo_softc(fifo); 4707 struct umidi_sub_chan *sub; 4708 uint32_t n; 4709 4710 for (n = 0; n < UMIDI_CABLES_MAX; n++) { 4711 sub = &chan->sub[n]; 4712 if ((sub->fifo.fp[USB_FIFO_RX] == fifo) || 4713 (sub->fifo.fp[USB_FIFO_TX] == fifo)) { 4714 return (sub); 4715 } 4716 } 4717 4718 panic("%s:%d cannot find usb_fifo!\n", 4719 __FILE__, __LINE__); 4720 4721 return (NULL); 4722} 4723 4724static void 4725umidi_start_read(struct usb_fifo *fifo) 4726{ 4727 struct umidi_chan *chan = usb_fifo_softc(fifo); 4728 4729 usbd_transfer_start(chan->xfer[UMIDI_RX_TRANSFER]); 4730} 4731 4732static void 4733umidi_stop_read(struct usb_fifo *fifo) 4734{ 4735 struct umidi_chan *chan = usb_fifo_softc(fifo); 4736 struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo); 4737 4738 DPRINTF("\n"); 4739 4740 sub->read_open = 0; 4741 4742 if (--(chan->read_open_refcount) == 0) { 4743 /* 4744 * XXX don't stop the read transfer here, hence that causes 4745 * problems with some MIDI adapters 4746 */ 4747 DPRINTF("(stopping read transfer)\n"); 4748 } 4749} 4750 4751static void 4752umidi_start_write(struct usb_fifo *fifo) 4753{ 4754 struct umidi_chan *chan = usb_fifo_softc(fifo); 4755 4756 usbd_transfer_start(chan->xfer[UMIDI_TX_TRANSFER]); 4757} 4758 4759static void 4760umidi_stop_write(struct usb_fifo *fifo) 4761{ 4762 struct umidi_chan *chan = usb_fifo_softc(fifo); 4763 struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo); 4764 4765 DPRINTF("\n"); 4766 4767 sub->write_open = 0; 4768 4769 if (--(chan->write_open_refcount) == 0) { 4770 DPRINTF("(stopping write transfer)\n"); 4771 usbd_transfer_stop(chan->xfer[UMIDI_TX_TRANSFER]); 4772 } 4773} 4774 4775static int 4776umidi_open(struct usb_fifo *fifo, int fflags) 4777{ 4778 struct umidi_chan *chan = usb_fifo_softc(fifo); 4779 struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo); 4780 4781 if (fflags & FREAD) { 4782 if (usb_fifo_alloc_buffer(fifo, 4, (1024 / 4))) { 4783 return (ENOMEM); 4784 } 4785 mtx_lock(&chan->mtx); 4786 chan->read_open_refcount++; 4787 sub->read_open = 1; 4788 mtx_unlock(&chan->mtx); 4789 } 4790 if (fflags & FWRITE) { 4791 if (usb_fifo_alloc_buffer(fifo, 32, (1024 / 32))) { 4792 return (ENOMEM); 4793 } 4794 /* clear stall first */ 4795 mtx_lock(&chan->mtx); 4796 usbd_xfer_set_stall(chan->xfer[UMIDI_TX_TRANSFER]); 4797 chan->write_open_refcount++; 4798 sub->write_open = 1; 4799 4800 /* reset */ 4801 sub->state = UMIDI_ST_UNKNOWN; 4802 mtx_unlock(&chan->mtx); 4803 } 4804 return (0); /* success */ 4805} 4806 4807static void 4808umidi_close(struct usb_fifo *fifo, int fflags) 4809{ 4810 if (fflags & FREAD) { 4811 usb_fifo_free_buffer(fifo); 4812 } 4813 if (fflags & FWRITE) { 4814 usb_fifo_free_buffer(fifo); 4815 } 4816} 4817 4818 4819static int 4820umidi_ioctl(struct usb_fifo *fifo, u_long cmd, void *data, 4821 int fflags) 4822{ 4823 return (ENODEV); 4824} 4825 4826static void 4827umidi_init(device_t dev) 4828{ 4829 struct uaudio_softc *sc = device_get_softc(dev); 4830 struct umidi_chan *chan = &sc->sc_midi_chan; 4831 4832 mtx_init(&chan->mtx, "umidi lock", NULL, MTX_DEF | MTX_RECURSE); 4833} 4834 4835static struct usb_fifo_methods umidi_fifo_methods = { 4836 .f_start_read = &umidi_start_read, 4837 .f_start_write = &umidi_start_write, 4838 .f_stop_read = &umidi_stop_read, 4839 .f_stop_write = &umidi_stop_write, 4840 .f_open = &umidi_open, 4841 .f_close = &umidi_close, 4842 .f_ioctl = &umidi_ioctl, 4843 .basename[0] = "umidi", 4844}; 4845 4846static int 4847umidi_probe(device_t dev) 4848{ 4849 struct uaudio_softc *sc = device_get_softc(dev); 4850 struct usb_attach_arg *uaa = device_get_ivars(dev); 4851 struct umidi_chan *chan = &sc->sc_midi_chan; 4852 struct umidi_sub_chan *sub; 4853 int unit = device_get_unit(dev); 4854 int error; 4855 uint32_t n; 4856 4857 if (usb_test_quirk(uaa, UQ_SINGLE_CMD_MIDI)) 4858 chan->single_command = 1; 4859 4860 if (usbd_set_alt_interface_index(sc->sc_udev, chan->iface_index, 4861 chan->iface_alt_index)) { 4862 DPRINTF("setting of alternate index failed!\n"); 4863 goto detach; 4864 } 4865 usbd_set_parent_iface(sc->sc_udev, chan->iface_index, 4866 sc->sc_mixer_iface_index); 4867 4868 error = usbd_transfer_setup(uaa->device, &chan->iface_index, 4869 chan->xfer, umidi_config, UMIDI_N_TRANSFER, 4870 chan, &chan->mtx); 4871 if (error) { 4872 DPRINTF("error=%s\n", usbd_errstr(error)); 4873 goto detach; 4874 } 4875 if ((chan->max_cable > UMIDI_CABLES_MAX) || 4876 (chan->max_cable == 0)) { 4877 chan->max_cable = UMIDI_CABLES_MAX; 4878 } 4879 4880 for (n = 0; n < chan->max_cable; n++) { 4881 4882 sub = &chan->sub[n]; 4883 4884 error = usb_fifo_attach(sc->sc_udev, chan, &chan->mtx, 4885 &umidi_fifo_methods, &sub->fifo, unit, n, 4886 chan->iface_index, 4887 UID_ROOT, GID_OPERATOR, 0644); 4888 if (error) { 4889 goto detach; 4890 } 4891 } 4892 4893 mtx_lock(&chan->mtx); 4894 4895 /* clear stall first */ 4896 usbd_xfer_set_stall(chan->xfer[UMIDI_RX_TRANSFER]); 4897 4898 /* 4899 * NOTE: At least one device will not work properly unless the 4900 * BULK IN pipe is open all the time. This might have to do 4901 * about that the internal queues of the device overflow if we 4902 * don't read them regularly. 4903 */ 4904 usbd_transfer_start(chan->xfer[UMIDI_RX_TRANSFER]); 4905 4906 mtx_unlock(&chan->mtx); 4907 4908 return (0); /* success */ 4909 4910detach: 4911 return (ENXIO); /* failure */ 4912} 4913 4914static int 4915umidi_detach(device_t dev) 4916{ 4917 struct uaudio_softc *sc = device_get_softc(dev); 4918 struct umidi_chan *chan = &sc->sc_midi_chan; 4919 uint32_t n; 4920 4921 for (n = 0; n < UMIDI_CABLES_MAX; n++) { 4922 usb_fifo_detach(&chan->sub[n].fifo); 4923 } 4924 4925 mtx_lock(&chan->mtx); 4926 4927 usbd_transfer_stop(chan->xfer[UMIDI_RX_TRANSFER]); 4928 4929 mtx_unlock(&chan->mtx); 4930 4931 usbd_transfer_unsetup(chan->xfer, UMIDI_N_TRANSFER); 4932 4933 mtx_destroy(&chan->mtx); 4934 4935 return (0); 4936} 4937 4938DRIVER_MODULE(uaudio, uhub, uaudio_driver, uaudio_devclass, NULL, 0); 4939MODULE_DEPEND(uaudio, usb, 1, 1, 1); 4940MODULE_DEPEND(uaudio, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 4941MODULE_VERSION(uaudio, 1); 4942