uaudio.c revision 192505
1221828Sgrehan/* $NetBSD: uaudio.c,v 1.91 2004/11/05 17:46:14 kent Exp $ */ 2221828Sgrehan/* $FreeBSD: head/sys/dev/sound/usb/uaudio.c 192505 2009-05-21 02:09:12Z thompsa $ */ 3221828Sgrehan 4221828Sgrehan/*- 5221828Sgrehan * Copyright (c) 1999 The NetBSD Foundation, Inc. 6221828Sgrehan * All rights reserved. 7221828Sgrehan * 8221828Sgrehan * This code is derived from software contributed to The NetBSD Foundation 9221828Sgrehan * by Lennart Augustsson (lennart@augustsson.net) at 10221828Sgrehan * Carlstedt Research & Technology. 11221828Sgrehan * 12221828Sgrehan * Redistribution and use in source and binary forms, with or without 13221828Sgrehan * modification, are permitted provided that the following conditions 14221828Sgrehan * are met: 15221828Sgrehan * 1. Redistributions of source code must retain the above copyright 16221828Sgrehan * notice, this list of conditions and the following disclaimer. 17221828Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 18221828Sgrehan * notice, this list of conditions and the following disclaimer in the 19221828Sgrehan * documentation and/or other materials provided with the distribution. 20221828Sgrehan * 21221828Sgrehan * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22221828Sgrehan * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23221828Sgrehan * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24221828Sgrehan * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25221828Sgrehan * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26221828Sgrehan * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27221828Sgrehan * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28221828Sgrehan * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29221828Sgrehan * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30221828Sgrehan * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31221828Sgrehan * POSSIBILITY OF SUCH DAMAGE. 32221828Sgrehan */ 33234695Sgrehan 34221828Sgrehan/* 35221828Sgrehan * USB audio specs: http://www.usb.org/developers/devclass_docs/audio10.pdf 36221828Sgrehan * http://www.usb.org/developers/devclass_docs/frmts10.pdf 37221828Sgrehan * http://www.usb.org/developers/devclass_docs/termt10.pdf 38221828Sgrehan */ 39221828Sgrehan 40221828Sgrehan/* 41221828Sgrehan * Also merged: 42256072Sneel * $NetBSD: uaudio.c,v 1.94 2005/01/15 15:19:53 kent Exp $ 43221828Sgrehan * $NetBSD: uaudio.c,v 1.95 2005/01/16 06:02:19 dsainty Exp $ 44221828Sgrehan * $NetBSD: uaudio.c,v 1.96 2005/01/16 12:46:00 kent Exp $ 45221828Sgrehan * $NetBSD: uaudio.c,v 1.97 2005/02/24 08:19:38 martin Exp $ 46221828Sgrehan */ 47221828Sgrehan 48256072Sneel#include "usbdevs.h" 49256072Sneel#include <dev/usb/usb.h> 50256072Sneel#include <dev/usb/usb_mfunc.h> 51256072Sneel#include <dev/usb/usb_error.h> 52256072Sneel 53256072Sneel#define USB_DEBUG_VAR uaudio_debug 54221828Sgrehan 55261275Sjhb#include <dev/usb/usb_core.h> 56221828Sgrehan#include <dev/usb/usb_lookup.h> 57221828Sgrehan#include <dev/usb/usb_debug.h> 58241489Sneel#include <dev/usb/usb_util.h> 59262350Sjhb#include <dev/usb/usb_busdma.h> 60221914Sjhb#include <dev/usb/usb_parse.h> 61256072Sneel#include <dev/usb/usb_request.h> 62221828Sgrehan#include <dev/usb/usb_mbuf.h> 63221828Sgrehan#include <dev/usb/usb_dev.h> 64261088Sjhb#include <dev/usb/usb_dynamic.h> 65268976Sjhb 66261088Sjhb#include <dev/usb/quirk/usb_quirk.h> 67268976Sjhb 68256072Sneel#include <sys/reboot.h> /* for bootverbose */ 69242275Sneel 70221828Sgrehan#include <dev/sound/pcm/sound.h> 71221828Sgrehan#include <dev/sound/usb/uaudioreg.h> 72268891Sjhb#include <dev/sound/usb/uaudio.h> 73268891Sjhb#include <dev/sound/chip.h> 74261088Sjhb#include "feeder_if.h" 75261088Sjhb 76221828Sgrehanstatic int uaudio_default_rate = 96000; 77276429Sneelstatic int uaudio_default_bits = 32; 78284894Sneelstatic int uaudio_default_channels = 2; 79221828Sgrehan 80221828Sgrehan#if USB_DEBUG 81242065Sneelstatic int uaudio_debug = 0; 82221828Sgrehan 83221828SgrehanSYSCTL_NODE(_hw_usb, OID_AUTO, uaudio, CTLFLAG_RW, 0, "USB uaudio"); 84221828SgrehanSYSCTL_INT(_hw_usb_uaudio, OID_AUTO, debug, CTLFLAG_RW, 85221828Sgrehan &uaudio_debug, 0, "uaudio debug level"); 86221828SgrehanSYSCTL_INT(_hw_usb_uaudio, OID_AUTO, default_rate, CTLFLAG_RW, 87221828Sgrehan &uaudio_default_rate, 0, "uaudio default sample rate"); 88270071SgrehanSYSCTL_INT(_hw_usb_uaudio, OID_AUTO, default_bits, CTLFLAG_RW, 89270071Sgrehan &uaudio_default_bits, 0, "uaudio default sample bits"); 90270071SgrehanSYSCTL_INT(_hw_usb_uaudio, OID_AUTO, default_channels, CTLFLAG_RW, 91270071Sgrehan &uaudio_default_channels, 0, "uaudio default sample channels"); 92270071Sgrehan#endif 93270071Sgrehan 94270071Sgrehan#define UAUDIO_MINFRAMES 16 /* must be factor of 8 due HS-USB */ 95221828Sgrehan#define UAUDIO_NCHANBUFS 2 /* number of outstanding request */ 96270071Sgrehan#define UAUDIO_RECURSE_LIMIT 24 /* rounds */ 97270071Sgrehan 98270071Sgrehan#define MAKE_WORD(h,l) (((h) << 8) | (l)) 99284900Sneel#define BIT_TEST(bm,bno) (((bm)[(bno) / 8] >> (7 - ((bno) % 8))) & 1) 100270071Sgrehan 101270071Sgrehanstruct uaudio_mixer_node { 102270159Sgrehan int32_t minval; 103270071Sgrehan int32_t maxval; 104270071Sgrehan#define MIX_MAX_CHAN 8 105270071Sgrehan int32_t wValue[MIX_MAX_CHAN]; /* using nchan */ 106284894Sneel uint32_t delta; 107284894Sneel uint32_t mul; 108284894Sneel uint32_t ctl; 109270071Sgrehan 110270071Sgrehan uint16_t wData[MIX_MAX_CHAN]; /* using nchan */ 111270071Sgrehan uint16_t wIndex; 112270071Sgrehan 113284894Sneel uint8_t update[(MIX_MAX_CHAN + 7) / 8]; 114221828Sgrehan uint8_t nchan; 115221828Sgrehan uint8_t type; 116270071Sgrehan#define MIX_ON_OFF 1 117242065Sneel#define MIX_SIGNED_16 2 118242065Sneel#define MIX_UNSIGNED_16 3 119242065Sneel#define MIX_SIGNED_8 4 120256072Sneel#define MIX_SELECTOR 5 121241489Sneel#define MIX_UNKNOWN 6 122256072Sneel#define MIX_SIZE(n) ((((n) == MIX_SIGNED_16) || \ 123295124Sgrehan ((n) == MIX_UNSIGNED_16)) ? 2 : 1) 124295124Sgrehan#define MIX_UNSIGNED(n) ((n) == MIX_UNSIGNED_16) 125295124Sgrehan 126295124Sgrehan#define MAX_SELECTOR_INPUT_PIN 256 127295124Sgrehan uint8_t slctrtype[MAX_SELECTOR_INPUT_PIN]; 128295124Sgrehan uint8_t class; 129295124Sgrehan 130256072Sneel struct uaudio_mixer_node *next; 131256072Sneel}; 132295124Sgrehan 133295124Sgrehanstruct uaudio_chan { 134295124Sgrehan struct pcmchan_caps pcm_cap; /* capabilities */ 135295124Sgrehan 136256072Sneel struct snd_dbuf *pcm_buf; 137295124Sgrehan const struct usb2_config *usb2_cfg; 138221828Sgrehan struct mtx *pcm_mtx; /* lock protecting this structure */ 139270071Sgrehan struct uaudio_softc *priv_sc; 140270071Sgrehan struct pcm_channel *pcm_ch; 141270071Sgrehan struct usb2_xfer *xfer[UAUDIO_NCHANBUFS]; 142270071Sgrehan const struct usb2_audio_streaming_interface_descriptor *p_asid; 143270071Sgrehan const struct usb2_audio_streaming_type1_descriptor *p_asf1d; 144270071Sgrehan const struct usb2_audio_streaming_endpoint_descriptor *p_sed; 145221828Sgrehan const usb2_endpoint_descriptor_audio_t *p_ed1; 146270071Sgrehan const usb2_endpoint_descriptor_audio_t *p_ed2; 147270071Sgrehan const struct uaudio_format *p_fmt; 148270071Sgrehan 149270071Sgrehan uint8_t *buf; /* pointer to buffer */ 150270071Sgrehan uint8_t *start; /* upper layer buffer start */ 151270071Sgrehan uint8_t *end; /* upper layer buffer end */ 152276429Sneel uint8_t *cur; /* current position in upper layer 153284894Sneel * buffer */ 154270071Sgrehan 155270071Sgrehan uint32_t intr_size; /* in bytes */ 156270071Sgrehan uint32_t block_size; 157270071Sgrehan uint32_t sample_rate; 158270071Sgrehan uint32_t format; 159270071Sgrehan uint32_t pcm_format[2]; 160270071Sgrehan 161270071Sgrehan uint16_t bytes_per_frame; 162270071Sgrehan 163295124Sgrehan uint8_t valid; 164295124Sgrehan uint8_t iface_index; 165270071Sgrehan uint8_t iface_alt_index; 166270071Sgrehan}; 167270071Sgrehan 168221828Sgrehan#define UMIDI_N_TRANSFER 4 /* units */ 169221828Sgrehan#define UMIDI_CABLES_MAX 16 /* units */ 170249396Sneel#define UMIDI_BULK_SIZE 1024 /* bytes */ 171249396Sneel 172221828Sgrehanstruct umidi_sub_chan { 173266339Sjhb struct usb2_fifo_sc fifo; 174221828Sgrehan uint8_t *temp_cmd; 175261275Sjhb uint8_t temp_0[4]; 176221828Sgrehan uint8_t temp_1[4]; 177256072Sneel uint8_t state; 178284900Sneel#define UMIDI_ST_UNKNOWN 0 /* scan for command */ 179284900Sneel#define UMIDI_ST_1PARAM 1 180221828Sgrehan#define UMIDI_ST_2PARAM_1 2 181256072Sneel#define UMIDI_ST_2PARAM_2 3 182256072Sneel#define UMIDI_ST_SYSEX_0 4 183256072Sneel#define UMIDI_ST_SYSEX_1 5 184256072Sneel#define UMIDI_ST_SYSEX_2 6 185221828Sgrehan 186221828Sgrehan uint8_t read_open:1; 187221828Sgrehan uint8_t write_open:1; 188221828Sgrehan uint8_t unused:6; 189221828Sgrehan}; 190221828Sgrehan 191221828Sgrehanstruct umidi_chan { 192221828Sgrehan 193221828Sgrehan struct umidi_sub_chan sub[UMIDI_CABLES_MAX]; 194221828Sgrehan struct mtx mtx; 195221828Sgrehan 196221828Sgrehan struct usb2_xfer *xfer[UMIDI_N_TRANSFER]; 197266339Sjhb 198266339Sjhb uint8_t iface_index; 199266339Sjhb uint8_t iface_alt_index; 200266339Sjhb 201221828Sgrehan uint8_t flags; 202245021Sneel#define UMIDI_FLAG_READ_STALL 0x01 203245021Sneel#define UMIDI_FLAG_WRITE_STALL 0x02 204221828Sgrehan 205221828Sgrehan uint8_t read_open_refcount; 206221828Sgrehan uint8_t write_open_refcount; 207221828Sgrehan 208248389Sneel uint8_t curr_cable; 209221828Sgrehan uint8_t max_cable; 210266339Sjhb uint8_t valid; 211266339Sjhb}; 212268935Sjhb 213268935Sjhbstruct uaudio_softc { 214268935Sjhb struct sbuf sc_sndstat; 215268935Sjhb struct sndcard_func sc_sndcard_func; 216268935Sjhb struct uaudio_chan sc_rec_chan; 217268935Sjhb struct uaudio_chan sc_play_chan; 218268935Sjhb struct umidi_chan sc_midi_chan; 219268935Sjhb 220268935Sjhb struct usb2_device *sc_udev; 221268935Sjhb struct usb2_xfer *sc_mixer_xfer[1]; 222266339Sjhb struct uaudio_mixer_node *sc_mixer_root; 223266339Sjhb struct uaudio_mixer_node *sc_mixer_curr; 224266339Sjhb 225266339Sjhb uint32_t sc_mix_info; 226276403Sneel uint32_t sc_recsrc_info; 227276403Sneel 228276403Sneel uint16_t sc_audio_rev; 229276403Sneel uint16_t sc_mixer_count; 230276403Sneel 231284899Sneel uint8_t sc_sndstat_valid; 232284899Sneel uint8_t sc_mixer_iface_index; 233284899Sneel uint8_t sc_mixer_iface_no; 234284899Sneel uint8_t sc_mixer_chan; 235284899Sneel uint8_t sc_pcm_registered:1; 236295124Sgrehan uint8_t sc_mixer_init:1; 237295124Sgrehan uint8_t sc_uq_audio_swap_lr:1; 238284900Sneel uint8_t sc_uq_au_inp_async:1; 239284900Sneel uint8_t sc_uq_au_no_xu:1; 240284900Sneel uint8_t sc_uq_bad_adc:1; 241284900Sneel}; 242284900Sneel 243284900Sneelstruct uaudio_search_result { 244284900Sneel uint8_t bit_input[(256 + 7) / 8]; 245284900Sneel uint8_t bit_output[(256 + 7) / 8]; 246284900Sneel uint8_t bit_visited[(256 + 7) / 8]; 247284900Sneel uint8_t recurse_level; 248284900Sneel uint8_t id_max; 249284900Sneel}; 250284900Sneel 251284900Sneelstruct uaudio_terminal_node { 252284900Sneel union { 253284900Sneel const struct usb2_descriptor *desc; 254284900Sneel const struct usb2_audio_input_terminal *it; 255284900Sneel const struct usb2_audio_output_terminal *ot; 256284900Sneel const struct usb2_audio_mixer_unit_0 *mu; 257284900Sneel const struct usb2_audio_selector_unit *su; 258284900Sneel const struct usb2_audio_feature_unit *fu; 259284900Sneel const struct usb2_audio_processing_unit_0 *pu; 260221828Sgrehan const struct usb2_audio_extension_unit_0 *eu; 261270071Sgrehan } u; 262221828Sgrehan struct uaudio_search_result usr; 263266339Sjhb struct uaudio_terminal_node *root; 264266339Sjhb}; 265266339Sjhb 266270071Sgrehanstruct uaudio_format { 267270071Sgrehan uint16_t wFormat; 268270071Sgrehan uint8_t bPrecision; 269270071Sgrehan uint32_t freebsd_fmt; 270221828Sgrehan const char *description; 271221828Sgrehan}; 272221828Sgrehan 273270071Sgrehanstatic const struct uaudio_format uaudio_formats[] = { 274221828Sgrehan 275221828Sgrehan {UA_FMT_PCM8, 8, AFMT_U8, "8-bit U-LE PCM"}, 276270071Sgrehan {UA_FMT_PCM8, 16, AFMT_U16_LE, "16-bit U-LE PCM"}, 277270071Sgrehan {UA_FMT_PCM8, 24, AFMT_U24_LE, "24-bit U-LE PCM"}, 278270071Sgrehan {UA_FMT_PCM8, 32, AFMT_U32_LE, "32-bit U-LE PCM"}, 279270071Sgrehan 280221828Sgrehan {UA_FMT_PCM, 8, AFMT_S8, "8-bit S-LE PCM"}, 281221828Sgrehan {UA_FMT_PCM, 16, AFMT_S16_LE, "16-bit S-LE PCM"}, 282270071Sgrehan {UA_FMT_PCM, 24, AFMT_S24_LE, "24-bit S-LE PCM"}, 283270071Sgrehan {UA_FMT_PCM, 32, AFMT_S32_LE, "32-bit S-LE PCM"}, 284270071Sgrehan 285270071Sgrehan {UA_FMT_ALAW, 8, AFMT_A_LAW, "8-bit A-Law"}, 286270071Sgrehan {UA_FMT_MULAW, 8, AFMT_MU_LAW, "8-bit mu-Law"}, 287270071Sgrehan 288270071Sgrehan {0, 0, 0, NULL} 289270071Sgrehan}; 290270071Sgrehan 291270071Sgrehan#define UAC_OUTPUT 0 292266339Sjhb#define UAC_INPUT 1 293267447Sjhb#define UAC_EQUAL 2 294284900Sneel#define UAC_RECORD 3 295270159Sgrehan#define UAC_NCLASSES 4 296270071Sgrehan 297270071Sgrehan#if USB_DEBUG 298270071Sgrehanstatic const char *uac_names[] = { 299267427Sjhb "outputs", "inputs", "equalization", "record" 300234695Sgrehan}; 301270071Sgrehan 302221828Sgrehan#endif 303221828Sgrehan 304276403Sneel/* prototypes */ 305276403Sneel 306276403Sneelstatic device_probe_t uaudio_probe; 307276403Sneelstatic device_attach_t uaudio_attach; 308276403Sneelstatic device_detach_t uaudio_detach; 309276403Sneel 310276403Sneelstatic usb2_callback_t uaudio_chan_play_callback; 311240894Sneelstatic usb2_callback_t uaudio_chan_record_callback; 312240894Sneelstatic usb2_callback_t uaudio_mixer_write_cfg_callback; 313240894Sneelstatic usb2_callback_t umidi_read_clear_stall_callback; 314240894Sneelstatic usb2_callback_t umidi_bulk_read_callback; 315240894Sneelstatic usb2_callback_t umidi_write_clear_stall_callback; 316240894Sneelstatic usb2_callback_t umidi_bulk_write_callback; 317240894Sneel 318240894Sneelstatic void uaudio_chan_fill_info_sub(struct uaudio_softc *, 319240894Sneel struct usb2_device *, uint32_t, uint16_t, uint8_t, uint8_t); 320240894Sneelstatic void uaudio_chan_fill_info(struct uaudio_softc *, 321240894Sneel struct usb2_device *); 322240894Sneelstatic void uaudio_mixer_add_ctl_sub(struct uaudio_softc *, 323240894Sneel struct uaudio_mixer_node *); 324261275Sjhbstatic void uaudio_mixer_add_ctl(struct uaudio_softc *, 325261275Sjhb struct uaudio_mixer_node *); 326261275Sjhbstatic void uaudio_mixer_add_input(struct uaudio_softc *, 327261275Sjhb const struct uaudio_terminal_node *, int); 328261275Sjhbstatic void uaudio_mixer_add_output(struct uaudio_softc *, 329261275Sjhb const struct uaudio_terminal_node *, int); 330221828Sgrehanstatic void uaudio_mixer_add_mixer(struct uaudio_softc *, 331221828Sgrehan const struct uaudio_terminal_node *, int); 332221828Sgrehanstatic void uaudio_mixer_add_selector(struct uaudio_softc *, 333221828Sgrehan const struct uaudio_terminal_node *, int); 334221828Sgrehanstatic uint32_t uaudio_mixer_feature_get_bmaControls( 335242275Sneel const struct usb2_audio_feature_unit *, uint8_t); 336221828Sgrehanstatic void uaudio_mixer_add_feature(struct uaudio_softc *, 337266339Sjhb const struct uaudio_terminal_node *, int); 338266339Sjhbstatic void uaudio_mixer_add_processing_updown(struct uaudio_softc *, 339266339Sjhb const struct uaudio_terminal_node *, int); 340266339Sjhbstatic void uaudio_mixer_add_processing(struct uaudio_softc *, 341221828Sgrehan const struct uaudio_terminal_node *, int); 342221828Sgrehanstatic void uaudio_mixer_add_extension(struct uaudio_softc *, 343221828Sgrehan const struct uaudio_terminal_node *, int); 344221828Sgrehanstatic struct usb2_audio_cluster uaudio_mixer_get_cluster(uint8_t, 345221828Sgrehan const struct uaudio_terminal_node *); 346221828Sgrehanstatic uint16_t uaudio_mixer_determine_class(const struct uaudio_terminal_node *, 347221828Sgrehan struct uaudio_mixer_node *); 348221828Sgrehanstatic uint16_t uaudio_mixer_feature_name(const struct uaudio_terminal_node *, 349221828Sgrehan struct uaudio_mixer_node *); 350221828Sgrehanstatic const struct uaudio_terminal_node *uaudio_mixer_get_input( 351221828Sgrehan const struct uaudio_terminal_node *, uint8_t); 352261275Sjhbstatic const struct uaudio_terminal_node *uaudio_mixer_get_output( 353221828Sgrehan const struct uaudio_terminal_node *, uint8_t); 354266339Sjhbstatic void uaudio_mixer_find_inputs_sub(struct uaudio_terminal_node *, 355221828Sgrehan const uint8_t *, uint8_t, struct uaudio_search_result *); 356221828Sgrehanstatic void uaudio_mixer_find_outputs_sub(struct uaudio_terminal_node *, 357221828Sgrehan uint8_t, uint8_t, struct uaudio_search_result *); 358221828Sgrehanstatic void uaudio_mixer_fill_info(struct uaudio_softc *, 359221828Sgrehan struct usb2_device *, void *); 360221828Sgrehanstatic uint16_t uaudio_mixer_get(struct usb2_device *, uint8_t, 361221828Sgrehan struct uaudio_mixer_node *); 362221828Sgrehanstatic void uaudio_mixer_ctl_set(struct uaudio_softc *, 363221828Sgrehan struct uaudio_mixer_node *, uint8_t, int32_t val); 364221828Sgrehanstatic usb2_error_t uaudio_set_speed(struct usb2_device *, uint8_t, uint32_t); 365284899Sneelstatic int uaudio_mixer_signext(uint8_t, int); 366267070Sjhbstatic int uaudio_mixer_bsd2value(struct uaudio_mixer_node *, int32_t val); 367221828Sgrehanstatic const void *uaudio_mixer_verify_desc(const void *, uint32_t); 368249396Sneelstatic void uaudio_mixer_init(struct uaudio_softc *); 369249396Sneelstatic uint8_t umidi_convert_to_usb(struct umidi_sub_chan *, uint8_t, uint8_t); 370221828Sgrehanstatic struct umidi_sub_chan *umidi_sub_by_fifo(struct usb2_fifo *); 371221828Sgrehanstatic void umidi_start_read(struct usb2_fifo *); 372241454Sneelstatic void umidi_stop_read(struct usb2_fifo *); 373241454Sneelstatic void umidi_start_write(struct usb2_fifo *); 374261275Sjhbstatic void umidi_stop_write(struct usb2_fifo *); 375241454Sneelstatic int umidi_open(struct usb2_fifo *, int); 376266339Sjhbstatic int umidi_ioctl(struct usb2_fifo *, u_long cmd, void *, int); 377266339Sjhbstatic void umidi_close(struct usb2_fifo *, int); 378241454Sneelstatic void umidi_init(device_t dev); 379253854Sgrehanstatic int32_t umidi_probe(device_t dev); 380253854Sgrehanstatic int32_t umidi_detach(device_t dev); 381253854Sgrehan 382253854Sgrehan#if USB_DEBUG 383253854Sgrehanstatic void uaudio_chan_dump_ep_desc( 384253854Sgrehan const usb2_endpoint_descriptor_audio_t *); 385241454Sneelstatic void uaudio_mixer_dump_cluster(uint8_t, 386221828Sgrehan const struct uaudio_terminal_node *); 387221828Sgrehanstatic const char *uaudio_mixer_get_terminal_name(uint16_t); 388221828Sgrehan#endif 389221828Sgrehan 390221828Sgrehanstatic const struct usb2_config 391221828Sgrehan uaudio_cfg_record[UAUDIO_NCHANBUFS] = { 392221828Sgrehan [0] = { 393221828Sgrehan .type = UE_ISOCHRONOUS, 394221828Sgrehan .endpoint = UE_ADDR_ANY, 395221828Sgrehan .direction = UE_DIR_IN, 396221828Sgrehan .bufsize = 0, /* use "wMaxPacketSize * frames" */ 397221828Sgrehan .frames = UAUDIO_MINFRAMES, 398221828Sgrehan .flags = {.short_xfer_ok = 1,}, 399221828Sgrehan .callback = &uaudio_chan_record_callback, 400221828Sgrehan }, 401245704Sneel 402245704Sneel [1] = { 403245704Sneel .type = UE_ISOCHRONOUS, 404245704Sneel .endpoint = UE_ADDR_ANY, 405245704Sneel .direction = UE_DIR_IN, 406245704Sneel .bufsize = 0, /* use "wMaxPacketSize * frames" */ 407245704Sneel .frames = UAUDIO_MINFRAMES, 408221828Sgrehan .flags = {.short_xfer_ok = 1,}, 409245704Sneel .callback = &uaudio_chan_record_callback, 410221828Sgrehan }, 411221828Sgrehan}; 412270071Sgrehan 413270071Sgrehanstatic const struct usb2_config 414270071Sgrehan uaudio_cfg_play[UAUDIO_NCHANBUFS] = { 415270071Sgrehan [0] = { 416270071Sgrehan .type = UE_ISOCHRONOUS, 417270071Sgrehan .endpoint = UE_ADDR_ANY, 418270071Sgrehan .direction = UE_DIR_OUT, 419270071Sgrehan .bufsize = 0, /* use "wMaxPacketSize * frames" */ 420270071Sgrehan .frames = UAUDIO_MINFRAMES, 421270071Sgrehan .flags = {.short_xfer_ok = 1,}, 422270071Sgrehan .callback = &uaudio_chan_play_callback, 423276429Sneel }, 424284894Sneel 425284894Sneel [1] = { 426270071Sgrehan .type = UE_ISOCHRONOUS, 427270071Sgrehan .endpoint = UE_ADDR_ANY, 428270071Sgrehan .direction = UE_DIR_OUT, 429270071Sgrehan .bufsize = 0, /* use "wMaxPacketSize * frames" */ 430270071Sgrehan .frames = UAUDIO_MINFRAMES, 431270071Sgrehan .flags = {.short_xfer_ok = 1,}, 432270071Sgrehan .callback = &uaudio_chan_play_callback, 433270071Sgrehan }, 434270071Sgrehan}; 435270071Sgrehan 436249396Sneelstatic const struct usb2_config 437249396Sneel uaudio_mixer_config[1] = { 438221828Sgrehan [0] = { 439221828Sgrehan .type = UE_CONTROL, 440256072Sneel .endpoint = 0x00, /* Control pipe */ 441221828Sgrehan .direction = UE_DIR_ANY, 442249396Sneel .bufsize = (sizeof(struct usb2_device_request) + 4), 443249396Sneel .callback = &uaudio_mixer_write_cfg_callback, 444249396Sneel .timeout = 1000, /* 1 second */ 445249396Sneel }, 446249396Sneel}; 447249396Sneel 448249396Sneelstatic const 449221828Sgrehanuint8_t umidi_cmd_to_len[16] = { 450249396Sneel [0x0] = 0, /* reserved */ 451221828Sgrehan [0x1] = 0, /* reserved */ 452276429Sneel [0x2] = 2, /* bytes */ 453256072Sneel [0x3] = 3, /* bytes */ 454256072Sneel [0x4] = 3, /* bytes */ 455256072Sneel [0x5] = 1, /* bytes */ 456221828Sgrehan [0x6] = 2, /* bytes */ 457221828Sgrehan [0x7] = 3, /* bytes */ 458266339Sjhb [0x8] = 3, /* bytes */ 459266339Sjhb [0x9] = 3, /* bytes */ 460221828Sgrehan [0xA] = 3, /* bytes */ 461270071Sgrehan [0xB] = 3, /* bytes */ 462221828Sgrehan [0xC] = 2, /* bytes */ 463249396Sneel [0xD] = 2, /* bytes */ 464249396Sneel [0xE] = 3, /* bytes */ 465221828Sgrehan [0xF] = 1, /* bytes */ 466221828Sgrehan}; 467241178Sneel 468270071Sgrehanstatic const struct usb2_config 469221828Sgrehan umidi_config[UMIDI_N_TRANSFER] = { 470295124Sgrehan [0] = { 471221828Sgrehan .type = UE_BULK, 472221828Sgrehan .endpoint = UE_ADDR_ANY, 473221828Sgrehan .direction = UE_DIR_OUT, 474221828Sgrehan .bufsize = UMIDI_BULK_SIZE, 475256072Sneel .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 476256072Sneel .callback = &umidi_bulk_write_callback, 477256072Sneel }, 478284894Sneel 479284894Sneel [1] = { 480284894Sneel .type = UE_BULK, 481284894Sneel .endpoint = UE_ADDR_ANY, 482276429Sneel .direction = UE_DIR_IN, 483268891Sjhb .bufsize = UMIDI_BULK_SIZE, 484261088Sjhb .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 485268891Sjhb .callback = &umidi_bulk_read_callback, 486261088Sjhb }, 487261088Sjhb 488270071Sgrehan [2] = { 489270071Sgrehan .type = UE_CONTROL, 490221828Sgrehan .endpoint = 0x00, /* Control pipe */ 491270071Sgrehan .direction = UE_DIR_ANY, 492241178Sneel .bufsize = sizeof(struct usb2_device_request), 493295124Sgrehan .flags = {}, 494295124Sgrehan .callback = &umidi_write_clear_stall_callback, 495295124Sgrehan .timeout = 1000, /* 1 second */ 496295124Sgrehan .interval = 50, /* 50ms */ 497295124Sgrehan }, 498295124Sgrehan 499295124Sgrehan [3] = { 500295124Sgrehan .type = UE_CONTROL, 501295124Sgrehan .endpoint = 0x00, /* Control pipe */ 502295124Sgrehan .direction = UE_DIR_ANY, 503295124Sgrehan .bufsize = sizeof(struct usb2_device_request), 504295124Sgrehan .flags = {}, 505295124Sgrehan .callback = &umidi_read_clear_stall_callback, 506295124Sgrehan .timeout = 1000, /* 1 second */ 507270071Sgrehan .interval = 50, /* 50ms */ 508295124Sgrehan }, 509295124Sgrehan}; 510221828Sgrehan 511270071Sgrehanstatic devclass_t uaudio_devclass; 512270071Sgrehan 513270071Sgrehanstatic device_method_t uaudio_methods[] = { 514270071Sgrehan DEVMETHOD(device_probe, uaudio_probe), 515221828Sgrehan DEVMETHOD(device_attach, uaudio_attach), 516270071Sgrehan DEVMETHOD(device_detach, uaudio_detach), 517270071Sgrehan DEVMETHOD(device_suspend, bus_generic_suspend), 518270071Sgrehan DEVMETHOD(device_resume, bus_generic_resume), 519270071Sgrehan DEVMETHOD(device_shutdown, bus_generic_shutdown), 520221828Sgrehan DEVMETHOD(bus_print_child, bus_generic_print_child), 521221828Sgrehan {0, 0} 522221828Sgrehan}; 523270071Sgrehan 524270071Sgrehanstatic driver_t uaudio_driver = { 525270071Sgrehan .name = "uaudio", 526270071Sgrehan .methods = uaudio_methods, 527270071Sgrehan .size = sizeof(struct uaudio_softc), 528270071Sgrehan}; 529270071Sgrehan 530270071Sgrehanstatic int 531270071Sgrehanuaudio_probe(device_t dev) 532270071Sgrehan{ 533270071Sgrehan struct usb2_attach_arg *uaa = device_get_ivars(dev); 534270071Sgrehan 535270071Sgrehan if (uaa->usb_mode != USB_MODE_HOST) 536270071Sgrehan return (ENXIO); 537270071Sgrehan 538270071Sgrehan if (uaa->use_generic == 0) 539270071Sgrehan return (ENXIO); 540270071Sgrehan 541270071Sgrehan /* trigger on the control interface */ 542221828Sgrehan 543221828Sgrehan if ((uaa->info.bInterfaceClass == UICLASS_AUDIO) && 544221828Sgrehan (uaa->info.bInterfaceSubClass == UISUBCLASS_AUDIOCONTROL)) { 545221828Sgrehan if (usb2_test_quirk(uaa, UQ_BAD_AUDIO)) 546221828Sgrehan return (ENXIO); 547221828Sgrehan else 548221828Sgrehan return (0); 549221828Sgrehan } 550221828Sgrehan return (ENXIO); 551256072Sneel} 552221828Sgrehan 553256072Sneelstatic int 554256072Sneeluaudio_attach(device_t dev) 555256072Sneel{ 556256072Sneel struct usb2_attach_arg *uaa = device_get_ivars(dev); 557221828Sgrehan struct uaudio_softc *sc = device_get_softc(dev); 558221828Sgrehan struct usb2_interface_descriptor *id; 559221828Sgrehan device_t child; 560221828Sgrehan 561221828Sgrehan sc->sc_play_chan.priv_sc = sc; 562221828Sgrehan sc->sc_rec_chan.priv_sc = sc; 563256072Sneel sc->sc_udev = uaa->device; 564256072Sneel 565221828Sgrehan if (usb2_test_quirk(uaa, UQ_AUDIO_SWAP_LR)) 566221828Sgrehan sc->sc_uq_audio_swap_lr = 1; 567295124Sgrehan 568295124Sgrehan if (usb2_test_quirk(uaa, UQ_AU_INP_ASYNC)) 569295124Sgrehan sc->sc_uq_au_inp_async = 1; 570295124Sgrehan 571295124Sgrehan if (usb2_test_quirk(uaa, UQ_AU_NO_XU)) 572295124Sgrehan sc->sc_uq_au_no_xu = 1; 573295124Sgrehan 574295124Sgrehan if (usb2_test_quirk(uaa, UQ_BAD_ADC)) 575241041Sneel sc->sc_uq_bad_adc = 1; 576295124Sgrehan 577241041Sneel umidi_init(dev); 578241041Sneel 579295124Sgrehan device_set_usb2_desc(dev); 580295124Sgrehan 581295124Sgrehan id = usb2_get_interface_descriptor(uaa->iface); 582295124Sgrehan 583295124Sgrehan uaudio_chan_fill_info(sc, uaa->device); 584295124Sgrehan 585295124Sgrehan uaudio_mixer_fill_info(sc, uaa->device, id); 586295124Sgrehan 587295124Sgrehan sc->sc_mixer_iface_index = uaa->info.bIfaceIndex; 588295124Sgrehan sc->sc_mixer_iface_no = uaa->info.bIfaceNum; 589295124Sgrehan 590241041Sneel DPRINTF("audio rev %d.%02x\n", 591241041Sneel sc->sc_audio_rev >> 8, 592256072Sneel sc->sc_audio_rev & 0xff); 593295124Sgrehan 594256072Sneel DPRINTF("%d mixer controls\n", 595295124Sgrehan sc->sc_mixer_count); 596241041Sneel 597241041Sneel if (sc->sc_play_chan.valid) { 598221828Sgrehan device_printf(dev, "Play: %d Hz, %d ch, %s format\n", 599295124Sgrehan sc->sc_play_chan.sample_rate, 600221828Sgrehan sc->sc_play_chan.p_asf1d->bNrChannels, 601256072Sneel sc->sc_play_chan.p_fmt->description); 602295124Sgrehan } else { 603221828Sgrehan device_printf(dev, "No playback!\n"); 604295124Sgrehan } 605241041Sneel 606241041Sneel if (sc->sc_rec_chan.valid) { 607295124Sgrehan device_printf(dev, "Record: %d Hz, %d ch, %s format\n", 608241041Sneel sc->sc_rec_chan.sample_rate, 609221828Sgrehan sc->sc_rec_chan.p_asf1d->bNrChannels, 610295124Sgrehan sc->sc_rec_chan.p_fmt->description); 611295124Sgrehan } else { 612295124Sgrehan device_printf(dev, "No recording!\n"); 613295124Sgrehan } 614295124Sgrehan 615295124Sgrehan if (sc->sc_midi_chan.valid) { 616295124Sgrehan 617241041Sneel if (umidi_probe(dev)) { 618295124Sgrehan goto detach; 619295124Sgrehan } 620256072Sneel device_printf(dev, "MIDI sequencer\n"); 621256072Sneel } else { 622256072Sneel device_printf(dev, "No midi sequencer\n"); 623295124Sgrehan } 624295124Sgrehan 625295124Sgrehan DPRINTF("doing child attach\n"); 626295124Sgrehan 627241178Sneel /* attach the children */ 628295124Sgrehan 629295124Sgrehan sc->sc_sndcard_func.func = SCF_PCM; 630295124Sgrehan 631295124Sgrehan child = device_add_child(dev, "pcm", -1); 632295124Sgrehan 633256072Sneel if (child == NULL) { 634295124Sgrehan DPRINTF("out of memory\n"); 635295124Sgrehan goto detach; 636295124Sgrehan } 637295124Sgrehan device_set_ivars(child, &sc->sc_sndcard_func); 638295124Sgrehan 639295124Sgrehan if (bus_generic_attach(dev)) { 640295124Sgrehan DPRINTF("child attach failed\n"); 641295124Sgrehan goto detach; 642295124Sgrehan } 643295124Sgrehan return (0); /* success */ 644256072Sneel 645256072Sneeldetach: 646256072Sneel uaudio_detach(dev); 647295124Sgrehan return (ENXIO); 648295124Sgrehan} 649270159Sgrehan 650295124Sgrehanstatic void 651270159Sgrehanuaudio_pcm_setflags(device_t dev, uint32_t flags) 652295124Sgrehan{ 653295124Sgrehan pcm_setflags(dev, pcm_getflags(dev) | flags); 654295124Sgrehan} 655295124Sgrehan 656295124Sgrehanint 657295124Sgrehanuaudio_attach_sub(device_t dev, kobj_class_t mixer_class, kobj_class_t chan_class) 658295124Sgrehan{ 659270159Sgrehan struct uaudio_softc *sc = device_get_softc(device_get_parent(dev)); 660270159Sgrehan char status[SND_STATUSLEN]; 661270159Sgrehan 662295124Sgrehan uaudio_mixer_init(sc); 663295124Sgrehan 664295124Sgrehan if (sc->sc_uq_audio_swap_lr) { 665256072Sneel DPRINTF("hardware has swapped left and right\n"); 666256072Sneel uaudio_pcm_setflags(dev, SD_F_PSWAPLR); 667295124Sgrehan } 668295124Sgrehan if (!(sc->sc_mix_info & SOUND_MASK_PCM)) { 669295124Sgrehan 670256072Sneel DPRINTF("emulating master volume\n"); 671295124Sgrehan 672295124Sgrehan /* 673256072Sneel * Emulate missing pcm mixer controller 674295124Sgrehan * through FEEDER_VOLUME 675295124Sgrehan */ 676256072Sneel uaudio_pcm_setflags(dev, SD_F_SOFTPCMVOL); 677295124Sgrehan } 678295124Sgrehan if (mixer_init(dev, mixer_class, sc)) { 679295124Sgrehan goto detach; 680295124Sgrehan } 681295124Sgrehan sc->sc_mixer_init = 1; 682295124Sgrehan 683295124Sgrehan snprintf(status, sizeof(status), "at ? %s", PCM_KLDSTRING(snd_uaudio)); 684295124Sgrehan 685295124Sgrehan if (pcm_register(dev, sc, 686295124Sgrehan sc->sc_play_chan.valid ? 1 : 0, 687295124Sgrehan sc->sc_rec_chan.valid ? 1 : 0)) { 688295124Sgrehan goto detach; 689295124Sgrehan } 690295124Sgrehan sc->sc_pcm_registered = 1; 691295124Sgrehan 692295124Sgrehan if (sc->sc_play_chan.valid) { 693295124Sgrehan pcm_addchan(dev, PCMDIR_PLAY, chan_class, sc); 694295124Sgrehan } 695295124Sgrehan if (sc->sc_rec_chan.valid) { 696295124Sgrehan pcm_addchan(dev, PCMDIR_REC, chan_class, sc); 697295124Sgrehan } 698256072Sneel pcm_setstatus(dev, status); 699295124Sgrehan 700295124Sgrehan return (0); /* success */ 701295124Sgrehan 702295124Sgrehandetach: 703295124Sgrehan uaudio_detach_sub(dev); 704295124Sgrehan return (ENXIO); 705295124Sgrehan} 706295124Sgrehan 707295124Sgrehanint 708295124Sgrehanuaudio_detach_sub(device_t dev) 709295124Sgrehan{ 710295124Sgrehan struct uaudio_softc *sc = device_get_softc(device_get_parent(dev)); 711295124Sgrehan int error = 0; 712295124Sgrehan 713295124Sgrehanrepeat: 714295124Sgrehan if (sc->sc_pcm_registered) { 715295124Sgrehan error = pcm_unregister(dev); 716295124Sgrehan } else { 717295124Sgrehan if (sc->sc_mixer_init) { 718295124Sgrehan error = mixer_uninit(dev); 719295124Sgrehan } 720295124Sgrehan } 721295124Sgrehan 722295124Sgrehan if (error) { 723295124Sgrehan device_printf(dev, "Waiting for sound application to exit!\n"); 724295124Sgrehan usb2_pause_mtx(NULL, 2 * hz); 725295124Sgrehan goto repeat; /* try again */ 726256072Sneel } 727256072Sneel return (0); /* success */ 728295124Sgrehan} 729295124Sgrehan 730295124Sgrehanstatic int 731256072Sneeluaudio_detach(device_t dev) 732295124Sgrehan{ 733295124Sgrehan struct uaudio_softc *sc = device_get_softc(dev); 734256072Sneel 735295124Sgrehan if (bus_generic_detach(dev)) { 736295124Sgrehan DPRINTF("detach failed!\n"); 737295124Sgrehan } 738295124Sgrehan sbuf_delete(&sc->sc_sndstat); 739256072Sneel sc->sc_sndstat_valid = 0; 740295124Sgrehan 741295124Sgrehan umidi_detach(dev); 742295124Sgrehan 743256072Sneel return (0); 744295124Sgrehan} 745295124Sgrehan 746295124Sgrehan/*========================================================================* 747295124Sgrehan * AS - Audio Stream - routines 748295124Sgrehan *========================================================================*/ 749295124Sgrehan 750295124Sgrehan#if USB_DEBUG 751295124Sgrehanstatic void 752295124Sgrehanuaudio_chan_dump_ep_desc(const usb2_endpoint_descriptor_audio_t *ed) 753295124Sgrehan{ 754295124Sgrehan if (ed) { 755295124Sgrehan DPRINTF("endpoint=%p bLength=%d bDescriptorType=%d \n" 756295124Sgrehan "bEndpointAddress=%d bmAttributes=0x%x \n" 757295124Sgrehan "wMaxPacketSize=%d bInterval=%d \n" 758295124Sgrehan "bRefresh=%d bSynchAddress=%d\n", 759256072Sneel ed, ed->bLength, ed->bDescriptorType, 760295124Sgrehan ed->bEndpointAddress, ed->bmAttributes, 761256072Sneel UGETW(ed->wMaxPacketSize), ed->bInterval, 762295124Sgrehan ed->bRefresh, ed->bSynchAddress); 763295124Sgrehan } 764295124Sgrehan} 765295124Sgrehan 766295124Sgrehan#endif 767295124Sgrehan 768295124Sgrehanstatic void 769295124Sgrehanuaudio_chan_fill_info_sub(struct uaudio_softc *sc, struct usb2_device *udev, 770295124Sgrehan uint32_t rate, uint16_t fps, uint8_t channels, 771295124Sgrehan uint8_t bit_resolution) 772295124Sgrehan{ 773295124Sgrehan struct usb2_descriptor *desc = NULL; 774295124Sgrehan const struct usb2_audio_streaming_interface_descriptor *asid = NULL; 775256072Sneel const struct usb2_audio_streaming_type1_descriptor *asf1d = NULL; 776295124Sgrehan const struct usb2_audio_streaming_endpoint_descriptor *sed = NULL; 777241178Sneel const usb2_endpoint_descriptor_audio_t *ed1 = NULL; 778295124Sgrehan const usb2_endpoint_descriptor_audio_t *ed2 = NULL; 779295124Sgrehan struct usb2_config_descriptor *cd = usb2_get_config_descriptor(udev); 780295124Sgrehan struct usb2_interface_descriptor *id; 781295124Sgrehan const struct uaudio_format *p_fmt; 782295124Sgrehan struct uaudio_chan *chan; 783295124Sgrehan uint16_t curidx = 0xFFFF; 784295124Sgrehan uint16_t lastidx = 0xFFFF; 785295124Sgrehan uint16_t alt_index = 0; 786256072Sneel uint16_t wFormat; 787256072Sneel uint8_t ep_dir; 788295124Sgrehan uint8_t ep_type; 789295124Sgrehan uint8_t ep_sync; 790295124Sgrehan uint8_t bChannels; 791295124Sgrehan uint8_t bBitResolution; 792295124Sgrehan uint8_t x; 793295124Sgrehan uint8_t audio_if = 0; 794295124Sgrehan uint8_t sample_size; 795295124Sgrehan 796295124Sgrehan while ((desc = usb2_desc_foreach(cd, desc))) { 797295124Sgrehan 798295124Sgrehan if ((desc->bDescriptorType == UDESC_INTERFACE) && 799295124Sgrehan (desc->bLength >= sizeof(*id))) { 800295124Sgrehan 801295124Sgrehan id = (void *)desc; 802295124Sgrehan 803295124Sgrehan if (id->bInterfaceNumber != lastidx) { 804295124Sgrehan lastidx = id->bInterfaceNumber; 805295124Sgrehan curidx++; 806256072Sneel alt_index = 0; 807256072Sneel 808256072Sneel } else { 809256072Sneel alt_index++; 810256072Sneel } 811295124Sgrehan 812256072Sneel if ((id->bInterfaceClass == UICLASS_AUDIO) && 813256072Sneel (id->bInterfaceSubClass == UISUBCLASS_AUDIOSTREAM)) { 814256072Sneel audio_if = 1; 815256072Sneel } else { 816256072Sneel audio_if = 0; 817295124Sgrehan } 818295124Sgrehan 819295124Sgrehan if ((id->bInterfaceClass == UICLASS_AUDIO) && 820295124Sgrehan (id->bInterfaceSubClass == UISUBCLASS_MIDISTREAM)) { 821256072Sneel 822295124Sgrehan /* 823295124Sgrehan * XXX could allow multiple MIDI interfaces 824295124Sgrehan * XXX 825295124Sgrehan */ 826295124Sgrehan 827295124Sgrehan if ((sc->sc_midi_chan.valid == 0) && 828295124Sgrehan usb2_get_iface(udev, curidx)) { 829295124Sgrehan sc->sc_midi_chan.iface_index = curidx; 830295124Sgrehan sc->sc_midi_chan.iface_alt_index = alt_index; 831295124Sgrehan sc->sc_midi_chan.valid = 1; 832295124Sgrehan } 833295124Sgrehan } 834295124Sgrehan asid = NULL; 835295124Sgrehan asf1d = NULL; 836295124Sgrehan ed1 = NULL; 837295124Sgrehan ed2 = NULL; 838295124Sgrehan sed = NULL; 839295124Sgrehan } 840295124Sgrehan if ((desc->bDescriptorType == UDESC_CS_INTERFACE) && 841256072Sneel (desc->bDescriptorSubtype == AS_GENERAL) && 842256072Sneel (desc->bLength >= sizeof(*asid))) { 843256072Sneel if (asid == NULL) { 844256072Sneel asid = (void *)desc; 845256072Sneel } 846256072Sneel } 847256072Sneel if ((desc->bDescriptorType == UDESC_CS_INTERFACE) && 848256072Sneel (desc->bDescriptorSubtype == FORMAT_TYPE) && 849256072Sneel (desc->bLength >= sizeof(*asf1d))) { 850256072Sneel if (asf1d == NULL) { 851256072Sneel asf1d = (void *)desc; 852256072Sneel if (asf1d->bFormatType != FORMAT_TYPE_I) { 853256072Sneel DPRINTFN(11, "ignored bFormatType = %d\n", 854256072Sneel asf1d->bFormatType); 855256072Sneel asf1d = NULL; 856256072Sneel continue; 857256072Sneel } 858241178Sneel if (asf1d->bLength < (sizeof(*asf1d) + 859241178Sneel (asf1d->bSamFreqType == 0) ? 6 : 860256072Sneel (asf1d->bSamFreqType * 3))) { 861256072Sneel DPRINTFN(11, "'asf1d' descriptor is too short\n"); 862256072Sneel asf1d = NULL; 863256072Sneel continue; 864256072Sneel } 865256072Sneel } 866256072Sneel } 867256072Sneel if ((desc->bDescriptorType == UDESC_ENDPOINT) && 868256072Sneel (desc->bLength >= sizeof(*ed1))) { 869256072Sneel if (ed1 == NULL) { 870256072Sneel ed1 = (void *)desc; 871256072Sneel if (UE_GET_XFERTYPE(ed1->bmAttributes) != UE_ISOCHRONOUS) { 872256072Sneel ed1 = NULL; 873256072Sneel } 874256072Sneel } else { 875256072Sneel if (ed2 == NULL) { 876256072Sneel ed2 = (void *)desc; 877256072Sneel if (UE_GET_XFERTYPE(ed2->bmAttributes) != UE_ISOCHRONOUS) { 878256072Sneel ed2 = NULL; 879256072Sneel continue; 880221828Sgrehan } 881256072Sneel if (ed2->bSynchAddress != 0) { 882295124Sgrehan DPRINTFN(11, "invalid endpoint: bSynchAddress != 0\n"); 883256072Sneel ed2 = NULL; 884295124Sgrehan continue; 885256072Sneel } 886256072Sneel if (ed2->bEndpointAddress != ed1->bSynchAddress) { 887221828Sgrehan DPRINTFN(11, "invalid endpoint addresses: " 888256072Sneel "ep[0]->bSynchAddress=0x%x " 889256072Sneel "ep[1]->bEndpointAddress=0x%x\n", 890256072Sneel ed1->bSynchAddress, 891256072Sneel ed2->bEndpointAddress); 892256072Sneel ed2 = NULL; 893256072Sneel continue; 894295124Sgrehan } 895267070Sjhb } 896256072Sneel } 897256072Sneel } 898295124Sgrehan if ((desc->bDescriptorType == UDESC_CS_ENDPOINT) && 899256072Sneel (desc->bDescriptorSubtype == AS_GENERAL) && 900256072Sneel (desc->bLength >= sizeof(*sed))) { 901256072Sneel if (sed == NULL) { 902256072Sneel sed = (void *)desc; 903256072Sneel } 904256072Sneel } 905221828Sgrehan if (audio_if && asid && asf1d && ed1 && sed) { 906221828Sgrehan 907256072Sneel ep_dir = UE_GET_DIR(ed1->bEndpointAddress); 908295124Sgrehan ep_type = UE_GET_ISO_TYPE(ed1->bmAttributes); 909256072Sneel ep_sync = 0; 910221828Sgrehan 911295124Sgrehan if ((sc->sc_uq_au_inp_async) && 912295124Sgrehan (ep_dir == UE_DIR_IN) && (ep_type == UE_ISO_ADAPT)) { 913256072Sneel ep_type = UE_ISO_ASYNC; 914295124Sgrehan } 915295124Sgrehan if ((ep_dir == UE_DIR_IN) && (ep_type == UE_ISO_ADAPT)) { 916295124Sgrehan ep_sync = 1; 917295124Sgrehan } 918295124Sgrehan if ((ep_dir != UE_DIR_IN) && (ep_type == UE_ISO_ASYNC)) { 919295124Sgrehan ep_sync = 1; 920295124Sgrehan } 921295124Sgrehan /* Ignore sync endpoint information until further. */ 922295124Sgrehan#if 0 923295124Sgrehan if (ep_sync && (!ed2)) { 924295124Sgrehan continue; 925295124Sgrehan } 926295124Sgrehan /* 927295124Sgrehan * we can't handle endpoints that need a sync pipe 928295124Sgrehan * yet 929295124Sgrehan */ 930295124Sgrehan 931256072Sneel if (ep_sync) { 932256072Sneel DPRINTF("skipped sync interface\n"); 933256072Sneel audio_if = 0; 934241148Sneel continue; 935295124Sgrehan } 936295124Sgrehan#endif 937295124Sgrehan 938295124Sgrehan wFormat = UGETW(asid->wFormatTag); 939295124Sgrehan bChannels = asf1d->bNrChannels; 940295124Sgrehan bBitResolution = asf1d->bBitResolution; 941295124Sgrehan 942295124Sgrehan if (asf1d->bSamFreqType == 0) { 943295124Sgrehan DPRINTFN(16, "Sample rate: %d-%dHz\n", 944295124Sgrehan UA_SAMP_LO(asf1d), UA_SAMP_HI(asf1d)); 945256072Sneel 946256072Sneel if ((rate >= UA_SAMP_LO(asf1d)) && 947256072Sneel (rate <= UA_SAMP_HI(asf1d))) { 948256072Sneel goto found_rate; 949256072Sneel } 950256072Sneel } else { 951256072Sneel 952256072Sneel for (x = 0; x < asf1d->bSamFreqType; x++) { 953221828Sgrehan DPRINTFN(16, "Sample rate = %dHz\n", 954221828Sgrehan UA_GETSAMP(asf1d, x)); 955256072Sneel 956256072Sneel if (rate == UA_GETSAMP(asf1d, x)) { 957256072Sneel goto found_rate; 958256072Sneel } 959256072Sneel } 960256072Sneel } 961256072Sneel 962256072Sneel audio_if = 0; 963256072Sneel continue; 964256072Sneel 965221828Sgrehan found_rate: 966221828Sgrehan 967221828Sgrehan for (p_fmt = uaudio_formats; 968221828Sgrehan p_fmt->wFormat; 969221828Sgrehan p_fmt++) { 970221828Sgrehan if ((p_fmt->wFormat == wFormat) && 971221828Sgrehan (p_fmt->bPrecision == bBitResolution)) { 972221828Sgrehan goto found_format; 973221828Sgrehan } 974221828Sgrehan } 975221828Sgrehan 976221828Sgrehan audio_if = 0; 977221828Sgrehan continue; 978221828Sgrehan 979284894Sneel found_format: 980221828Sgrehan 981284894Sneel if ((bChannels == channels) && 982284894Sneel (bBitResolution == bit_resolution)) { 983221828Sgrehan 984284894Sneel chan = (ep_dir == UE_DIR_IN) ? 985221828Sgrehan &sc->sc_rec_chan : 986221828Sgrehan &sc->sc_play_chan; 987221828Sgrehan 988221828Sgrehan if ((chan->valid == 0) && usb2_get_iface(udev, curidx)) { 989221828Sgrehan 990284894Sneel chan->valid = 1; 991284894Sneel#if USB_DEBUG 992284894Sneel uaudio_chan_dump_ep_desc(ed1); 993284894Sneel uaudio_chan_dump_ep_desc(ed2); 994284894Sneel 995284894Sneel if (sed->bmAttributes & UA_SED_FREQ_CONTROL) { 996284894Sneel DPRINTFN(2, "FREQ_CONTROL\n"); 997284894Sneel } 998284894Sneel if (sed->bmAttributes & UA_SED_PITCH_CONTROL) { 999221828Sgrehan DPRINTFN(2, "PITCH_CONTROL\n"); 1000221828Sgrehan } 1001221828Sgrehan#endif 1002221828Sgrehan DPRINTF("Sample rate = %dHz, channels = %d, " 1003221828Sgrehan "bits = %d, format = %s\n", rate, channels, 1004221828Sgrehan bit_resolution, p_fmt->description); 1005221828Sgrehan 1006221828Sgrehan chan->sample_rate = rate; 1007221828Sgrehan chan->p_asid = asid; 1008221828Sgrehan chan->p_asf1d = asf1d; 1009221828Sgrehan chan->p_ed1 = ed1; 1010221828Sgrehan chan->p_ed2 = ed2; 1011221828Sgrehan chan->p_fmt = p_fmt; 1012221828Sgrehan chan->p_sed = sed; 1013221828Sgrehan chan->iface_index = curidx; 1014221828Sgrehan chan->iface_alt_index = alt_index; 1015221828Sgrehan 1016221828Sgrehan if (ep_dir == UE_DIR_IN) 1017221828Sgrehan chan->usb2_cfg = 1018221828Sgrehan uaudio_cfg_record; 1019221828Sgrehan else 1020221828Sgrehan chan->usb2_cfg = 1021221828Sgrehan uaudio_cfg_play; 1022221828Sgrehan 1023221828Sgrehan sample_size = ((chan->p_asf1d->bNrChannels * 1024221828Sgrehan chan->p_asf1d->bBitResolution) / 8); 1025221828Sgrehan 1026221828Sgrehan /* 1027221828Sgrehan * NOTE: "chan->bytes_per_frame" 1028221828Sgrehan * should not be zero! 1029221828Sgrehan */ 1030221828Sgrehan chan->bytes_per_frame = ((rate / fps) * sample_size); 1031221828Sgrehan 1032221828Sgrehan if (sc->sc_sndstat_valid) { 1033221828Sgrehan sbuf_printf(&sc->sc_sndstat, "\n\t" 1034221828Sgrehan "mode %d.%d:(%s) %dch, %d/%dbit, %s, %dHz", 1035221828Sgrehan curidx, alt_index, 1036221828Sgrehan (ep_dir == UE_DIR_IN) ? "input" : "output", 1037221828Sgrehan asf1d->bNrChannels, asf1d->bBitResolution, 1038221828Sgrehan asf1d->bSubFrameSize * 8, 1039221828Sgrehan p_fmt->description, rate); 1040221828Sgrehan } 1041221828Sgrehan } 1042221828Sgrehan } 1043221828Sgrehan audio_if = 0; 1044221828Sgrehan continue; 1045221828Sgrehan } 1046221828Sgrehan } 1047221828Sgrehan} 1048221828Sgrehan 1049221828Sgrehanstatic void 1050221828Sgrehanuaudio_chan_fill_info(struct uaudio_softc *sc, struct usb2_device *udev) 1051221828Sgrehan{ 1052221828Sgrehan uint32_t rate = uaudio_default_rate; 1053221828Sgrehan uint32_t z; 1054221828Sgrehan uint16_t fps = usb2_get_isoc_fps(udev); 1055221828Sgrehan uint8_t bits = uaudio_default_bits; 1056221828Sgrehan uint8_t y; 1057221828Sgrehan uint8_t channels = uaudio_default_channels; 1058221828Sgrehan uint8_t x; 1059221828Sgrehan 1060221828Sgrehan bits -= (bits % 8); 1061221828Sgrehan if ((bits == 0) || (bits > 32)) { 1062221828Sgrehan /* set a valid value */ 1063221828Sgrehan bits = 32; 1064234695Sgrehan } 1065234695Sgrehan rate -= (rate % fps); 1066242122Sneel if ((rate == 0) || (rate > 192000)) { 1067242122Sneel /* set a valid value */ 1068221828Sgrehan rate = 192000 - (192000 % fps); 1069234695Sgrehan } 1070242122Sneel if ((channels == 0) || (channels > 2)) { 1071267427Sjhb /* set a valid value */ 1072267427Sjhb channels = 2; 1073267427Sjhb } 1074267427Sjhb if (sbuf_new(&sc->sc_sndstat, NULL, 4096, SBUF_AUTOEXTEND)) { 1075242122Sneel sc->sc_sndstat_valid = 1; 1076242122Sneel } 1077242122Sneel /* try to search for a valid config */ 1078242122Sneel 1079242122Sneel for (x = channels; x; x--) { 1080221828Sgrehan for (y = bits; y; y -= 8) { 1081221828Sgrehan for (z = rate; z; z -= fps) { 1082221828Sgrehan uaudio_chan_fill_info_sub(sc, udev, z, fps, x, y); 1083221828Sgrehan 1084221828Sgrehan if (sc->sc_rec_chan.valid && 1085221828Sgrehan sc->sc_play_chan.valid) { 1086242122Sneel goto done; 1087242122Sneel } 1088242122Sneel } 1089267427Sjhb } 1090267427Sjhb } 1091267427Sjhb 1092267427Sjhbdone: 1093267427Sjhb if (sc->sc_sndstat_valid) { 1094267427Sjhb sbuf_finish(&sc->sc_sndstat); 1095242122Sneel } 1096242122Sneel} 1097234695Sgrehan 1098221828Sgrehanstatic void 1099221828Sgrehanuaudio_chan_play_callback(struct usb2_xfer *xfer) 1100221828Sgrehan{ 1101248389Sneel struct uaudio_chan *ch = xfer->priv_sc; 1102242065Sneel uint32_t *p_len = xfer->frlengths; 1103256072Sneel uint32_t total; 1104284900Sneel uint32_t blockcount; 1105266393Sjhb uint32_t n; 1106256072Sneel uint32_t offset; 1107284900Sneel 1108256072Sneel /* allow dynamic sizing of play buffer */ 1109256072Sneel total = ch->intr_size; 1110284900Sneel 1111256072Sneel /* allow dynamic sizing of play buffer */ 1112256072Sneel blockcount = total / ch->bytes_per_frame; 1113256072Sneel 1114266393Sjhb /* align units */ 1115266393Sjhb blockcount -= (blockcount % UAUDIO_MINFRAMES); 1116266393Sjhb 1117266393Sjhb /* range check - min */ 1118266393Sjhb if (blockcount == 0) { 1119284900Sneel blockcount = UAUDIO_MINFRAMES; 1120284900Sneel } 1121284900Sneel /* range check - max */ 1122284900Sneel if (blockcount > xfer->max_frame_count) { 1123284900Sneel blockcount = xfer->max_frame_count; 1124266393Sjhb } 1125284900Sneel /* compute the total length */ 1126266393Sjhb total = blockcount * ch->bytes_per_frame; 1127266393Sjhb 1128266393Sjhb switch (USB_GET_STATE(xfer)) { 1129266393Sjhb case USB_ST_TRANSFERRED: 1130266393Sjhbtr_transferred: 1131266393Sjhb if (xfer->actlen < xfer->sumlen) { 1132266393Sjhb DPRINTF("short transfer, " 1133266393Sjhb "%d of %d bytes\n", xfer->actlen, total); 1134266393Sjhb } 1135266393Sjhb chn_intr(ch->pcm_ch); 1136266393Sjhb 1137266393Sjhb case USB_ST_SETUP: 1138266393Sjhb if (ch->bytes_per_frame > xfer->max_frame_size) { 1139266393Sjhb DPRINTF("bytes per transfer, %d, " 1140256072Sneel "exceeds maximum, %d!\n", 1141256072Sneel ch->bytes_per_frame, 1142256072Sneel xfer->max_frame_size); 1143256072Sneel break; 1144256072Sneel } 1145256072Sneel /* setup frame length */ 1146256072Sneel xfer->nframes = blockcount; 1147256072Sneel for (n = 0; n != blockcount; n++) { 1148256072Sneel p_len[n] = ch->bytes_per_frame; 1149256072Sneel } 1150256072Sneel 1151256072Sneel if (ch->end == ch->start) { 1152256072Sneel DPRINTF("no buffer!\n"); 1153256072Sneel break; 1154256072Sneel } 1155256072Sneel DPRINTFN(6, "transfer %d bytes\n", total); 1156256072Sneel 1157256072Sneel offset = 0; 1158256072Sneel 1159266393Sjhb while (total > 0) { 1160266393Sjhb 1161266393Sjhb n = (ch->end - ch->cur); 1162284900Sneel if (n > total) { 1163284900Sneel n = total; 1164284900Sneel } 1165266393Sjhb usb2_copy_in(xfer->frbuffers, offset, ch->cur, n); 1166266393Sjhb 1167266393Sjhb total -= n; 1168256072Sneel ch->cur += n; 1169266393Sjhb offset += n; 1170256072Sneel 1171266393Sjhb if (ch->cur >= ch->end) { 1172266393Sjhb ch->cur = ch->start; 1173266393Sjhb } 1174266393Sjhb } 1175256072Sneel 1176256072Sneel usb2_start_hardware(xfer); 1177256072Sneel break; 1178256072Sneel 1179256072Sneel default: /* Error */ 1180256072Sneel if (xfer->error == USB_ERR_CANCELLED) { 1181256072Sneel break; 1182266393Sjhb } 1183256072Sneel goto tr_transferred; 1184256072Sneel } 1185256072Sneel} 1186256072Sneel 1187284900Sneelstatic void 1188256072Sneeluaudio_chan_record_callback(struct usb2_xfer *xfer) 1189256072Sneel{ 1190256072Sneel struct uaudio_chan *ch = xfer->priv_sc; 1191284900Sneel uint32_t *p_len = xfer->frlengths; 1192256072Sneel uint32_t n; 1193256072Sneel uint32_t m; 1194256072Sneel uint32_t total; 1195266339Sjhb uint32_t blockcount; 1196266339Sjhb uint32_t offset0; 1197266339Sjhb uint32_t offset1; 1198266339Sjhb 1199266339Sjhb /* allow dynamic sizing of play buffer */ 1200266339Sjhb total = ch->intr_size; 1201266339Sjhb 1202266339Sjhb /* allow dynamic sizing of play buffer */ 1203266339Sjhb blockcount = total / ch->bytes_per_frame; 1204266339Sjhb 1205266339Sjhb /* align units */ 1206266339Sjhb blockcount -= (blockcount % UAUDIO_MINFRAMES); 1207266339Sjhb 1208266339Sjhb /* range check - min */ 1209266339Sjhb if (blockcount == 0) { 1210266339Sjhb blockcount = UAUDIO_MINFRAMES; 1211266339Sjhb } 1212266339Sjhb /* range check - max */ 1213266339Sjhb if (blockcount > xfer->max_frame_count) { 1214266339Sjhb blockcount = xfer->max_frame_count; 1215266339Sjhb } 1216266339Sjhb /* compute the total length */ 1217266339Sjhb total = blockcount * ch->bytes_per_frame; 1218266339Sjhb 1219266339Sjhb switch (USB_GET_STATE(xfer)) { 1220266339Sjhb case USB_ST_TRANSFERRED: 1221266339Sjhbtr_transferred: 1222266339Sjhb if (xfer->actlen < total) { 1223266339Sjhb DPRINTF("short transfer, " 1224266339Sjhb "%d of %d bytes\n", xfer->actlen, total); 1225266339Sjhb } else { 1226266339Sjhb DPRINTFN(6, "transferred %d bytes\n", xfer->actlen); 1227266339Sjhb } 1228266339Sjhb 1229266339Sjhb offset0 = 0; 1230266339Sjhb 1231266339Sjhb for (n = 0; n != xfer->nframes; n++) { 1232266339Sjhb 1233266339Sjhb offset1 = offset0; 1234266339Sjhb 1235266339Sjhb while (p_len[n] > 0) { 1236266339Sjhb 1237266339Sjhb m = (ch->end - ch->cur); 1238266339Sjhb 1239266339Sjhb if (m > p_len[n]) { 1240266339Sjhb m = p_len[n]; 1241266339Sjhb } 1242266339Sjhb usb2_copy_out(xfer->frbuffers, offset1, ch->cur, m); 1243266339Sjhb 1244266339Sjhb p_len[n] -= m; 1245266339Sjhb offset1 += m; 1246266339Sjhb ch->cur += m; 1247266339Sjhb 1248266339Sjhb if (ch->cur >= ch->end) { 1249266339Sjhb ch->cur = ch->start; 1250266339Sjhb } 1251266339Sjhb } 1252256072Sneel 1253256072Sneel offset0 += ch->bytes_per_frame; 1254256072Sneel } 1255256072Sneel 1256262350Sjhb chn_intr(ch->pcm_ch); 1257256072Sneel 1258256072Sneel case USB_ST_SETUP: 1259268935Sjhb if (ch->bytes_per_frame > xfer->max_frame_size) { 1260284894Sneel DPRINTF("bytes per transfer, %d, " 1261256072Sneel "exceeds maximum, %d!\n", 1262268935Sjhb ch->bytes_per_frame, 1263268935Sjhb xfer->max_frame_size); 1264256072Sneel return; 1265268935Sjhb } 1266268935Sjhb xfer->nframes = blockcount; 1267256072Sneel for (n = 0; n != xfer->nframes; n++) { 1268256072Sneel p_len[n] = ch->bytes_per_frame; 1269268935Sjhb } 1270268935Sjhb 1271268935Sjhb if (ch->end == ch->start) { 1272268935Sjhb DPRINTF("no buffer!\n"); 1273268935Sjhb return; 1274268935Sjhb } 1275268935Sjhb usb2_start_hardware(xfer); 1276268935Sjhb return; 1277268935Sjhb 1278268935Sjhb default: /* Error */ 1279284900Sneel if (xfer->error == USB_ERR_CANCELLED) { 1280268935Sjhb return; 1281268935Sjhb } 1282268935Sjhb goto tr_transferred; 1283268935Sjhb } 1284268935Sjhb} 1285268935Sjhb 1286268935Sjhbvoid * 1287268935Sjhbuaudio_chan_init(struct uaudio_softc *sc, struct snd_dbuf *b, 1288268935Sjhb struct pcm_channel *c, int dir) 1289256072Sneel{ 1290270159Sgrehan struct uaudio_chan *ch = ((dir == PCMDIR_PLAY) ? 1291270159Sgrehan &sc->sc_play_chan : &sc->sc_rec_chan); 1292270159Sgrehan uint32_t buf_size; 1293270159Sgrehan uint8_t endpoint; 1294268935Sjhb uint8_t iface_index; 1295268935Sjhb uint8_t alt_index; 1296268935Sjhb usb2_error_t err; 1297268935Sjhb 1298268935Sjhb /* compute required buffer size */ 1299268935Sjhb buf_size = (ch->bytes_per_frame * UAUDIO_MINFRAMES); 1300268935Sjhb 1301268935Sjhb /* setup interrupt interval */ 1302268935Sjhb ch->intr_size = buf_size; 1303268935Sjhb 1304268935Sjhb /* double buffering */ 1305268935Sjhb buf_size *= 2; 1306268935Sjhb 1307268935Sjhb ch->buf = malloc(buf_size, M_DEVBUF, M_WAITOK | M_ZERO); 1308268935Sjhb if (ch->buf == NULL) { 1309268935Sjhb goto error; 1310268935Sjhb } 1311268935Sjhb if (sndbuf_setup(b, ch->buf, buf_size) != 0) { 1312268935Sjhb goto error; 1313268935Sjhb } 1314268935Sjhb ch->start = ch->buf; 1315256072Sneel ch->end = ch->buf + buf_size; 1316284900Sneel ch->cur = ch->buf; 1317270159Sgrehan ch->pcm_ch = c; 1318270159Sgrehan ch->pcm_mtx = c->lock; 1319270159Sgrehan ch->pcm_buf = b; 1320270159Sgrehan 1321270159Sgrehan if (ch->pcm_mtx == NULL) { 1322284900Sneel DPRINTF("ERROR: PCM channels does not have a mutex!\n"); 1323256072Sneel goto error; 1324256072Sneel } 1325268935Sjhb /* setup play/record format */ 1326268935Sjhb 1327268935Sjhb ch->pcm_cap.fmtlist = ch->pcm_format; 1328268935Sjhb 1329256072Sneel ch->pcm_format[0] = 0; 1330256072Sneel ch->pcm_format[1] = 0; 1331268935Sjhb 1332268935Sjhb ch->pcm_cap.minspeed = ch->sample_rate; 1333266339Sjhb ch->pcm_cap.maxspeed = ch->sample_rate; 1334256072Sneel 1335256072Sneel ch->pcm_cap.fmtlist[0] = ch->p_fmt->freebsd_fmt; 1336256072Sneel 1337256072Sneel if (ch->p_asf1d->bNrChannels == 2) { 1338262350Sjhb ch->pcm_cap.fmtlist[0] |= AFMT_STEREO; 1339256072Sneel } 1340256072Sneel ch->pcm_cap.fmtlist[1] = 0; 1341256072Sneel 1342256072Sneel 1343256072Sneel /* set alternate interface corresponding to the mode */ 1344256072Sneel 1345256072Sneel endpoint = ch->p_ed1->bEndpointAddress; 1346256072Sneel iface_index = ch->iface_index; 1347256072Sneel alt_index = ch->iface_alt_index; 1348284894Sneel 1349284894Sneel DPRINTF("endpoint=0x%02x, speed=%d, iface=%d alt=%d\n", 1350284894Sneel endpoint, ch->sample_rate, iface_index, alt_index); 1351256072Sneel 1352256072Sneel err = usb2_set_alt_interface_index(sc->sc_udev, iface_index, alt_index); 1353256072Sneel if (err) { 1354256072Sneel DPRINTF("setting of alternate index failed: %s!\n", 1355256072Sneel usb2_errstr(err)); 1356256072Sneel goto error; 1357256072Sneel } 1358256072Sneel usb2_set_parent_iface(sc->sc_udev, iface_index, sc->sc_mixer_iface_index); 1359276349Sneel 1360276349Sneel /* 1361276349Sneel * If just one sampling rate is supported, 1362276349Sneel * no need to call "uaudio_set_speed()". 1363256072Sneel * Roland SD-90 freezes by a SAMPLING_FREQ_CONTROL request. 1364276349Sneel */ 1365256072Sneel if (ch->p_asf1d->bSamFreqType != 1) { 1366256072Sneel if (uaudio_set_speed(sc->sc_udev, endpoint, ch->sample_rate)) { 1367256072Sneel /* 1368256072Sneel * If the endpoint is adaptive setting the speed may 1369256072Sneel * fail. 1370261088Sjhb */ 1371261088Sjhb DPRINTF("setting of sample rate failed! (continuing anyway)\n"); 1372256072Sneel } 1373256072Sneel } 1374256072Sneel if (usb2_transfer_setup(sc->sc_udev, &iface_index, ch->xfer, 1375256072Sneel ch->usb2_cfg, UAUDIO_NCHANBUFS, ch, ch->pcm_mtx)) { 1376256072Sneel DPRINTF("could not allocate USB transfers!\n"); 1377256072Sneel goto error; 1378256072Sneel } 1379256072Sneel return (ch); 1380262350Sjhb 1381256072Sneelerror: 1382256072Sneel uaudio_chan_free(ch); 1383256072Sneel return (NULL); 1384256072Sneel} 1385284899Sneel 1386268976Sjhbint 1387261088Sjhbuaudio_chan_free(struct uaudio_chan *ch) 1388261088Sjhb{ 1389270159Sgrehan if (ch->buf != NULL) { 1390284900Sneel free(ch->buf, M_DEVBUF); 1391256072Sneel ch->buf = NULL; 1392256072Sneel } 1393256072Sneel usb2_transfer_unsetup(ch->xfer, UAUDIO_NCHANBUFS); 1394256072Sneel 1395284900Sneel ch->valid = 0; 1396284900Sneel 1397284900Sneel return (0); 1398256072Sneel} 1399256072Sneel 1400284899Sneelint 1401270159Sgrehanuaudio_chan_set_param_blocksize(struct uaudio_chan *ch, uint32_t blocksize) 1402256072Sneel{ 1403268976Sjhb uaudio_chan_set_param_fragments(ch, blocksize, 0 - 1); 1404270159Sgrehan 1405256072Sneel return (ch->block_size); 1406276349Sneel} 1407276349Sneel 1408256072Sneelint 1409276403Sneeluaudio_chan_set_param_fragments(struct uaudio_chan *ch, uint32_t blocksize, 1410284899Sneel uint32_t blockcount) 1411284900Sneel{ 1412276403Sneel /* we only support one size */ 1413276403Sneel blocksize = ch->intr_size; 1414276403Sneel blockcount = 2; 1415276403Sneel 1416284900Sneel if ((sndbuf_getblksz(ch->pcm_buf) != blocksize) || 1417276403Sneel (sndbuf_getblkcnt(ch->pcm_buf) != blockcount)) { 1418284900Sneel DPRINTFN(1, "resizing to %u x " 1419284900Sneel "%u bytes\n", blockcount, blocksize); 1420256072Sneel if (sndbuf_resize(ch->pcm_buf, blockcount, blocksize)) { 1421284900Sneel DPRINTFN(0, "failed to resize sound buffer, count=%u, " 1422284900Sneel "size=%u\n", blockcount, blocksize); 1423284900Sneel } 1424284900Sneel } 1425284900Sneel ch->block_size = sndbuf_getblksz(ch->pcm_buf); 1426284900Sneel 1427256072Sneel return (1); 1428276403Sneel} 1429284900Sneel 1430276403Sneelint 1431284900Sneeluaudio_chan_set_param_speed(struct uaudio_chan *ch, uint32_t speed) 1432284900Sneel{ 1433284900Sneel if (speed != ch->sample_rate) { 1434284900Sneel DPRINTF("rate conversion required\n"); 1435276403Sneel } 1436261088Sjhb return (ch->sample_rate); 1437261088Sjhb} 1438261088Sjhb 1439261088Sjhbint 1440261088Sjhbuaudio_chan_getptr(struct uaudio_chan *ch) 1441261088Sjhb{ 1442261088Sjhb return (ch->cur - ch->start); 1443261088Sjhb} 1444261088Sjhb 1445261088Sjhbstruct pcmchan_caps * 1446261088Sjhbuaudio_chan_getcaps(struct uaudio_chan *ch) 1447262350Sjhb{ 1448256072Sneel return (&ch->pcm_cap); 1449256072Sneel} 1450256072Sneel 1451270159Sgrehanint 1452270159Sgrehanuaudio_chan_set_param_format(struct uaudio_chan *ch, uint32_t format) 1453256072Sneel{ 1454256072Sneel ch->format = format; 1455256072Sneel return (0); 1456256072Sneel} 1457268935Sjhb 1458268935Sjhbint 1459268935Sjhbuaudio_chan_start(struct uaudio_chan *ch) 1460268935Sjhb{ 1461268935Sjhb ch->cur = ch->start; 1462268935Sjhb 1463268935Sjhb#if (UAUDIO_NCHANBUFS != 2) 1464268935Sjhb#error "please update code" 1465268935Sjhb#endif 1466268935Sjhb if (ch->xfer[0]) { 1467268935Sjhb usb2_transfer_start(ch->xfer[0]); 1468268935Sjhb } 1469268935Sjhb if (ch->xfer[1]) { 1470268935Sjhb usb2_transfer_start(ch->xfer[1]); 1471268935Sjhb } 1472268935Sjhb return (0); 1473268935Sjhb} 1474268935Sjhb 1475268935Sjhbint 1476268935Sjhbuaudio_chan_stop(struct uaudio_chan *ch) 1477268935Sjhb{ 1478268935Sjhb#if (UAUDIO_NCHANBUFS != 2) 1479268935Sjhb#error "please update code" 1480268935Sjhb#endif 1481268935Sjhb usb2_transfer_stop(ch->xfer[0]); 1482268935Sjhb usb2_transfer_stop(ch->xfer[1]); 1483268935Sjhb return (0); 1484284900Sneel} 1485268935Sjhb 1486284900Sneel/*========================================================================* 1487268935Sjhb * AC - Audio Controller - routines 1488268935Sjhb *========================================================================*/ 1489268935Sjhb 1490268935Sjhbstatic void 1491268935Sjhbuaudio_mixer_add_ctl_sub(struct uaudio_softc *sc, struct uaudio_mixer_node *mc) 1492268935Sjhb{ 1493268935Sjhb struct uaudio_mixer_node *p_mc_new = 1494268935Sjhb malloc(sizeof(*p_mc_new), M_USBDEV, M_WAITOK); 1495268935Sjhb 1496268935Sjhb if (p_mc_new) { 1497268935Sjhb bcopy(mc, p_mc_new, sizeof(*p_mc_new)); 1498268935Sjhb p_mc_new->next = sc->sc_mixer_root; 1499268935Sjhb sc->sc_mixer_root = p_mc_new; 1500268935Sjhb sc->sc_mixer_count++; 1501268935Sjhb } else { 1502268935Sjhb DPRINTF("out of memory\n"); 1503268935Sjhb } 1504268935Sjhb} 1505268935Sjhb 1506268935Sjhbstatic void 1507268935Sjhbuaudio_mixer_add_ctl(struct uaudio_softc *sc, struct uaudio_mixer_node *mc) 1508268935Sjhb{ 1509284900Sneel int32_t res; 1510284900Sneel 1511284900Sneel if (mc->class < UAC_NCLASSES) { 1512284900Sneel DPRINTF("adding %s.%d\n", 1513284900Sneel uac_names[mc->class], mc->ctl); 1514284900Sneel } else { 1515284900Sneel DPRINTF("adding %d\n", mc->ctl); 1516284900Sneel } 1517284900Sneel 1518284900Sneel mc->delta = 0; 1519284900Sneel if (mc->type == MIX_ON_OFF) { 1520284900Sneel mc->minval = 0; 1521284900Sneel mc->maxval = 1; 1522221828Sgrehan } else if (mc->type == MIX_SELECTOR) { 1523268935Sjhb 1524268935Sjhb } else { 1525268935Sjhb 1526268935Sjhb /* determine min and max values */ 1527268935Sjhb 1528268935Sjhb mc->minval = uaudio_mixer_get(sc->sc_udev, GET_MIN, mc); 1529268935Sjhb 1530268935Sjhb mc->minval = uaudio_mixer_signext(mc->type, mc->minval); 1531268935Sjhb 1532268935Sjhb mc->maxval = uaudio_mixer_get(sc->sc_udev, GET_MAX, mc); 1533268935Sjhb 1534268935Sjhb mc->maxval = 1 + uaudio_mixer_signext(mc->type, mc->maxval); 1535268935Sjhb 1536268935Sjhb mc->mul = mc->maxval - mc->minval; 1537268935Sjhb if (mc->mul == 0) { 1538268935Sjhb mc->mul = 1; 1539268935Sjhb } 1540268935Sjhb res = uaudio_mixer_get(sc->sc_udev, GET_RES, mc); 1541268935Sjhb if (res > 0) { 1542268935Sjhb mc->delta = ((res * 255) + (mc->mul / 2)) / mc->mul; 1543268935Sjhb } 1544268935Sjhb } 1545268935Sjhb 1546268935Sjhb if (mc->maxval < mc->minval) { 1547268935Sjhb mc->maxval = mc->minval; 1548268935Sjhb } 1549268935Sjhb uaudio_mixer_add_ctl_sub(sc, mc); 1550268935Sjhb 1551268935Sjhb#if USB_DEBUG 1552268935Sjhb if (uaudio_debug > 2) { 1553268935Sjhb uint8_t i; 1554268935Sjhb 1555268935Sjhb for (i = 0; i < mc->nchan; i++) { 1556268935Sjhb DPRINTF("[mix] wValue=%04x\n", mc->wValue[0]); 1557268935Sjhb } 1558268935Sjhb DPRINTF("[mix] wIndex=%04x type=%d ctl='%d' " 1559268935Sjhb "min=%d max=%d\n", 1560268935Sjhb mc->wIndex, mc->type, mc->ctl, 1561268935Sjhb mc->minval, mc->maxval); 1562268935Sjhb } 1563268935Sjhb#endif 1564270074Sgrehan} 1565270074Sgrehan 1566270074Sgrehanstatic void 1567270074Sgrehanuaudio_mixer_add_input(struct uaudio_softc *sc, 1568270074Sgrehan const struct uaudio_terminal_node *iot, int id) 1569270074Sgrehan{ 1570270074Sgrehan#if USB_DEBUG 1571270074Sgrehan const struct usb2_audio_input_terminal *d = iot[id].u.it; 1572270074Sgrehan 1573270074Sgrehan DPRINTFN(3, "bTerminalId=%d wTerminalType=0x%04x " 1574270074Sgrehan "bAssocTerminal=%d bNrChannels=%d wChannelConfig=%d " 1575270074Sgrehan "iChannelNames=%d\n", 1576270074Sgrehan d->bTerminalId, UGETW(d->wTerminalType), d->bAssocTerminal, 1577270074Sgrehan d->bNrChannels, UGETW(d->wChannelConfig), 1578270074Sgrehan d->iChannelNames); 1579284900Sneel#endif 1580284900Sneel} 1581284900Sneel 1582284900Sneelstatic void 1583284900Sneeluaudio_mixer_add_output(struct uaudio_softc *sc, 1584284900Sneel const struct uaudio_terminal_node *iot, int id) 1585284900Sneel{ 1586284900Sneel#if USB_DEBUG 1587284900Sneel const struct usb2_audio_output_terminal *d = iot[id].u.ot; 1588284900Sneel 1589284900Sneel DPRINTFN(3, "bTerminalId=%d wTerminalType=0x%04x " 1590284900Sneel "bAssocTerminal=%d bSourceId=%d iTerminal=%d\n", 1591270074Sgrehan d->bTerminalId, UGETW(d->wTerminalType), d->bAssocTerminal, 1592270074Sgrehan d->bSourceId, d->iTerminal); 1593270074Sgrehan#endif 1594270074Sgrehan} 1595270074Sgrehan 1596270074Sgrehanstatic void 1597270074Sgrehanuaudio_mixer_add_mixer(struct uaudio_softc *sc, 1598270074Sgrehan const struct uaudio_terminal_node *iot, int id) 1599270074Sgrehan{ 1600270074Sgrehan struct uaudio_mixer_node mix; 1601270074Sgrehan 1602268935Sjhb const struct usb2_audio_mixer_unit_0 *d0 = iot[id].u.mu; 1603221828Sgrehan const struct usb2_audio_mixer_unit_1 *d1; 1604221828Sgrehan 1605284900Sneel uint32_t bno; /* bit number */ 1606256072Sneel uint32_t p; /* bit number accumulator */ 1607221828Sgrehan uint32_t mo; /* matching outputs */ 1608221828Sgrehan uint32_t mc; /* matching channels */ 1609284894Sneel uint32_t ichs; /* input channels */ 1610242065Sneel uint32_t ochs; /* output channels */ 1611262350Sjhb uint32_t c; 1612256072Sneel uint32_t chs; /* channels */ 1613221828Sgrehan uint32_t i; 1614221828Sgrehan uint32_t o; 1615221828Sgrehan 1616221828Sgrehan DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n", 1617221828Sgrehan d0->bUnitId, d0->bNrInPins); 1618221828Sgrehan 1619270070Sgrehan /* compute the number of input channels */ 1620270070Sgrehan 1621270070Sgrehan ichs = 0; 1622270070Sgrehan for (i = 0; i < d0->bNrInPins; i++) { 1623270070Sgrehan ichs += (uaudio_mixer_get_cluster(d0->baSourceId[i], iot) 1624270070Sgrehan .bNrChannels); 1625256072Sneel } 1626221828Sgrehan 1627256072Sneel d1 = (const void *)(d0->baSourceId + d0->bNrInPins); 1628284900Sneel 1629284900Sneel /* and the number of output channels */ 1630284900Sneel 1631242065Sneel ochs = d1->bNrChannels; 1632221828Sgrehan 1633221828Sgrehan DPRINTFN(3, "ichs=%d ochs=%d\n", ichs, ochs); 1634256072Sneel 1635256072Sneel bzero(&mix, sizeof(mix)); 1636256072Sneel 1637221828Sgrehan mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 1638221828Sgrehan uaudio_mixer_determine_class(&iot[id], &mix); 1639221828Sgrehan mix.type = MIX_SIGNED_16; 1640221914Sjhb 1641221828Sgrehan if (uaudio_mixer_verify_desc(d0, ((ichs * ochs) + 7) / 8) == NULL) { 1642221828Sgrehan return; 1643241489Sneel } 1644256072Sneel for (p = i = 0; i < d0->bNrInPins; i++) { 1645284900Sneel chs = uaudio_mixer_get_cluster(d0->baSourceId[i], iot).bNrChannels; 1646256072Sneel mc = 0; 1647241489Sneel for (c = 0; c < chs; c++) { 1648221828Sgrehan mo = 0; 1649221828Sgrehan for (o = 0; o < ochs; o++) { 1650221828Sgrehan bno = ((p + c) * ochs) + o; 1651221828Sgrehan if (BIT_TEST(d1->bmControls, bno)) { 1652221828Sgrehan mo++; 1653221828Sgrehan } 1654256072Sneel } 1655262350Sjhb if (mo == 1) { 1656284894Sneel mc++; 1657256072Sneel } 1658284900Sneel } 1659284900Sneel if ((mc == chs) && (chs <= MIX_MAX_CHAN)) { 1660284900Sneel 1661268935Sjhb /* repeat bit-scan */ 1662268935Sjhb 1663268935Sjhb mc = 0; 1664266339Sjhb for (c = 0; c < chs; c++) { 1665266339Sjhb for (o = 0; o < ochs; o++) { 1666266339Sjhb bno = ((p + c) * ochs) + o; 1667266339Sjhb if (BIT_TEST(d1->bmControls, bno)) { 1668266339Sjhb mix.wValue[mc++] = MAKE_WORD(p + c + 1, o + 1); 1669266339Sjhb } 1670266339Sjhb } 1671266339Sjhb } 1672256072Sneel mix.nchan = chs; 1673262350Sjhb uaudio_mixer_add_ctl(sc, &mix); 1674262350Sjhb } else { 1675256072Sneel /* XXX */ 1676256072Sneel } 1677256072Sneel p += chs; 1678256072Sneel } 1679256072Sneel} 1680256072Sneel 1681256072Sneelstatic void 1682268976Sjhbuaudio_mixer_add_selector(struct uaudio_softc *sc, 1683268976Sjhb const struct uaudio_terminal_node *iot, int id) 1684268976Sjhb{ 1685268976Sjhb const struct usb2_audio_selector_unit *d = iot[id].u.su; 1686276349Sneel struct uaudio_mixer_node mix; 1687276349Sneel uint16_t i; 1688276349Sneel 1689276349Sneel DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n", 1690256072Sneel d->bUnitId, d->bNrInPins); 1691262350Sjhb 1692256072Sneel if (d->bNrInPins == 0) { 1693242065Sneel return; 1694256072Sneel } 1695242065Sneel bzero(&mix, sizeof(mix)); 1696284894Sneel 1697242065Sneel mix.wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no); 1698242065Sneel mix.wValue[0] = MAKE_WORD(0, 0); 1699284900Sneel uaudio_mixer_determine_class(&iot[id], &mix); 1700284900Sneel mix.nchan = 1; 1701256072Sneel mix.type = MIX_SELECTOR; 1702256072Sneel 1703221828Sgrehan mix.ctl = SOUND_MIXER_NRDEVICES; 1704221828Sgrehan mix.minval = 1; 1705221828Sgrehan mix.maxval = d->bNrInPins; 1706221828Sgrehan 1707284894Sneel if (mix.maxval > MAX_SELECTOR_INPUT_PIN) { 1708284894Sneel mix.maxval = MAX_SELECTOR_INPUT_PIN; 1709284894Sneel } 1710284894Sneel mix.mul = (mix.maxval - mix.minval); 1711284894Sneel for (i = 0; i < MAX_SELECTOR_INPUT_PIN; i++) { 1712284894Sneel mix.slctrtype[i] = SOUND_MIXER_NRDEVICES; 1713284894Sneel } 1714284894Sneel 1715284894Sneel for (i = 0; i < mix.maxval; i++) { 1716284894Sneel mix.slctrtype[i] = uaudio_mixer_feature_name 1717284894Sneel (&iot[d->baSourceId[i]], &mix); 1718284894Sneel } 1719284894Sneel 1720284894Sneel mix.class = 0; /* not used */ 1721284894Sneel 1722284894Sneel uaudio_mixer_add_ctl(sc, &mix); 1723284894Sneel} 1724284894Sneel 1725284894Sneelstatic uint32_t 1726284894Sneeluaudio_mixer_feature_get_bmaControls(const struct usb2_audio_feature_unit *d, 1727284894Sneel uint8_t index) 1728284894Sneel{ 1729284894Sneel uint32_t temp = 0; 1730284894Sneel uint32_t offset = (index * d->bControlSize); 1731284894Sneel 1732284894Sneel if (d->bControlSize > 0) { 1733284894Sneel temp |= d->bmaControls[offset]; 1734284894Sneel if (d->bControlSize > 1) { 1735284894Sneel temp |= d->bmaControls[offset + 1] << 8; 1736284894Sneel if (d->bControlSize > 2) { 1737284894Sneel temp |= d->bmaControls[offset + 2] << 16; 1738284894Sneel if (d->bControlSize > 3) { 1739284894Sneel temp |= d->bmaControls[offset + 3] << 24; 1740284894Sneel } 1741284894Sneel } 1742284894Sneel } 1743284894Sneel } 1744284894Sneel return (temp); 1745284894Sneel} 1746284894Sneel 1747284894Sneelstatic void 1748284894Sneeluaudio_mixer_add_feature(struct uaudio_softc *sc, 1749284894Sneel const struct uaudio_terminal_node *iot, int id) 1750270159Sgrehan{ 1751270159Sgrehan const struct usb2_audio_feature_unit *d = iot[id].u.fu; 1752270159Sgrehan struct uaudio_mixer_node mix; 1753270159Sgrehan uint32_t fumask; 1754270159Sgrehan uint32_t mmask; 1755270159Sgrehan uint32_t cmask; 1756270159Sgrehan uint16_t mixernumber; 1757270159Sgrehan uint8_t nchan; 1758270159Sgrehan uint8_t chan; 1759270159Sgrehan uint8_t ctl; 1760270159Sgrehan uint8_t i; 1761270159Sgrehan 1762270159Sgrehan if (d->bControlSize == 0) { 1763270159Sgrehan return; 1764270159Sgrehan } 1765270159Sgrehan bzero(&mix, sizeof(mix)); 1766270159Sgrehan 1767270159Sgrehan nchan = (d->bLength - 7) / d->bControlSize; 1768270159Sgrehan mmask = uaudio_mixer_feature_get_bmaControls(d, 0); 1769270159Sgrehan cmask = 0; 1770270159Sgrehan 1771270159Sgrehan if (nchan == 0) { 1772270159Sgrehan return; 1773270159Sgrehan } 1774270159Sgrehan /* figure out what we can control */ 1775270159Sgrehan 1776270159Sgrehan for (chan = 1; chan < nchan; chan++) { 1777270159Sgrehan DPRINTFN(10, "chan=%d mask=%x\n", 1778270159Sgrehan chan, uaudio_mixer_feature_get_bmaControls(d, chan)); 1779270159Sgrehan 1780270159Sgrehan cmask |= uaudio_mixer_feature_get_bmaControls(d, chan); 1781270159Sgrehan } 1782270159Sgrehan 1783270159Sgrehan if (nchan > MIX_MAX_CHAN) { 1784270159Sgrehan nchan = MIX_MAX_CHAN; 1785270159Sgrehan } 1786270159Sgrehan mix.wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no); 1787270159Sgrehan 1788270159Sgrehan for (ctl = 1; ctl <= LOUDNESS_CONTROL; ctl++) { 1789270159Sgrehan 1790270159Sgrehan fumask = FU_MASK(ctl); 1791270159Sgrehan 1792270159Sgrehan DPRINTFN(5, "ctl=%d fumask=0x%04x\n", 1793270159Sgrehan ctl, fumask); 1794270159Sgrehan 1795270159Sgrehan if (mmask & fumask) { 1796270159Sgrehan mix.nchan = 1; 1797270159Sgrehan mix.wValue[0] = MAKE_WORD(ctl, 0); 1798270159Sgrehan } else if (cmask & fumask) { 1799270159Sgrehan mix.nchan = nchan - 1; 1800270159Sgrehan for (i = 1; i < nchan; i++) { 1801270159Sgrehan if (uaudio_mixer_feature_get_bmaControls(d, i) & fumask) 1802270159Sgrehan mix.wValue[i - 1] = MAKE_WORD(ctl, i); 1803270159Sgrehan else 1804270159Sgrehan mix.wValue[i - 1] = -1; 1805270159Sgrehan } 1806270159Sgrehan } else { 1807270159Sgrehan continue; 1808270159Sgrehan } 1809270159Sgrehan 1810270159Sgrehan mixernumber = uaudio_mixer_feature_name(&iot[id], &mix); 1811270159Sgrehan 1812270159Sgrehan switch (ctl) { 1813270159Sgrehan case MUTE_CONTROL: 1814270159Sgrehan mix.type = MIX_ON_OFF; 1815270159Sgrehan mix.ctl = SOUND_MIXER_NRDEVICES; 1816270159Sgrehan break; 1817270159Sgrehan 1818270159Sgrehan case VOLUME_CONTROL: 1819270159Sgrehan mix.type = MIX_SIGNED_16; 1820270159Sgrehan mix.ctl = mixernumber; 1821270159Sgrehan break; 1822270159Sgrehan 1823270159Sgrehan case BASS_CONTROL: 1824270159Sgrehan mix.type = MIX_SIGNED_8; 1825270159Sgrehan mix.ctl = SOUND_MIXER_BASS; 1826270159Sgrehan break; 1827270159Sgrehan 1828270159Sgrehan case MID_CONTROL: 1829270159Sgrehan mix.type = MIX_SIGNED_8; 1830270159Sgrehan mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 1831270159Sgrehan break; 1832270159Sgrehan 1833270159Sgrehan case TREBLE_CONTROL: 1834270159Sgrehan mix.type = MIX_SIGNED_8; 1835270159Sgrehan mix.ctl = SOUND_MIXER_TREBLE; 1836270159Sgrehan break; 1837270159Sgrehan 1838270159Sgrehan case GRAPHIC_EQUALIZER_CONTROL: 1839270159Sgrehan continue; /* XXX don't add anything */ 1840270159Sgrehan break; 1841270159Sgrehan 1842270159Sgrehan case AGC_CONTROL: 1843270159Sgrehan mix.type = MIX_ON_OFF; 1844270159Sgrehan mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 1845270159Sgrehan break; 1846270159Sgrehan 1847270159Sgrehan case DELAY_CONTROL: 1848270159Sgrehan mix.type = MIX_UNSIGNED_16; 1849270159Sgrehan mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 1850270159Sgrehan break; 1851270159Sgrehan 1852270159Sgrehan case BASS_BOOST_CONTROL: 1853270159Sgrehan mix.type = MIX_ON_OFF; 1854270159Sgrehan mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 1855270159Sgrehan break; 1856270159Sgrehan 1857270159Sgrehan case LOUDNESS_CONTROL: 1858270159Sgrehan mix.type = MIX_ON_OFF; 1859270159Sgrehan mix.ctl = SOUND_MIXER_LOUD; /* Is this correct ? */ 1860270159Sgrehan break; 1861270159Sgrehan 1862270159Sgrehan default: 1863270159Sgrehan mix.type = MIX_UNKNOWN; 1864270159Sgrehan break; 1865270159Sgrehan } 1866270159Sgrehan 1867270159Sgrehan if (mix.type != MIX_UNKNOWN) { 1868270159Sgrehan uaudio_mixer_add_ctl(sc, &mix); 1869270159Sgrehan } 1870270159Sgrehan } 1871270159Sgrehan} 1872270159Sgrehan 1873270159Sgrehanstatic void 1874270159Sgrehanuaudio_mixer_add_processing_updown(struct uaudio_softc *sc, 1875270159Sgrehan const struct uaudio_terminal_node *iot, int id) 1876270159Sgrehan{ 1877270159Sgrehan const struct usb2_audio_processing_unit_0 *d0 = iot[id].u.pu; 1878270159Sgrehan const struct usb2_audio_processing_unit_1 *d1 = 1879284894Sneel (const void *)(d0->baSourceId + d0->bNrInPins); 1880270159Sgrehan const struct usb2_audio_processing_unit_updown *ud = 1881284894Sneel (const void *)(d1->bmControls + d1->bControlSize); 1882270159Sgrehan struct uaudio_mixer_node mix; 1883284894Sneel uint8_t i; 1884270159Sgrehan 1885270159Sgrehan if (uaudio_mixer_verify_desc(d0, sizeof(*ud)) == NULL) { 1886270159Sgrehan return; 1887270159Sgrehan } 1888270159Sgrehan if (uaudio_mixer_verify_desc(d0, sizeof(*ud) + (2 * ud->bNrModes)) 1889270159Sgrehan == NULL) { 1890270159Sgrehan return; 1891270159Sgrehan } 1892270159Sgrehan DPRINTFN(3, "bUnitId=%d bNrModes=%d\n", 1893270159Sgrehan d0->bUnitId, ud->bNrModes); 1894270159Sgrehan 1895270159Sgrehan if (!(d1->bmControls[0] & UA_PROC_MASK(UD_MODE_SELECT_CONTROL))) { 1896270159Sgrehan DPRINTF("no mode select\n"); 1897270159Sgrehan return; 1898270159Sgrehan } 1899270159Sgrehan bzero(&mix, sizeof(mix)); 1900270159Sgrehan 1901270159Sgrehan mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 1902270159Sgrehan mix.nchan = 1; 1903270159Sgrehan mix.wValue[0] = MAKE_WORD(UD_MODE_SELECT_CONTROL, 0); 1904270159Sgrehan uaudio_mixer_determine_class(&iot[id], &mix); 1905270159Sgrehan mix.type = MIX_ON_OFF; /* XXX */ 1906270159Sgrehan 1907270159Sgrehan for (i = 0; i < ud->bNrModes; i++) { 1908284894Sneel DPRINTFN(3, "i=%d bm=0x%x\n", i, UGETW(ud->waModes[i])); 1909270159Sgrehan /* XXX */ 1910270159Sgrehan } 1911270159Sgrehan 1912270159Sgrehan uaudio_mixer_add_ctl(sc, &mix); 1913270159Sgrehan} 1914270159Sgrehan 1915270159Sgrehanstatic void 1916270159Sgrehanuaudio_mixer_add_processing(struct uaudio_softc *sc, 1917270159Sgrehan const struct uaudio_terminal_node *iot, int id) 1918270159Sgrehan{ 1919270159Sgrehan const struct usb2_audio_processing_unit_0 *d0 = iot[id].u.pu; 1920270159Sgrehan const struct usb2_audio_processing_unit_1 *d1 = 1921270159Sgrehan (const void *)(d0->baSourceId + d0->bNrInPins); 1922270159Sgrehan struct uaudio_mixer_node mix; 1923270159Sgrehan uint16_t ptype; 1924270159Sgrehan 1925270159Sgrehan bzero(&mix, sizeof(mix)); 1926270159Sgrehan 1927270159Sgrehan ptype = UGETW(d0->wProcessType); 1928270159Sgrehan 1929270159Sgrehan DPRINTFN(3, "wProcessType=%d bUnitId=%d " 1930270159Sgrehan "bNrInPins=%d\n", ptype, d0->bUnitId, d0->bNrInPins); 1931270159Sgrehan 1932270159Sgrehan if (d1->bControlSize == 0) { 1933270159Sgrehan return; 1934270159Sgrehan } 1935270159Sgrehan if (d1->bmControls[0] & UA_PROC_ENABLE_MASK) { 1936270159Sgrehan mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 1937270159Sgrehan mix.nchan = 1; 1938270159Sgrehan mix.wValue[0] = MAKE_WORD(XX_ENABLE_CONTROL, 0); 1939270159Sgrehan uaudio_mixer_determine_class(&iot[id], &mix); 1940270159Sgrehan mix.type = MIX_ON_OFF; 1941270159Sgrehan uaudio_mixer_add_ctl(sc, &mix); 1942270159Sgrehan } 1943270159Sgrehan switch (ptype) { 1944270159Sgrehan case UPDOWNMIX_PROCESS: 1945270159Sgrehan uaudio_mixer_add_processing_updown(sc, iot, id); 1946284894Sneel break; 1947284894Sneel 1948221828Sgrehan case DOLBY_PROLOGIC_PROCESS: 1949267427Sjhb case P3D_STEREO_EXTENDER_PROCESS: 1950284900Sneel case REVERBATION_PROCESS: 1951284894Sneel case CHORUS_PROCESS: 1952267427Sjhb case DYN_RANGE_COMP_PROCESS: 1953221828Sgrehan default: 1954221828Sgrehan DPRINTF("unit %d, type=%d is not implemented\n", 1955221828Sgrehan d0->bUnitId, ptype); 1956284894Sneel break; 1957221828Sgrehan } 1958221828Sgrehan} 1959270159Sgrehan 1960270159Sgrehanstatic void 1961270159Sgrehanuaudio_mixer_add_extension(struct uaudio_softc *sc, 1962270159Sgrehan const struct uaudio_terminal_node *iot, int id) 1963270159Sgrehan{ 1964284894Sneel const struct usb2_audio_extension_unit_0 *d0 = iot[id].u.eu; 1965270159Sgrehan const struct usb2_audio_extension_unit_1 *d1 = 1966270159Sgrehan (const void *)(d0->baSourceId + d0->bNrInPins); 1967267427Sjhb struct uaudio_mixer_node mix; 1968221828Sgrehan 1969267427Sjhb DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n", 1970267427Sjhb d0->bUnitId, d0->bNrInPins); 1971284894Sneel 1972267427Sjhb if (sc->sc_uq_au_no_xu) { 1973267427Sjhb return; 1974267427Sjhb } 1975284900Sneel if (d1->bControlSize == 0) { 1976284900Sneel return; 1977284900Sneel } 1978284900Sneel if (d1->bmControls[0] & UA_EXT_ENABLE_MASK) { 1979284900Sneel 1980284900Sneel bzero(&mix, sizeof(mix)); 1981284900Sneel 1982284900Sneel mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 1983284900Sneel mix.nchan = 1; 1984284900Sneel mix.wValue[0] = MAKE_WORD(UA_EXT_ENABLE, 0); 1985284894Sneel uaudio_mixer_determine_class(&iot[id], &mix); 1986284894Sneel mix.type = MIX_ON_OFF; 1987284894Sneel 1988284894Sneel uaudio_mixer_add_ctl(sc, &mix); 1989284894Sneel } 1990284894Sneel} 1991284894Sneel 1992284894Sneelstatic const void * 1993284894Sneeluaudio_mixer_verify_desc(const void *arg, uint32_t len) 1994284894Sneel{ 1995284894Sneel const struct usb2_audio_mixer_unit_1 *d1; 1996284894Sneel const struct usb2_audio_extension_unit_1 *e1; 1997284894Sneel const struct usb2_audio_processing_unit_1 *u1; 1998267427Sjhb 1999284894Sneel union { 2000284894Sneel const struct usb2_descriptor *desc; 2001284894Sneel const struct usb2_audio_input_terminal *it; 2002284894Sneel const struct usb2_audio_output_terminal *ot; 2003267427Sjhb const struct usb2_audio_mixer_unit_0 *mu; 2004221828Sgrehan const struct usb2_audio_selector_unit *su; 2005221828Sgrehan const struct usb2_audio_feature_unit *fu; 2006270159Sgrehan const struct usb2_audio_processing_unit_0 *pu; 2007270159Sgrehan const struct usb2_audio_extension_unit_0 *eu; 2008270159Sgrehan } u; 2009267427Sjhb 2010270159Sgrehan u.desc = arg; 2011284894Sneel 2012267427Sjhb if (u.desc == NULL) { 2013270159Sgrehan goto error; 2014284894Sneel } 2015270159Sgrehan if (u.desc->bDescriptorType != UDESC_CS_INTERFACE) { 2016284894Sneel goto error; 2017284894Sneel } 2018267427Sjhb switch (u.desc->bDescriptorSubtype) { 2019267427Sjhb case UDESCSUB_AC_INPUT: 2020267427Sjhb len += sizeof(*u.it); 2021267427Sjhb break; 2022270159Sgrehan 2023268976Sjhb case UDESCSUB_AC_OUTPUT: 2024270159Sgrehan len += sizeof(*u.ot); 2025268976Sjhb break; 2026268976Sjhb 2027270159Sgrehan case UDESCSUB_AC_MIXER: 2028268976Sjhb len += sizeof(*u.mu); 2029268976Sjhb 2030268976Sjhb if (u.desc->bLength < len) { 2031268976Sjhb goto error; 2032268976Sjhb } 2033268976Sjhb len += u.mu->bNrInPins; 2034270159Sgrehan 2035268976Sjhb if (u.desc->bLength < len) { 2036268976Sjhb goto error; 2037248389Sneel } 2038241982Sneel d1 = (const void *)(u.mu->baSourceId + u.mu->bNrInPins); 2039221828Sgrehan 2040241982Sneel len += sizeof(*d1); 2041221828Sgrehan break; 2042241982Sneel 2043221828Sgrehan case UDESCSUB_AC_SELECTOR: 2044241982Sneel len += sizeof(*u.su); 2045221828Sgrehan 2046221828Sgrehan if (u.desc->bLength < len) { 2047241982Sneel goto error; 2048241982Sneel } 2049241982Sneel len += u.su->bNrInPins; 2050266339Sjhb break; 2051241982Sneel 2052221828Sgrehan case UDESCSUB_AC_FEATURE: 2053221828Sgrehan len += (sizeof(*u.fu) + 1); 2054221828Sgrehan break; 2055241982Sneel 2056241982Sneel case UDESCSUB_AC_PROCESSING: 2057241982Sneel len += sizeof(*u.pu); 2058241982Sneel 2059241982Sneel if (u.desc->bLength < len) { 2060241982Sneel goto error; 2061241982Sneel } 2062241982Sneel len += u.pu->bNrInPins; 2063241982Sneel 2064241982Sneel if (u.desc->bLength < len) { 2065241982Sneel goto error; 2066241982Sneel } 2067241982Sneel u1 = (const void *)(u.pu->baSourceId + u.pu->bNrInPins); 2068241982Sneel 2069241982Sneel len += sizeof(*u1); 2070241982Sneel 2071241982Sneel if (u.desc->bLength < len) { 2072241982Sneel goto error; 2073241982Sneel } 2074241982Sneel len += u1->bControlSize; 2075241982Sneel 2076241982Sneel break; 2077241982Sneel 2078241982Sneel case UDESCSUB_AC_EXTENSION: 2079241982Sneel len += sizeof(*u.eu); 2080241982Sneel 2081241982Sneel if (u.desc->bLength < len) { 2082241982Sneel goto error; 2083241982Sneel } 2084268891Sjhb len += u.eu->bNrInPins; 2085268891Sjhb 2086241982Sneel if (u.desc->bLength < len) { 2087268891Sjhb goto error; 2088268891Sjhb } 2089268891Sjhb e1 = (const void *)(u.eu->baSourceId + u.eu->bNrInPins); 2090268891Sjhb 2091268891Sjhb len += sizeof(*e1); 2092268891Sjhb 2093268891Sjhb if (u.desc->bLength < len) { 2094268891Sjhb goto error; 2095268891Sjhb } 2096268891Sjhb len += e1->bControlSize; 2097268891Sjhb break; 2098268891Sjhb 2099268891Sjhb default: 2100268891Sjhb goto error; 2101268891Sjhb } 2102268891Sjhb 2103268891Sjhb if (u.desc->bLength < len) { 2104268891Sjhb goto error; 2105268891Sjhb } 2106268891Sjhb return (u.desc); 2107268891Sjhb 2108268891Sjhberror: 2109268891Sjhb if (u.desc) { 2110268891Sjhb DPRINTF("invalid descriptor, type=%d, " 2111268891Sjhb "sub_type=%d, len=%d of %d bytes\n", 2112268891Sjhb u.desc->bDescriptorType, 2113268891Sjhb u.desc->bDescriptorSubtype, 2114268891Sjhb u.desc->bLength, len); 2115268891Sjhb } 2116268891Sjhb return (NULL); 2117268891Sjhb} 2118268891Sjhb 2119268891Sjhb#if USB_DEBUG 2120268891Sjhbstatic void 2121268891Sjhbuaudio_mixer_dump_cluster(uint8_t id, const struct uaudio_terminal_node *iot) 2122268891Sjhb{ 2123268891Sjhb static const char *channel_names[16] = { 2124268891Sjhb "LEFT", "RIGHT", "CENTER", "LFE", 2125268891Sjhb "LEFT_SURROUND", "RIGHT_SURROUND", "LEFT_CENTER", "RIGHT_CENTER", 2126268891Sjhb "SURROUND", "LEFT_SIDE", "RIGHT_SIDE", "TOP", 2127268891Sjhb "RESERVED12", "RESERVED13", "RESERVED14", "RESERVED15", 2128268891Sjhb }; 2129268891Sjhb uint16_t cc; 2130268891Sjhb uint8_t i; 2131268891Sjhb const struct usb2_audio_cluster cl = uaudio_mixer_get_cluster(id, iot); 2132221828Sgrehan 2133221828Sgrehan cc = UGETW(cl.wChannelConfig); 2134221828Sgrehan 2135221828Sgrehan DPRINTF("cluster: bNrChannels=%u iChannelNames=%u wChannelConfig=" 2136221828Sgrehan "0x%04x:\n", cl.iChannelNames, cl.bNrChannels, cc); 2137221828Sgrehan 2138221828Sgrehan for (i = 0; cc; i++) { 2139221828Sgrehan if (cc & 1) { 2140221828Sgrehan DPRINTF(" - %s\n", channel_names[i]); 2141221828Sgrehan } 2142221828Sgrehan cc >>= 1; 2143221828Sgrehan } 2144221828Sgrehan} 2145221828Sgrehan 2146221828Sgrehan#endif 2147221828Sgrehan 2148221828Sgrehanstatic struct usb2_audio_cluster 2149221828Sgrehanuaudio_mixer_get_cluster(uint8_t id, const struct uaudio_terminal_node *iot) 2150221828Sgrehan{ 2151221828Sgrehan struct usb2_audio_cluster r; 2152221828Sgrehan const struct usb2_descriptor *dp; 2153221828Sgrehan uint8_t i; 2154221828Sgrehan 2155221828Sgrehan for (i = 0; i < UAUDIO_RECURSE_LIMIT; i++) { /* avoid infinite loops */ 2156221828Sgrehan dp = iot[id].u.desc; 2157221828Sgrehan if (dp == NULL) { 2158221828Sgrehan goto error; 2159221828Sgrehan } 2160221828Sgrehan switch (dp->bDescriptorSubtype) { 2161261088Sjhb case UDESCSUB_AC_INPUT: 2162261088Sjhb r.bNrChannels = iot[id].u.it->bNrChannels; 2163261088Sjhb r.wChannelConfig[0] = iot[id].u.it->wChannelConfig[0]; 2164261088Sjhb r.wChannelConfig[1] = iot[id].u.it->wChannelConfig[1]; 2165261088Sjhb r.iChannelNames = iot[id].u.it->iChannelNames; 2166261088Sjhb goto done; 2167261088Sjhb 2168261088Sjhb case UDESCSUB_AC_OUTPUT: 2169261088Sjhb id = iot[id].u.ot->bSourceId; 2170261088Sjhb break; 2171261088Sjhb 2172261088Sjhb case UDESCSUB_AC_MIXER: 2173261088Sjhb r = *(const struct usb2_audio_cluster *) 2174261088Sjhb &iot[id].u.mu->baSourceId[iot[id].u.mu-> 2175221828Sgrehan bNrInPins]; 2176221828Sgrehan goto done; 2177221828Sgrehan 2178246188Sneel case UDESCSUB_AC_SELECTOR: 2179246188Sneel if (iot[id].u.su->bNrInPins > 0) { 2180221828Sgrehan /* XXX This is not really right */ 2181221828Sgrehan id = iot[id].u.su->baSourceId[0]; 2182221828Sgrehan } 2183246188Sneel break; 2184246188Sneel 2185246188Sneel case UDESCSUB_AC_FEATURE: 2186246188Sneel id = iot[id].u.fu->bSourceId; 2187246188Sneel break; 2188246188Sneel 2189246188Sneel case UDESCSUB_AC_PROCESSING: 2190221828Sgrehan r = *((const struct usb2_audio_cluster *) 2191246188Sneel &iot[id].u.pu->baSourceId[iot[id].u.pu-> 2192246188Sneel bNrInPins]); 2193246188Sneel goto done; 2194221828Sgrehan 2195246188Sneel case UDESCSUB_AC_EXTENSION: 2196246188Sneel r = *((const struct usb2_audio_cluster *) 2197246188Sneel &iot[id].u.eu->baSourceId[iot[id].u.eu-> 2198246188Sneel bNrInPins]); 2199246188Sneel goto done; 2200221828Sgrehan 2201246188Sneel default: 2202246188Sneel goto error; 2203246188Sneel } 2204246188Sneel } 2205246188Sneelerror: 2206221828Sgrehan DPRINTF("bad data\n"); 2207246188Sneel bzero(&r, sizeof(r)); 2208246188Sneeldone: 2209221828Sgrehan return (r); 2210246188Sneel} 2211246188Sneel 2212246188Sneel#if USB_DEBUG 2213221828Sgrehan 2214221828Sgrehanstruct uaudio_tt_to_string { 2215221828Sgrehan uint16_t terminal_type; 2216221828Sgrehan const char *desc; 2217221828Sgrehan}; 2218221828Sgrehan 2219221828Sgrehanstatic const struct uaudio_tt_to_string uaudio_tt_to_string[] = { 2220221828Sgrehan 2221221828Sgrehan /* USB terminal types */ 2222221828Sgrehan {UAT_UNDEFINED, "UAT_UNDEFINED"}, 2223221828Sgrehan {UAT_STREAM, "UAT_STREAM"}, 2224241489Sneel {UAT_VENDOR, "UAT_VENDOR"}, 2225266393Sjhb 2226266393Sjhb /* input terminal types */ 2227221828Sgrehan {UATI_UNDEFINED, "UATI_UNDEFINED"}, 2228241489Sneel {UATI_MICROPHONE, "UATI_MICROPHONE"}, 2229221828Sgrehan {UATI_DESKMICROPHONE, "UATI_DESKMICROPHONE"}, 2230221828Sgrehan {UATI_PERSONALMICROPHONE, "UATI_PERSONALMICROPHONE"}, 2231221828Sgrehan {UATI_OMNIMICROPHONE, "UATI_OMNIMICROPHONE"}, 2232221828Sgrehan {UATI_MICROPHONEARRAY, "UATI_MICROPHONEARRAY"}, 2233221828Sgrehan {UATI_PROCMICROPHONEARR, "UATI_PROCMICROPHONEARR"}, 2234221828Sgrehan 2235221828Sgrehan /* output terminal types */ 2236241489Sneel {UATO_UNDEFINED, "UATO_UNDEFINED"}, 2237284900Sneel {UATO_SPEAKER, "UATO_SPEAKER"}, 2238241489Sneel {UATO_HEADPHONES, "UATO_HEADPHONES"}, 2239241489Sneel {UATO_DISPLAYAUDIO, "UATO_DISPLAYAUDIO"}, 2240241489Sneel {UATO_DESKTOPSPEAKER, "UATO_DESKTOPSPEAKER"}, 2241221828Sgrehan {UATO_ROOMSPEAKER, "UATO_ROOMSPEAKER"}, 2242221828Sgrehan {UATO_COMMSPEAKER, "UATO_COMMSPEAKER"}, 2243241489Sneel {UATO_SUBWOOFER, "UATO_SUBWOOFER"}, 2244249879Sgrehan 2245221828Sgrehan /* bidir terminal types */ 2246221828Sgrehan {UATB_UNDEFINED, "UATB_UNDEFINED"}, 2247241489Sneel {UATB_HANDSET, "UATB_HANDSET"}, 2248221828Sgrehan {UATB_HEADSET, "UATB_HEADSET"}, 2249221828Sgrehan {UATB_SPEAKERPHONE, "UATB_SPEAKERPHONE"}, 2250221828Sgrehan {UATB_SPEAKERPHONEESUP, "UATB_SPEAKERPHONEESUP"}, 2251221828Sgrehan {UATB_SPEAKERPHONEECANC, "UATB_SPEAKERPHONEECANC"}, 2252221828Sgrehan 2253221828Sgrehan /* telephony terminal types */ 2254241489Sneel {UATT_UNDEFINED, "UATT_UNDEFINED"}, 2255241489Sneel {UATT_PHONELINE, "UATT_PHONELINE"}, 2256249879Sgrehan {UATT_TELEPHONE, "UATT_TELEPHONE"}, 2257249879Sgrehan {UATT_DOWNLINEPHONE, "UATT_DOWNLINEPHONE"}, 2258241489Sneel 2259221828Sgrehan /* external terminal types */ 2260241489Sneel {UATE_UNDEFINED, "UATE_UNDEFINED"}, 2261221828Sgrehan {UATE_ANALOGCONN, "UATE_ANALOGCONN"}, 2262221828Sgrehan {UATE_LINECONN, "UATE_LINECONN"}, 2263270070Sgrehan {UATE_LEGACYCONN, "UATE_LEGACYCONN"}, 2264221828Sgrehan {UATE_DIGITALAUIFC, "UATE_DIGITALAUIFC"}, 2265221828Sgrehan {UATE_SPDIF, "UATE_SPDIF"}, 2266221828Sgrehan {UATE_1394DA, "UATE_1394DA"}, 2267270070Sgrehan {UATE_1394DV, "UATE_1394DV"}, 2268270070Sgrehan 2269266339Sjhb /* embedded function terminal types */ 2270270070Sgrehan {UATF_UNDEFINED, "UATF_UNDEFINED"}, 2271270070Sgrehan {UATF_CALIBNOISE, "UATF_CALIBNOISE"}, 2272270070Sgrehan {UATF_EQUNOISE, "UATF_EQUNOISE"}, 2273266339Sjhb {UATF_CDPLAYER, "UATF_CDPLAYER"}, 2274266339Sjhb {UATF_DAT, "UATF_DAT"}, 2275270070Sgrehan {UATF_DCC, "UATF_DCC"}, 2276221828Sgrehan {UATF_MINIDISK, "UATF_MINIDISK"}, 2277221828Sgrehan {UATF_ANALOGTAPE, "UATF_ANALOGTAPE"}, 2278223621Sgrehan {UATF_PHONOGRAPH, "UATF_PHONOGRAPH"}, 2279221828Sgrehan {UATF_VCRAUDIO, "UATF_VCRAUDIO"}, 2280221828Sgrehan {UATF_VIDEODISCAUDIO, "UATF_VIDEODISCAUDIO"}, 2281221828Sgrehan {UATF_DVDAUDIO, "UATF_DVDAUDIO"}, 2282221828Sgrehan {UATF_TVTUNERAUDIO, "UATF_TVTUNERAUDIO"}, 2283221828Sgrehan {UATF_SATELLITE, "UATF_SATELLITE"}, 2284221828Sgrehan {UATF_CABLETUNER, "UATF_CABLETUNER"}, 2285270070Sgrehan {UATF_DSS, "UATF_DSS"}, 2286270070Sgrehan {UATF_RADIORECV, "UATF_RADIORECV"}, 2287270070Sgrehan {UATF_RADIOXMIT, "UATF_RADIOXMIT"}, 2288270070Sgrehan {UATF_MULTITRACK, "UATF_MULTITRACK"}, 2289270070Sgrehan {UATF_SYNTHESIZER, "UATF_SYNTHESIZER"}, 2290270070Sgrehan 2291270070Sgrehan /* unknown */ 2292221828Sgrehan {0x0000, "UNKNOWN"}, 2293221828Sgrehan}; 2294221828Sgrehan 2295221828Sgrehanstatic const char * 2296221828Sgrehanuaudio_mixer_get_terminal_name(uint16_t terminal_type) 2297221828Sgrehan{ 2298240922Sneel const struct uaudio_tt_to_string *uat = uaudio_tt_to_string; 2299240922Sneel 2300240922Sneel while (uat->terminal_type) { 2301240922Sneel if (uat->terminal_type == terminal_type) { 2302240922Sneel break; 2303240922Sneel } 2304240922Sneel uat++; 2305240922Sneel } 2306240922Sneel if (uat->terminal_type == 0) { 2307240922Sneel DPRINTF("unknown terminal type (0x%04x)", terminal_type); 2308240922Sneel } 2309240922Sneel return (uat->desc); 2310240922Sneel} 2311240922Sneel 2312240922Sneel#endif 2313240922Sneel 2314240922Sneelstatic uint16_t 2315240922Sneeluaudio_mixer_determine_class(const struct uaudio_terminal_node *iot, 2316248392Sneel struct uaudio_mixer_node *mix) 2317240922Sneel{ 2318240922Sneel uint16_t terminal_type = 0x0000; 2319240922Sneel const struct uaudio_terminal_node *input[2]; 2320240922Sneel const struct uaudio_terminal_node *output[2]; 2321240943Sneel 2322240943Sneel input[0] = uaudio_mixer_get_input(iot, 0); 2323240922Sneel input[1] = uaudio_mixer_get_input(iot, 1); 2324240922Sneel 2325241489Sneel output[0] = uaudio_mixer_get_output(iot, 0); 2326262350Sjhb output[1] = uaudio_mixer_get_output(iot, 1); 2327262350Sjhb 2328262350Sjhb /* 2329262350Sjhb * check if there is only 2330262350Sjhb * one output terminal: 2331262350Sjhb */ 2332262350Sjhb if (output[0] && (!output[1])) { 2333284900Sneel terminal_type = UGETW(output[0]->u.ot->wTerminalType); 2334284900Sneel } 2335241489Sneel /* 2336241489Sneel * If the only output terminal is USB, 2337241489Sneel * the class is UAC_RECORD. 2338241489Sneel */ 2339266393Sjhb if ((terminal_type & 0xff00) == (UAT_UNDEFINED & 0xff00)) { 2340266393Sjhb 2341266339Sjhb mix->class = UAC_RECORD; 2342266393Sjhb if (input[0] && (!input[1])) { 2343266339Sjhb terminal_type = UGETW(input[0]->u.it->wTerminalType); 2344266339Sjhb } else { 2345266393Sjhb terminal_type = 0; 2346266339Sjhb } 2347266393Sjhb goto done; 2348266393Sjhb } 2349266393Sjhb /* 2350266393Sjhb * if the unit is connected to just 2351266393Sjhb * one input terminal, the 2352266393Sjhb * class is UAC_INPUT: 2353266393Sjhb */ 2354266393Sjhb if (input[0] && (!input[1])) { 2355266339Sjhb mix->class = UAC_INPUT; 2356266393Sjhb terminal_type = UGETW(input[0]->u.it->wTerminalType); 2357266393Sjhb goto done; 2358266393Sjhb } 2359266393Sjhb /* 2360266393Sjhb * Otherwise, the class is UAC_OUTPUT. 2361242065Sneel */ 2362284900Sneel mix->class = UAC_OUTPUT; 2363284900Sneeldone: 2364284900Sneel return (terminal_type); 2365284900Sneel} 2366284900Sneel 2367284900Sneelstruct uaudio_tt_to_feature { 2368284900Sneel uint16_t terminal_type; 2369284900Sneel uint16_t feature; 2370284900Sneel}; 2371242065Sneel 2372241489Sneelstatic const struct uaudio_tt_to_feature uaudio_tt_to_feature[] = { 2373256072Sneel 2374256072Sneel {UAT_STREAM, SOUND_MIXER_PCM}, 2375256072Sneel 2376256072Sneel {UATI_MICROPHONE, SOUND_MIXER_MIC}, 2377256072Sneel {UATI_DESKMICROPHONE, SOUND_MIXER_MIC}, 2378256072Sneel {UATI_PERSONALMICROPHONE, SOUND_MIXER_MIC}, 2379256072Sneel {UATI_OMNIMICROPHONE, SOUND_MIXER_MIC}, 2380261088Sjhb {UATI_MICROPHONEARRAY, SOUND_MIXER_MIC}, 2381261088Sjhb {UATI_PROCMICROPHONEARR, SOUND_MIXER_MIC}, 2382261088Sjhb 2383261088Sjhb {UATO_SPEAKER, SOUND_MIXER_SPEAKER}, 2384261088Sjhb {UATO_DESKTOPSPEAKER, SOUND_MIXER_SPEAKER}, 2385261088Sjhb {UATO_ROOMSPEAKER, SOUND_MIXER_SPEAKER}, 2386261088Sjhb {UATO_COMMSPEAKER, SOUND_MIXER_SPEAKER}, 2387261088Sjhb 2388261088Sjhb {UATE_ANALOGCONN, SOUND_MIXER_LINE}, 2389266339Sjhb {UATE_LINECONN, SOUND_MIXER_LINE}, 2390266339Sjhb {UATE_LEGACYCONN, SOUND_MIXER_LINE}, 2391266339Sjhb 2392266339Sjhb {UATE_DIGITALAUIFC, SOUND_MIXER_ALTPCM}, 2393266339Sjhb {UATE_SPDIF, SOUND_MIXER_ALTPCM}, 2394266339Sjhb {UATE_1394DA, SOUND_MIXER_ALTPCM}, 2395266339Sjhb {UATE_1394DV, SOUND_MIXER_ALTPCM}, 2396266339Sjhb 2397266339Sjhb {UATF_CDPLAYER, SOUND_MIXER_CD}, 2398266339Sjhb 2399266339Sjhb {UATF_SYNTHESIZER, SOUND_MIXER_SYNTH}, 2400266339Sjhb 2401266339Sjhb {UATF_VIDEODISCAUDIO, SOUND_MIXER_VIDEO}, 2402266339Sjhb {UATF_DVDAUDIO, SOUND_MIXER_VIDEO}, 2403266339Sjhb {UATF_TVTUNERAUDIO, SOUND_MIXER_VIDEO}, 2404266339Sjhb 2405266339Sjhb /* telephony terminal types */ 2406266339Sjhb {UATT_UNDEFINED, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 2407266339Sjhb {UATT_PHONELINE, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 2408266339Sjhb {UATT_TELEPHONE, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 2409266339Sjhb {UATT_DOWNLINEPHONE, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 2410266339Sjhb 2411266339Sjhb {UATF_RADIORECV, SOUND_MIXER_RADIO}, 2412266339Sjhb {UATF_RADIOXMIT, SOUND_MIXER_RADIO}, 2413266339Sjhb 2414266339Sjhb {UAT_UNDEFINED, SOUND_MIXER_VOLUME}, 2415266339Sjhb {UAT_VENDOR, SOUND_MIXER_VOLUME}, 2416266339Sjhb {UATI_UNDEFINED, SOUND_MIXER_VOLUME}, 2417266339Sjhb 2418266339Sjhb /* output terminal types */ 2419266339Sjhb {UATO_UNDEFINED, SOUND_MIXER_VOLUME}, 2420266339Sjhb {UATO_DISPLAYAUDIO, SOUND_MIXER_VOLUME}, 2421266339Sjhb {UATO_SUBWOOFER, SOUND_MIXER_VOLUME}, 2422266339Sjhb {UATO_HEADPHONES, SOUND_MIXER_VOLUME}, 2423266339Sjhb 2424266339Sjhb /* bidir terminal types */ 2425266339Sjhb {UATB_UNDEFINED, SOUND_MIXER_VOLUME}, 2426266339Sjhb {UATB_HANDSET, SOUND_MIXER_VOLUME}, 2427266339Sjhb {UATB_HEADSET, SOUND_MIXER_VOLUME}, 2428266339Sjhb {UATB_SPEAKERPHONE, SOUND_MIXER_VOLUME}, 2429266339Sjhb {UATB_SPEAKERPHONEESUP, SOUND_MIXER_VOLUME}, 2430266339Sjhb {UATB_SPEAKERPHONEECANC, SOUND_MIXER_VOLUME}, 2431266339Sjhb 2432266339Sjhb /* external terminal types */ 2433266339Sjhb {UATE_UNDEFINED, SOUND_MIXER_VOLUME}, 2434266339Sjhb 2435266339Sjhb /* embedded function terminal types */ 2436266339Sjhb {UATF_UNDEFINED, SOUND_MIXER_VOLUME}, 2437268891Sjhb {UATF_CALIBNOISE, SOUND_MIXER_VOLUME}, 2438268891Sjhb {UATF_EQUNOISE, SOUND_MIXER_VOLUME}, 2439268891Sjhb {UATF_DAT, SOUND_MIXER_VOLUME}, 2440268891Sjhb {UATF_DCC, SOUND_MIXER_VOLUME}, 2441268891Sjhb {UATF_MINIDISK, SOUND_MIXER_VOLUME}, 2442268891Sjhb {UATF_ANALOGTAPE, SOUND_MIXER_VOLUME}, 2443268891Sjhb {UATF_PHONOGRAPH, SOUND_MIXER_VOLUME}, 2444268891Sjhb {UATF_VCRAUDIO, SOUND_MIXER_VOLUME}, 2445268891Sjhb {UATF_SATELLITE, SOUND_MIXER_VOLUME}, 2446268891Sjhb {UATF_CABLETUNER, SOUND_MIXER_VOLUME}, 2447268891Sjhb {UATF_DSS, SOUND_MIXER_VOLUME}, 2448268891Sjhb {UATF_MULTITRACK, SOUND_MIXER_VOLUME}, 2449268976Sjhb {0xffff, SOUND_MIXER_VOLUME}, 2450276429Sneel 2451276429Sneel /* default */ 2452276429Sneel {0x0000, SOUND_MIXER_VOLUME}, 2453276429Sneel}; 2454276429Sneel 2455276429Sneelstatic uint16_t 2456276429Sneeluaudio_mixer_feature_name(const struct uaudio_terminal_node *iot, 2457284894Sneel struct uaudio_mixer_node *mix) 2458284894Sneel{ 2459284894Sneel const struct uaudio_tt_to_feature *uat = uaudio_tt_to_feature; 2460284894Sneel uint16_t terminal_type = uaudio_mixer_determine_class(iot, mix); 2461284894Sneel 2462284894Sneel if ((mix->class == UAC_RECORD) && (terminal_type == 0)) { 2463284894Sneel return (SOUND_MIXER_IMIX); 2464268976Sjhb } 2465268976Sjhb while (uat->terminal_type) { 2466268976Sjhb if (uat->terminal_type == terminal_type) { 2467268976Sjhb break; 2468268976Sjhb } 2469268976Sjhb uat++; 2470268976Sjhb } 2471268976Sjhb 2472268976Sjhb DPRINTF("terminal_type=%s (0x%04x) -> %d\n", 2473268976Sjhb uaudio_mixer_get_terminal_name(terminal_type), 2474268976Sjhb terminal_type, uat->feature); 2475268976Sjhb 2476268976Sjhb return (uat->feature); 2477268976Sjhb} 2478268976Sjhb 2479268976Sjhbconst static struct uaudio_terminal_node * 2480270074Sgrehanuaudio_mixer_get_input(const struct uaudio_terminal_node *iot, uint8_t index) 2481270159Sgrehan{ 2482270159Sgrehan struct uaudio_terminal_node *root = iot->root; 2483270159Sgrehan uint8_t n; 2484270159Sgrehan 2485270159Sgrehan n = iot->usr.id_max; 2486270074Sgrehan do { 2487270159Sgrehan if (iot->usr.bit_input[n / 8] & (1 << (n % 8))) { 2488270159Sgrehan if (!index--) { 2489270159Sgrehan return (root + n); 2490270159Sgrehan } 2491270159Sgrehan } 2492270159Sgrehan } while (n--); 2493270159Sgrehan 2494270159Sgrehan return (NULL); 2495270159Sgrehan} 2496270159Sgrehan 2497284900Sneelconst static struct uaudio_terminal_node * 2498270159Sgrehanuaudio_mixer_get_output(const struct uaudio_terminal_node *iot, uint8_t index) 2499270159Sgrehan{ 2500270159Sgrehan struct uaudio_terminal_node *root = iot->root; 2501270159Sgrehan uint8_t n; 2502270159Sgrehan 2503270159Sgrehan n = iot->usr.id_max; 2504270159Sgrehan do { 2505270159Sgrehan if (iot->usr.bit_output[n / 8] & (1 << (n % 8))) { 2506270159Sgrehan if (!index--) { 2507270159Sgrehan return (root + n); 2508270159Sgrehan } 2509270159Sgrehan } 2510284900Sneel } while (n--); 2511284900Sneel 2512270159Sgrehan return (NULL); 2513270159Sgrehan} 2514270159Sgrehan 2515270159Sgrehanstatic void 2516270159Sgrehanuaudio_mixer_find_inputs_sub(struct uaudio_terminal_node *root, 2517270159Sgrehan const uint8_t *p_id, uint8_t n_id, 2518270159Sgrehan struct uaudio_search_result *info) 2519270159Sgrehan{ 2520270159Sgrehan struct uaudio_terminal_node *iot; 2521270159Sgrehan uint8_t n; 2522270159Sgrehan uint8_t i; 2523295124Sgrehan 2524295124Sgrehan if (info->recurse_level >= UAUDIO_RECURSE_LIMIT) { 2525270159Sgrehan return; 2526270159Sgrehan } 2527270159Sgrehan info->recurse_level++; 2528270159Sgrehan 2529270159Sgrehan for (n = 0; n < n_id; n++) { 2530270159Sgrehan 2531270159Sgrehan i = p_id[n]; 2532270159Sgrehan 2533284900Sneel if (info->bit_visited[i / 8] & (1 << (i % 8))) { 2534270159Sgrehan /* don't go into a circle */ 2535284900Sneel DPRINTF("avoided going into a circle at id=%d!\n", i); 2536270159Sgrehan continue; 2537270159Sgrehan } else { 2538270159Sgrehan info->bit_visited[i / 8] |= (1 << (i % 8)); 2539270159Sgrehan } 2540270159Sgrehan 2541270159Sgrehan iot = (root + i); 2542270159Sgrehan 2543270159Sgrehan if (iot->u.desc == NULL) { 2544270159Sgrehan continue; 2545270159Sgrehan } 2546270159Sgrehan switch (iot->u.desc->bDescriptorSubtype) { 2547270159Sgrehan case UDESCSUB_AC_INPUT: 2548270159Sgrehan info->bit_input[i / 8] |= (1 << (i % 8)); 2549270159Sgrehan break; 2550270159Sgrehan 2551270159Sgrehan case UDESCSUB_AC_FEATURE: 2552270159Sgrehan uaudio_mixer_find_inputs_sub 2553270159Sgrehan (root, &iot->u.fu->bSourceId, 1, info); 2554270159Sgrehan break; 2555270159Sgrehan 2556270159Sgrehan case UDESCSUB_AC_OUTPUT: 2557270159Sgrehan uaudio_mixer_find_inputs_sub 2558270159Sgrehan (root, &iot->u.ot->bSourceId, 1, info); 2559270159Sgrehan break; 2560270159Sgrehan 2561270159Sgrehan case UDESCSUB_AC_MIXER: 2562270159Sgrehan uaudio_mixer_find_inputs_sub 2563270159Sgrehan (root, iot->u.mu->baSourceId, 2564270159Sgrehan iot->u.mu->bNrInPins, info); 2565270159Sgrehan break; 2566270159Sgrehan 2567270159Sgrehan case UDESCSUB_AC_SELECTOR: 2568270159Sgrehan uaudio_mixer_find_inputs_sub 2569270159Sgrehan (root, iot->u.su->baSourceId, 2570270159Sgrehan iot->u.su->bNrInPins, info); 2571270159Sgrehan break; 2572270159Sgrehan 2573270159Sgrehan case UDESCSUB_AC_PROCESSING: 2574270074Sgrehan uaudio_mixer_find_inputs_sub 2575270074Sgrehan (root, iot->u.pu->baSourceId, 2576270074Sgrehan iot->u.pu->bNrInPins, info); 2577270074Sgrehan break; 2578270074Sgrehan 2579270074Sgrehan case UDESCSUB_AC_EXTENSION: 2580270074Sgrehan uaudio_mixer_find_inputs_sub 2581270074Sgrehan (root, iot->u.eu->baSourceId, 2582270074Sgrehan iot->u.eu->bNrInPins, info); 2583270074Sgrehan break; 2584270074Sgrehan 2585270074Sgrehan case UDESCSUB_AC_HEADER: 2586270074Sgrehan default: 2587270074Sgrehan break; 2588270074Sgrehan } 2589270074Sgrehan } 2590270074Sgrehan info->recurse_level--; 2591270074Sgrehan} 2592270074Sgrehan 2593270074Sgrehanstatic void 2594270074Sgrehanuaudio_mixer_find_outputs_sub(struct uaudio_terminal_node *root, uint8_t id, 2595270074Sgrehan uint8_t n_id, struct uaudio_search_result *info) 2596270074Sgrehan{ 2597270074Sgrehan struct uaudio_terminal_node *iot = (root + id); 2598270074Sgrehan uint8_t j; 2599270074Sgrehan 2600270074Sgrehan j = n_id; 2601270074Sgrehan do { 2602270074Sgrehan if ((j != id) && ((root + j)->u.desc) && 2603 ((root + j)->u.desc->bDescriptorSubtype == UDESCSUB_AC_OUTPUT)) { 2604 2605 /* 2606 * "j" (output) <--- virtual wire <--- "id" (input) 2607 * 2608 * if "j" has "id" on the input, then "id" have "j" on 2609 * the output, because they are connected: 2610 */ 2611 if ((root + j)->usr.bit_input[id / 8] & (1 << (id % 8))) { 2612 iot->usr.bit_output[j / 8] |= (1 << (j % 8)); 2613 } 2614 } 2615 } while (j--); 2616} 2617 2618static void 2619uaudio_mixer_fill_info(struct uaudio_softc *sc, struct usb2_device *udev, 2620 void *desc) 2621{ 2622 const struct usb2_audio_control_descriptor *acdp; 2623 struct usb2_config_descriptor *cd = usb2_get_config_descriptor(udev); 2624 const struct usb2_descriptor *dp; 2625 const struct usb2_audio_unit *au; 2626 struct uaudio_terminal_node *iot = NULL; 2627 uint16_t wTotalLen; 2628 uint8_t ID_max = 0; /* inclusive */ 2629 uint8_t i; 2630 2631 desc = usb2_desc_foreach(cd, desc); 2632 2633 if (desc == NULL) { 2634 DPRINTF("no Audio Control header\n"); 2635 goto done; 2636 } 2637 acdp = desc; 2638 2639 if ((acdp->bLength < sizeof(*acdp)) || 2640 (acdp->bDescriptorType != UDESC_CS_INTERFACE) || 2641 (acdp->bDescriptorSubtype != UDESCSUB_AC_HEADER)) { 2642 DPRINTF("invalid Audio Control header\n"); 2643 goto done; 2644 } 2645 /* "wTotalLen" is allowed to be corrupt */ 2646 wTotalLen = UGETW(acdp->wTotalLength) - acdp->bLength; 2647 2648 /* get USB audio revision */ 2649 sc->sc_audio_rev = UGETW(acdp->bcdADC); 2650 2651 DPRINTFN(3, "found AC header, vers=%03x, len=%d\n", 2652 sc->sc_audio_rev, wTotalLen); 2653 2654 if (sc->sc_audio_rev != UAUDIO_VERSION) { 2655 2656 if (sc->sc_uq_bad_adc) { 2657 2658 } else { 2659 DPRINTF("invalid audio version\n"); 2660 goto done; 2661 } 2662 } 2663 iot = malloc(sizeof(struct uaudio_terminal_node) * 256, M_TEMP, 2664 M_WAITOK | M_ZERO); 2665 2666 if (iot == NULL) { 2667 DPRINTF("no memory!\n"); 2668 goto done; 2669 } 2670 while ((desc = usb2_desc_foreach(cd, desc))) { 2671 2672 dp = desc; 2673 2674 if (dp->bLength > wTotalLen) { 2675 break; 2676 } else { 2677 wTotalLen -= dp->bLength; 2678 } 2679 2680 au = uaudio_mixer_verify_desc(dp, 0); 2681 2682 if (au) { 2683 iot[au->bUnitId].u.desc = (const void *)au; 2684 if (au->bUnitId > ID_max) { 2685 ID_max = au->bUnitId; 2686 } 2687 } 2688 } 2689 2690 DPRINTF("Maximum ID=%d\n", ID_max); 2691 2692 /* 2693 * determine sourcing inputs for 2694 * all nodes in the tree: 2695 */ 2696 i = ID_max; 2697 do { 2698 uaudio_mixer_find_inputs_sub(iot, &i, 1, &((iot + i)->usr)); 2699 } while (i--); 2700 2701 /* 2702 * determine outputs for 2703 * all nodes in the tree: 2704 */ 2705 i = ID_max; 2706 do { 2707 uaudio_mixer_find_outputs_sub(iot, i, ID_max, &((iot + i)->usr)); 2708 } while (i--); 2709 2710 /* set "id_max" and "root" */ 2711 2712 i = ID_max; 2713 do { 2714 (iot + i)->usr.id_max = ID_max; 2715 (iot + i)->root = iot; 2716 } while (i--); 2717 2718#if USB_DEBUG 2719 i = ID_max; 2720 do { 2721 uint8_t j; 2722 2723 if (iot[i].u.desc == NULL) { 2724 continue; 2725 } 2726 DPRINTF("id %d:\n", i); 2727 2728 switch (iot[i].u.desc->bDescriptorSubtype) { 2729 case UDESCSUB_AC_INPUT: 2730 DPRINTF(" - AC_INPUT type=%s\n", 2731 uaudio_mixer_get_terminal_name 2732 (UGETW(iot[i].u.it->wTerminalType))); 2733 uaudio_mixer_dump_cluster(i, iot); 2734 break; 2735 2736 case UDESCSUB_AC_OUTPUT: 2737 DPRINTF(" - AC_OUTPUT type=%s " 2738 "src=%d\n", uaudio_mixer_get_terminal_name 2739 (UGETW(iot[i].u.ot->wTerminalType)), 2740 iot[i].u.ot->bSourceId); 2741 break; 2742 2743 case UDESCSUB_AC_MIXER: 2744 DPRINTF(" - AC_MIXER src:\n"); 2745 for (j = 0; j < iot[i].u.mu->bNrInPins; j++) { 2746 DPRINTF(" - %d\n", iot[i].u.mu->baSourceId[j]); 2747 } 2748 uaudio_mixer_dump_cluster(i, iot); 2749 break; 2750 2751 case UDESCSUB_AC_SELECTOR: 2752 DPRINTF(" - AC_SELECTOR src:\n"); 2753 for (j = 0; j < iot[i].u.su->bNrInPins; j++) { 2754 DPRINTF(" - %d\n", iot[i].u.su->baSourceId[j]); 2755 } 2756 break; 2757 2758 case UDESCSUB_AC_FEATURE: 2759 DPRINTF(" - AC_FEATURE src=%d\n", iot[i].u.fu->bSourceId); 2760 break; 2761 2762 case UDESCSUB_AC_PROCESSING: 2763 DPRINTF(" - AC_PROCESSING src:\n"); 2764 for (j = 0; j < iot[i].u.pu->bNrInPins; j++) { 2765 DPRINTF(" - %d\n", iot[i].u.pu->baSourceId[j]); 2766 } 2767 uaudio_mixer_dump_cluster(i, iot); 2768 break; 2769 2770 case UDESCSUB_AC_EXTENSION: 2771 DPRINTF(" - AC_EXTENSION src:\n"); 2772 for (j = 0; j < iot[i].u.eu->bNrInPins; j++) { 2773 DPRINTF("%d ", iot[i].u.eu->baSourceId[j]); 2774 } 2775 uaudio_mixer_dump_cluster(i, iot); 2776 break; 2777 2778 default: 2779 DPRINTF("unknown audio control (subtype=%d)\n", 2780 iot[i].u.desc->bDescriptorSubtype); 2781 } 2782 2783 DPRINTF("Inputs to this ID are:\n"); 2784 2785 j = ID_max; 2786 do { 2787 if (iot[i].usr.bit_input[j / 8] & (1 << (j % 8))) { 2788 DPRINTF(" -- ID=%d\n", j); 2789 } 2790 } while (j--); 2791 2792 DPRINTF("Outputs from this ID are:\n"); 2793 2794 j = ID_max; 2795 do { 2796 if (iot[i].usr.bit_output[j / 8] & (1 << (j % 8))) { 2797 DPRINTF(" -- ID=%d\n", j); 2798 } 2799 } while (j--); 2800 2801 } while (i--); 2802#endif 2803 2804 /* 2805 * scan the config to create a linked 2806 * list of "mixer" nodes: 2807 */ 2808 2809 i = ID_max; 2810 do { 2811 dp = iot[i].u.desc; 2812 2813 if (dp == NULL) { 2814 continue; 2815 } 2816 DPRINTFN(11, "id=%d subtype=%d\n", 2817 i, dp->bDescriptorSubtype); 2818 2819 switch (dp->bDescriptorSubtype) { 2820 case UDESCSUB_AC_HEADER: 2821 DPRINTF("unexpected AC header\n"); 2822 break; 2823 2824 case UDESCSUB_AC_INPUT: 2825 uaudio_mixer_add_input(sc, iot, i); 2826 break; 2827 2828 case UDESCSUB_AC_OUTPUT: 2829 uaudio_mixer_add_output(sc, iot, i); 2830 break; 2831 2832 case UDESCSUB_AC_MIXER: 2833 uaudio_mixer_add_mixer(sc, iot, i); 2834 break; 2835 2836 case UDESCSUB_AC_SELECTOR: 2837 uaudio_mixer_add_selector(sc, iot, i); 2838 break; 2839 2840 case UDESCSUB_AC_FEATURE: 2841 uaudio_mixer_add_feature(sc, iot, i); 2842 break; 2843 2844 case UDESCSUB_AC_PROCESSING: 2845 uaudio_mixer_add_processing(sc, iot, i); 2846 break; 2847 2848 case UDESCSUB_AC_EXTENSION: 2849 uaudio_mixer_add_extension(sc, iot, i); 2850 break; 2851 2852 default: 2853 DPRINTF("bad AC desc subtype=0x%02x\n", 2854 dp->bDescriptorSubtype); 2855 break; 2856 } 2857 2858 } while (i--); 2859 2860done: 2861 if (iot) { 2862 free(iot, M_TEMP); 2863 } 2864} 2865 2866static uint16_t 2867uaudio_mixer_get(struct usb2_device *udev, uint8_t what, 2868 struct uaudio_mixer_node *mc) 2869{ 2870 struct usb2_device_request req; 2871 uint16_t val; 2872 uint16_t len = MIX_SIZE(mc->type); 2873 uint8_t data[4]; 2874 usb2_error_t err; 2875 2876 if (mc->wValue[0] == -1) { 2877 return (0); 2878 } 2879 req.bmRequestType = UT_READ_CLASS_INTERFACE; 2880 req.bRequest = what; 2881 USETW(req.wValue, mc->wValue[0]); 2882 USETW(req.wIndex, mc->wIndex); 2883 USETW(req.wLength, len); 2884 2885 err = usb2_do_request(udev, &Giant, &req, data); 2886 if (err) { 2887 DPRINTF("err=%s\n", usb2_errstr(err)); 2888 return (0); 2889 } 2890 if (len < 1) { 2891 data[0] = 0; 2892 } 2893 if (len < 2) { 2894 data[1] = 0; 2895 } 2896 val = (data[0] | (data[1] << 8)); 2897 2898 DPRINTFN(3, "val=%d\n", val); 2899 2900 return (val); 2901} 2902 2903static void 2904uaudio_mixer_write_cfg_callback(struct usb2_xfer *xfer) 2905{ 2906 struct usb2_device_request req; 2907 struct uaudio_softc *sc = xfer->priv_sc; 2908 struct uaudio_mixer_node *mc = sc->sc_mixer_curr; 2909 uint16_t len; 2910 uint8_t repeat = 1; 2911 uint8_t update; 2912 uint8_t chan; 2913 uint8_t buf[2]; 2914 2915 DPRINTF("\n"); 2916 2917 switch (USB_GET_STATE(xfer)) { 2918 case USB_ST_TRANSFERRED: 2919tr_transferred: 2920 case USB_ST_SETUP: 2921tr_setup: 2922 2923 if (mc == NULL) { 2924 mc = sc->sc_mixer_root; 2925 sc->sc_mixer_curr = mc; 2926 sc->sc_mixer_chan = 0; 2927 repeat = 0; 2928 } 2929 while (mc) { 2930 while (sc->sc_mixer_chan < mc->nchan) { 2931 2932 len = MIX_SIZE(mc->type); 2933 2934 chan = sc->sc_mixer_chan; 2935 2936 sc->sc_mixer_chan++; 2937 2938 update = ((mc->update[chan / 8] & (1 << (chan % 8))) && 2939 (mc->wValue[chan] != -1)); 2940 2941 mc->update[chan / 8] &= ~(1 << (chan % 8)); 2942 2943 if (update) { 2944 2945 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 2946 req.bRequest = SET_CUR; 2947 USETW(req.wValue, mc->wValue[chan]); 2948 USETW(req.wIndex, mc->wIndex); 2949 USETW(req.wLength, len); 2950 2951 if (len > 0) { 2952 buf[0] = (mc->wData[chan] & 0xFF); 2953 } 2954 if (len > 1) { 2955 buf[1] = (mc->wData[chan] >> 8) & 0xFF; 2956 } 2957 usb2_copy_in(xfer->frbuffers, 0, &req, sizeof(req)); 2958 usb2_copy_in(xfer->frbuffers + 1, 0, buf, len); 2959 2960 xfer->frlengths[0] = sizeof(req); 2961 xfer->frlengths[1] = len; 2962 xfer->nframes = xfer->frlengths[1] ? 2 : 1; 2963 usb2_start_hardware(xfer); 2964 return; 2965 } 2966 } 2967 2968 mc = mc->next; 2969 sc->sc_mixer_curr = mc; 2970 sc->sc_mixer_chan = 0; 2971 } 2972 2973 if (repeat) { 2974 goto tr_setup; 2975 } 2976 break; 2977 2978 default: /* Error */ 2979 DPRINTF("error=%s\n", usb2_errstr(xfer->error)); 2980 if (xfer->error == USB_ERR_CANCELLED) { 2981 /* do nothing - we are detaching */ 2982 break; 2983 } 2984 goto tr_transferred; 2985 } 2986} 2987 2988static usb2_error_t 2989uaudio_set_speed(struct usb2_device *udev, uint8_t endpt, uint32_t speed) 2990{ 2991 struct usb2_device_request req; 2992 uint8_t data[3]; 2993 2994 DPRINTFN(6, "endpt=%d speed=%u\n", endpt, speed); 2995 2996 req.bmRequestType = UT_WRITE_CLASS_ENDPOINT; 2997 req.bRequest = SET_CUR; 2998 USETW2(req.wValue, SAMPLING_FREQ_CONTROL, 0); 2999 USETW(req.wIndex, endpt); 3000 USETW(req.wLength, 3); 3001 data[0] = speed; 3002 data[1] = speed >> 8; 3003 data[2] = speed >> 16; 3004 3005 return (usb2_do_request(udev, &Giant, &req, data)); 3006} 3007 3008static int 3009uaudio_mixer_signext(uint8_t type, int val) 3010{ 3011 if (!MIX_UNSIGNED(type)) { 3012 if (MIX_SIZE(type) == 2) { 3013 val = (int16_t)val; 3014 } else { 3015 val = (int8_t)val; 3016 } 3017 } 3018 return (val); 3019} 3020 3021static int 3022uaudio_mixer_bsd2value(struct uaudio_mixer_node *mc, int32_t val) 3023{ 3024 if (mc->type == MIX_ON_OFF) { 3025 val = (val != 0); 3026 } else if (mc->type == MIX_SELECTOR) { 3027 if ((val < mc->minval) || 3028 (val > mc->maxval)) { 3029 val = mc->minval; 3030 } 3031 } else { 3032 val = (((val + (mc->delta / 2)) * mc->mul) / 255) + mc->minval; 3033 } 3034 3035 DPRINTFN(6, "type=0x%03x val=%d min=%d max=%d val=%d\n", 3036 mc->type, val, mc->minval, mc->maxval, val); 3037 return (val); 3038} 3039 3040static void 3041uaudio_mixer_ctl_set(struct uaudio_softc *sc, struct uaudio_mixer_node *mc, 3042 uint8_t chan, int32_t val) 3043{ 3044 val = uaudio_mixer_bsd2value(mc, val); 3045 3046 mc->update[chan / 8] |= (1 << (chan % 8)); 3047 mc->wData[chan] = val; 3048 3049 /* start the transfer, if not already started */ 3050 3051 usb2_transfer_start(sc->sc_mixer_xfer[0]); 3052} 3053 3054static void 3055uaudio_mixer_init(struct uaudio_softc *sc) 3056{ 3057 struct uaudio_mixer_node *mc; 3058 int32_t i; 3059 3060 for (mc = sc->sc_mixer_root; mc; 3061 mc = mc->next) { 3062 3063 if (mc->ctl != SOUND_MIXER_NRDEVICES) { 3064 /* 3065 * Set device mask bits. See 3066 * /usr/include/machine/soundcard.h 3067 */ 3068 sc->sc_mix_info |= (1 << mc->ctl); 3069 } 3070 if ((mc->ctl == SOUND_MIXER_NRDEVICES) && 3071 (mc->type == MIX_SELECTOR)) { 3072 3073 for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { 3074 if (mc->slctrtype[i - 1] == SOUND_MIXER_NRDEVICES) { 3075 continue; 3076 } 3077 sc->sc_recsrc_info |= 1 << mc->slctrtype[i - 1]; 3078 } 3079 } 3080 } 3081} 3082 3083int 3084uaudio_mixer_init_sub(struct uaudio_softc *sc, struct snd_mixer *m) 3085{ 3086 DPRINTF("\n"); 3087 3088 if (usb2_transfer_setup(sc->sc_udev, &sc->sc_mixer_iface_index, 3089 sc->sc_mixer_xfer, uaudio_mixer_config, 1, sc, 3090 mixer_get_lock(m))) { 3091 DPRINTFN(0, "could not allocate USB " 3092 "transfer for audio mixer!\n"); 3093 return (ENOMEM); 3094 } 3095 if (!(sc->sc_mix_info & SOUND_MASK_VOLUME)) { 3096 mix_setparentchild(m, SOUND_MIXER_VOLUME, SOUND_MASK_PCM); 3097 mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE); 3098 } 3099 mix_setdevs(m, sc->sc_mix_info); 3100 mix_setrecdevs(m, sc->sc_recsrc_info); 3101 return (0); 3102} 3103 3104int 3105uaudio_mixer_uninit_sub(struct uaudio_softc *sc) 3106{ 3107 DPRINTF("\n"); 3108 3109 usb2_transfer_unsetup(sc->sc_mixer_xfer, 1); 3110 3111 return (0); 3112} 3113 3114void 3115uaudio_mixer_set(struct uaudio_softc *sc, unsigned type, 3116 unsigned left, unsigned right) 3117{ 3118 struct uaudio_mixer_node *mc; 3119 3120 for (mc = sc->sc_mixer_root; mc; 3121 mc = mc->next) { 3122 3123 if (mc->ctl == type) { 3124 if (mc->nchan == 2) { 3125 /* set Right */ 3126 uaudio_mixer_ctl_set(sc, mc, 1, (int)(right * 255) / 100); 3127 } 3128 /* set Left or Mono */ 3129 uaudio_mixer_ctl_set(sc, mc, 0, (int)(left * 255) / 100); 3130 } 3131 } 3132} 3133 3134uint32_t 3135uaudio_mixer_setrecsrc(struct uaudio_softc *sc, uint32_t src) 3136{ 3137 struct uaudio_mixer_node *mc; 3138 uint32_t mask; 3139 uint32_t temp; 3140 int32_t i; 3141 3142 for (mc = sc->sc_mixer_root; mc; 3143 mc = mc->next) { 3144 3145 if ((mc->ctl == SOUND_MIXER_NRDEVICES) && 3146 (mc->type == MIX_SELECTOR)) { 3147 3148 /* compute selector mask */ 3149 3150 mask = 0; 3151 for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { 3152 mask |= (1 << mc->slctrtype[i - 1]); 3153 } 3154 3155 temp = mask & src; 3156 if (temp == 0) { 3157 continue; 3158 } 3159 /* find the first set bit */ 3160 temp = (-temp) & temp; 3161 3162 /* update "src" */ 3163 src &= ~mask; 3164 src |= temp; 3165 3166 for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { 3167 if (temp != (1 << mc->slctrtype[i - 1])) { 3168 continue; 3169 } 3170 uaudio_mixer_ctl_set(sc, mc, 0, i); 3171 break; 3172 } 3173 } 3174 } 3175 return (src); 3176} 3177 3178/*========================================================================* 3179 * MIDI support routines 3180 *========================================================================*/ 3181 3182static void 3183umidi_read_clear_stall_callback(struct usb2_xfer *xfer) 3184{ 3185 struct umidi_chan *chan = xfer->priv_sc; 3186 struct usb2_xfer *xfer_other = chan->xfer[1]; 3187 3188 if (usb2_clear_stall_callback(xfer, xfer_other)) { 3189 DPRINTF("stall cleared\n"); 3190 chan->flags &= ~UMIDI_FLAG_READ_STALL; 3191 usb2_transfer_start(xfer_other); 3192 } 3193} 3194 3195static void 3196umidi_bulk_read_callback(struct usb2_xfer *xfer) 3197{ 3198 struct umidi_chan *chan = xfer->priv_sc; 3199 struct umidi_sub_chan *sub; 3200 uint8_t buf[1]; 3201 uint8_t cmd_len; 3202 uint8_t cn; 3203 uint16_t pos; 3204 3205 switch (USB_GET_STATE(xfer)) { 3206 case USB_ST_TRANSFERRED: 3207 3208 DPRINTF("actlen=%d bytes\n", xfer->actlen); 3209 3210 if (xfer->actlen == 0) { 3211 /* should not happen */ 3212 goto tr_error; 3213 } 3214 pos = 0; 3215 3216 while (xfer->actlen >= 4) { 3217 3218 usb2_copy_out(xfer->frbuffers, pos, buf, 1); 3219 3220 cmd_len = umidi_cmd_to_len[buf[0] & 0xF]; /* command length */ 3221 cn = buf[0] >> 4; /* cable number */ 3222 sub = &chan->sub[cn]; 3223 3224 if (cmd_len && (cn < chan->max_cable) && sub->read_open) { 3225 usb2_fifo_put_data(sub->fifo.fp[USB_FIFO_RX], xfer->frbuffers, 3226 pos + 1, cmd_len, 1); 3227 } else { 3228 /* ignore the command */ 3229 } 3230 3231 xfer->actlen -= 4; 3232 pos += 4; 3233 } 3234 3235 case USB_ST_SETUP: 3236 DPRINTF("start\n"); 3237 3238 if (chan->flags & UMIDI_FLAG_READ_STALL) { 3239 usb2_transfer_start(chan->xfer[3]); 3240 return; 3241 } 3242 xfer->frlengths[0] = xfer->max_data_length; 3243 usb2_start_hardware(xfer); 3244 return; 3245 3246 default: 3247tr_error: 3248 3249 DPRINTF("error=%s\n", usb2_errstr(xfer->error)); 3250 3251 if (xfer->error != USB_ERR_CANCELLED) { 3252 /* try to clear stall first */ 3253 chan->flags |= UMIDI_FLAG_READ_STALL; 3254 usb2_transfer_start(chan->xfer[3]); 3255 } 3256 return; 3257 3258 } 3259} 3260 3261static void 3262umidi_write_clear_stall_callback(struct usb2_xfer *xfer) 3263{ 3264 struct umidi_chan *chan = xfer->priv_sc; 3265 struct usb2_xfer *xfer_other = chan->xfer[0]; 3266 3267 if (usb2_clear_stall_callback(xfer, xfer_other)) { 3268 DPRINTF("stall cleared\n"); 3269 chan->flags &= ~UMIDI_FLAG_WRITE_STALL; 3270 usb2_transfer_start(xfer_other); 3271 } 3272} 3273 3274/* 3275 * The following statemachine, that converts MIDI commands to 3276 * USB MIDI packets, derives from Linux's usbmidi.c, which 3277 * was written by "Clemens Ladisch": 3278 * 3279 * Returns: 3280 * 0: No command 3281 * Else: Command is complete 3282 */ 3283static uint8_t 3284umidi_convert_to_usb(struct umidi_sub_chan *sub, uint8_t cn, uint8_t b) 3285{ 3286 uint8_t p0 = (cn << 4); 3287 3288 if (b >= 0xf8) { 3289 sub->temp_0[0] = p0 | 0x0f; 3290 sub->temp_0[1] = b; 3291 sub->temp_0[2] = 0; 3292 sub->temp_0[3] = 0; 3293 sub->temp_cmd = sub->temp_0; 3294 return (1); 3295 3296 } else if (b >= 0xf0) { 3297 switch (b) { 3298 case 0xf0: /* system exclusive begin */ 3299 sub->temp_1[1] = b; 3300 sub->state = UMIDI_ST_SYSEX_1; 3301 break; 3302 case 0xf1: /* MIDI time code */ 3303 case 0xf3: /* song select */ 3304 sub->temp_1[1] = b; 3305 sub->state = UMIDI_ST_1PARAM; 3306 break; 3307 case 0xf2: /* song position pointer */ 3308 sub->temp_1[1] = b; 3309 sub->state = UMIDI_ST_2PARAM_1; 3310 break; 3311 case 0xf4: /* unknown */ 3312 case 0xf5: /* unknown */ 3313 sub->state = UMIDI_ST_UNKNOWN; 3314 break; 3315 case 0xf6: /* tune request */ 3316 sub->temp_1[0] = p0 | 0x05; 3317 sub->temp_1[1] = 0xf6; 3318 sub->temp_1[2] = 0; 3319 sub->temp_1[3] = 0; 3320 sub->temp_cmd = sub->temp_1; 3321 sub->state = UMIDI_ST_UNKNOWN; 3322 return (1); 3323 3324 case 0xf7: /* system exclusive end */ 3325 switch (sub->state) { 3326 case UMIDI_ST_SYSEX_0: 3327 sub->temp_1[0] = p0 | 0x05; 3328 sub->temp_1[1] = 0xf7; 3329 sub->temp_1[2] = 0; 3330 sub->temp_1[3] = 0; 3331 sub->temp_cmd = sub->temp_1; 3332 sub->state = UMIDI_ST_UNKNOWN; 3333 return (1); 3334 case UMIDI_ST_SYSEX_1: 3335 sub->temp_1[0] = p0 | 0x06; 3336 sub->temp_1[2] = 0xf7; 3337 sub->temp_1[3] = 0; 3338 sub->temp_cmd = sub->temp_1; 3339 sub->state = UMIDI_ST_UNKNOWN; 3340 return (1); 3341 case UMIDI_ST_SYSEX_2: 3342 sub->temp_1[0] = p0 | 0x07; 3343 sub->temp_1[3] = 0xf7; 3344 sub->temp_cmd = sub->temp_1; 3345 sub->state = UMIDI_ST_UNKNOWN; 3346 return (1); 3347 } 3348 sub->state = UMIDI_ST_UNKNOWN; 3349 break; 3350 } 3351 } else if (b >= 0x80) { 3352 sub->temp_1[1] = b; 3353 if ((b >= 0xc0) && (b <= 0xdf)) { 3354 sub->state = UMIDI_ST_1PARAM; 3355 } else { 3356 sub->state = UMIDI_ST_2PARAM_1; 3357 } 3358 } else { /* b < 0x80 */ 3359 switch (sub->state) { 3360 case UMIDI_ST_1PARAM: 3361 if (sub->temp_1[1] < 0xf0) { 3362 p0 |= sub->temp_1[1] >> 4; 3363 } else { 3364 p0 |= 0x02; 3365 sub->state = UMIDI_ST_UNKNOWN; 3366 } 3367 sub->temp_1[0] = p0; 3368 sub->temp_1[2] = b; 3369 sub->temp_1[3] = 0; 3370 sub->temp_cmd = sub->temp_1; 3371 return (1); 3372 case UMIDI_ST_2PARAM_1: 3373 sub->temp_1[2] = b; 3374 sub->state = UMIDI_ST_2PARAM_2; 3375 break; 3376 case UMIDI_ST_2PARAM_2: 3377 if (sub->temp_1[1] < 0xf0) { 3378 p0 |= sub->temp_1[1] >> 4; 3379 sub->state = UMIDI_ST_2PARAM_1; 3380 } else { 3381 p0 |= 0x03; 3382 sub->state = UMIDI_ST_UNKNOWN; 3383 } 3384 sub->temp_1[0] = p0; 3385 sub->temp_1[3] = b; 3386 sub->temp_cmd = sub->temp_1; 3387 return (1); 3388 case UMIDI_ST_SYSEX_0: 3389 sub->temp_1[1] = b; 3390 sub->state = UMIDI_ST_SYSEX_1; 3391 break; 3392 case UMIDI_ST_SYSEX_1: 3393 sub->temp_1[2] = b; 3394 sub->state = UMIDI_ST_SYSEX_2; 3395 break; 3396 case UMIDI_ST_SYSEX_2: 3397 sub->temp_1[0] = p0 | 0x04; 3398 sub->temp_1[3] = b; 3399 sub->temp_cmd = sub->temp_1; 3400 sub->state = UMIDI_ST_SYSEX_0; 3401 return (1); 3402 } 3403 } 3404 return (0); 3405} 3406 3407static void 3408umidi_bulk_write_callback(struct usb2_xfer *xfer) 3409{ 3410 struct umidi_chan *chan = xfer->priv_sc; 3411 struct umidi_sub_chan *sub; 3412 uint32_t actlen; 3413 uint16_t total_length; 3414 uint8_t buf; 3415 uint8_t start_cable; 3416 uint8_t tr_any; 3417 3418 switch (USB_GET_STATE(xfer)) { 3419 case USB_ST_TRANSFERRED: 3420 DPRINTF("actlen=%d bytes\n", xfer->actlen); 3421 3422 case USB_ST_SETUP: 3423 3424 DPRINTF("start\n"); 3425 3426 if (chan->flags & UMIDI_FLAG_WRITE_STALL) { 3427 usb2_transfer_start(chan->xfer[2]); 3428 return; 3429 } 3430 total_length = 0; /* reset */ 3431 3432 start_cable = chan->curr_cable; 3433 3434 tr_any = 0; 3435 3436 while (1) { 3437 3438 /* round robin de-queueing */ 3439 3440 sub = &chan->sub[chan->curr_cable]; 3441 3442 if (sub->write_open) { 3443 usb2_fifo_get_data(sub->fifo.fp[USB_FIFO_TX], 3444 xfer->frbuffers, total_length, 3445 1, &actlen, 0); 3446 } else { 3447 actlen = 0; 3448 } 3449 3450 if (actlen) { 3451 usb2_copy_out(xfer->frbuffers, total_length, &buf, 1); 3452 3453 tr_any = 1; 3454 3455 DPRINTF("byte=0x%02x\n", buf); 3456 3457 if (umidi_convert_to_usb(sub, chan->curr_cable, buf)) { 3458 3459 DPRINTF("sub= %02x %02x %02x %02x\n", 3460 sub->temp_cmd[0], sub->temp_cmd[1], 3461 sub->temp_cmd[2], sub->temp_cmd[3]); 3462 3463 usb2_copy_in(xfer->frbuffers, total_length, 3464 sub->temp_cmd, 4); 3465 3466 total_length += 4; 3467 3468 if (total_length >= UMIDI_BULK_SIZE) { 3469 break; 3470 } 3471 } else { 3472 continue; 3473 } 3474 } 3475 chan->curr_cable++; 3476 if (chan->curr_cable >= chan->max_cable) { 3477 chan->curr_cable = 0; 3478 } 3479 if (chan->curr_cable == start_cable) { 3480 if (tr_any == 0) { 3481 break; 3482 } 3483 tr_any = 0; 3484 } 3485 } 3486 3487 if (total_length) { 3488 xfer->frlengths[0] = total_length; 3489 usb2_start_hardware(xfer); 3490 } 3491 return; 3492 3493 default: /* Error */ 3494 3495 DPRINTF("error=%s\n", usb2_errstr(xfer->error)); 3496 3497 if (xfer->error != USB_ERR_CANCELLED) { 3498 /* try to clear stall first */ 3499 chan->flags |= UMIDI_FLAG_WRITE_STALL; 3500 usb2_transfer_start(chan->xfer[2]); 3501 } 3502 return; 3503 3504 } 3505} 3506 3507static struct umidi_sub_chan * 3508umidi_sub_by_fifo(struct usb2_fifo *fifo) 3509{ 3510 struct umidi_chan *chan = fifo->priv_sc0; 3511 struct umidi_sub_chan *sub; 3512 uint32_t n; 3513 3514 for (n = 0; n < UMIDI_CABLES_MAX; n++) { 3515 sub = &chan->sub[n]; 3516 if ((sub->fifo.fp[USB_FIFO_RX] == fifo) || 3517 (sub->fifo.fp[USB_FIFO_TX] == fifo)) { 3518 return (sub); 3519 } 3520 } 3521 3522 panic("%s:%d cannot find usb2_fifo!\n", 3523 __FILE__, __LINE__); 3524 3525 return (NULL); 3526} 3527 3528static void 3529umidi_start_read(struct usb2_fifo *fifo) 3530{ 3531 struct umidi_chan *chan = fifo->priv_sc0; 3532 3533 usb2_transfer_start(chan->xfer[1]); 3534} 3535 3536static void 3537umidi_stop_read(struct usb2_fifo *fifo) 3538{ 3539 struct umidi_chan *chan = fifo->priv_sc0; 3540 struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo); 3541 3542 DPRINTF("\n"); 3543 3544 sub->read_open = 0; 3545 3546 if (--(chan->read_open_refcount) == 0) { 3547 /* 3548 * XXX don't stop the read transfer here, hence that causes 3549 * problems with some MIDI adapters 3550 */ 3551 DPRINTF("(stopping read transfer)\n"); 3552 } 3553} 3554 3555static void 3556umidi_start_write(struct usb2_fifo *fifo) 3557{ 3558 struct umidi_chan *chan = fifo->priv_sc0; 3559 3560 usb2_transfer_start(chan->xfer[0]); 3561} 3562 3563static void 3564umidi_stop_write(struct usb2_fifo *fifo) 3565{ 3566 struct umidi_chan *chan = fifo->priv_sc0; 3567 struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo); 3568 3569 DPRINTF("\n"); 3570 3571 sub->write_open = 0; 3572 3573 if (--(chan->write_open_refcount) == 0) { 3574 DPRINTF("(stopping write transfer)\n"); 3575 usb2_transfer_stop(chan->xfer[2]); 3576 usb2_transfer_stop(chan->xfer[0]); 3577 } 3578} 3579 3580static int 3581umidi_open(struct usb2_fifo *fifo, int fflags) 3582{ 3583 struct umidi_chan *chan = fifo->priv_sc0; 3584 struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo); 3585 3586 if (fflags & FREAD) { 3587 if (usb2_fifo_alloc_buffer(fifo, 4, (1024 / 4))) { 3588 return (ENOMEM); 3589 } 3590 mtx_lock(fifo->priv_mtx); 3591 chan->read_open_refcount++; 3592 sub->read_open = 1; 3593 mtx_unlock(fifo->priv_mtx); 3594 } 3595 if (fflags & FWRITE) { 3596 if (usb2_fifo_alloc_buffer(fifo, 32, (1024 / 32))) { 3597 return (ENOMEM); 3598 } 3599 /* clear stall first */ 3600 mtx_lock(fifo->priv_mtx); 3601 chan->flags |= UMIDI_FLAG_WRITE_STALL; 3602 chan->write_open_refcount++; 3603 sub->write_open = 1; 3604 3605 /* reset */ 3606 sub->state = UMIDI_ST_UNKNOWN; 3607 mtx_unlock(fifo->priv_mtx); 3608 } 3609 return (0); /* success */ 3610} 3611 3612static void 3613umidi_close(struct usb2_fifo *fifo, int fflags) 3614{ 3615 if (fflags & FREAD) { 3616 usb2_fifo_free_buffer(fifo); 3617 } 3618 if (fflags & FWRITE) { 3619 usb2_fifo_free_buffer(fifo); 3620 } 3621} 3622 3623 3624static int 3625umidi_ioctl(struct usb2_fifo *fifo, u_long cmd, void *data, 3626 int fflags) 3627{ 3628 return (ENODEV); 3629} 3630 3631static void 3632umidi_init(device_t dev) 3633{ 3634 struct uaudio_softc *sc = device_get_softc(dev); 3635 struct umidi_chan *chan = &sc->sc_midi_chan; 3636 3637 mtx_init(&chan->mtx, "umidi lock", NULL, MTX_DEF | MTX_RECURSE); 3638} 3639 3640static struct usb2_fifo_methods umidi_fifo_methods = { 3641 .f_start_read = &umidi_start_read, 3642 .f_start_write = &umidi_start_write, 3643 .f_stop_read = &umidi_stop_read, 3644 .f_stop_write = &umidi_stop_write, 3645 .f_open = &umidi_open, 3646 .f_close = &umidi_close, 3647 .f_ioctl = &umidi_ioctl, 3648 .basename[0] = "umidi", 3649}; 3650 3651static int32_t 3652umidi_probe(device_t dev) 3653{ 3654 struct uaudio_softc *sc = device_get_softc(dev); 3655 struct usb2_attach_arg *uaa = device_get_ivars(dev); 3656 struct umidi_chan *chan = &sc->sc_midi_chan; 3657 struct umidi_sub_chan *sub; 3658 int unit = device_get_unit(dev); 3659 int error; 3660 uint32_t n; 3661 3662 if (usb2_set_alt_interface_index(sc->sc_udev, chan->iface_index, 3663 chan->iface_alt_index)) { 3664 DPRINTF("setting of alternate index failed!\n"); 3665 goto detach; 3666 } 3667 usb2_set_parent_iface(sc->sc_udev, chan->iface_index, sc->sc_mixer_iface_index); 3668 3669 error = usb2_transfer_setup(uaa->device, &chan->iface_index, 3670 chan->xfer, umidi_config, UMIDI_N_TRANSFER, 3671 chan, &chan->mtx); 3672 if (error) { 3673 DPRINTF("error=%s\n", usb2_errstr(error)); 3674 goto detach; 3675 } 3676 if ((chan->max_cable > UMIDI_CABLES_MAX) || 3677 (chan->max_cable == 0)) { 3678 chan->max_cable = UMIDI_CABLES_MAX; 3679 } 3680 3681 for (n = 0; n < chan->max_cable; n++) { 3682 3683 sub = &chan->sub[n]; 3684 3685 error = usb2_fifo_attach(sc->sc_udev, chan, &chan->mtx, 3686 &umidi_fifo_methods, &sub->fifo, unit, n, 3687 chan->iface_index, 3688 UID_ROOT, GID_OPERATOR, 0644); 3689 if (error) { 3690 goto detach; 3691 } 3692 } 3693 3694 mtx_lock(&chan->mtx); 3695 3696 /* clear stall first */ 3697 chan->flags |= UMIDI_FLAG_READ_STALL; 3698 3699 /* 3700 * NOTE: at least one device will not work properly unless 3701 * the BULK pipe is open all the time. 3702 */ 3703 usb2_transfer_start(chan->xfer[1]); 3704 3705 mtx_unlock(&chan->mtx); 3706 3707 return (0); /* success */ 3708 3709detach: 3710 return (ENXIO); /* failure */ 3711} 3712 3713static int32_t 3714umidi_detach(device_t dev) 3715{ 3716 struct uaudio_softc *sc = device_get_softc(dev); 3717 struct umidi_chan *chan = &sc->sc_midi_chan; 3718 uint32_t n; 3719 3720 for (n = 0; n < UMIDI_CABLES_MAX; n++) { 3721 usb2_fifo_detach(&chan->sub[n].fifo); 3722 } 3723 3724 mtx_lock(&chan->mtx); 3725 3726 usb2_transfer_stop(chan->xfer[3]); 3727 usb2_transfer_stop(chan->xfer[1]); 3728 3729 mtx_unlock(&chan->mtx); 3730 3731 usb2_transfer_unsetup(chan->xfer, UMIDI_N_TRANSFER); 3732 3733 mtx_destroy(&chan->mtx); 3734 3735 return (0); 3736} 3737 3738DRIVER_MODULE(uaudio, uhub, uaudio_driver, uaudio_devclass, NULL, 0); 3739MODULE_DEPEND(uaudio, usb, 1, 1, 1); 3740MODULE_DEPEND(uaudio, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 3741MODULE_VERSION(uaudio, 1); 3742