uaudio.c revision 185948
1184610Salfred/* $NetBSD: uaudio.c,v 1.91 2004/11/05 17:46:14 kent Exp $ */ 2184610Salfred/* $FreeBSD: head/sys/dev/usb2/sound/uaudio2.c 185948 2008-12-11 23:13:02Z thompsa $ */ 3184610Salfred 4184610Salfred/*- 5184610Salfred * Copyright (c) 1999 The NetBSD Foundation, Inc. 6184610Salfred * All rights reserved. 7184610Salfred * 8184610Salfred * This code is derived from software contributed to The NetBSD Foundation 9184610Salfred * by Lennart Augustsson (lennart@augustsson.net) at 10184610Salfred * Carlstedt Research & Technology. 11184610Salfred * 12184610Salfred * Redistribution and use in source and binary forms, with or without 13184610Salfred * modification, are permitted provided that the following conditions 14184610Salfred * are met: 15184610Salfred * 1. Redistributions of source code must retain the above copyright 16184610Salfred * notice, this list of conditions and the following disclaimer. 17184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 18184610Salfred * notice, this list of conditions and the following disclaimer in the 19184610Salfred * documentation and/or other materials provided with the distribution. 20184610Salfred * 3. All advertising materials mentioning features or use of this software 21184610Salfred * must display the following acknowledgement: 22184610Salfred * This product includes software developed by the NetBSD 23184610Salfred * Foundation, Inc. and its contributors. 24184610Salfred * 4. Neither the name of The NetBSD Foundation nor the names of its 25184610Salfred * contributors may be used to endorse or promote products derived 26184610Salfred * from this software without specific prior written permission. 27184610Salfred * 28184610Salfred * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 29184610Salfred * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 30184610Salfred * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 31184610Salfred * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 32184610Salfred * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33184610Salfred * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34184610Salfred * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35184610Salfred * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36184610Salfred * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37184610Salfred * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38184610Salfred * POSSIBILITY OF SUCH DAMAGE. 39184610Salfred */ 40184610Salfred 41184610Salfred/* 42184610Salfred * USB audio specs: http://www.usb.org/developers/devclass_docs/audio10.pdf 43184610Salfred * http://www.usb.org/developers/devclass_docs/frmts10.pdf 44184610Salfred * http://www.usb.org/developers/devclass_docs/termt10.pdf 45184610Salfred */ 46184610Salfred 47184610Salfred/* 48184610Salfred * Also merged: 49184610Salfred * $NetBSD: uaudio.c,v 1.94 2005/01/15 15:19:53 kent Exp $ 50184610Salfred * $NetBSD: uaudio.c,v 1.95 2005/01/16 06:02:19 dsainty Exp $ 51184610Salfred * $NetBSD: uaudio.c,v 1.96 2005/01/16 12:46:00 kent Exp $ 52184610Salfred * $NetBSD: uaudio.c,v 1.97 2005/02/24 08:19:38 martin Exp $ 53184610Salfred */ 54184610Salfred 55184610Salfred#include <dev/usb2/include/usb2_devid.h> 56184610Salfred#include <dev/usb2/include/usb2_standard.h> 57184610Salfred#include <dev/usb2/include/usb2_mfunc.h> 58184610Salfred#include <dev/usb2/include/usb2_error.h> 59184610Salfred 60184610Salfred#define USB_DEBUG_VAR uaudio_debug 61184610Salfred 62184610Salfred#include <dev/usb2/core/usb2_core.h> 63184610Salfred#include <dev/usb2/core/usb2_lookup.h> 64184610Salfred#include <dev/usb2/core/usb2_debug.h> 65184610Salfred#include <dev/usb2/core/usb2_util.h> 66184610Salfred#include <dev/usb2/core/usb2_busdma.h> 67184610Salfred#include <dev/usb2/core/usb2_parse.h> 68184610Salfred#include <dev/usb2/core/usb2_request.h> 69184610Salfred#include <dev/usb2/core/usb2_mbuf.h> 70184610Salfred#include <dev/usb2/core/usb2_dev.h> 71184610Salfred#include <dev/usb2/core/usb2_dynamic.h> 72184610Salfred 73184610Salfred#include <dev/usb2/quirk/usb2_quirk.h> 74184610Salfred#include <dev/usb2/sound/uaudio2_reg.h> 75184610Salfred#include <dev/usb2/sound/uaudio2.h> 76184610Salfred 77184610Salfred#include <sys/reboot.h> /* for bootverbose */ 78184610Salfred 79184610Salfred#include <dev/sound/pcm/sound.h> 80184610Salfred#include <dev/sound/chip.h> 81184610Salfred#include "feeder_if.h" 82184610Salfred 83184610Salfred#if USB_DEBUG 84184610Salfredstatic int uaudio_debug = 0; 85184610Salfred 86184610SalfredSYSCTL_NODE(_hw_usb2, OID_AUTO, uaudio, CTLFLAG_RW, 0, "USB uaudio"); 87184610SalfredSYSCTL_INT(_hw_usb2_uaudio, OID_AUTO, debug, CTLFLAG_RW, 88184610Salfred &uaudio_debug, 0, "uaudio debug level"); 89184610Salfred#endif 90184610Salfred 91184610Salfredstatic uint32_t uaudio_default_rate = 96000; 92184610Salfredstatic uint8_t uaudio_default_bits = 32; 93184610Salfredstatic uint8_t uaudio_default_channels = 2; 94184610Salfred 95184610Salfred#define UAUDIO_NCHANBUFS 2 /* number of outstanding request */ 96184610Salfred#define UAUDIO_NFRAMES 25 /* ms of sound in each request */ 97184610Salfred#define UAUDIO_RECURSE_LIMIT 24 /* rounds */ 98184610Salfred#define UAUDIO_DEFAULT_BUFSZ ((2 * 96000 * 4 * 2) / (1000 / UAUDIO_NCHANBUFS)) /* bytes */ 99184610Salfred 100184610Salfred#define MAKE_WORD(h,l) (((h) << 8) | (l)) 101184610Salfred#define BIT_TEST(bm,bno) (((bm)[(bno) / 8] >> (7 - ((bno) % 8))) & 1) 102184610Salfred 103184610Salfredstruct uaudio_mixer_node { 104184610Salfred int32_t minval; 105184610Salfred int32_t maxval; 106184610Salfred#define MIX_MAX_CHAN 8 107184610Salfred int32_t wValue[MIX_MAX_CHAN]; /* using nchan */ 108184610Salfred uint32_t delta; 109184610Salfred uint32_t mul; 110184610Salfred uint32_t ctl; 111184610Salfred 112184610Salfred uint16_t wData[MIX_MAX_CHAN]; /* using nchan */ 113184610Salfred uint16_t wIndex; 114184610Salfred 115184610Salfred uint8_t update[(MIX_MAX_CHAN + 7) / 8]; 116184610Salfred uint8_t nchan; 117184610Salfred uint8_t type; 118184610Salfred#define MIX_ON_OFF 1 119184610Salfred#define MIX_SIGNED_16 2 120184610Salfred#define MIX_UNSIGNED_16 3 121184610Salfred#define MIX_SIGNED_8 4 122184610Salfred#define MIX_SELECTOR 5 123184610Salfred#define MIX_UNKNOWN 6 124184610Salfred#define MIX_SIZE(n) ((((n) == MIX_SIGNED_16) || \ 125184610Salfred ((n) == MIX_UNSIGNED_16)) ? 2 : 1) 126184610Salfred#define MIX_UNSIGNED(n) ((n) == MIX_UNSIGNED_16) 127184610Salfred 128184610Salfred#define MAX_SELECTOR_INPUT_PIN 256 129184610Salfred uint8_t slctrtype[MAX_SELECTOR_INPUT_PIN]; 130184610Salfred uint8_t class; 131184610Salfred 132184610Salfred struct uaudio_mixer_node *next; 133184610Salfred}; 134184610Salfred 135184610Salfredstruct uaudio_chan { 136184610Salfred struct pcmchan_caps pcm_cap; /* capabilities */ 137184610Salfred 138184610Salfred struct snd_dbuf *pcm_buf; 139184610Salfred const struct usb2_config *usb2_cfg; 140184610Salfred struct mtx *pcm_mtx; /* lock protecting this structure */ 141184610Salfred struct uaudio_softc *priv_sc; 142184610Salfred struct pcm_channel *pcm_ch; 143184610Salfred struct usb2_xfer *xfer[UAUDIO_NCHANBUFS]; 144184610Salfred const struct usb2_audio_streaming_interface_descriptor *p_asid; 145184610Salfred const struct usb2_audio_streaming_type1_descriptor *p_asf1d; 146184610Salfred const struct usb2_audio_streaming_endpoint_descriptor *p_sed; 147184610Salfred const usb2_endpoint_descriptor_audio_t *p_ed1; 148184610Salfred const usb2_endpoint_descriptor_audio_t *p_ed2; 149184610Salfred const struct uaudio_format *p_fmt; 150184610Salfred 151184610Salfred uint8_t *buf; /* pointer to buffer */ 152184610Salfred uint8_t *start; /* upper layer buffer start */ 153184610Salfred uint8_t *end; /* upper layer buffer end */ 154184610Salfred uint8_t *cur; /* current position in upper layer 155184610Salfred * buffer */ 156184610Salfred 157184610Salfred uint32_t block_size; 158184610Salfred uint32_t sample_rate; 159184610Salfred uint32_t format; 160184610Salfred uint32_t pcm_format[2]; 161184610Salfred 162184610Salfred uint16_t bytes_per_frame; 163184610Salfred 164184610Salfred uint8_t valid; 165184610Salfred uint8_t iface_index; 166184610Salfred uint8_t iface_alt_index; 167184610Salfred}; 168184610Salfred 169184610Salfred#define UMIDI_N_TRANSFER 4 /* units */ 170184610Salfred#define UMIDI_CABLES_MAX 16 /* units */ 171184610Salfred#define UMIDI_BULK_SIZE 1024 /* bytes */ 172184610Salfred 173184610Salfredstruct umidi_sub_chan { 174184610Salfred struct usb2_fifo_sc fifo; 175184610Salfred uint8_t *temp_cmd; 176184610Salfred uint8_t temp_0[4]; 177184610Salfred uint8_t temp_1[4]; 178184610Salfred uint8_t state; 179184610Salfred#define UMIDI_ST_UNKNOWN 0 /* scan for command */ 180184610Salfred#define UMIDI_ST_1PARAM 1 181184610Salfred#define UMIDI_ST_2PARAM_1 2 182184610Salfred#define UMIDI_ST_2PARAM_2 3 183184610Salfred#define UMIDI_ST_SYSEX_0 4 184184610Salfred#define UMIDI_ST_SYSEX_1 5 185184610Salfred#define UMIDI_ST_SYSEX_2 6 186184610Salfred 187184610Salfred uint8_t read_open:1; 188184610Salfred uint8_t write_open:1; 189184610Salfred uint8_t unused:6; 190184610Salfred}; 191184610Salfred 192184610Salfredstruct umidi_chan { 193184610Salfred 194184610Salfred struct umidi_sub_chan sub[UMIDI_CABLES_MAX]; 195184610Salfred struct mtx mtx; 196184610Salfred 197184610Salfred struct usb2_xfer *xfer[UMIDI_N_TRANSFER]; 198184610Salfred 199184610Salfred uint8_t iface_index; 200184610Salfred uint8_t iface_alt_index; 201184610Salfred 202184610Salfred uint8_t flags; 203184610Salfred#define UMIDI_FLAG_READ_STALL 0x01 204184610Salfred#define UMIDI_FLAG_WRITE_STALL 0x02 205184610Salfred 206184610Salfred uint8_t read_open_refcount; 207184610Salfred uint8_t write_open_refcount; 208184610Salfred 209184610Salfred uint8_t curr_cable; 210184610Salfred uint8_t max_cable; 211184610Salfred uint8_t valid; 212184610Salfred}; 213184610Salfred 214184610Salfredstruct uaudio_softc { 215184610Salfred struct sbuf sc_sndstat; 216184610Salfred struct sndcard_func sc_sndcard_func; 217184610Salfred struct uaudio_chan sc_rec_chan; 218184610Salfred struct uaudio_chan sc_play_chan; 219184610Salfred struct umidi_chan sc_midi_chan; 220184610Salfred 221184610Salfred struct usb2_device *sc_udev; 222184610Salfred struct usb2_xfer *sc_mixer_xfer[1]; 223184610Salfred struct uaudio_mixer_node *sc_mixer_root; 224184610Salfred struct uaudio_mixer_node *sc_mixer_curr; 225184610Salfred 226184610Salfred uint32_t sc_mix_info; 227184610Salfred uint32_t sc_recsrc_info; 228184610Salfred 229184610Salfred uint16_t sc_audio_rev; 230184610Salfred uint16_t sc_mixer_count; 231184610Salfred 232184610Salfred uint8_t sc_sndstat_valid; 233184610Salfred uint8_t sc_mixer_iface_index; 234184610Salfred uint8_t sc_mixer_iface_no; 235184610Salfred uint8_t sc_mixer_chan; 236184610Salfred uint8_t sc_pcm_registered:1; 237184610Salfred uint8_t sc_mixer_init:1; 238184610Salfred uint8_t sc_uq_audio_swap_lr:1; 239184610Salfred uint8_t sc_uq_au_inp_async:1; 240184610Salfred uint8_t sc_uq_au_no_xu:1; 241184610Salfred uint8_t sc_uq_bad_adc:1; 242184610Salfred}; 243184610Salfred 244184610Salfredstruct uaudio_search_result { 245184610Salfred uint8_t bit_input[(256 + 7) / 8]; 246184610Salfred uint8_t bit_output[(256 + 7) / 8]; 247184610Salfred uint8_t bit_visited[(256 + 7) / 8]; 248184610Salfred uint8_t recurse_level; 249184610Salfred uint8_t id_max; 250184610Salfred}; 251184610Salfred 252184610Salfredstruct uaudio_terminal_node { 253184610Salfred union { 254184610Salfred const struct usb2_descriptor *desc; 255184610Salfred const struct usb2_audio_input_terminal *it; 256184610Salfred const struct usb2_audio_output_terminal *ot; 257184610Salfred const struct usb2_audio_mixer_unit_0 *mu; 258184610Salfred const struct usb2_audio_selector_unit *su; 259184610Salfred const struct usb2_audio_feature_unit *fu; 260184610Salfred const struct usb2_audio_processing_unit_0 *pu; 261184610Salfred const struct usb2_audio_extension_unit_0 *eu; 262184610Salfred } u; 263184610Salfred struct uaudio_search_result usr; 264184610Salfred struct uaudio_terminal_node *root; 265184610Salfred}; 266184610Salfred 267184610Salfredstruct uaudio_format { 268184610Salfred uint16_t wFormat; 269184610Salfred uint8_t bPrecision; 270184610Salfred uint32_t freebsd_fmt; 271184610Salfred const char *description; 272184610Salfred}; 273184610Salfred 274184610Salfredstatic const struct uaudio_format uaudio_formats[] = { 275184610Salfred 276184610Salfred {UA_FMT_PCM8, 8, AFMT_U8, "8-bit U-LE PCM"}, 277184610Salfred {UA_FMT_PCM8, 16, AFMT_U16_LE, "16-bit U-LE PCM"}, 278184610Salfred {UA_FMT_PCM8, 24, AFMT_U24_LE, "24-bit U-LE PCM"}, 279184610Salfred {UA_FMT_PCM8, 32, AFMT_U32_LE, "32-bit U-LE PCM"}, 280184610Salfred 281184610Salfred {UA_FMT_PCM, 8, AFMT_S8, "8-bit S-LE PCM"}, 282184610Salfred {UA_FMT_PCM, 16, AFMT_S16_LE, "16-bit S-LE PCM"}, 283184610Salfred {UA_FMT_PCM, 24, AFMT_S24_LE, "24-bit S-LE PCM"}, 284184610Salfred {UA_FMT_PCM, 32, AFMT_S32_LE, "32-bit S-LE PCM"}, 285184610Salfred 286184610Salfred {UA_FMT_ALAW, 8, AFMT_A_LAW, "8-bit A-Law"}, 287184610Salfred {UA_FMT_MULAW, 8, AFMT_MU_LAW, "8-bit mu-Law"}, 288184610Salfred 289184610Salfred {0, 0, 0, NULL} 290184610Salfred}; 291184610Salfred 292184610Salfred#define UAC_OUTPUT 0 293184610Salfred#define UAC_INPUT 1 294184610Salfred#define UAC_EQUAL 2 295184610Salfred#define UAC_RECORD 3 296184610Salfred#define UAC_NCLASSES 4 297184610Salfred 298184610Salfred#if USB_DEBUG 299184610Salfredstatic const char *uac_names[] = { 300184610Salfred "outputs", "inputs", "equalization", "record" 301184610Salfred}; 302184610Salfred 303184610Salfred#endif 304184610Salfred 305184610Salfred/* prototypes */ 306184610Salfred 307184610Salfredstatic device_probe_t uaudio_probe; 308184610Salfredstatic device_attach_t uaudio_attach; 309184610Salfredstatic device_detach_t uaudio_detach; 310184610Salfred 311184610Salfredstatic usb2_callback_t uaudio_chan_play_callback; 312184610Salfredstatic usb2_callback_t uaudio_chan_record_callback; 313184610Salfredstatic usb2_callback_t uaudio_mixer_write_cfg_callback; 314184610Salfredstatic usb2_callback_t umidi_read_clear_stall_callback; 315184610Salfredstatic usb2_callback_t umidi_bulk_read_callback; 316184610Salfredstatic usb2_callback_t umidi_write_clear_stall_callback; 317184610Salfredstatic usb2_callback_t umidi_bulk_write_callback; 318184610Salfred 319185948Sthompsastatic void uaudio_chan_fill_info_sub(struct uaudio_softc *, 320185948Sthompsa struct usb2_device *, uint32_t, uint16_t, uint8_t, uint8_t); 321185948Sthompsastatic void uaudio_chan_fill_info(struct uaudio_softc *, 322185948Sthompsa struct usb2_device *); 323185948Sthompsastatic void uaudio_mixer_add_ctl_sub(struct uaudio_softc *, 324185948Sthompsa struct uaudio_mixer_node *); 325185948Sthompsastatic void uaudio_mixer_add_ctl(struct uaudio_softc *, 326185948Sthompsa struct uaudio_mixer_node *); 327185948Sthompsastatic void uaudio_mixer_add_input(struct uaudio_softc *, 328185948Sthompsa const struct uaudio_terminal_node *, int); 329185948Sthompsastatic void uaudio_mixer_add_output(struct uaudio_softc *, 330185948Sthompsa const struct uaudio_terminal_node *, int); 331185948Sthompsastatic void uaudio_mixer_add_mixer(struct uaudio_softc *, 332185948Sthompsa const struct uaudio_terminal_node *, int); 333185948Sthompsastatic void uaudio_mixer_add_selector(struct uaudio_softc *, 334185948Sthompsa const struct uaudio_terminal_node *, int); 335185948Sthompsastatic uint32_t uaudio_mixer_feature_get_bmaControls( 336185948Sthompsa const struct usb2_audio_feature_unit *, uint8_t); 337185948Sthompsastatic void uaudio_mixer_add_feature(struct uaudio_softc *, 338185948Sthompsa const struct uaudio_terminal_node *, int); 339185948Sthompsastatic void uaudio_mixer_add_processing_updown(struct uaudio_softc *, 340185948Sthompsa const struct uaudio_terminal_node *, int); 341185948Sthompsastatic void uaudio_mixer_add_processing(struct uaudio_softc *, 342185948Sthompsa const struct uaudio_terminal_node *, int); 343185948Sthompsastatic void uaudio_mixer_add_extension(struct uaudio_softc *, 344185948Sthompsa const struct uaudio_terminal_node *, int); 345185948Sthompsastatic struct usb2_audio_cluster uaudio_mixer_get_cluster(uint8_t, 346185948Sthompsa const struct uaudio_terminal_node *); 347185948Sthompsastatic uint16_t uaudio_mixer_determine_class(const struct uaudio_terminal_node *, 348185948Sthompsa struct uaudio_mixer_node *); 349185948Sthompsastatic uint16_t uaudio_mixer_feature_name(const struct uaudio_terminal_node *, 350185948Sthompsa struct uaudio_mixer_node *); 351185948Sthompsastatic const struct uaudio_terminal_node *uaudio_mixer_get_input( 352185948Sthompsa const struct uaudio_terminal_node *, uint8_t); 353185948Sthompsastatic const struct uaudio_terminal_node *uaudio_mixer_get_output( 354185948Sthompsa const struct uaudio_terminal_node *, uint8_t); 355185948Sthompsastatic void uaudio_mixer_find_inputs_sub(struct uaudio_terminal_node *, 356185948Sthompsa const uint8_t *, uint8_t, struct uaudio_search_result *); 357185948Sthompsastatic void uaudio_mixer_find_outputs_sub(struct uaudio_terminal_node *, 358185948Sthompsa uint8_t, uint8_t, struct uaudio_search_result *); 359185948Sthompsastatic void uaudio_mixer_fill_info(struct uaudio_softc *, 360185948Sthompsa struct usb2_device *, void *); 361185948Sthompsastatic uint16_t uaudio_mixer_get(struct usb2_device *, uint8_t, 362185948Sthompsa struct uaudio_mixer_node *); 363185948Sthompsastatic void uaudio_mixer_ctl_set(struct uaudio_softc *, 364185948Sthompsa struct uaudio_mixer_node *, uint8_t, int32_t val); 365185948Sthompsastatic usb2_error_t uaudio_set_speed(struct usb2_device *, uint8_t, uint32_t); 366185948Sthompsastatic int uaudio_mixer_signext(uint8_t, int); 367185948Sthompsastatic int uaudio_mixer_bsd2value(struct uaudio_mixer_node *, int32_t val); 368185948Sthompsastatic const void *uaudio_mixer_verify_desc(const void *, uint32_t); 369185948Sthompsastatic void uaudio_mixer_init(struct uaudio_softc *); 370185948Sthompsastatic uint8_t umidi_convert_to_usb(struct umidi_sub_chan *, uint8_t, uint8_t); 371185948Sthompsastatic struct umidi_sub_chan *umidi_sub_by_fifo(struct usb2_fifo *); 372185948Sthompsastatic void umidi_start_read(struct usb2_fifo *); 373185948Sthompsastatic void umidi_stop_read(struct usb2_fifo *); 374185948Sthompsastatic void umidi_start_write(struct usb2_fifo *); 375185948Sthompsastatic void umidi_stop_write(struct usb2_fifo *); 376185948Sthompsastatic int umidi_open(struct usb2_fifo *, int, struct thread *); 377185948Sthompsastatic int umidi_ioctl(struct usb2_fifo *, u_long cmd, void *, int, struct thread *); 378185948Sthompsastatic void umidi_close(struct usb2_fifo *, int, struct thread *); 379185948Sthompsastatic void umidi_init(device_t dev); 380185948Sthompsastatic int32_t umidi_probe(device_t dev); 381185948Sthompsastatic int32_t umidi_detach(device_t dev); 382184610Salfred 383184610Salfred#if USB_DEBUG 384185948Sthompsastatic void uaudio_chan_dump_ep_desc( 385185948Sthompsa const usb2_endpoint_descriptor_audio_t *); 386185948Sthompsastatic void uaudio_mixer_dump_cluster(uint8_t, 387185948Sthompsa const struct uaudio_terminal_node *); 388185948Sthompsastatic const char *uaudio_mixer_get_terminal_name(uint16_t); 389184610Salfred#endif 390184610Salfred 391184610Salfredstatic const struct usb2_config 392184610Salfred uaudio_cfg_record_full_speed[UAUDIO_NCHANBUFS] = { 393184610Salfred [0] = { 394184610Salfred .type = UE_ISOCHRONOUS, 395184610Salfred .endpoint = UE_ADDR_ANY, 396184610Salfred .direction = UE_DIR_IN, 397184610Salfred .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */ 398184610Salfred .mh.frames = UAUDIO_NFRAMES, 399184610Salfred .mh.flags = {.short_xfer_ok = 1,}, 400184610Salfred .mh.callback = &uaudio_chan_record_callback, 401184610Salfred }, 402184610Salfred 403184610Salfred [1] = { 404184610Salfred .type = UE_ISOCHRONOUS, 405184610Salfred .endpoint = UE_ADDR_ANY, 406184610Salfred .direction = UE_DIR_IN, 407184610Salfred .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */ 408184610Salfred .mh.frames = UAUDIO_NFRAMES, 409184610Salfred .mh.flags = {.short_xfer_ok = 1,}, 410184610Salfred .mh.callback = &uaudio_chan_record_callback, 411184610Salfred }, 412184610Salfred}; 413184610Salfred 414184610Salfredstatic const struct usb2_config 415184610Salfred uaudio_cfg_record_high_speed[UAUDIO_NCHANBUFS] = { 416184610Salfred [0] = { 417184610Salfred .type = UE_ISOCHRONOUS, 418184610Salfred .endpoint = UE_ADDR_ANY, 419184610Salfred .direction = UE_DIR_IN, 420184610Salfred .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */ 421184610Salfred .mh.frames = (UAUDIO_NFRAMES * 8), 422184610Salfred .mh.flags = {.short_xfer_ok = 1,}, 423184610Salfred .mh.callback = &uaudio_chan_record_callback, 424184610Salfred }, 425184610Salfred 426184610Salfred [1] = { 427184610Salfred .type = UE_ISOCHRONOUS, 428184610Salfred .endpoint = UE_ADDR_ANY, 429184610Salfred .direction = UE_DIR_IN, 430184610Salfred .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */ 431184610Salfred .mh.frames = (UAUDIO_NFRAMES * 8), 432184610Salfred .mh.flags = {.short_xfer_ok = 1,}, 433184610Salfred .mh.callback = &uaudio_chan_record_callback, 434184610Salfred }, 435184610Salfred}; 436184610Salfred 437184610Salfredstatic const struct usb2_config 438184610Salfred uaudio_cfg_play_full_speed[UAUDIO_NCHANBUFS] = { 439184610Salfred [0] = { 440184610Salfred .type = UE_ISOCHRONOUS, 441184610Salfred .endpoint = UE_ADDR_ANY, 442184610Salfred .direction = UE_DIR_OUT, 443184610Salfred .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */ 444184610Salfred .mh.frames = UAUDIO_NFRAMES, 445184610Salfred .mh.flags = {.short_xfer_ok = 1,}, 446184610Salfred .mh.callback = &uaudio_chan_play_callback, 447184610Salfred }, 448184610Salfred 449184610Salfred [1] = { 450184610Salfred .type = UE_ISOCHRONOUS, 451184610Salfred .endpoint = UE_ADDR_ANY, 452184610Salfred .direction = UE_DIR_OUT, 453184610Salfred .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */ 454184610Salfred .mh.frames = UAUDIO_NFRAMES, 455184610Salfred .mh.flags = {.short_xfer_ok = 1,}, 456184610Salfred .mh.callback = &uaudio_chan_play_callback, 457184610Salfred }, 458184610Salfred}; 459184610Salfred 460184610Salfredstatic const struct usb2_config 461184610Salfred uaudio_cfg_play_high_speed[UAUDIO_NCHANBUFS] = { 462184610Salfred [0] = { 463184610Salfred .type = UE_ISOCHRONOUS, 464184610Salfred .endpoint = UE_ADDR_ANY, 465184610Salfred .direction = UE_DIR_OUT, 466184610Salfred .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */ 467184610Salfred .mh.frames = (UAUDIO_NFRAMES * 8), 468184610Salfred .mh.flags = {.short_xfer_ok = 1,}, 469184610Salfred .mh.callback = &uaudio_chan_play_callback, 470184610Salfred }, 471184610Salfred 472184610Salfred [1] = { 473184610Salfred .type = UE_ISOCHRONOUS, 474184610Salfred .endpoint = UE_ADDR_ANY, 475184610Salfred .direction = UE_DIR_OUT, 476184610Salfred .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */ 477184610Salfred .mh.frames = (UAUDIO_NFRAMES * 8), 478184610Salfred .mh.flags = {.short_xfer_ok = 1,}, 479184610Salfred .mh.callback = &uaudio_chan_play_callback, 480184610Salfred }, 481184610Salfred}; 482184610Salfred 483184610Salfredstatic const struct usb2_config 484184610Salfred uaudio_mixer_config[1] = { 485184610Salfred [0] = { 486184610Salfred .type = UE_CONTROL, 487184610Salfred .endpoint = 0x00, /* Control pipe */ 488184610Salfred .direction = UE_DIR_ANY, 489184610Salfred .mh.bufsize = (sizeof(struct usb2_device_request) + 4), 490184610Salfred .mh.callback = &uaudio_mixer_write_cfg_callback, 491184610Salfred .mh.timeout = 1000, /* 1 second */ 492184610Salfred }, 493184610Salfred}; 494184610Salfred 495184610Salfredstatic const 496184610Salfreduint8_t umidi_cmd_to_len[16] = { 497184610Salfred [0x0] = 0, /* reserved */ 498184610Salfred [0x1] = 0, /* reserved */ 499184610Salfred [0x2] = 2, /* bytes */ 500184610Salfred [0x3] = 3, /* bytes */ 501184610Salfred [0x4] = 3, /* bytes */ 502184610Salfred [0x5] = 1, /* bytes */ 503184610Salfred [0x6] = 2, /* bytes */ 504184610Salfred [0x7] = 3, /* bytes */ 505184610Salfred [0x8] = 3, /* bytes */ 506184610Salfred [0x9] = 3, /* bytes */ 507184610Salfred [0xA] = 3, /* bytes */ 508184610Salfred [0xB] = 3, /* bytes */ 509184610Salfred [0xC] = 2, /* bytes */ 510184610Salfred [0xD] = 2, /* bytes */ 511184610Salfred [0xE] = 3, /* bytes */ 512184610Salfred [0xF] = 1, /* bytes */ 513184610Salfred}; 514184610Salfred 515184610Salfredstatic const struct usb2_config 516184610Salfred umidi_config[UMIDI_N_TRANSFER] = { 517184610Salfred [0] = { 518184610Salfred .type = UE_BULK, 519184610Salfred .endpoint = UE_ADDR_ANY, 520184610Salfred .direction = UE_DIR_OUT, 521184610Salfred .mh.bufsize = UMIDI_BULK_SIZE, 522184610Salfred .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 523184610Salfred .mh.callback = &umidi_bulk_write_callback, 524184610Salfred }, 525184610Salfred 526184610Salfred [1] = { 527184610Salfred .type = UE_BULK, 528184610Salfred .endpoint = UE_ADDR_ANY, 529184610Salfred .direction = UE_DIR_IN, 530184610Salfred .mh.bufsize = UMIDI_BULK_SIZE, 531184610Salfred .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 532184610Salfred .mh.callback = &umidi_bulk_read_callback, 533184610Salfred }, 534184610Salfred 535184610Salfred [2] = { 536184610Salfred .type = UE_CONTROL, 537184610Salfred .endpoint = 0x00, /* Control pipe */ 538184610Salfred .direction = UE_DIR_ANY, 539184610Salfred .mh.bufsize = sizeof(struct usb2_device_request), 540184610Salfred .mh.flags = {}, 541184610Salfred .mh.callback = &umidi_write_clear_stall_callback, 542184610Salfred .mh.timeout = 1000, /* 1 second */ 543184610Salfred .mh.interval = 50, /* 50ms */ 544184610Salfred }, 545184610Salfred 546184610Salfred [3] = { 547184610Salfred .type = UE_CONTROL, 548184610Salfred .endpoint = 0x00, /* Control pipe */ 549184610Salfred .direction = UE_DIR_ANY, 550184610Salfred .mh.bufsize = sizeof(struct usb2_device_request), 551184610Salfred .mh.flags = {}, 552184610Salfred .mh.callback = &umidi_read_clear_stall_callback, 553184610Salfred .mh.timeout = 1000, /* 1 second */ 554184610Salfred .mh.interval = 50, /* 50ms */ 555184610Salfred }, 556184610Salfred}; 557184610Salfred 558184610Salfredstatic devclass_t uaudio_devclass; 559184610Salfred 560184610Salfredstatic device_method_t uaudio_methods[] = { 561184610Salfred DEVMETHOD(device_probe, uaudio_probe), 562184610Salfred DEVMETHOD(device_attach, uaudio_attach), 563184610Salfred DEVMETHOD(device_detach, uaudio_detach), 564184610Salfred DEVMETHOD(device_suspend, bus_generic_suspend), 565184610Salfred DEVMETHOD(device_resume, bus_generic_resume), 566184610Salfred DEVMETHOD(device_shutdown, bus_generic_shutdown), 567184610Salfred DEVMETHOD(bus_print_child, bus_generic_print_child), 568184610Salfred {0, 0} 569184610Salfred}; 570184610Salfred 571184610Salfredstatic driver_t uaudio_driver = { 572184610Salfred .name = "uaudio", 573184610Salfred .methods = uaudio_methods, 574184610Salfred .size = sizeof(struct uaudio_softc), 575184610Salfred}; 576184610Salfred 577184610Salfredstatic int 578184610Salfreduaudio_probe(device_t dev) 579184610Salfred{ 580184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 581184610Salfred 582184610Salfred if (uaa->usb2_mode != USB_MODE_HOST) { 583184610Salfred return (ENXIO); 584184610Salfred } 585184610Salfred /* trigger on the control interface */ 586184610Salfred 587184610Salfred if ((uaa->info.bInterfaceClass == UICLASS_AUDIO) && 588184610Salfred (uaa->info.bInterfaceSubClass == UISUBCLASS_AUDIOCONTROL)) { 589184610Salfred if (usb2_test_quirk(uaa, UQ_BAD_AUDIO)) 590184610Salfred return (ENXIO); 591184610Salfred else 592184610Salfred return (0); 593184610Salfred } 594184610Salfred return (ENXIO); 595184610Salfred} 596184610Salfred 597184610Salfredstatic int 598184610Salfreduaudio_attach(device_t dev) 599184610Salfred{ 600184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 601184610Salfred struct uaudio_softc *sc = device_get_softc(dev); 602184610Salfred struct usb2_interface_descriptor *id; 603184610Salfred device_t child; 604184610Salfred 605184610Salfred if (sc == NULL) { 606184610Salfred return (ENOMEM); 607184610Salfred } 608184610Salfred sc->sc_play_chan.priv_sc = sc; 609184610Salfred sc->sc_rec_chan.priv_sc = sc; 610184610Salfred sc->sc_udev = uaa->device; 611184610Salfred 612184610Salfred if (usb2_test_quirk(uaa, UQ_AUDIO_SWAP_LR)) 613184610Salfred sc->sc_uq_audio_swap_lr = 1; 614184610Salfred 615184610Salfred if (usb2_test_quirk(uaa, UQ_AU_INP_ASYNC)) 616184610Salfred sc->sc_uq_au_inp_async = 1; 617184610Salfred 618184610Salfred if (usb2_test_quirk(uaa, UQ_AU_NO_XU)) 619184610Salfred sc->sc_uq_au_no_xu = 1; 620184610Salfred 621184610Salfred if (usb2_test_quirk(uaa, UQ_BAD_ADC)) 622184610Salfred sc->sc_uq_bad_adc = 1; 623184610Salfred 624184610Salfred umidi_init(dev); 625184610Salfred 626184610Salfred device_set_usb2_desc(dev); 627184610Salfred 628184610Salfred id = usb2_get_interface_descriptor(uaa->iface); 629184610Salfred 630184610Salfred uaudio_chan_fill_info(sc, uaa->device); 631184610Salfred 632184610Salfred uaudio_mixer_fill_info(sc, uaa->device, id); 633184610Salfred 634184610Salfred sc->sc_mixer_iface_index = uaa->info.bIfaceIndex; 635184610Salfred sc->sc_mixer_iface_no = uaa->info.bIfaceNum; 636184610Salfred 637184610Salfred DPRINTF("audio rev %d.%02x\n", 638184610Salfred sc->sc_audio_rev >> 8, 639184610Salfred sc->sc_audio_rev & 0xff); 640184610Salfred 641184610Salfred DPRINTF("%d mixer controls\n", 642184610Salfred sc->sc_mixer_count); 643184610Salfred 644184610Salfred if (sc->sc_play_chan.valid) { 645184610Salfred device_printf(dev, "Play: %d Hz, %d ch, %s format\n", 646184610Salfred sc->sc_play_chan.sample_rate, 647184610Salfred sc->sc_play_chan.p_asf1d->bNrChannels, 648184610Salfred sc->sc_play_chan.p_fmt->description); 649184610Salfred } else { 650184610Salfred device_printf(dev, "No playback!\n"); 651184610Salfred } 652184610Salfred 653184610Salfred if (sc->sc_rec_chan.valid) { 654184610Salfred device_printf(dev, "Record: %d Hz, %d ch, %s format\n", 655184610Salfred sc->sc_rec_chan.sample_rate, 656184610Salfred sc->sc_rec_chan.p_asf1d->bNrChannels, 657184610Salfred sc->sc_rec_chan.p_fmt->description); 658184610Salfred } else { 659184610Salfred device_printf(dev, "No recording!\n"); 660184610Salfred } 661184610Salfred 662184610Salfred if (sc->sc_midi_chan.valid) { 663184610Salfred 664184610Salfred if (umidi_probe(dev)) { 665184610Salfred goto detach; 666184610Salfred } 667184610Salfred device_printf(dev, "MIDI sequencer\n"); 668184610Salfred } else { 669184610Salfred device_printf(dev, "No midi sequencer\n"); 670184610Salfred } 671184610Salfred 672184610Salfred DPRINTF("doing child attach\n"); 673184610Salfred 674184610Salfred /* attach the children */ 675184610Salfred 676184610Salfred sc->sc_sndcard_func.func = SCF_PCM; 677184610Salfred 678184610Salfred child = device_add_child(dev, "pcm", -1); 679184610Salfred 680184610Salfred if (child == NULL) { 681184610Salfred DPRINTF("out of memory\n"); 682184610Salfred goto detach; 683184610Salfred } 684184610Salfred device_set_ivars(child, &sc->sc_sndcard_func); 685184610Salfred 686184610Salfred if (bus_generic_attach(dev)) { 687184610Salfred DPRINTF("child attach failed\n"); 688184610Salfred goto detach; 689184610Salfred } 690184610Salfred return (0); /* success */ 691184610Salfred 692184610Salfreddetach: 693184610Salfred uaudio_detach(dev); 694184610Salfred return (ENXIO); 695184610Salfred} 696184610Salfred 697184610Salfredstatic void 698184610Salfreduaudio_pcm_setflags(device_t dev, uint32_t flags) 699184610Salfred{ 700184610Salfred pcm_setflags(dev, pcm_getflags(dev) | flags); 701184610Salfred} 702184610Salfred 703184610Salfredint 704184610Salfreduaudio_attach_sub(device_t dev, kobj_class_t mixer_class, kobj_class_t chan_class) 705184610Salfred{ 706184610Salfred struct uaudio_softc *sc = device_get_softc(device_get_parent(dev)); 707184610Salfred char status[SND_STATUSLEN]; 708184610Salfred 709184610Salfred if (bootverbose) { 710184610Salfred device_printf(dev, "using a default buffer " 711184610Salfred "size of %u bytes\n", UAUDIO_DEFAULT_BUFSZ); 712184610Salfred } 713184610Salfred uaudio_mixer_init(sc); 714184610Salfred 715184610Salfred if (sc->sc_uq_audio_swap_lr) { 716184610Salfred DPRINTF("hardware has swapped left and right\n"); 717184610Salfred uaudio_pcm_setflags(dev, SD_F_PSWAPLR); 718184610Salfred } 719184610Salfred if (!(sc->sc_mix_info & SOUND_MASK_PCM)) { 720184610Salfred 721184610Salfred DPRINTF("emulating master volume\n"); 722184610Salfred 723184610Salfred /* 724184610Salfred * Emulate missing pcm mixer controller 725184610Salfred * through FEEDER_VOLUME 726184610Salfred */ 727184610Salfred uaudio_pcm_setflags(dev, SD_F_SOFTPCMVOL); 728184610Salfred } 729184610Salfred if (mixer_init(dev, mixer_class, sc)) { 730184610Salfred goto detach; 731184610Salfred } 732184610Salfred sc->sc_mixer_init = 1; 733184610Salfred 734184610Salfred snprintf(status, sizeof(status), "at ? %s", PCM_KLDSTRING(snd_uaudio)); 735184610Salfred 736184610Salfred if (pcm_register(dev, sc, 737184610Salfred sc->sc_play_chan.valid ? 1 : 0, 738184610Salfred sc->sc_rec_chan.valid ? 1 : 0)) { 739184610Salfred goto detach; 740184610Salfred } 741184610Salfred sc->sc_pcm_registered = 1; 742184610Salfred 743184610Salfred if (sc->sc_play_chan.valid) { 744184610Salfred pcm_addchan(dev, PCMDIR_PLAY, chan_class, sc); 745184610Salfred } 746184610Salfred if (sc->sc_rec_chan.valid) { 747184610Salfred pcm_addchan(dev, PCMDIR_REC, chan_class, sc); 748184610Salfred } 749184610Salfred pcm_setstatus(dev, status); 750184610Salfred 751184610Salfred return (0); /* success */ 752184610Salfred 753184610Salfreddetach: 754184610Salfred uaudio_detach_sub(dev); 755184610Salfred return (ENXIO); 756184610Salfred} 757184610Salfred 758184610Salfredint 759184610Salfreduaudio_detach_sub(device_t dev) 760184610Salfred{ 761184610Salfred struct uaudio_softc *sc = device_get_softc(device_get_parent(dev)); 762184610Salfred int error = 0; 763184610Salfred 764184610Salfredrepeat: 765184610Salfred if (sc->sc_pcm_registered) { 766184610Salfred error = pcm_unregister(dev); 767184610Salfred } else { 768184610Salfred if (sc->sc_mixer_init) { 769184610Salfred error = mixer_uninit(dev); 770184610Salfred } 771184610Salfred } 772184610Salfred 773184610Salfred if (error) { 774184610Salfred device_printf(dev, "Waiting for sound application to exit!\n"); 775184610Salfred mtx_lock(&Giant); 776184610Salfred usb2_pause_mtx(&Giant, 2000); 777184610Salfred mtx_unlock(&Giant); 778184610Salfred goto repeat; /* try again */ 779184610Salfred } 780184610Salfred return (0); /* success */ 781184610Salfred} 782184610Salfred 783184610Salfredstatic int 784184610Salfreduaudio_detach(device_t dev) 785184610Salfred{ 786184610Salfred struct uaudio_softc *sc = device_get_softc(dev); 787184610Salfred 788184610Salfred if (bus_generic_detach(dev)) { 789184610Salfred DPRINTF("detach failed!\n"); 790184610Salfred } 791184610Salfred sbuf_delete(&sc->sc_sndstat); 792184610Salfred sc->sc_sndstat_valid = 0; 793184610Salfred 794184610Salfred umidi_detach(dev); 795184610Salfred 796184610Salfred return (0); 797184610Salfred} 798184610Salfred 799184610Salfred/*========================================================================* 800184610Salfred * AS - Audio Stream - routines 801184610Salfred *========================================================================*/ 802184610Salfred 803184610Salfred#if USB_DEBUG 804184610Salfredstatic void 805184610Salfreduaudio_chan_dump_ep_desc(const usb2_endpoint_descriptor_audio_t *ed) 806184610Salfred{ 807184610Salfred if (ed) { 808184610Salfred DPRINTF("endpoint=%p bLength=%d bDescriptorType=%d \n" 809184610Salfred "bEndpointAddress=%d bmAttributes=0x%x \n" 810184610Salfred "wMaxPacketSize=%d bInterval=%d \n" 811184610Salfred "bRefresh=%d bSynchAddress=%d\n", 812184610Salfred ed, ed->bLength, ed->bDescriptorType, 813184610Salfred ed->bEndpointAddress, ed->bmAttributes, 814184610Salfred UGETW(ed->wMaxPacketSize), ed->bInterval, 815184610Salfred ed->bRefresh, ed->bSynchAddress); 816184610Salfred } 817184610Salfred return; 818184610Salfred} 819184610Salfred 820184610Salfred#endif 821184610Salfred 822184610Salfredstatic void 823184610Salfreduaudio_chan_fill_info_sub(struct uaudio_softc *sc, struct usb2_device *udev, 824184610Salfred uint32_t rate, uint16_t fps, uint8_t channels, 825184610Salfred uint8_t bit_resolution) 826184610Salfred{ 827184610Salfred struct usb2_descriptor *desc = NULL; 828184610Salfred const struct usb2_audio_streaming_interface_descriptor *asid = NULL; 829184610Salfred const struct usb2_audio_streaming_type1_descriptor *asf1d = NULL; 830184610Salfred const struct usb2_audio_streaming_endpoint_descriptor *sed = NULL; 831184610Salfred const usb2_endpoint_descriptor_audio_t *ed1 = NULL; 832184610Salfred const usb2_endpoint_descriptor_audio_t *ed2 = NULL; 833184610Salfred struct usb2_config_descriptor *cd = usb2_get_config_descriptor(udev); 834184610Salfred struct usb2_interface_descriptor *id; 835184610Salfred const struct uaudio_format *p_fmt; 836184610Salfred struct uaudio_chan *chan; 837184610Salfred uint16_t curidx = 0xFFFF; 838184610Salfred uint16_t lastidx = 0xFFFF; 839184610Salfred uint16_t alt_index = 0; 840184610Salfred uint16_t wFormat; 841184610Salfred uint8_t ep_dir; 842184610Salfred uint8_t ep_type; 843184610Salfred uint8_t ep_sync; 844184610Salfred uint8_t bChannels; 845184610Salfred uint8_t bBitResolution; 846184610Salfred uint8_t x; 847184610Salfred uint8_t audio_if = 0; 848184610Salfred uint8_t sample_size; 849184610Salfred 850184610Salfred while ((desc = usb2_desc_foreach(cd, desc))) { 851184610Salfred 852184610Salfred if ((desc->bDescriptorType == UDESC_INTERFACE) && 853184610Salfred (desc->bLength >= sizeof(*id))) { 854184610Salfred 855184610Salfred id = (void *)desc; 856184610Salfred 857184610Salfred if (id->bInterfaceNumber != lastidx) { 858184610Salfred lastidx = id->bInterfaceNumber; 859184610Salfred curidx++; 860184610Salfred alt_index = 0; 861184610Salfred 862184610Salfred } else { 863184610Salfred alt_index++; 864184610Salfred } 865184610Salfred 866184610Salfred if ((id->bInterfaceClass == UICLASS_AUDIO) && 867184610Salfred (id->bInterfaceSubClass == UISUBCLASS_AUDIOSTREAM)) { 868184610Salfred audio_if = 1; 869184610Salfred } else { 870184610Salfred audio_if = 0; 871184610Salfred } 872184610Salfred 873184610Salfred if ((id->bInterfaceClass == UICLASS_AUDIO) && 874184610Salfred (id->bInterfaceSubClass == UISUBCLASS_MIDISTREAM)) { 875184610Salfred 876184610Salfred /* 877184610Salfred * XXX could allow multiple MIDI interfaces 878184610Salfred * XXX 879184610Salfred */ 880184610Salfred 881184610Salfred if ((sc->sc_midi_chan.valid == 0) && 882184610Salfred usb2_get_iface(udev, curidx)) { 883184610Salfred sc->sc_midi_chan.iface_index = curidx; 884184610Salfred sc->sc_midi_chan.iface_alt_index = alt_index; 885184610Salfred sc->sc_midi_chan.valid = 1; 886184610Salfred } 887184610Salfred } 888184610Salfred asid = NULL; 889184610Salfred asf1d = NULL; 890184610Salfred ed1 = NULL; 891184610Salfred ed2 = NULL; 892184610Salfred sed = NULL; 893184610Salfred } 894184610Salfred if ((desc->bDescriptorType == UDESC_CS_INTERFACE) && 895184610Salfred (desc->bDescriptorSubtype == AS_GENERAL) && 896184610Salfred (desc->bLength >= sizeof(*asid))) { 897184610Salfred if (asid == NULL) { 898184610Salfred asid = (void *)desc; 899184610Salfred } 900184610Salfred } 901184610Salfred if ((desc->bDescriptorType == UDESC_CS_INTERFACE) && 902184610Salfred (desc->bDescriptorSubtype == FORMAT_TYPE) && 903184610Salfred (desc->bLength >= sizeof(*asf1d))) { 904184610Salfred if (asf1d == NULL) { 905184610Salfred asf1d = (void *)desc; 906184610Salfred if (asf1d->bFormatType != FORMAT_TYPE_I) { 907184610Salfred DPRINTFN(11, "ignored bFormatType = %d\n", 908184610Salfred asf1d->bFormatType); 909184610Salfred asf1d = NULL; 910184610Salfred continue; 911184610Salfred } 912184610Salfred if (asf1d->bLength < (sizeof(*asf1d) + 913184610Salfred (asf1d->bSamFreqType == 0) ? 6 : 914184610Salfred (asf1d->bSamFreqType * 3))) { 915184610Salfred DPRINTFN(11, "'asf1d' descriptor is too short\n"); 916184610Salfred asf1d = NULL; 917184610Salfred continue; 918184610Salfred } 919184610Salfred } 920184610Salfred } 921184610Salfred if ((desc->bDescriptorType == UDESC_ENDPOINT) && 922184610Salfred (desc->bLength >= sizeof(*ed1))) { 923184610Salfred if (ed1 == NULL) { 924184610Salfred ed1 = (void *)desc; 925184610Salfred if (UE_GET_XFERTYPE(ed1->bmAttributes) != UE_ISOCHRONOUS) { 926184610Salfred ed1 = NULL; 927184610Salfred } 928184610Salfred } else { 929184610Salfred if (ed2 == NULL) { 930184610Salfred ed2 = (void *)desc; 931184610Salfred if (UE_GET_XFERTYPE(ed2->bmAttributes) != UE_ISOCHRONOUS) { 932184610Salfred ed2 = NULL; 933184610Salfred continue; 934184610Salfred } 935184610Salfred if (ed2->bSynchAddress != 0) { 936184610Salfred DPRINTFN(11, "invalid endpoint: bSynchAddress != 0\n"); 937184610Salfred ed2 = NULL; 938184610Salfred continue; 939184610Salfred } 940184610Salfred if (ed2->bEndpointAddress != ed1->bSynchAddress) { 941184610Salfred DPRINTFN(11, "invalid endpoint addresses: " 942184610Salfred "ep[0]->bSynchAddress=0x%x " 943184610Salfred "ep[1]->bEndpointAddress=0x%x\n", 944184610Salfred ed1->bSynchAddress, 945184610Salfred ed2->bEndpointAddress); 946184610Salfred ed2 = NULL; 947184610Salfred continue; 948184610Salfred } 949184610Salfred } 950184610Salfred } 951184610Salfred } 952184610Salfred if ((desc->bDescriptorType == UDESC_CS_ENDPOINT) && 953184610Salfred (desc->bDescriptorSubtype == AS_GENERAL) && 954184610Salfred (desc->bLength >= sizeof(*sed))) { 955184610Salfred if (sed == NULL) { 956184610Salfred sed = (void *)desc; 957184610Salfred } 958184610Salfred } 959184610Salfred if (audio_if && asid && asf1d && ed1 && sed) { 960184610Salfred 961184610Salfred ep_dir = UE_GET_DIR(ed1->bEndpointAddress); 962184610Salfred ep_type = UE_GET_ISO_TYPE(ed1->bmAttributes); 963184610Salfred ep_sync = 0; 964184610Salfred 965184610Salfred if ((sc->sc_uq_au_inp_async) && 966184610Salfred (ep_dir == UE_DIR_IN) && (ep_type == UE_ISO_ADAPT)) { 967184610Salfred ep_type = UE_ISO_ASYNC; 968184610Salfred } 969184610Salfred if ((ep_dir == UE_DIR_IN) && (ep_type == UE_ISO_ADAPT)) { 970184610Salfred ep_sync = 1; 971184610Salfred } 972184610Salfred if ((ep_dir != UE_DIR_IN) && (ep_type == UE_ISO_ASYNC)) { 973184610Salfred ep_sync = 1; 974184610Salfred } 975184610Salfred /* Ignore sync endpoint information until further. */ 976184610Salfred#if 0 977184610Salfred if (ep_sync && (!ed2)) { 978184610Salfred continue; 979184610Salfred } 980184610Salfred /* 981184610Salfred * we can't handle endpoints that need a sync pipe 982184610Salfred * yet 983184610Salfred */ 984184610Salfred 985184610Salfred if (ep_sync) { 986184610Salfred DPRINTF("skipped sync interface\n"); 987184610Salfred audio_if = 0; 988184610Salfred continue; 989184610Salfred } 990184610Salfred#endif 991184610Salfred 992184610Salfred wFormat = UGETW(asid->wFormatTag); 993184610Salfred bChannels = asf1d->bNrChannels; 994184610Salfred bBitResolution = asf1d->bBitResolution; 995184610Salfred 996184610Salfred if (asf1d->bSamFreqType == 0) { 997184610Salfred DPRINTFN(16, "Sample rate: %d-%dHz\n", 998184610Salfred UA_SAMP_LO(asf1d), UA_SAMP_HI(asf1d)); 999184610Salfred 1000184610Salfred if ((rate >= UA_SAMP_LO(asf1d)) && 1001184610Salfred (rate <= UA_SAMP_HI(asf1d))) { 1002184610Salfred goto found_rate; 1003184610Salfred } 1004184610Salfred } else { 1005184610Salfred 1006184610Salfred for (x = 0; x < asf1d->bSamFreqType; x++) { 1007184610Salfred DPRINTFN(16, "Sample rate = %dHz\n", 1008184610Salfred UA_GETSAMP(asf1d, x)); 1009184610Salfred 1010184610Salfred if (rate == UA_GETSAMP(asf1d, x)) { 1011184610Salfred goto found_rate; 1012184610Salfred } 1013184610Salfred } 1014184610Salfred } 1015184610Salfred 1016184610Salfred audio_if = 0; 1017184610Salfred continue; 1018184610Salfred 1019184610Salfred found_rate: 1020184610Salfred 1021184610Salfred for (p_fmt = uaudio_formats; 1022184610Salfred p_fmt->wFormat; 1023184610Salfred p_fmt++) { 1024184610Salfred if ((p_fmt->wFormat == wFormat) && 1025184610Salfred (p_fmt->bPrecision == bBitResolution)) { 1026184610Salfred goto found_format; 1027184610Salfred } 1028184610Salfred } 1029184610Salfred 1030184610Salfred audio_if = 0; 1031184610Salfred continue; 1032184610Salfred 1033184610Salfred found_format: 1034184610Salfred 1035184610Salfred if ((bChannels == channels) && 1036184610Salfred (bBitResolution == bit_resolution)) { 1037184610Salfred 1038184610Salfred chan = (ep_dir == UE_DIR_IN) ? 1039184610Salfred &sc->sc_rec_chan : 1040184610Salfred &sc->sc_play_chan; 1041184610Salfred 1042184610Salfred if ((chan->valid == 0) && usb2_get_iface(udev, curidx)) { 1043184610Salfred 1044184610Salfred chan->valid = 1; 1045184610Salfred#if USB_DEBUG 1046184610Salfred uaudio_chan_dump_ep_desc(ed1); 1047184610Salfred uaudio_chan_dump_ep_desc(ed2); 1048184610Salfred 1049184610Salfred if (sed->bmAttributes & UA_SED_FREQ_CONTROL) { 1050184610Salfred DPRINTFN(2, "FREQ_CONTROL\n"); 1051184610Salfred } 1052184610Salfred if (sed->bmAttributes & UA_SED_PITCH_CONTROL) { 1053184610Salfred DPRINTFN(2, "PITCH_CONTROL\n"); 1054184610Salfred } 1055184610Salfred#endif 1056184610Salfred DPRINTF("Sample rate = %dHz, channels = %d, " 1057184610Salfred "bits = %d, format = %s\n", rate, channels, 1058184610Salfred bit_resolution, p_fmt->description); 1059184610Salfred 1060184610Salfred chan->sample_rate = rate; 1061184610Salfred chan->p_asid = asid; 1062184610Salfred chan->p_asf1d = asf1d; 1063184610Salfred chan->p_ed1 = ed1; 1064184610Salfred chan->p_ed2 = ed2; 1065184610Salfred chan->p_fmt = p_fmt; 1066184610Salfred chan->p_sed = sed; 1067184610Salfred chan->iface_index = curidx; 1068184610Salfred chan->iface_alt_index = alt_index; 1069184610Salfred 1070184610Salfred chan->usb2_cfg = 1071184610Salfred (ep_dir == UE_DIR_IN) ? 1072184610Salfred ((fps == 1000) ? 1073184610Salfred uaudio_cfg_record_full_speed : 1074184610Salfred uaudio_cfg_record_high_speed) : 1075184610Salfred ((fps == 1000) ? 1076184610Salfred uaudio_cfg_play_full_speed : 1077184610Salfred uaudio_cfg_play_high_speed); 1078184610Salfred 1079184610Salfred 1080184610Salfred sample_size = ((chan->p_asf1d->bNrChannels * 1081184610Salfred chan->p_asf1d->bBitResolution) / 8); 1082184610Salfred 1083184610Salfred chan->bytes_per_frame = ((rate / fps) * sample_size); 1084184610Salfred 1085184610Salfred if (sc->sc_sndstat_valid) { 1086184610Salfred sbuf_printf(&sc->sc_sndstat, "\n\t" 1087184610Salfred "mode %d.%d:(%s) %dch, %d/%dbit, %s, %dHz", 1088184610Salfred curidx, alt_index, 1089184610Salfred (ep_dir == UE_DIR_IN) ? "input" : "output", 1090184610Salfred asf1d->bNrChannels, asf1d->bBitResolution, 1091184610Salfred asf1d->bSubFrameSize * 8, 1092184610Salfred p_fmt->description, rate); 1093184610Salfred } 1094184610Salfred } 1095184610Salfred } 1096184610Salfred audio_if = 0; 1097184610Salfred continue; 1098184610Salfred } 1099184610Salfred } 1100184610Salfred return; 1101184610Salfred} 1102184610Salfred 1103184610Salfredstatic void 1104184610Salfreduaudio_chan_fill_info(struct uaudio_softc *sc, struct usb2_device *udev) 1105184610Salfred{ 1106184610Salfred uint32_t rate = uaudio_default_rate; 1107184610Salfred uint32_t z; 1108184610Salfred uint16_t fps = (usb2_get_speed(udev) == USB_SPEED_HIGH) ? 8000 : 1000; 1109184610Salfred uint8_t bits = uaudio_default_bits; 1110184610Salfred uint8_t y; 1111184610Salfred uint8_t channels = uaudio_default_channels; 1112184610Salfred uint8_t x; 1113184610Salfred 1114184610Salfred bits -= (bits % 8); 1115184610Salfred rate -= (rate % fps); 1116184610Salfred 1117184610Salfred if (sbuf_new(&sc->sc_sndstat, NULL, 4096, SBUF_AUTOEXTEND)) { 1118184610Salfred sc->sc_sndstat_valid = 1; 1119184610Salfred } 1120184610Salfred /* try to search for a valid config */ 1121184610Salfred 1122184610Salfred for (x = channels; x; x--) { 1123184610Salfred for (y = bits; y; y -= 8) { 1124184610Salfred for (z = rate; z; z -= fps) { 1125184610Salfred uaudio_chan_fill_info_sub(sc, udev, z, fps, x, y); 1126184610Salfred 1127184610Salfred if (sc->sc_rec_chan.valid && 1128184610Salfred sc->sc_play_chan.valid) { 1129184610Salfred goto done; 1130184610Salfred } 1131184610Salfred } 1132184610Salfred } 1133184610Salfred } 1134184610Salfred 1135184610Salfreddone: 1136184610Salfred if (sc->sc_sndstat_valid) { 1137184610Salfred sbuf_finish(&sc->sc_sndstat); 1138184610Salfred } 1139184610Salfred return; 1140184610Salfred} 1141184610Salfred 1142184610Salfredstatic void 1143184610Salfreduaudio_chan_play_callback(struct usb2_xfer *xfer) 1144184610Salfred{ 1145184610Salfred struct uaudio_chan *ch = xfer->priv_sc; 1146184610Salfred uint32_t *p_len = xfer->frlengths; 1147184610Salfred uint32_t total = (sndbuf_getblkcnt(ch->pcm_buf) * 1148184610Salfred sndbuf_getblksz(ch->pcm_buf)) / 2; 1149184610Salfred uint32_t blockcount; 1150184610Salfred uint32_t n; 1151184610Salfred uint32_t offset; 1152184610Salfred 1153184610Salfred /* allow dynamic sizing of play buffer */ 1154184610Salfred blockcount = total / ch->bytes_per_frame; 1155184610Salfred 1156184610Salfred /* align to 8 units */ 1157184610Salfred blockcount &= ~7; 1158184610Salfred 1159184610Salfred /* range check - min */ 1160184610Salfred if (blockcount == 0) { 1161184610Salfred blockcount = 8; 1162184610Salfred } 1163184610Salfred /* range check - max */ 1164184610Salfred if (blockcount > xfer->max_frame_count) { 1165184610Salfred blockcount = xfer->max_frame_count; 1166184610Salfred } 1167184610Salfred /* compute the total length */ 1168184610Salfred total = blockcount * ch->bytes_per_frame; 1169184610Salfred 1170184610Salfred switch (USB_GET_STATE(xfer)) { 1171184610Salfred case USB_ST_TRANSFERRED: 1172184610Salfredtr_transferred: 1173184610Salfred if (xfer->actlen < xfer->sumlen) { 1174184610Salfred DPRINTF("short transfer, " 1175184610Salfred "%d of %d bytes\n", xfer->actlen, total); 1176184610Salfred } 1177184610Salfred chn_intr(ch->pcm_ch); 1178184610Salfred 1179184610Salfred case USB_ST_SETUP: 1180184610Salfred if (ch->bytes_per_frame > xfer->max_frame_size) { 1181184610Salfred DPRINTF("bytes per transfer, %d, " 1182184610Salfred "exceeds maximum, %d!\n", 1183184610Salfred ch->bytes_per_frame, 1184184610Salfred xfer->max_frame_size); 1185184610Salfred break; 1186184610Salfred } 1187184610Salfred /* setup frame length */ 1188184610Salfred xfer->nframes = blockcount; 1189184610Salfred for (n = 0; n != blockcount; n++) { 1190184610Salfred p_len[n] = ch->bytes_per_frame; 1191184610Salfred } 1192184610Salfred 1193184610Salfred if (ch->end == ch->start) { 1194184610Salfred DPRINTF("no buffer!\n"); 1195184610Salfred break; 1196184610Salfred } 1197184610Salfred DPRINTFN(6, "transfer %d bytes\n", total); 1198184610Salfred 1199184610Salfred offset = 0; 1200184610Salfred 1201184610Salfred while (total > 0) { 1202184610Salfred 1203184610Salfred n = (ch->end - ch->cur); 1204184610Salfred if (n > total) { 1205184610Salfred n = total; 1206184610Salfred } 1207184610Salfred usb2_copy_in(xfer->frbuffers, offset, ch->cur, n); 1208184610Salfred 1209184610Salfred total -= n; 1210184610Salfred ch->cur += n; 1211184610Salfred offset += n; 1212184610Salfred 1213184610Salfred if (ch->cur >= ch->end) { 1214184610Salfred ch->cur = ch->start; 1215184610Salfred } 1216184610Salfred } 1217184610Salfred 1218184610Salfred usb2_start_hardware(xfer); 1219184610Salfred break; 1220184610Salfred 1221184610Salfred default: /* Error */ 1222184610Salfred if (xfer->error == USB_ERR_CANCELLED) { 1223184610Salfred break; 1224184610Salfred } 1225184610Salfred goto tr_transferred; 1226184610Salfred } 1227184610Salfred return; 1228184610Salfred} 1229184610Salfred 1230184610Salfredstatic void 1231184610Salfreduaudio_chan_record_callback(struct usb2_xfer *xfer) 1232184610Salfred{ 1233184610Salfred struct uaudio_chan *ch = xfer->priv_sc; 1234184610Salfred uint32_t *p_len = xfer->frlengths; 1235184610Salfred uint32_t n; 1236184610Salfred uint32_t m; 1237184610Salfred uint32_t total = (sndbuf_getblkcnt(ch->pcm_buf) * 1238184610Salfred sndbuf_getblksz(ch->pcm_buf)) / 2; 1239184610Salfred uint32_t blockcount; 1240184610Salfred uint32_t offset0; 1241184610Salfred uint32_t offset1; 1242184610Salfred 1243184610Salfred /* allow dynamic sizing of play buffer */ 1244184610Salfred blockcount = total / ch->bytes_per_frame; 1245184610Salfred 1246184610Salfred /* align to 8 units */ 1247184610Salfred blockcount &= ~7; 1248184610Salfred 1249184610Salfred /* range check - min */ 1250184610Salfred if (blockcount == 0) { 1251184610Salfred blockcount = 8; 1252184610Salfred } 1253184610Salfred /* range check - max */ 1254184610Salfred if (blockcount > xfer->max_frame_count) { 1255184610Salfred blockcount = xfer->max_frame_count; 1256184610Salfred } 1257184610Salfred /* compute the total length */ 1258184610Salfred total = blockcount * ch->bytes_per_frame; 1259184610Salfred 1260184610Salfred switch (USB_GET_STATE(xfer)) { 1261184610Salfred case USB_ST_TRANSFERRED: 1262184610Salfredtr_transferred: 1263184610Salfred if (xfer->actlen < total) { 1264184610Salfred DPRINTF("short transfer, " 1265184610Salfred "%d of %d bytes\n", xfer->actlen, total); 1266184610Salfred } else { 1267184610Salfred DPRINTFN(6, "transferred %d bytes\n", xfer->actlen); 1268184610Salfred } 1269184610Salfred 1270184610Salfred offset0 = 0; 1271184610Salfred 1272184610Salfred for (n = 0; n != xfer->nframes; n++) { 1273184610Salfred 1274184610Salfred offset1 = offset0; 1275184610Salfred 1276184610Salfred while (p_len[n] > 0) { 1277184610Salfred 1278184610Salfred m = (ch->end - ch->cur); 1279184610Salfred 1280184610Salfred if (m > p_len[n]) { 1281184610Salfred m = p_len[n]; 1282184610Salfred } 1283184610Salfred usb2_copy_out(xfer->frbuffers, offset1, ch->cur, m); 1284184610Salfred 1285184610Salfred p_len[n] -= m; 1286184610Salfred offset1 += m; 1287184610Salfred ch->cur += m; 1288184610Salfred 1289184610Salfred if (ch->cur >= ch->end) { 1290184610Salfred ch->cur = ch->start; 1291184610Salfred } 1292184610Salfred } 1293184610Salfred 1294184610Salfred offset0 += ch->bytes_per_frame; 1295184610Salfred } 1296184610Salfred 1297184610Salfred chn_intr(ch->pcm_ch); 1298184610Salfred 1299184610Salfred case USB_ST_SETUP: 1300184610Salfred if (ch->bytes_per_frame > xfer->max_frame_size) { 1301184610Salfred DPRINTF("bytes per transfer, %d, " 1302184610Salfred "exceeds maximum, %d!\n", 1303184610Salfred ch->bytes_per_frame, 1304184610Salfred xfer->max_frame_size); 1305184610Salfred return; 1306184610Salfred } 1307184610Salfred xfer->nframes = blockcount; 1308184610Salfred for (n = 0; n != xfer->nframes; n++) { 1309184610Salfred p_len[n] = ch->bytes_per_frame; 1310184610Salfred } 1311184610Salfred 1312184610Salfred if (ch->end == ch->start) { 1313184610Salfred DPRINTF("no buffer!\n"); 1314184610Salfred return; 1315184610Salfred } 1316184610Salfred usb2_start_hardware(xfer); 1317184610Salfred return; 1318184610Salfred 1319184610Salfred default: /* Error */ 1320184610Salfred if (xfer->error == USB_ERR_CANCELLED) { 1321184610Salfred return; 1322184610Salfred } 1323184610Salfred goto tr_transferred; 1324184610Salfred } 1325184610Salfred} 1326184610Salfred 1327184610Salfredvoid * 1328184610Salfreduaudio_chan_init(struct uaudio_softc *sc, struct snd_dbuf *b, 1329184610Salfred struct pcm_channel *c, int dir) 1330184610Salfred{ 1331184610Salfred struct uaudio_chan *ch = ((dir == PCMDIR_PLAY) ? 1332184610Salfred &sc->sc_play_chan : &sc->sc_rec_chan); 1333184610Salfred uint8_t endpoint; 1334184610Salfred uint8_t iface_index; 1335184610Salfred uint8_t alt_index; 1336184610Salfred usb2_error_t err; 1337184610Salfred 1338184610Salfred ch->buf = malloc(UAUDIO_DEFAULT_BUFSZ, M_DEVBUF, M_WAITOK | M_ZERO); 1339184610Salfred 1340184610Salfred if (ch->buf == NULL) { 1341184610Salfred goto error; 1342184610Salfred } 1343184610Salfred if (sndbuf_setup(b, ch->buf, UAUDIO_DEFAULT_BUFSZ) != 0) { 1344184610Salfred goto error; 1345184610Salfred } 1346184610Salfred ch->start = ch->buf; 1347184610Salfred ch->end = ch->buf + UAUDIO_DEFAULT_BUFSZ; 1348184610Salfred ch->cur = ch->buf; 1349184610Salfred ch->pcm_ch = c; 1350184610Salfred ch->pcm_mtx = c->lock; 1351184610Salfred ch->pcm_buf = b; 1352184610Salfred 1353184610Salfred if (ch->pcm_mtx == NULL) { 1354184610Salfred DPRINTF("ERROR: PCM channels does not have a mutex!\n"); 1355184610Salfred goto error; 1356184610Salfred } 1357184610Salfred /* setup play/record format */ 1358184610Salfred 1359184610Salfred ch->pcm_cap.fmtlist = ch->pcm_format; 1360184610Salfred 1361184610Salfred ch->pcm_format[0] = 0; 1362184610Salfred ch->pcm_format[1] = 0; 1363184610Salfred 1364184610Salfred ch->pcm_cap.minspeed = ch->sample_rate; 1365184610Salfred ch->pcm_cap.maxspeed = ch->sample_rate; 1366184610Salfred 1367184610Salfred ch->pcm_cap.fmtlist[0] = ch->p_fmt->freebsd_fmt; 1368184610Salfred 1369184610Salfred if (ch->p_asf1d->bNrChannels == 2) { 1370184610Salfred ch->pcm_cap.fmtlist[0] |= AFMT_STEREO; 1371184610Salfred } 1372184610Salfred ch->pcm_cap.fmtlist[1] = 0; 1373184610Salfred 1374184610Salfred 1375184610Salfred /* set alternate interface corresponding to the mode */ 1376184610Salfred 1377184610Salfred endpoint = ch->p_ed1->bEndpointAddress; 1378184610Salfred iface_index = ch->iface_index; 1379184610Salfred alt_index = ch->iface_alt_index; 1380184610Salfred 1381184610Salfred DPRINTF("endpoint=0x%02x, speed=%d, iface=%d alt=%d\n", 1382184610Salfred endpoint, ch->sample_rate, iface_index, alt_index); 1383184610Salfred 1384184610Salfred err = usb2_set_alt_interface_index(sc->sc_udev, iface_index, alt_index); 1385184610Salfred if (err) { 1386184610Salfred DPRINTF("setting of alternate index failed: %s!\n", 1387184610Salfred usb2_errstr(err)); 1388184610Salfred goto error; 1389184610Salfred } 1390184610Salfred usb2_set_parent_iface(sc->sc_udev, iface_index, sc->sc_mixer_iface_index); 1391184610Salfred 1392184610Salfred /* 1393184610Salfred * If just one sampling rate is supported, 1394184610Salfred * no need to call "uaudio_set_speed()". 1395184610Salfred * Roland SD-90 freezes by a SAMPLING_FREQ_CONTROL request. 1396184610Salfred */ 1397184610Salfred if (ch->p_asf1d->bSamFreqType != 1) { 1398184610Salfred if (uaudio_set_speed(sc->sc_udev, endpoint, ch->sample_rate)) { 1399184610Salfred /* 1400184610Salfred * If the endpoint is adaptive setting the speed may 1401184610Salfred * fail. 1402184610Salfred */ 1403184610Salfred DPRINTF("setting of sample rate failed! (continuing anyway)\n"); 1404184610Salfred } 1405184610Salfred } 1406184610Salfred if (usb2_transfer_setup(sc->sc_udev, &iface_index, ch->xfer, 1407184610Salfred ch->usb2_cfg, UAUDIO_NCHANBUFS, ch, ch->pcm_mtx)) { 1408184610Salfred DPRINTF("could not allocate USB transfers!\n"); 1409184610Salfred goto error; 1410184610Salfred } 1411184610Salfred return (ch); 1412184610Salfred 1413184610Salfrederror: 1414184610Salfred uaudio_chan_free(ch); 1415184610Salfred return (NULL); 1416184610Salfred} 1417184610Salfred 1418184610Salfredint 1419184610Salfreduaudio_chan_free(struct uaudio_chan *ch) 1420184610Salfred{ 1421184610Salfred if (ch->buf != NULL) { 1422184610Salfred free(ch->buf, M_DEVBUF); 1423184610Salfred ch->buf = NULL; 1424184610Salfred } 1425184610Salfred usb2_transfer_unsetup(ch->xfer, UAUDIO_NCHANBUFS); 1426184610Salfred 1427184610Salfred ch->valid = 0; 1428184610Salfred 1429184610Salfred return (0); 1430184610Salfred} 1431184610Salfred 1432184610Salfredint 1433184610Salfreduaudio_chan_set_param_blocksize(struct uaudio_chan *ch, uint32_t blocksize) 1434184610Salfred{ 1435184610Salfred uaudio_chan_set_param_fragments(ch, blocksize, 0 - 1); 1436184610Salfred 1437184610Salfred return (ch->block_size); 1438184610Salfred} 1439184610Salfred 1440184610Salfredint 1441184610Salfreduaudio_chan_set_param_fragments(struct uaudio_chan *ch, uint32_t blocksize, 1442184610Salfred uint32_t blockcount) 1443184610Salfred{ 1444184610Salfred uint32_t max = sndbuf_getmaxsize(ch->pcm_buf); 1445184610Salfred 1446184610Salfred RANGE(blocksize, 128, max / 2); 1447184610Salfred 1448184610Salfred blockcount = max / blocksize; 1449184610Salfred RANGE(blockcount, 2, 512); 1450184610Salfred 1451184610Salfred if ((sndbuf_getblksz(ch->pcm_buf) != blocksize) || 1452184610Salfred (sndbuf_getblkcnt(ch->pcm_buf) != blockcount)) { 1453184610Salfred 1454184610Salfred if (sndbuf_resize(ch->pcm_buf, blockcount, blocksize)) { 1455184610Salfred DPRINTFN(0, "failed to resize sound buffer, count=%u, " 1456184610Salfred "size=%u\n", blockcount, blocksize); 1457184610Salfred } 1458184610Salfred } 1459184610Salfred ch->block_size = sndbuf_getblksz(ch->pcm_buf); 1460184610Salfred 1461184610Salfred return (1); 1462184610Salfred} 1463184610Salfred 1464184610Salfredint 1465184610Salfreduaudio_chan_set_param_speed(struct uaudio_chan *ch, uint32_t speed) 1466184610Salfred{ 1467184610Salfred if (speed != ch->sample_rate) { 1468184610Salfred DPRINTF("rate conversion required\n"); 1469184610Salfred } 1470184610Salfred return (ch->sample_rate); 1471184610Salfred} 1472184610Salfred 1473184610Salfredint 1474184610Salfreduaudio_chan_getptr(struct uaudio_chan *ch) 1475184610Salfred{ 1476184610Salfred return (ch->cur - ch->start); 1477184610Salfred} 1478184610Salfred 1479184610Salfredstruct pcmchan_caps * 1480184610Salfreduaudio_chan_getcaps(struct uaudio_chan *ch) 1481184610Salfred{ 1482184610Salfred return (&ch->pcm_cap); 1483184610Salfred} 1484184610Salfred 1485184610Salfredint 1486184610Salfreduaudio_chan_set_param_format(struct uaudio_chan *ch, uint32_t format) 1487184610Salfred{ 1488184610Salfred ch->format = format; 1489184610Salfred return (0); 1490184610Salfred} 1491184610Salfred 1492184610Salfredint 1493184610Salfreduaudio_chan_start(struct uaudio_chan *ch) 1494184610Salfred{ 1495184610Salfred ch->cur = ch->start; 1496184610Salfred 1497184610Salfred#if (UAUDIO_NCHANBUFS != 2) 1498184610Salfred#error "please update code" 1499184610Salfred#endif 1500184610Salfred if (ch->xfer[0]) { 1501184610Salfred usb2_transfer_start(ch->xfer[0]); 1502184610Salfred } 1503184610Salfred if (ch->xfer[1]) { 1504184610Salfred usb2_transfer_start(ch->xfer[1]); 1505184610Salfred } 1506184610Salfred return (0); 1507184610Salfred} 1508184610Salfred 1509184610Salfredint 1510184610Salfreduaudio_chan_stop(struct uaudio_chan *ch) 1511184610Salfred{ 1512184610Salfred#if (UAUDIO_NCHANBUFS != 2) 1513184610Salfred#error "please update code" 1514184610Salfred#endif 1515184610Salfred usb2_transfer_stop(ch->xfer[0]); 1516184610Salfred usb2_transfer_stop(ch->xfer[1]); 1517184610Salfred return (0); 1518184610Salfred} 1519184610Salfred 1520184610Salfred/*========================================================================* 1521184610Salfred * AC - Audio Controller - routines 1522184610Salfred *========================================================================*/ 1523184610Salfred 1524184610Salfredstatic void 1525184610Salfreduaudio_mixer_add_ctl_sub(struct uaudio_softc *sc, struct uaudio_mixer_node *mc) 1526184610Salfred{ 1527184610Salfred struct uaudio_mixer_node *p_mc_new = 1528184610Salfred malloc(sizeof(*p_mc_new), M_USBDEV, M_WAITOK); 1529184610Salfred 1530184610Salfred if (p_mc_new) { 1531184610Salfred bcopy(mc, p_mc_new, sizeof(*p_mc_new)); 1532184610Salfred p_mc_new->next = sc->sc_mixer_root; 1533184610Salfred sc->sc_mixer_root = p_mc_new; 1534184610Salfred sc->sc_mixer_count++; 1535184610Salfred } else { 1536184610Salfred DPRINTF("out of memory\n"); 1537184610Salfred } 1538184610Salfred return; 1539184610Salfred} 1540184610Salfred 1541184610Salfredstatic void 1542184610Salfreduaudio_mixer_add_ctl(struct uaudio_softc *sc, struct uaudio_mixer_node *mc) 1543184610Salfred{ 1544184610Salfred int32_t res; 1545184610Salfred 1546184610Salfred if (mc->class < UAC_NCLASSES) { 1547184610Salfred DPRINTF("adding %s.%d\n", 1548184610Salfred uac_names[mc->class], mc->ctl); 1549184610Salfred } else { 1550184610Salfred DPRINTF("adding %d\n", mc->ctl); 1551184610Salfred } 1552184610Salfred 1553184610Salfred mc->delta = 0; 1554184610Salfred if (mc->type == MIX_ON_OFF) { 1555184610Salfred mc->minval = 0; 1556184610Salfred mc->maxval = 1; 1557184610Salfred } else if (mc->type == MIX_SELECTOR) { 1558184610Salfred 1559184610Salfred } else { 1560184610Salfred 1561184610Salfred /* determine min and max values */ 1562184610Salfred 1563184610Salfred mc->minval = uaudio_mixer_get(sc->sc_udev, GET_MIN, mc); 1564184610Salfred 1565184610Salfred mc->minval = uaudio_mixer_signext(mc->type, mc->minval); 1566184610Salfred 1567184610Salfred mc->maxval = uaudio_mixer_get(sc->sc_udev, GET_MAX, mc); 1568184610Salfred 1569184610Salfred mc->maxval = 1 + uaudio_mixer_signext(mc->type, mc->maxval); 1570184610Salfred 1571184610Salfred mc->mul = mc->maxval - mc->minval; 1572184610Salfred if (mc->mul == 0) { 1573184610Salfred mc->mul = 1; 1574184610Salfred } 1575184610Salfred res = uaudio_mixer_get(sc->sc_udev, GET_RES, mc); 1576184610Salfred if (res > 0) { 1577184610Salfred mc->delta = ((res * 255) + (mc->mul / 2)) / mc->mul; 1578184610Salfred } 1579184610Salfred } 1580184610Salfred 1581184610Salfred if (mc->maxval < mc->minval) { 1582184610Salfred mc->maxval = mc->minval; 1583184610Salfred } 1584184610Salfred uaudio_mixer_add_ctl_sub(sc, mc); 1585184610Salfred 1586184610Salfred#if USB_DEBUG 1587184610Salfred if (uaudio_debug > 2) { 1588184610Salfred uint8_t i; 1589184610Salfred 1590184610Salfred for (i = 0; i < mc->nchan; i++) { 1591184610Salfred DPRINTF("[mix] wValue=%04x\n", mc->wValue[0]); 1592184610Salfred } 1593184610Salfred DPRINTF("[mix] wIndex=%04x type=%d ctl='%d' " 1594184610Salfred "min=%d max=%d\n", 1595184610Salfred mc->wIndex, mc->type, mc->ctl, 1596184610Salfred mc->minval, mc->maxval); 1597184610Salfred } 1598184610Salfred#endif 1599184610Salfred return; 1600184610Salfred} 1601184610Salfred 1602184610Salfredstatic void 1603184610Salfreduaudio_mixer_add_input(struct uaudio_softc *sc, 1604184610Salfred const struct uaudio_terminal_node *iot, int id) 1605184610Salfred{ 1606184610Salfred#if USB_DEBUG 1607184610Salfred const struct usb2_audio_input_terminal *d = iot[id].u.it; 1608184610Salfred 1609184610Salfred DPRINTFN(3, "bTerminalId=%d wTerminalType=0x%04x " 1610184610Salfred "bAssocTerminal=%d bNrChannels=%d wChannelConfig=%d " 1611184610Salfred "iChannelNames=%d\n", 1612184610Salfred d->bTerminalId, UGETW(d->wTerminalType), d->bAssocTerminal, 1613184610Salfred d->bNrChannels, UGETW(d->wChannelConfig), 1614184610Salfred d->iChannelNames); 1615184610Salfred#endif 1616184610Salfred return; 1617184610Salfred} 1618184610Salfred 1619184610Salfredstatic void 1620184610Salfreduaudio_mixer_add_output(struct uaudio_softc *sc, 1621184610Salfred const struct uaudio_terminal_node *iot, int id) 1622184610Salfred{ 1623184610Salfred#if USB_DEBUG 1624184610Salfred const struct usb2_audio_output_terminal *d = iot[id].u.ot; 1625184610Salfred 1626184610Salfred DPRINTFN(3, "bTerminalId=%d wTerminalType=0x%04x " 1627184610Salfred "bAssocTerminal=%d bSourceId=%d iTerminal=%d\n", 1628184610Salfred d->bTerminalId, UGETW(d->wTerminalType), d->bAssocTerminal, 1629184610Salfred d->bSourceId, d->iTerminal); 1630184610Salfred#endif 1631184610Salfred return; 1632184610Salfred} 1633184610Salfred 1634184610Salfredstatic void 1635184610Salfreduaudio_mixer_add_mixer(struct uaudio_softc *sc, 1636184610Salfred const struct uaudio_terminal_node *iot, int id) 1637184610Salfred{ 1638184610Salfred struct uaudio_mixer_node mix; 1639184610Salfred 1640184610Salfred const struct usb2_audio_mixer_unit_0 *d0 = iot[id].u.mu; 1641184610Salfred const struct usb2_audio_mixer_unit_1 *d1; 1642184610Salfred 1643184610Salfred uint32_t bno; /* bit number */ 1644184610Salfred uint32_t p; /* bit number accumulator */ 1645184610Salfred uint32_t mo; /* matching outputs */ 1646184610Salfred uint32_t mc; /* matching channels */ 1647184610Salfred uint32_t ichs; /* input channels */ 1648184610Salfred uint32_t ochs; /* output channels */ 1649184610Salfred uint32_t c; 1650184610Salfred uint32_t chs; /* channels */ 1651184610Salfred uint32_t i; 1652184610Salfred uint32_t o; 1653184610Salfred 1654184610Salfred DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n", 1655184610Salfred d0->bUnitId, d0->bNrInPins); 1656184610Salfred 1657184610Salfred /* compute the number of input channels */ 1658184610Salfred 1659184610Salfred ichs = 0; 1660184610Salfred for (i = 0; i < d0->bNrInPins; i++) { 1661184610Salfred ichs += (uaudio_mixer_get_cluster(d0->baSourceId[i], iot) 1662184610Salfred .bNrChannels); 1663184610Salfred } 1664184610Salfred 1665184610Salfred d1 = (const void *)(d0->baSourceId + d0->bNrInPins); 1666184610Salfred 1667184610Salfred /* and the number of output channels */ 1668184610Salfred 1669184610Salfred ochs = d1->bNrChannels; 1670184610Salfred 1671184610Salfred DPRINTFN(3, "ichs=%d ochs=%d\n", ichs, ochs); 1672184610Salfred 1673184610Salfred bzero(&mix, sizeof(mix)); 1674184610Salfred 1675184610Salfred mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 1676184610Salfred uaudio_mixer_determine_class(&iot[id], &mix); 1677184610Salfred mix.type = MIX_SIGNED_16; 1678184610Salfred 1679184610Salfred if (uaudio_mixer_verify_desc(d0, ((ichs * ochs) + 7) / 8) == NULL) { 1680184610Salfred return; 1681184610Salfred } 1682184610Salfred for (p = i = 0; i < d0->bNrInPins; i++) { 1683184610Salfred chs = uaudio_mixer_get_cluster(d0->baSourceId[i], iot).bNrChannels; 1684184610Salfred mc = 0; 1685184610Salfred for (c = 0; c < chs; c++) { 1686184610Salfred mo = 0; 1687184610Salfred for (o = 0; o < ochs; o++) { 1688184610Salfred bno = ((p + c) * ochs) + o; 1689184610Salfred if (BIT_TEST(d1->bmControls, bno)) { 1690184610Salfred mo++; 1691184610Salfred } 1692184610Salfred } 1693184610Salfred if (mo == 1) { 1694184610Salfred mc++; 1695184610Salfred } 1696184610Salfred } 1697184610Salfred if ((mc == chs) && (chs <= MIX_MAX_CHAN)) { 1698184610Salfred 1699184610Salfred /* repeat bit-scan */ 1700184610Salfred 1701184610Salfred mc = 0; 1702184610Salfred for (c = 0; c < chs; c++) { 1703184610Salfred for (o = 0; o < ochs; o++) { 1704184610Salfred bno = ((p + c) * ochs) + o; 1705184610Salfred if (BIT_TEST(d1->bmControls, bno)) { 1706184610Salfred mix.wValue[mc++] = MAKE_WORD(p + c + 1, o + 1); 1707184610Salfred } 1708184610Salfred } 1709184610Salfred } 1710184610Salfred mix.nchan = chs; 1711184610Salfred uaudio_mixer_add_ctl(sc, &mix); 1712184610Salfred } else { 1713184610Salfred /* XXX */ 1714184610Salfred } 1715184610Salfred p += chs; 1716184610Salfred } 1717184610Salfred return; 1718184610Salfred} 1719184610Salfred 1720184610Salfredstatic void 1721184610Salfreduaudio_mixer_add_selector(struct uaudio_softc *sc, 1722184610Salfred const struct uaudio_terminal_node *iot, int id) 1723184610Salfred{ 1724184610Salfred const struct usb2_audio_selector_unit *d = iot[id].u.su; 1725184610Salfred struct uaudio_mixer_node mix; 1726184610Salfred uint16_t i; 1727184610Salfred 1728184610Salfred DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n", 1729184610Salfred d->bUnitId, d->bNrInPins); 1730184610Salfred 1731184610Salfred if (d->bNrInPins == 0) { 1732184610Salfred return; 1733184610Salfred } 1734184610Salfred bzero(&mix, sizeof(mix)); 1735184610Salfred 1736184610Salfred mix.wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no); 1737184610Salfred mix.wValue[0] = MAKE_WORD(0, 0); 1738184610Salfred uaudio_mixer_determine_class(&iot[id], &mix); 1739184610Salfred mix.nchan = 1; 1740184610Salfred mix.type = MIX_SELECTOR; 1741184610Salfred 1742184610Salfred mix.ctl = SOUND_MIXER_NRDEVICES; 1743184610Salfred mix.minval = 1; 1744184610Salfred mix.maxval = d->bNrInPins; 1745184610Salfred 1746184610Salfred if (mix.maxval > MAX_SELECTOR_INPUT_PIN) { 1747184610Salfred mix.maxval = MAX_SELECTOR_INPUT_PIN; 1748184610Salfred } 1749184610Salfred mix.mul = (mix.maxval - mix.minval); 1750184610Salfred for (i = 0; i < MAX_SELECTOR_INPUT_PIN; i++) { 1751184610Salfred mix.slctrtype[i] = SOUND_MIXER_NRDEVICES; 1752184610Salfred } 1753184610Salfred 1754184610Salfred for (i = 0; i < mix.maxval; i++) { 1755184610Salfred mix.slctrtype[i] = uaudio_mixer_feature_name 1756184610Salfred (&iot[d->baSourceId[i]], &mix); 1757184610Salfred } 1758184610Salfred 1759184610Salfred mix.class = 0; /* not used */ 1760184610Salfred 1761184610Salfred uaudio_mixer_add_ctl(sc, &mix); 1762184610Salfred return; 1763184610Salfred} 1764184610Salfred 1765184610Salfredstatic uint32_t 1766184610Salfreduaudio_mixer_feature_get_bmaControls(const struct usb2_audio_feature_unit *d, 1767184610Salfred uint8_t index) 1768184610Salfred{ 1769184610Salfred uint32_t temp = 0; 1770184610Salfred uint32_t offset = (index * d->bControlSize); 1771184610Salfred 1772184610Salfred if (d->bControlSize > 0) { 1773184610Salfred temp |= d->bmaControls[offset]; 1774184610Salfred if (d->bControlSize > 1) { 1775184610Salfred temp |= d->bmaControls[offset + 1] << 8; 1776184610Salfred if (d->bControlSize > 2) { 1777184610Salfred temp |= d->bmaControls[offset + 2] << 16; 1778184610Salfred if (d->bControlSize > 3) { 1779184610Salfred temp |= d->bmaControls[offset + 3] << 24; 1780184610Salfred } 1781184610Salfred } 1782184610Salfred } 1783184610Salfred } 1784184610Salfred return (temp); 1785184610Salfred} 1786184610Salfred 1787184610Salfredstatic void 1788184610Salfreduaudio_mixer_add_feature(struct uaudio_softc *sc, 1789184610Salfred const struct uaudio_terminal_node *iot, int id) 1790184610Salfred{ 1791184610Salfred const struct usb2_audio_feature_unit *d = iot[id].u.fu; 1792184610Salfred struct uaudio_mixer_node mix; 1793184610Salfred uint32_t fumask; 1794184610Salfred uint32_t mmask; 1795184610Salfred uint32_t cmask; 1796184610Salfred uint16_t mixernumber; 1797184610Salfred uint8_t nchan; 1798184610Salfred uint8_t chan; 1799184610Salfred uint8_t ctl; 1800184610Salfred uint8_t i; 1801184610Salfred 1802184610Salfred if (d->bControlSize == 0) { 1803184610Salfred return; 1804184610Salfred } 1805184610Salfred bzero(&mix, sizeof(mix)); 1806184610Salfred 1807184610Salfred nchan = (d->bLength - 7) / d->bControlSize; 1808184610Salfred mmask = uaudio_mixer_feature_get_bmaControls(d, 0); 1809184610Salfred cmask = 0; 1810184610Salfred 1811184610Salfred if (nchan == 0) { 1812184610Salfred return; 1813184610Salfred } 1814184610Salfred /* figure out what we can control */ 1815184610Salfred 1816184610Salfred for (chan = 1; chan < nchan; chan++) { 1817184610Salfred DPRINTFN(10, "chan=%d mask=%x\n", 1818184610Salfred chan, uaudio_mixer_feature_get_bmaControls(d, chan)); 1819184610Salfred 1820184610Salfred cmask |= uaudio_mixer_feature_get_bmaControls(d, chan); 1821184610Salfred } 1822184610Salfred 1823184610Salfred if (nchan > MIX_MAX_CHAN) { 1824184610Salfred nchan = MIX_MAX_CHAN; 1825184610Salfred } 1826184610Salfred mix.wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no); 1827184610Salfred 1828184610Salfred for (ctl = 1; ctl <= LOUDNESS_CONTROL; ctl++) { 1829184610Salfred 1830184610Salfred fumask = FU_MASK(ctl); 1831184610Salfred 1832184610Salfred DPRINTFN(5, "ctl=%d fumask=0x%04x\n", 1833184610Salfred ctl, fumask); 1834184610Salfred 1835184610Salfred if (mmask & fumask) { 1836184610Salfred mix.nchan = 1; 1837184610Salfred mix.wValue[0] = MAKE_WORD(ctl, 0); 1838184610Salfred } else if (cmask & fumask) { 1839184610Salfred mix.nchan = nchan - 1; 1840184610Salfred for (i = 1; i < nchan; i++) { 1841184610Salfred if (uaudio_mixer_feature_get_bmaControls(d, i) & fumask) 1842184610Salfred mix.wValue[i - 1] = MAKE_WORD(ctl, i); 1843184610Salfred else 1844184610Salfred mix.wValue[i - 1] = -1; 1845184610Salfred } 1846184610Salfred } else { 1847184610Salfred continue; 1848184610Salfred } 1849184610Salfred 1850184610Salfred mixernumber = uaudio_mixer_feature_name(&iot[id], &mix); 1851184610Salfred 1852184610Salfred switch (ctl) { 1853184610Salfred case MUTE_CONTROL: 1854184610Salfred mix.type = MIX_ON_OFF; 1855184610Salfred mix.ctl = SOUND_MIXER_NRDEVICES; 1856184610Salfred break; 1857184610Salfred 1858184610Salfred case VOLUME_CONTROL: 1859184610Salfred mix.type = MIX_SIGNED_16; 1860184610Salfred mix.ctl = mixernumber; 1861184610Salfred break; 1862184610Salfred 1863184610Salfred case BASS_CONTROL: 1864184610Salfred mix.type = MIX_SIGNED_8; 1865184610Salfred mix.ctl = SOUND_MIXER_BASS; 1866184610Salfred break; 1867184610Salfred 1868184610Salfred case MID_CONTROL: 1869184610Salfred mix.type = MIX_SIGNED_8; 1870184610Salfred mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 1871184610Salfred break; 1872184610Salfred 1873184610Salfred case TREBLE_CONTROL: 1874184610Salfred mix.type = MIX_SIGNED_8; 1875184610Salfred mix.ctl = SOUND_MIXER_TREBLE; 1876184610Salfred break; 1877184610Salfred 1878184610Salfred case GRAPHIC_EQUALIZER_CONTROL: 1879184610Salfred continue; /* XXX don't add anything */ 1880184610Salfred break; 1881184610Salfred 1882184610Salfred case AGC_CONTROL: 1883184610Salfred mix.type = MIX_ON_OFF; 1884184610Salfred mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 1885184610Salfred break; 1886184610Salfred 1887184610Salfred case DELAY_CONTROL: 1888184610Salfred mix.type = MIX_UNSIGNED_16; 1889184610Salfred mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 1890184610Salfred break; 1891184610Salfred 1892184610Salfred case BASS_BOOST_CONTROL: 1893184610Salfred mix.type = MIX_ON_OFF; 1894184610Salfred mix.ctl = SOUND_MIXER_NRDEVICES; /* XXXXX */ 1895184610Salfred break; 1896184610Salfred 1897184610Salfred case LOUDNESS_CONTROL: 1898184610Salfred mix.type = MIX_ON_OFF; 1899184610Salfred mix.ctl = SOUND_MIXER_LOUD; /* Is this correct ? */ 1900184610Salfred break; 1901184610Salfred 1902184610Salfred default: 1903184610Salfred mix.type = MIX_UNKNOWN; 1904184610Salfred break; 1905184610Salfred } 1906184610Salfred 1907184610Salfred if (mix.type != MIX_UNKNOWN) { 1908184610Salfred uaudio_mixer_add_ctl(sc, &mix); 1909184610Salfred } 1910184610Salfred } 1911184610Salfred return; 1912184610Salfred} 1913184610Salfred 1914184610Salfredstatic void 1915184610Salfreduaudio_mixer_add_processing_updown(struct uaudio_softc *sc, 1916184610Salfred const struct uaudio_terminal_node *iot, int id) 1917184610Salfred{ 1918184610Salfred const struct usb2_audio_processing_unit_0 *d0 = iot[id].u.pu; 1919184610Salfred const struct usb2_audio_processing_unit_1 *d1 = 1920184610Salfred (const void *)(d0->baSourceId + d0->bNrInPins); 1921184610Salfred const struct usb2_audio_processing_unit_updown *ud = 1922184610Salfred (const void *)(d1->bmControls + d1->bControlSize); 1923184610Salfred struct uaudio_mixer_node mix; 1924184610Salfred uint8_t i; 1925184610Salfred 1926184610Salfred if (uaudio_mixer_verify_desc(d0, sizeof(*ud)) == NULL) { 1927184610Salfred return; 1928184610Salfred } 1929184610Salfred if (uaudio_mixer_verify_desc(d0, sizeof(*ud) + (2 * ud->bNrModes)) 1930184610Salfred == NULL) { 1931184610Salfred return; 1932184610Salfred } 1933184610Salfred DPRINTFN(3, "bUnitId=%d bNrModes=%d\n", 1934184610Salfred d0->bUnitId, ud->bNrModes); 1935184610Salfred 1936184610Salfred if (!(d1->bmControls[0] & UA_PROC_MASK(UD_MODE_SELECT_CONTROL))) { 1937184610Salfred DPRINTF("no mode select\n"); 1938184610Salfred return; 1939184610Salfred } 1940184610Salfred bzero(&mix, sizeof(mix)); 1941184610Salfred 1942184610Salfred mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 1943184610Salfred mix.nchan = 1; 1944184610Salfred mix.wValue[0] = MAKE_WORD(UD_MODE_SELECT_CONTROL, 0); 1945184610Salfred uaudio_mixer_determine_class(&iot[id], &mix); 1946184610Salfred mix.type = MIX_ON_OFF; /* XXX */ 1947184610Salfred 1948184610Salfred for (i = 0; i < ud->bNrModes; i++) { 1949184610Salfred DPRINTFN(3, "i=%d bm=0x%x\n", i, UGETW(ud->waModes[i])); 1950184610Salfred /* XXX */ 1951184610Salfred } 1952184610Salfred 1953184610Salfred uaudio_mixer_add_ctl(sc, &mix); 1954184610Salfred return; 1955184610Salfred} 1956184610Salfred 1957184610Salfredstatic void 1958184610Salfreduaudio_mixer_add_processing(struct uaudio_softc *sc, 1959184610Salfred const struct uaudio_terminal_node *iot, int id) 1960184610Salfred{ 1961184610Salfred const struct usb2_audio_processing_unit_0 *d0 = iot[id].u.pu; 1962184610Salfred const struct usb2_audio_processing_unit_1 *d1 = 1963184610Salfred (const void *)(d0->baSourceId + d0->bNrInPins); 1964184610Salfred struct uaudio_mixer_node mix; 1965184610Salfred uint16_t ptype; 1966184610Salfred 1967184610Salfred bzero(&mix, sizeof(mix)); 1968184610Salfred 1969184610Salfred ptype = UGETW(d0->wProcessType); 1970184610Salfred 1971184610Salfred DPRINTFN(3, "wProcessType=%d bUnitId=%d " 1972184610Salfred "bNrInPins=%d\n", ptype, d0->bUnitId, d0->bNrInPins); 1973184610Salfred 1974184610Salfred if (d1->bControlSize == 0) { 1975184610Salfred return; 1976184610Salfred } 1977184610Salfred if (d1->bmControls[0] & UA_PROC_ENABLE_MASK) { 1978184610Salfred mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 1979184610Salfred mix.nchan = 1; 1980184610Salfred mix.wValue[0] = MAKE_WORD(XX_ENABLE_CONTROL, 0); 1981184610Salfred uaudio_mixer_determine_class(&iot[id], &mix); 1982184610Salfred mix.type = MIX_ON_OFF; 1983184610Salfred uaudio_mixer_add_ctl(sc, &mix); 1984184610Salfred } 1985184610Salfred switch (ptype) { 1986184610Salfred case UPDOWNMIX_PROCESS: 1987184610Salfred uaudio_mixer_add_processing_updown(sc, iot, id); 1988184610Salfred break; 1989184610Salfred 1990184610Salfred case DOLBY_PROLOGIC_PROCESS: 1991184610Salfred case P3D_STEREO_EXTENDER_PROCESS: 1992184610Salfred case REVERBATION_PROCESS: 1993184610Salfred case CHORUS_PROCESS: 1994184610Salfred case DYN_RANGE_COMP_PROCESS: 1995184610Salfred default: 1996184610Salfred DPRINTF("unit %d, type=%d is not implemented\n", 1997184610Salfred d0->bUnitId, ptype); 1998184610Salfred break; 1999184610Salfred } 2000184610Salfred return; 2001184610Salfred} 2002184610Salfred 2003184610Salfredstatic void 2004184610Salfreduaudio_mixer_add_extension(struct uaudio_softc *sc, 2005184610Salfred const struct uaudio_terminal_node *iot, int id) 2006184610Salfred{ 2007184610Salfred const struct usb2_audio_extension_unit_0 *d0 = iot[id].u.eu; 2008184610Salfred const struct usb2_audio_extension_unit_1 *d1 = 2009184610Salfred (const void *)(d0->baSourceId + d0->bNrInPins); 2010184610Salfred struct uaudio_mixer_node mix; 2011184610Salfred 2012184610Salfred DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n", 2013184610Salfred d0->bUnitId, d0->bNrInPins); 2014184610Salfred 2015184610Salfred if (sc->sc_uq_au_no_xu) { 2016184610Salfred return; 2017184610Salfred } 2018184610Salfred if (d1->bControlSize == 0) { 2019184610Salfred return; 2020184610Salfred } 2021184610Salfred if (d1->bmControls[0] & UA_EXT_ENABLE_MASK) { 2022184610Salfred 2023184610Salfred bzero(&mix, sizeof(mix)); 2024184610Salfred 2025184610Salfred mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no); 2026184610Salfred mix.nchan = 1; 2027184610Salfred mix.wValue[0] = MAKE_WORD(UA_EXT_ENABLE, 0); 2028184610Salfred uaudio_mixer_determine_class(&iot[id], &mix); 2029184610Salfred mix.type = MIX_ON_OFF; 2030184610Salfred 2031184610Salfred uaudio_mixer_add_ctl(sc, &mix); 2032184610Salfred } 2033184610Salfred return; 2034184610Salfred} 2035184610Salfred 2036184610Salfredstatic const void * 2037184610Salfreduaudio_mixer_verify_desc(const void *arg, uint32_t len) 2038184610Salfred{ 2039184610Salfred const struct usb2_audio_mixer_unit_1 *d1; 2040184610Salfred const struct usb2_audio_extension_unit_1 *e1; 2041184610Salfred const struct usb2_audio_processing_unit_1 *u1; 2042184610Salfred 2043184610Salfred union { 2044184610Salfred const struct usb2_descriptor *desc; 2045184610Salfred const struct usb2_audio_input_terminal *it; 2046184610Salfred const struct usb2_audio_output_terminal *ot; 2047184610Salfred const struct usb2_audio_mixer_unit_0 *mu; 2048184610Salfred const struct usb2_audio_selector_unit *su; 2049184610Salfred const struct usb2_audio_feature_unit *fu; 2050184610Salfred const struct usb2_audio_processing_unit_0 *pu; 2051184610Salfred const struct usb2_audio_extension_unit_0 *eu; 2052184610Salfred } u; 2053184610Salfred 2054184610Salfred u.desc = arg; 2055184610Salfred 2056184610Salfred if (u.desc == NULL) { 2057184610Salfred goto error; 2058184610Salfred } 2059184610Salfred if (u.desc->bDescriptorType != UDESC_CS_INTERFACE) { 2060184610Salfred goto error; 2061184610Salfred } 2062184610Salfred switch (u.desc->bDescriptorSubtype) { 2063184610Salfred case UDESCSUB_AC_INPUT: 2064184610Salfred len += sizeof(*u.it); 2065184610Salfred break; 2066184610Salfred 2067184610Salfred case UDESCSUB_AC_OUTPUT: 2068184610Salfred len += sizeof(*u.ot); 2069184610Salfred break; 2070184610Salfred 2071184610Salfred case UDESCSUB_AC_MIXER: 2072184610Salfred len += sizeof(*u.mu); 2073184610Salfred 2074184610Salfred if (u.desc->bLength < len) { 2075184610Salfred goto error; 2076184610Salfred } 2077184610Salfred len += u.mu->bNrInPins; 2078184610Salfred 2079184610Salfred if (u.desc->bLength < len) { 2080184610Salfred goto error; 2081184610Salfred } 2082184610Salfred d1 = (const void *)(u.mu->baSourceId + u.mu->bNrInPins); 2083184610Salfred 2084184610Salfred len += sizeof(*d1); 2085184610Salfred break; 2086184610Salfred 2087184610Salfred case UDESCSUB_AC_SELECTOR: 2088184610Salfred len += sizeof(*u.su); 2089184610Salfred 2090184610Salfred if (u.desc->bLength < len) { 2091184610Salfred goto error; 2092184610Salfred } 2093184610Salfred len += u.su->bNrInPins; 2094184610Salfred break; 2095184610Salfred 2096184610Salfred case UDESCSUB_AC_FEATURE: 2097184610Salfred len += (sizeof(*u.fu) + 1); 2098184610Salfred break; 2099184610Salfred 2100184610Salfred case UDESCSUB_AC_PROCESSING: 2101184610Salfred len += sizeof(*u.pu); 2102184610Salfred 2103184610Salfred if (u.desc->bLength < len) { 2104184610Salfred goto error; 2105184610Salfred } 2106184610Salfred len += u.pu->bNrInPins; 2107184610Salfred 2108184610Salfred if (u.desc->bLength < len) { 2109184610Salfred goto error; 2110184610Salfred } 2111184610Salfred u1 = (const void *)(u.pu->baSourceId + u.pu->bNrInPins); 2112184610Salfred 2113184610Salfred len += sizeof(*u1); 2114184610Salfred 2115184610Salfred if (u.desc->bLength < len) { 2116184610Salfred goto error; 2117184610Salfred } 2118184610Salfred len += u1->bControlSize; 2119184610Salfred 2120184610Salfred break; 2121184610Salfred 2122184610Salfred case UDESCSUB_AC_EXTENSION: 2123184610Salfred len += sizeof(*u.eu); 2124184610Salfred 2125184610Salfred if (u.desc->bLength < len) { 2126184610Salfred goto error; 2127184610Salfred } 2128184610Salfred len += u.eu->bNrInPins; 2129184610Salfred 2130184610Salfred if (u.desc->bLength < len) { 2131184610Salfred goto error; 2132184610Salfred } 2133184610Salfred e1 = (const void *)(u.eu->baSourceId + u.eu->bNrInPins); 2134184610Salfred 2135184610Salfred len += sizeof(*e1); 2136184610Salfred 2137184610Salfred if (u.desc->bLength < len) { 2138184610Salfred goto error; 2139184610Salfred } 2140184610Salfred len += e1->bControlSize; 2141184610Salfred break; 2142184610Salfred 2143184610Salfred default: 2144184610Salfred goto error; 2145184610Salfred } 2146184610Salfred 2147184610Salfred if (u.desc->bLength < len) { 2148184610Salfred goto error; 2149184610Salfred } 2150184610Salfred return (u.desc); 2151184610Salfred 2152184610Salfrederror: 2153184610Salfred if (u.desc) { 2154184610Salfred DPRINTF("invalid descriptor, type=%d, " 2155184610Salfred "sub_type=%d, len=%d of %d bytes\n", 2156184610Salfred u.desc->bDescriptorType, 2157184610Salfred u.desc->bDescriptorSubtype, 2158184610Salfred u.desc->bLength, len); 2159184610Salfred } 2160184610Salfred return (NULL); 2161184610Salfred} 2162184610Salfred 2163184610Salfred#if USB_DEBUG 2164184610Salfredstatic void 2165184610Salfreduaudio_mixer_dump_cluster(uint8_t id, const struct uaudio_terminal_node *iot) 2166184610Salfred{ 2167184610Salfred static const char *channel_names[16] = { 2168184610Salfred "LEFT", "RIGHT", "CENTER", "LFE", 2169184610Salfred "LEFT_SURROUND", "RIGHT_SURROUND", "LEFT_CENTER", "RIGHT_CENTER", 2170184610Salfred "SURROUND", "LEFT_SIDE", "RIGHT_SIDE", "TOP", 2171184610Salfred "RESERVED12", "RESERVED13", "RESERVED14", "RESERVED15", 2172184610Salfred }; 2173184610Salfred uint16_t cc; 2174184610Salfred uint8_t i; 2175184610Salfred const struct usb2_audio_cluster cl = uaudio_mixer_get_cluster(id, iot); 2176184610Salfred 2177184610Salfred cc = UGETW(cl.wChannelConfig); 2178184610Salfred 2179184610Salfred DPRINTF("cluster: bNrChannels=%u iChannelNames=%u wChannelConfig=" 2180184610Salfred "0x%04x:\n", cl.iChannelNames, cl.bNrChannels, cc); 2181184610Salfred 2182184610Salfred for (i = 0; cc; i++) { 2183184610Salfred if (cc & 1) { 2184184610Salfred DPRINTF(" - %s\n", channel_names[i]); 2185184610Salfred } 2186184610Salfred cc >>= 1; 2187184610Salfred } 2188184610Salfred return; 2189184610Salfred} 2190184610Salfred 2191184610Salfred#endif 2192184610Salfred 2193184610Salfredstatic struct usb2_audio_cluster 2194184610Salfreduaudio_mixer_get_cluster(uint8_t id, const struct uaudio_terminal_node *iot) 2195184610Salfred{ 2196184610Salfred struct usb2_audio_cluster r; 2197184610Salfred const struct usb2_descriptor *dp; 2198184610Salfred uint8_t i; 2199184610Salfred 2200184610Salfred for (i = 0; i < UAUDIO_RECURSE_LIMIT; i++) { /* avoid infinite loops */ 2201184610Salfred dp = iot[id].u.desc; 2202184610Salfred if (dp == NULL) { 2203184610Salfred goto error; 2204184610Salfred } 2205184610Salfred switch (dp->bDescriptorSubtype) { 2206184610Salfred case UDESCSUB_AC_INPUT: 2207184610Salfred r.bNrChannels = iot[id].u.it->bNrChannels; 2208184610Salfred r.wChannelConfig[0] = iot[id].u.it->wChannelConfig[0]; 2209184610Salfred r.wChannelConfig[1] = iot[id].u.it->wChannelConfig[1]; 2210184610Salfred r.iChannelNames = iot[id].u.it->iChannelNames; 2211184610Salfred goto done; 2212184610Salfred 2213184610Salfred case UDESCSUB_AC_OUTPUT: 2214184610Salfred id = iot[id].u.ot->bSourceId; 2215184610Salfred break; 2216184610Salfred 2217184610Salfred case UDESCSUB_AC_MIXER: 2218184610Salfred r = *(const struct usb2_audio_cluster *) 2219184610Salfred &iot[id].u.mu->baSourceId[iot[id].u.mu-> 2220184610Salfred bNrInPins]; 2221184610Salfred goto done; 2222184610Salfred 2223184610Salfred case UDESCSUB_AC_SELECTOR: 2224184610Salfred if (iot[id].u.su->bNrInPins > 0) { 2225184610Salfred /* XXX This is not really right */ 2226184610Salfred id = iot[id].u.su->baSourceId[0]; 2227184610Salfred } 2228184610Salfred break; 2229184610Salfred 2230184610Salfred case UDESCSUB_AC_FEATURE: 2231184610Salfred id = iot[id].u.fu->bSourceId; 2232184610Salfred break; 2233184610Salfred 2234184610Salfred case UDESCSUB_AC_PROCESSING: 2235184610Salfred r = *((const struct usb2_audio_cluster *) 2236184610Salfred &iot[id].u.pu->baSourceId[iot[id].u.pu-> 2237184610Salfred bNrInPins]); 2238184610Salfred goto done; 2239184610Salfred 2240184610Salfred case UDESCSUB_AC_EXTENSION: 2241184610Salfred r = *((const struct usb2_audio_cluster *) 2242184610Salfred &iot[id].u.eu->baSourceId[iot[id].u.eu-> 2243184610Salfred bNrInPins]); 2244184610Salfred goto done; 2245184610Salfred 2246184610Salfred default: 2247184610Salfred goto error; 2248184610Salfred } 2249184610Salfred } 2250184610Salfrederror: 2251184610Salfred DPRINTF("bad data\n"); 2252184610Salfred bzero(&r, sizeof(r)); 2253184610Salfreddone: 2254184610Salfred return (r); 2255184610Salfred} 2256184610Salfred 2257184610Salfred#if USB_DEBUG 2258184610Salfred 2259184610Salfredstruct uaudio_tt_to_string { 2260184610Salfred uint16_t terminal_type; 2261184610Salfred const char *desc; 2262184610Salfred}; 2263184610Salfred 2264184610Salfredstatic const struct uaudio_tt_to_string uaudio_tt_to_string[] = { 2265184610Salfred 2266184610Salfred /* USB terminal types */ 2267184610Salfred {UAT_UNDEFINED, "UAT_UNDEFINED"}, 2268184610Salfred {UAT_STREAM, "UAT_STREAM"}, 2269184610Salfred {UAT_VENDOR, "UAT_VENDOR"}, 2270184610Salfred 2271184610Salfred /* input terminal types */ 2272184610Salfred {UATI_UNDEFINED, "UATI_UNDEFINED"}, 2273184610Salfred {UATI_MICROPHONE, "UATI_MICROPHONE"}, 2274184610Salfred {UATI_DESKMICROPHONE, "UATI_DESKMICROPHONE"}, 2275184610Salfred {UATI_PERSONALMICROPHONE, "UATI_PERSONALMICROPHONE"}, 2276184610Salfred {UATI_OMNIMICROPHONE, "UATI_OMNIMICROPHONE"}, 2277184610Salfred {UATI_MICROPHONEARRAY, "UATI_MICROPHONEARRAY"}, 2278184610Salfred {UATI_PROCMICROPHONEARR, "UATI_PROCMICROPHONEARR"}, 2279184610Salfred 2280184610Salfred /* output terminal types */ 2281184610Salfred {UATO_UNDEFINED, "UATO_UNDEFINED"}, 2282184610Salfred {UATO_SPEAKER, "UATO_SPEAKER"}, 2283184610Salfred {UATO_HEADPHONES, "UATO_HEADPHONES"}, 2284184610Salfred {UATO_DISPLAYAUDIO, "UATO_DISPLAYAUDIO"}, 2285184610Salfred {UATO_DESKTOPSPEAKER, "UATO_DESKTOPSPEAKER"}, 2286184610Salfred {UATO_ROOMSPEAKER, "UATO_ROOMSPEAKER"}, 2287184610Salfred {UATO_COMMSPEAKER, "UATO_COMMSPEAKER"}, 2288184610Salfred {UATO_SUBWOOFER, "UATO_SUBWOOFER"}, 2289184610Salfred 2290184610Salfred /* bidir terminal types */ 2291184610Salfred {UATB_UNDEFINED, "UATB_UNDEFINED"}, 2292184610Salfred {UATB_HANDSET, "UATB_HANDSET"}, 2293184610Salfred {UATB_HEADSET, "UATB_HEADSET"}, 2294184610Salfred {UATB_SPEAKERPHONE, "UATB_SPEAKERPHONE"}, 2295184610Salfred {UATB_SPEAKERPHONEESUP, "UATB_SPEAKERPHONEESUP"}, 2296184610Salfred {UATB_SPEAKERPHONEECANC, "UATB_SPEAKERPHONEECANC"}, 2297184610Salfred 2298184610Salfred /* telephony terminal types */ 2299184610Salfred {UATT_UNDEFINED, "UATT_UNDEFINED"}, 2300184610Salfred {UATT_PHONELINE, "UATT_PHONELINE"}, 2301184610Salfred {UATT_TELEPHONE, "UATT_TELEPHONE"}, 2302184610Salfred {UATT_DOWNLINEPHONE, "UATT_DOWNLINEPHONE"}, 2303184610Salfred 2304184610Salfred /* external terminal types */ 2305184610Salfred {UATE_UNDEFINED, "UATE_UNDEFINED"}, 2306184610Salfred {UATE_ANALOGCONN, "UATE_ANALOGCONN"}, 2307184610Salfred {UATE_LINECONN, "UATE_LINECONN"}, 2308184610Salfred {UATE_LEGACYCONN, "UATE_LEGACYCONN"}, 2309184610Salfred {UATE_DIGITALAUIFC, "UATE_DIGITALAUIFC"}, 2310184610Salfred {UATE_SPDIF, "UATE_SPDIF"}, 2311184610Salfred {UATE_1394DA, "UATE_1394DA"}, 2312184610Salfred {UATE_1394DV, "UATE_1394DV"}, 2313184610Salfred 2314184610Salfred /* embedded function terminal types */ 2315184610Salfred {UATF_UNDEFINED, "UATF_UNDEFINED"}, 2316184610Salfred {UATF_CALIBNOISE, "UATF_CALIBNOISE"}, 2317184610Salfred {UATF_EQUNOISE, "UATF_EQUNOISE"}, 2318184610Salfred {UATF_CDPLAYER, "UATF_CDPLAYER"}, 2319184610Salfred {UATF_DAT, "UATF_DAT"}, 2320184610Salfred {UATF_DCC, "UATF_DCC"}, 2321184610Salfred {UATF_MINIDISK, "UATF_MINIDISK"}, 2322184610Salfred {UATF_ANALOGTAPE, "UATF_ANALOGTAPE"}, 2323184610Salfred {UATF_PHONOGRAPH, "UATF_PHONOGRAPH"}, 2324184610Salfred {UATF_VCRAUDIO, "UATF_VCRAUDIO"}, 2325184610Salfred {UATF_VIDEODISCAUDIO, "UATF_VIDEODISCAUDIO"}, 2326184610Salfred {UATF_DVDAUDIO, "UATF_DVDAUDIO"}, 2327184610Salfred {UATF_TVTUNERAUDIO, "UATF_TVTUNERAUDIO"}, 2328184610Salfred {UATF_SATELLITE, "UATF_SATELLITE"}, 2329184610Salfred {UATF_CABLETUNER, "UATF_CABLETUNER"}, 2330184610Salfred {UATF_DSS, "UATF_DSS"}, 2331184610Salfred {UATF_RADIORECV, "UATF_RADIORECV"}, 2332184610Salfred {UATF_RADIOXMIT, "UATF_RADIOXMIT"}, 2333184610Salfred {UATF_MULTITRACK, "UATF_MULTITRACK"}, 2334184610Salfred {UATF_SYNTHESIZER, "UATF_SYNTHESIZER"}, 2335184610Salfred 2336184610Salfred /* unknown */ 2337184610Salfred {0x0000, "UNKNOWN"}, 2338184610Salfred}; 2339184610Salfred 2340184610Salfredstatic const char * 2341184610Salfreduaudio_mixer_get_terminal_name(uint16_t terminal_type) 2342184610Salfred{ 2343184610Salfred const struct uaudio_tt_to_string *uat = uaudio_tt_to_string; 2344184610Salfred 2345184610Salfred while (uat->terminal_type) { 2346184610Salfred if (uat->terminal_type == terminal_type) { 2347184610Salfred break; 2348184610Salfred } 2349184610Salfred uat++; 2350184610Salfred } 2351184610Salfred if (uat->terminal_type == 0) { 2352184610Salfred DPRINTF("unknown terminal type (0x%04x)", terminal_type); 2353184610Salfred } 2354184610Salfred return (uat->desc); 2355184610Salfred} 2356184610Salfred 2357184610Salfred#endif 2358184610Salfred 2359184610Salfredstatic uint16_t 2360184610Salfreduaudio_mixer_determine_class(const struct uaudio_terminal_node *iot, 2361184610Salfred struct uaudio_mixer_node *mix) 2362184610Salfred{ 2363184610Salfred uint16_t terminal_type = 0x0000; 2364184610Salfred const struct uaudio_terminal_node *input[2]; 2365184610Salfred const struct uaudio_terminal_node *output[2]; 2366184610Salfred 2367184610Salfred input[0] = uaudio_mixer_get_input(iot, 0); 2368184610Salfred input[1] = uaudio_mixer_get_input(iot, 1); 2369184610Salfred 2370184610Salfred output[0] = uaudio_mixer_get_output(iot, 0); 2371184610Salfred output[1] = uaudio_mixer_get_output(iot, 1); 2372184610Salfred 2373184610Salfred /* 2374184610Salfred * check if there is only 2375184610Salfred * one output terminal: 2376184610Salfred */ 2377184610Salfred if (output[0] && (!output[1])) { 2378184610Salfred terminal_type = UGETW(output[0]->u.ot->wTerminalType); 2379184610Salfred } 2380184610Salfred /* 2381184610Salfred * If the only output terminal is USB, 2382184610Salfred * the class is UAC_RECORD. 2383184610Salfred */ 2384184610Salfred if ((terminal_type & 0xff00) == (UAT_UNDEFINED & 0xff00)) { 2385184610Salfred 2386184610Salfred mix->class = UAC_RECORD; 2387184610Salfred if (input[0] && (!input[1])) { 2388184610Salfred terminal_type = UGETW(input[0]->u.it->wTerminalType); 2389184610Salfred } else { 2390184610Salfred terminal_type = 0; 2391184610Salfred } 2392184610Salfred goto done; 2393184610Salfred } 2394184610Salfred /* 2395184610Salfred * if the unit is connected to just 2396184610Salfred * one input terminal, the 2397184610Salfred * class is UAC_INPUT: 2398184610Salfred */ 2399184610Salfred if (input[0] && (!input[1])) { 2400184610Salfred mix->class = UAC_INPUT; 2401184610Salfred terminal_type = UGETW(input[0]->u.it->wTerminalType); 2402184610Salfred goto done; 2403184610Salfred } 2404184610Salfred /* 2405184610Salfred * Otherwise, the class is UAC_OUTPUT. 2406184610Salfred */ 2407184610Salfred mix->class = UAC_OUTPUT; 2408184610Salfreddone: 2409184610Salfred return (terminal_type); 2410184610Salfred} 2411184610Salfred 2412184610Salfredstruct uaudio_tt_to_feature { 2413184610Salfred uint16_t terminal_type; 2414184610Salfred uint16_t feature; 2415184610Salfred}; 2416184610Salfred 2417184610Salfredstatic const struct uaudio_tt_to_feature uaudio_tt_to_feature[] = { 2418184610Salfred 2419184610Salfred {UAT_STREAM, SOUND_MIXER_PCM}, 2420184610Salfred 2421184610Salfred {UATI_MICROPHONE, SOUND_MIXER_MIC}, 2422184610Salfred {UATI_DESKMICROPHONE, SOUND_MIXER_MIC}, 2423184610Salfred {UATI_PERSONALMICROPHONE, SOUND_MIXER_MIC}, 2424184610Salfred {UATI_OMNIMICROPHONE, SOUND_MIXER_MIC}, 2425184610Salfred {UATI_MICROPHONEARRAY, SOUND_MIXER_MIC}, 2426184610Salfred {UATI_PROCMICROPHONEARR, SOUND_MIXER_MIC}, 2427184610Salfred 2428184610Salfred {UATO_SPEAKER, SOUND_MIXER_SPEAKER}, 2429184610Salfred {UATO_DESKTOPSPEAKER, SOUND_MIXER_SPEAKER}, 2430184610Salfred {UATO_ROOMSPEAKER, SOUND_MIXER_SPEAKER}, 2431184610Salfred {UATO_COMMSPEAKER, SOUND_MIXER_SPEAKER}, 2432184610Salfred 2433184610Salfred {UATE_ANALOGCONN, SOUND_MIXER_LINE}, 2434184610Salfred {UATE_LINECONN, SOUND_MIXER_LINE}, 2435184610Salfred {UATE_LEGACYCONN, SOUND_MIXER_LINE}, 2436184610Salfred 2437184610Salfred {UATE_DIGITALAUIFC, SOUND_MIXER_ALTPCM}, 2438184610Salfred {UATE_SPDIF, SOUND_MIXER_ALTPCM}, 2439184610Salfred {UATE_1394DA, SOUND_MIXER_ALTPCM}, 2440184610Salfred {UATE_1394DV, SOUND_MIXER_ALTPCM}, 2441184610Salfred 2442184610Salfred {UATF_CDPLAYER, SOUND_MIXER_CD}, 2443184610Salfred 2444184610Salfred {UATF_SYNTHESIZER, SOUND_MIXER_SYNTH}, 2445184610Salfred 2446184610Salfred {UATF_VIDEODISCAUDIO, SOUND_MIXER_VIDEO}, 2447184610Salfred {UATF_DVDAUDIO, SOUND_MIXER_VIDEO}, 2448184610Salfred {UATF_TVTUNERAUDIO, SOUND_MIXER_VIDEO}, 2449184610Salfred 2450184610Salfred /* telephony terminal types */ 2451184610Salfred {UATT_UNDEFINED, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 2452184610Salfred {UATT_PHONELINE, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 2453184610Salfred {UATT_TELEPHONE, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 2454184610Salfred {UATT_DOWNLINEPHONE, SOUND_MIXER_PHONEIN}, /* SOUND_MIXER_PHONEOUT */ 2455184610Salfred 2456184610Salfred {UATF_RADIORECV, SOUND_MIXER_RADIO}, 2457184610Salfred {UATF_RADIOXMIT, SOUND_MIXER_RADIO}, 2458184610Salfred 2459184610Salfred {UAT_UNDEFINED, SOUND_MIXER_VOLUME}, 2460184610Salfred {UAT_VENDOR, SOUND_MIXER_VOLUME}, 2461184610Salfred {UATI_UNDEFINED, SOUND_MIXER_VOLUME}, 2462184610Salfred 2463184610Salfred /* output terminal types */ 2464184610Salfred {UATO_UNDEFINED, SOUND_MIXER_VOLUME}, 2465184610Salfred {UATO_DISPLAYAUDIO, SOUND_MIXER_VOLUME}, 2466184610Salfred {UATO_SUBWOOFER, SOUND_MIXER_VOLUME}, 2467184610Salfred {UATO_HEADPHONES, SOUND_MIXER_VOLUME}, 2468184610Salfred 2469184610Salfred /* bidir terminal types */ 2470184610Salfred {UATB_UNDEFINED, SOUND_MIXER_VOLUME}, 2471184610Salfred {UATB_HANDSET, SOUND_MIXER_VOLUME}, 2472184610Salfred {UATB_HEADSET, SOUND_MIXER_VOLUME}, 2473184610Salfred {UATB_SPEAKERPHONE, SOUND_MIXER_VOLUME}, 2474184610Salfred {UATB_SPEAKERPHONEESUP, SOUND_MIXER_VOLUME}, 2475184610Salfred {UATB_SPEAKERPHONEECANC, SOUND_MIXER_VOLUME}, 2476184610Salfred 2477184610Salfred /* external terminal types */ 2478184610Salfred {UATE_UNDEFINED, SOUND_MIXER_VOLUME}, 2479184610Salfred 2480184610Salfred /* embedded function terminal types */ 2481184610Salfred {UATF_UNDEFINED, SOUND_MIXER_VOLUME}, 2482184610Salfred {UATF_CALIBNOISE, SOUND_MIXER_VOLUME}, 2483184610Salfred {UATF_EQUNOISE, SOUND_MIXER_VOLUME}, 2484184610Salfred {UATF_DAT, SOUND_MIXER_VOLUME}, 2485184610Salfred {UATF_DCC, SOUND_MIXER_VOLUME}, 2486184610Salfred {UATF_MINIDISK, SOUND_MIXER_VOLUME}, 2487184610Salfred {UATF_ANALOGTAPE, SOUND_MIXER_VOLUME}, 2488184610Salfred {UATF_PHONOGRAPH, SOUND_MIXER_VOLUME}, 2489184610Salfred {UATF_VCRAUDIO, SOUND_MIXER_VOLUME}, 2490184610Salfred {UATF_SATELLITE, SOUND_MIXER_VOLUME}, 2491184610Salfred {UATF_CABLETUNER, SOUND_MIXER_VOLUME}, 2492184610Salfred {UATF_DSS, SOUND_MIXER_VOLUME}, 2493184610Salfred {UATF_MULTITRACK, SOUND_MIXER_VOLUME}, 2494184610Salfred {0xffff, SOUND_MIXER_VOLUME}, 2495184610Salfred 2496184610Salfred /* default */ 2497184610Salfred {0x0000, SOUND_MIXER_VOLUME}, 2498184610Salfred}; 2499184610Salfred 2500184610Salfredstatic uint16_t 2501184610Salfreduaudio_mixer_feature_name(const struct uaudio_terminal_node *iot, 2502184610Salfred struct uaudio_mixer_node *mix) 2503184610Salfred{ 2504184610Salfred const struct uaudio_tt_to_feature *uat = uaudio_tt_to_feature; 2505184610Salfred uint16_t terminal_type = uaudio_mixer_determine_class(iot, mix); 2506184610Salfred 2507184610Salfred if ((mix->class == UAC_RECORD) && (terminal_type == 0)) { 2508184610Salfred return (SOUND_MIXER_IMIX); 2509184610Salfred } 2510184610Salfred while (uat->terminal_type) { 2511184610Salfred if (uat->terminal_type == terminal_type) { 2512184610Salfred break; 2513184610Salfred } 2514184610Salfred uat++; 2515184610Salfred } 2516184610Salfred 2517184610Salfred DPRINTF("terminal_type=%s (0x%04x) -> %d\n", 2518184610Salfred uaudio_mixer_get_terminal_name(terminal_type), 2519184610Salfred terminal_type, uat->feature); 2520184610Salfred 2521184610Salfred return (uat->feature); 2522184610Salfred} 2523184610Salfred 2524184610Salfredconst static struct uaudio_terminal_node * 2525184610Salfreduaudio_mixer_get_input(const struct uaudio_terminal_node *iot, uint8_t index) 2526184610Salfred{ 2527184610Salfred struct uaudio_terminal_node *root = iot->root; 2528184610Salfred uint8_t n; 2529184610Salfred 2530184610Salfred n = iot->usr.id_max; 2531184610Salfred do { 2532184610Salfred if (iot->usr.bit_input[n / 8] & (1 << (n % 8))) { 2533184610Salfred if (!index--) { 2534184610Salfred return (root + n); 2535184610Salfred } 2536184610Salfred } 2537184610Salfred } while (n--); 2538184610Salfred 2539184610Salfred return (NULL); 2540184610Salfred} 2541184610Salfred 2542184610Salfredconst static struct uaudio_terminal_node * 2543184610Salfreduaudio_mixer_get_output(const struct uaudio_terminal_node *iot, uint8_t index) 2544184610Salfred{ 2545184610Salfred struct uaudio_terminal_node *root = iot->root; 2546184610Salfred uint8_t n; 2547184610Salfred 2548184610Salfred n = iot->usr.id_max; 2549184610Salfred do { 2550184610Salfred if (iot->usr.bit_output[n / 8] & (1 << (n % 8))) { 2551184610Salfred if (!index--) { 2552184610Salfred return (root + n); 2553184610Salfred } 2554184610Salfred } 2555184610Salfred } while (n--); 2556184610Salfred 2557184610Salfred return (NULL); 2558184610Salfred} 2559184610Salfred 2560184610Salfredstatic void 2561184610Salfreduaudio_mixer_find_inputs_sub(struct uaudio_terminal_node *root, 2562184610Salfred const uint8_t *p_id, uint8_t n_id, 2563184610Salfred struct uaudio_search_result *info) 2564184610Salfred{ 2565184610Salfred struct uaudio_terminal_node *iot; 2566184610Salfred uint8_t n; 2567184610Salfred uint8_t i; 2568184610Salfred 2569184610Salfred if (info->recurse_level >= UAUDIO_RECURSE_LIMIT) { 2570184610Salfred return; 2571184610Salfred } 2572184610Salfred info->recurse_level++; 2573184610Salfred 2574184610Salfred for (n = 0; n < n_id; n++) { 2575184610Salfred 2576184610Salfred i = p_id[n]; 2577184610Salfred 2578184610Salfred if (info->bit_visited[i / 8] & (1 << (i % 8))) { 2579184610Salfred /* don't go into a circle */ 2580184610Salfred DPRINTF("avoided going into a circle at id=%d!\n", i); 2581184610Salfred continue; 2582184610Salfred } else { 2583184610Salfred info->bit_visited[i / 8] |= (1 << (i % 8)); 2584184610Salfred } 2585184610Salfred 2586184610Salfred iot = (root + i); 2587184610Salfred 2588184610Salfred if (iot->u.desc == NULL) { 2589184610Salfred continue; 2590184610Salfred } 2591184610Salfred switch (iot->u.desc->bDescriptorSubtype) { 2592184610Salfred case UDESCSUB_AC_INPUT: 2593184610Salfred info->bit_input[i / 8] |= (1 << (i % 8)); 2594184610Salfred break; 2595184610Salfred 2596184610Salfred case UDESCSUB_AC_FEATURE: 2597184610Salfred uaudio_mixer_find_inputs_sub 2598184610Salfred (root, &iot->u.fu->bSourceId, 1, info); 2599184610Salfred break; 2600184610Salfred 2601184610Salfred case UDESCSUB_AC_OUTPUT: 2602184610Salfred uaudio_mixer_find_inputs_sub 2603184610Salfred (root, &iot->u.ot->bSourceId, 1, info); 2604184610Salfred break; 2605184610Salfred 2606184610Salfred case UDESCSUB_AC_MIXER: 2607184610Salfred uaudio_mixer_find_inputs_sub 2608184610Salfred (root, iot->u.mu->baSourceId, 2609184610Salfred iot->u.mu->bNrInPins, info); 2610184610Salfred break; 2611184610Salfred 2612184610Salfred case UDESCSUB_AC_SELECTOR: 2613184610Salfred uaudio_mixer_find_inputs_sub 2614184610Salfred (root, iot->u.su->baSourceId, 2615184610Salfred iot->u.su->bNrInPins, info); 2616184610Salfred break; 2617184610Salfred 2618184610Salfred case UDESCSUB_AC_PROCESSING: 2619184610Salfred uaudio_mixer_find_inputs_sub 2620184610Salfred (root, iot->u.pu->baSourceId, 2621184610Salfred iot->u.pu->bNrInPins, info); 2622184610Salfred break; 2623184610Salfred 2624184610Salfred case UDESCSUB_AC_EXTENSION: 2625184610Salfred uaudio_mixer_find_inputs_sub 2626184610Salfred (root, iot->u.eu->baSourceId, 2627184610Salfred iot->u.eu->bNrInPins, info); 2628184610Salfred break; 2629184610Salfred 2630184610Salfred case UDESCSUB_AC_HEADER: 2631184610Salfred default: 2632184610Salfred break; 2633184610Salfred } 2634184610Salfred } 2635184610Salfred info->recurse_level--; 2636184610Salfred return; 2637184610Salfred} 2638184610Salfred 2639184610Salfredstatic void 2640184610Salfreduaudio_mixer_find_outputs_sub(struct uaudio_terminal_node *root, uint8_t id, 2641184610Salfred uint8_t n_id, struct uaudio_search_result *info) 2642184610Salfred{ 2643184610Salfred struct uaudio_terminal_node *iot = (root + id); 2644184610Salfred uint8_t j; 2645184610Salfred 2646184610Salfred j = n_id; 2647184610Salfred do { 2648184610Salfred if ((j != id) && ((root + j)->u.desc) && 2649184610Salfred ((root + j)->u.desc->bDescriptorSubtype == UDESCSUB_AC_OUTPUT)) { 2650184610Salfred 2651184610Salfred /* 2652184610Salfred * "j" (output) <--- virtual wire <--- "id" (input) 2653184610Salfred * 2654184610Salfred * if "j" has "id" on the input, then "id" have "j" on 2655184610Salfred * the output, because they are connected: 2656184610Salfred */ 2657184610Salfred if ((root + j)->usr.bit_input[id / 8] & (1 << (id % 8))) { 2658184610Salfred iot->usr.bit_output[j / 8] |= (1 << (j % 8)); 2659184610Salfred } 2660184610Salfred } 2661184610Salfred } while (j--); 2662184610Salfred 2663184610Salfred return; 2664184610Salfred} 2665184610Salfred 2666184610Salfredstatic void 2667184610Salfreduaudio_mixer_fill_info(struct uaudio_softc *sc, struct usb2_device *udev, 2668184610Salfred void *desc) 2669184610Salfred{ 2670184610Salfred const struct usb2_audio_control_descriptor *acdp; 2671184610Salfred struct usb2_config_descriptor *cd = usb2_get_config_descriptor(udev); 2672184610Salfred const struct usb2_descriptor *dp; 2673184610Salfred const struct usb2_audio_unit *au; 2674184610Salfred struct uaudio_terminal_node *iot = NULL; 2675184610Salfred uint16_t wTotalLen; 2676184610Salfred uint8_t ID_max = 0; /* inclusive */ 2677184610Salfred uint8_t i; 2678184610Salfred 2679184610Salfred desc = usb2_desc_foreach(cd, desc); 2680184610Salfred 2681184610Salfred if (desc == NULL) { 2682184610Salfred DPRINTF("no Audio Control header\n"); 2683184610Salfred goto done; 2684184610Salfred } 2685184610Salfred acdp = desc; 2686184610Salfred 2687184610Salfred if ((acdp->bLength < sizeof(*acdp)) || 2688184610Salfred (acdp->bDescriptorType != UDESC_CS_INTERFACE) || 2689184610Salfred (acdp->bDescriptorSubtype != UDESCSUB_AC_HEADER)) { 2690184610Salfred DPRINTF("invalid Audio Control header\n"); 2691184610Salfred goto done; 2692184610Salfred } 2693184610Salfred wTotalLen = UGETW(cd->wTotalLength); 2694184610Salfred sc->sc_audio_rev = UGETW(acdp->bcdADC); 2695184610Salfred 2696184610Salfred DPRINTFN(3, "found AC header, vers=%03x, len=%d\n", 2697184610Salfred sc->sc_audio_rev, wTotalLen); 2698184610Salfred 2699184610Salfred if (sc->sc_audio_rev != UAUDIO_VERSION) { 2700184610Salfred 2701184610Salfred if (sc->sc_uq_bad_adc) { 2702184610Salfred 2703184610Salfred } else { 2704184610Salfred DPRINTF("invalid audio version\n"); 2705184610Salfred goto done; 2706184610Salfred } 2707184610Salfred } 2708184610Salfred iot = malloc(sizeof(struct uaudio_terminal_node) * 256, M_TEMP, 2709184610Salfred M_WAITOK | M_ZERO); 2710184610Salfred 2711184610Salfred if (iot == NULL) { 2712184610Salfred DPRINTF("no memory!\n"); 2713184610Salfred goto done; 2714184610Salfred } 2715184610Salfred while ((desc = usb2_desc_foreach(cd, desc))) { 2716184610Salfred 2717184610Salfred dp = desc; 2718184610Salfred 2719184610Salfred if (dp->bLength > wTotalLen) { 2720184610Salfred break; 2721184610Salfred } else { 2722184610Salfred wTotalLen -= dp->bLength; 2723184610Salfred } 2724184610Salfred 2725184610Salfred au = uaudio_mixer_verify_desc(dp, 0); 2726184610Salfred 2727184610Salfred if (au) { 2728184610Salfred iot[au->bUnitId].u.desc = (const void *)au; 2729184610Salfred if (au->bUnitId > ID_max) { 2730184610Salfred ID_max = au->bUnitId; 2731184610Salfred } 2732184610Salfred } 2733184610Salfred } 2734184610Salfred 2735184610Salfred DPRINTF("Maximum ID=%d\n", ID_max); 2736184610Salfred 2737184610Salfred /* 2738184610Salfred * determine sourcing inputs for 2739184610Salfred * all nodes in the tree: 2740184610Salfred */ 2741184610Salfred i = ID_max; 2742184610Salfred do { 2743184610Salfred uaudio_mixer_find_inputs_sub(iot, &i, 1, &((iot + i)->usr)); 2744184610Salfred } while (i--); 2745184610Salfred 2746184610Salfred /* 2747184610Salfred * determine outputs for 2748184610Salfred * all nodes in the tree: 2749184610Salfred */ 2750184610Salfred i = ID_max; 2751184610Salfred do { 2752184610Salfred uaudio_mixer_find_outputs_sub(iot, i, ID_max, &((iot + i)->usr)); 2753184610Salfred } while (i--); 2754184610Salfred 2755184610Salfred /* set "id_max" and "root" */ 2756184610Salfred 2757184610Salfred i = ID_max; 2758184610Salfred do { 2759184610Salfred (iot + i)->usr.id_max = ID_max; 2760184610Salfred (iot + i)->root = iot; 2761184610Salfred } while (i--); 2762184610Salfred 2763184610Salfred#if USB_DEBUG 2764184610Salfred i = ID_max; 2765184610Salfred do { 2766184610Salfred uint8_t j; 2767184610Salfred 2768184610Salfred if (iot[i].u.desc == NULL) { 2769184610Salfred continue; 2770184610Salfred } 2771184610Salfred DPRINTF("id %d:\n", i); 2772184610Salfred 2773184610Salfred switch (iot[i].u.desc->bDescriptorSubtype) { 2774184610Salfred case UDESCSUB_AC_INPUT: 2775184610Salfred DPRINTF(" - AC_INPUT type=%s\n", 2776184610Salfred uaudio_mixer_get_terminal_name 2777184610Salfred (UGETW(iot[i].u.it->wTerminalType))); 2778184610Salfred uaudio_mixer_dump_cluster(i, iot); 2779184610Salfred break; 2780184610Salfred 2781184610Salfred case UDESCSUB_AC_OUTPUT: 2782184610Salfred DPRINTF(" - AC_OUTPUT type=%s " 2783184610Salfred "src=%d\n", uaudio_mixer_get_terminal_name 2784184610Salfred (UGETW(iot[i].u.ot->wTerminalType)), 2785184610Salfred iot[i].u.ot->bSourceId); 2786184610Salfred break; 2787184610Salfred 2788184610Salfred case UDESCSUB_AC_MIXER: 2789184610Salfred DPRINTF(" - AC_MIXER src:\n"); 2790184610Salfred for (j = 0; j < iot[i].u.mu->bNrInPins; j++) { 2791184610Salfred DPRINTF(" - %d\n", iot[i].u.mu->baSourceId[j]); 2792184610Salfred } 2793184610Salfred uaudio_mixer_dump_cluster(i, iot); 2794184610Salfred break; 2795184610Salfred 2796184610Salfred case UDESCSUB_AC_SELECTOR: 2797184610Salfred DPRINTF(" - AC_SELECTOR src:\n"); 2798184610Salfred for (j = 0; j < iot[i].u.su->bNrInPins; j++) { 2799184610Salfred DPRINTF(" - %d\n", iot[i].u.su->baSourceId[j]); 2800184610Salfred } 2801184610Salfred break; 2802184610Salfred 2803184610Salfred case UDESCSUB_AC_FEATURE: 2804184610Salfred DPRINTF(" - AC_FEATURE src=%d\n", iot[i].u.fu->bSourceId); 2805184610Salfred break; 2806184610Salfred 2807184610Salfred case UDESCSUB_AC_PROCESSING: 2808184610Salfred DPRINTF(" - AC_PROCESSING src:\n"); 2809184610Salfred for (j = 0; j < iot[i].u.pu->bNrInPins; j++) { 2810184610Salfred DPRINTF(" - %d\n", iot[i].u.pu->baSourceId[j]); 2811184610Salfred } 2812184610Salfred uaudio_mixer_dump_cluster(i, iot); 2813184610Salfred break; 2814184610Salfred 2815184610Salfred case UDESCSUB_AC_EXTENSION: 2816184610Salfred DPRINTF(" - AC_EXTENSION src:\n"); 2817184610Salfred for (j = 0; j < iot[i].u.eu->bNrInPins; j++) { 2818184610Salfred DPRINTF("%d ", iot[i].u.eu->baSourceId[j]); 2819184610Salfred } 2820184610Salfred uaudio_mixer_dump_cluster(i, iot); 2821184610Salfred break; 2822184610Salfred 2823184610Salfred default: 2824184610Salfred DPRINTF("unknown audio control (subtype=%d)\n", 2825184610Salfred iot[i].u.desc->bDescriptorSubtype); 2826184610Salfred } 2827184610Salfred 2828184610Salfred DPRINTF("Inputs to this ID are:\n"); 2829184610Salfred 2830184610Salfred j = ID_max; 2831184610Salfred do { 2832184610Salfred if (iot[i].usr.bit_input[j / 8] & (1 << (j % 8))) { 2833184610Salfred DPRINTF(" -- ID=%d\n", j); 2834184610Salfred } 2835184610Salfred } while (j--); 2836184610Salfred 2837184610Salfred DPRINTF("Outputs from this ID are:\n"); 2838184610Salfred 2839184610Salfred j = ID_max; 2840184610Salfred do { 2841184610Salfred if (iot[i].usr.bit_output[j / 8] & (1 << (j % 8))) { 2842184610Salfred DPRINTF(" -- ID=%d\n", j); 2843184610Salfred } 2844184610Salfred } while (j--); 2845184610Salfred 2846184610Salfred } while (i--); 2847184610Salfred#endif 2848184610Salfred 2849184610Salfred /* 2850184610Salfred * scan the config to create a linked 2851184610Salfred * list of "mixer" nodes: 2852184610Salfred */ 2853184610Salfred 2854184610Salfred i = ID_max; 2855184610Salfred do { 2856184610Salfred dp = iot[i].u.desc; 2857184610Salfred 2858184610Salfred if (dp == NULL) { 2859184610Salfred continue; 2860184610Salfred } 2861184610Salfred DPRINTFN(11, "id=%d subtype=%d\n", 2862184610Salfred i, dp->bDescriptorSubtype); 2863184610Salfred 2864184610Salfred switch (dp->bDescriptorSubtype) { 2865184610Salfred case UDESCSUB_AC_HEADER: 2866184610Salfred DPRINTF("unexpected AC header\n"); 2867184610Salfred break; 2868184610Salfred 2869184610Salfred case UDESCSUB_AC_INPUT: 2870184610Salfred uaudio_mixer_add_input(sc, iot, i); 2871184610Salfred break; 2872184610Salfred 2873184610Salfred case UDESCSUB_AC_OUTPUT: 2874184610Salfred uaudio_mixer_add_output(sc, iot, i); 2875184610Salfred break; 2876184610Salfred 2877184610Salfred case UDESCSUB_AC_MIXER: 2878184610Salfred uaudio_mixer_add_mixer(sc, iot, i); 2879184610Salfred break; 2880184610Salfred 2881184610Salfred case UDESCSUB_AC_SELECTOR: 2882184610Salfred uaudio_mixer_add_selector(sc, iot, i); 2883184610Salfred break; 2884184610Salfred 2885184610Salfred case UDESCSUB_AC_FEATURE: 2886184610Salfred uaudio_mixer_add_feature(sc, iot, i); 2887184610Salfred break; 2888184610Salfred 2889184610Salfred case UDESCSUB_AC_PROCESSING: 2890184610Salfred uaudio_mixer_add_processing(sc, iot, i); 2891184610Salfred break; 2892184610Salfred 2893184610Salfred case UDESCSUB_AC_EXTENSION: 2894184610Salfred uaudio_mixer_add_extension(sc, iot, i); 2895184610Salfred break; 2896184610Salfred 2897184610Salfred default: 2898184610Salfred DPRINTF("bad AC desc subtype=0x%02x\n", 2899184610Salfred dp->bDescriptorSubtype); 2900184610Salfred break; 2901184610Salfred } 2902184610Salfred 2903184610Salfred } while (i--); 2904184610Salfred 2905184610Salfreddone: 2906184610Salfred if (iot) { 2907184610Salfred free(iot, M_TEMP); 2908184610Salfred } 2909184610Salfred return; 2910184610Salfred} 2911184610Salfred 2912184610Salfredstatic uint16_t 2913184610Salfreduaudio_mixer_get(struct usb2_device *udev, uint8_t what, 2914184610Salfred struct uaudio_mixer_node *mc) 2915184610Salfred{ 2916184610Salfred struct usb2_device_request req; 2917184610Salfred uint16_t val; 2918184610Salfred uint16_t len = MIX_SIZE(mc->type); 2919184610Salfred uint8_t data[4]; 2920184610Salfred usb2_error_t err; 2921184610Salfred 2922184610Salfred if (mc->wValue[0] == -1) { 2923184610Salfred return (0); 2924184610Salfred } 2925184610Salfred req.bmRequestType = UT_READ_CLASS_INTERFACE; 2926184610Salfred req.bRequest = what; 2927184610Salfred USETW(req.wValue, mc->wValue[0]); 2928184610Salfred USETW(req.wIndex, mc->wIndex); 2929184610Salfred USETW(req.wLength, len); 2930184610Salfred 2931184610Salfred err = usb2_do_request(udev, &Giant, &req, data); 2932184610Salfred if (err) { 2933184610Salfred DPRINTF("err=%s\n", usb2_errstr(err)); 2934184610Salfred return (0); 2935184610Salfred } 2936184610Salfred if (len < 1) { 2937184610Salfred data[0] = 0; 2938184610Salfred } 2939184610Salfred if (len < 2) { 2940184610Salfred data[1] = 0; 2941184610Salfred } 2942184610Salfred val = (data[0] | (data[1] << 8)); 2943184610Salfred 2944184610Salfred DPRINTFN(3, "val=%d\n", val); 2945184610Salfred 2946184610Salfred return (val); 2947184610Salfred} 2948184610Salfred 2949184610Salfredstatic void 2950184610Salfreduaudio_mixer_write_cfg_callback(struct usb2_xfer *xfer) 2951184610Salfred{ 2952184610Salfred struct usb2_device_request req; 2953184610Salfred struct uaudio_softc *sc = xfer->priv_sc; 2954184610Salfred struct uaudio_mixer_node *mc = sc->sc_mixer_curr; 2955184610Salfred uint16_t len; 2956184610Salfred uint8_t repeat = 1; 2957184610Salfred uint8_t update; 2958184610Salfred uint8_t chan; 2959184610Salfred uint8_t buf[2]; 2960184610Salfred 2961184610Salfred switch (USB_GET_STATE(xfer)) { 2962184610Salfred case USB_ST_TRANSFERRED: 2963184610Salfredtr_transferred: 2964184610Salfred case USB_ST_SETUP: 2965184610Salfredtr_setup: 2966184610Salfred 2967184610Salfred if (mc == NULL) { 2968184610Salfred mc = sc->sc_mixer_root; 2969184610Salfred sc->sc_mixer_curr = mc; 2970184610Salfred sc->sc_mixer_chan = 0; 2971184610Salfred repeat = 0; 2972184610Salfred } 2973184610Salfred while (mc) { 2974184610Salfred while (sc->sc_mixer_chan < mc->nchan) { 2975184610Salfred 2976184610Salfred len = MIX_SIZE(mc->type); 2977184610Salfred 2978184610Salfred chan = sc->sc_mixer_chan; 2979184610Salfred 2980184610Salfred sc->sc_mixer_chan++; 2981184610Salfred 2982184610Salfred update = ((mc->update[chan / 8] & (1 << (chan % 8))) && 2983184610Salfred (mc->wValue[chan] != -1)); 2984184610Salfred 2985184610Salfred mc->update[chan / 8] &= ~(1 << (chan % 8)); 2986184610Salfred 2987184610Salfred if (update) { 2988184610Salfred 2989184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 2990184610Salfred req.bRequest = SET_CUR; 2991184610Salfred USETW(req.wValue, mc->wValue[chan]); 2992184610Salfred USETW(req.wIndex, mc->wIndex); 2993184610Salfred USETW(req.wLength, len); 2994184610Salfred 2995184610Salfred if (len > 0) { 2996184610Salfred buf[0] = (mc->wData[chan] & 0xFF); 2997184610Salfred } 2998184610Salfred if (len > 1) { 2999184610Salfred buf[1] = (mc->wData[chan] >> 8) & 0xFF; 3000184610Salfred } 3001184610Salfred usb2_copy_in(xfer->frbuffers, 0, &req, sizeof(req)); 3002184610Salfred usb2_copy_in(xfer->frbuffers + 1, 0, buf, len); 3003184610Salfred 3004184610Salfred xfer->frlengths[0] = sizeof(req); 3005184610Salfred xfer->frlengths[1] = len; 3006184610Salfred xfer->nframes = xfer->frlengths[1] ? 2 : 1; 3007184610Salfred usb2_start_hardware(xfer); 3008184610Salfred return; 3009184610Salfred } 3010184610Salfred } 3011184610Salfred 3012184610Salfred mc = mc->next; 3013184610Salfred sc->sc_mixer_curr = mc; 3014184610Salfred sc->sc_mixer_chan = 0; 3015184610Salfred } 3016184610Salfred 3017184610Salfred if (repeat) { 3018184610Salfred goto tr_setup; 3019184610Salfred } 3020184610Salfred return; 3021184610Salfred 3022184610Salfred default: /* Error */ 3023184610Salfred DPRINTF("error=%s\n", usb2_errstr(xfer->error)); 3024184610Salfred 3025184610Salfred goto tr_transferred; 3026184610Salfred } 3027184610Salfred} 3028184610Salfred 3029184610Salfredstatic usb2_error_t 3030184610Salfreduaudio_set_speed(struct usb2_device *udev, uint8_t endpt, uint32_t speed) 3031184610Salfred{ 3032184610Salfred struct usb2_device_request req; 3033184610Salfred uint8_t data[3]; 3034184610Salfred 3035184610Salfred DPRINTFN(6, "endpt=%d speed=%u\n", endpt, speed); 3036184610Salfred 3037184610Salfred req.bmRequestType = UT_WRITE_CLASS_ENDPOINT; 3038184610Salfred req.bRequest = SET_CUR; 3039184610Salfred USETW2(req.wValue, SAMPLING_FREQ_CONTROL, 0); 3040184610Salfred USETW(req.wIndex, endpt); 3041184610Salfred USETW(req.wLength, 3); 3042184610Salfred data[0] = speed; 3043184610Salfred data[1] = speed >> 8; 3044184610Salfred data[2] = speed >> 16; 3045184610Salfred 3046184610Salfred return (usb2_do_request(udev, &Giant, &req, data)); 3047184610Salfred} 3048184610Salfred 3049184610Salfredstatic int 3050184610Salfreduaudio_mixer_signext(uint8_t type, int val) 3051184610Salfred{ 3052184610Salfred if (!MIX_UNSIGNED(type)) { 3053184610Salfred if (MIX_SIZE(type) == 2) { 3054184610Salfred val = (int16_t)val; 3055184610Salfred } else { 3056184610Salfred val = (int8_t)val; 3057184610Salfred } 3058184610Salfred } 3059184610Salfred return (val); 3060184610Salfred} 3061184610Salfred 3062184610Salfredstatic int 3063184610Salfreduaudio_mixer_bsd2value(struct uaudio_mixer_node *mc, int32_t val) 3064184610Salfred{ 3065184610Salfred if (mc->type == MIX_ON_OFF) { 3066184610Salfred val = (val != 0); 3067184610Salfred } else if (mc->type == MIX_SELECTOR) { 3068184610Salfred if ((val < mc->minval) || 3069184610Salfred (val > mc->maxval)) { 3070184610Salfred val = mc->minval; 3071184610Salfred } 3072184610Salfred } else { 3073184610Salfred val = (((val + (mc->delta / 2)) * mc->mul) / 255) + mc->minval; 3074184610Salfred } 3075184610Salfred 3076185087Salfred DPRINTFN(6, "type=0x%03x val=%d min=%d max=%d val=%d\n", 3077185087Salfred mc->type, val, mc->minval, mc->maxval, val); 3078184610Salfred return (val); 3079184610Salfred} 3080184610Salfred 3081184610Salfredstatic void 3082184610Salfreduaudio_mixer_ctl_set(struct uaudio_softc *sc, struct uaudio_mixer_node *mc, 3083184610Salfred uint8_t chan, int32_t val) 3084184610Salfred{ 3085184610Salfred val = uaudio_mixer_bsd2value(mc, val); 3086184610Salfred 3087184610Salfred mc->update[chan / 8] |= (1 << (chan % 8)); 3088184610Salfred mc->wData[chan] = val; 3089184610Salfred 3090184610Salfred /* start the transfer, if not already started */ 3091184610Salfred 3092184610Salfred usb2_transfer_start(sc->sc_mixer_xfer[0]); 3093184610Salfred 3094184610Salfred return; 3095184610Salfred} 3096184610Salfred 3097184610Salfredstatic void 3098184610Salfreduaudio_mixer_init(struct uaudio_softc *sc) 3099184610Salfred{ 3100184610Salfred struct uaudio_mixer_node *mc; 3101184610Salfred int32_t i; 3102184610Salfred 3103184610Salfred for (mc = sc->sc_mixer_root; mc; 3104184610Salfred mc = mc->next) { 3105184610Salfred 3106184610Salfred if (mc->ctl != SOUND_MIXER_NRDEVICES) { 3107184610Salfred /* 3108184610Salfred * Set device mask bits. See 3109184610Salfred * /usr/include/machine/soundcard.h 3110184610Salfred */ 3111184610Salfred sc->sc_mix_info |= (1 << mc->ctl); 3112184610Salfred } 3113184610Salfred if ((mc->ctl == SOUND_MIXER_NRDEVICES) && 3114184610Salfred (mc->type == MIX_SELECTOR)) { 3115184610Salfred 3116184610Salfred for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { 3117184610Salfred if (mc->slctrtype[i - 1] == SOUND_MIXER_NRDEVICES) { 3118184610Salfred continue; 3119184610Salfred } 3120184610Salfred sc->sc_recsrc_info |= 1 << mc->slctrtype[i - 1]; 3121184610Salfred } 3122184610Salfred } 3123184610Salfred } 3124184610Salfred return; 3125184610Salfred} 3126184610Salfred 3127184610Salfredint 3128184610Salfreduaudio_mixer_init_sub(struct uaudio_softc *sc, struct snd_mixer *m) 3129184610Salfred{ 3130184610Salfred DPRINTF("\n"); 3131184610Salfred 3132184610Salfred if (usb2_transfer_setup(sc->sc_udev, &sc->sc_mixer_iface_index, 3133184610Salfred sc->sc_mixer_xfer, uaudio_mixer_config, 1, sc, 3134184610Salfred mixer_get_lock(m))) { 3135184610Salfred DPRINTFN(0, "could not allocate USB " 3136184610Salfred "transfer for audio mixer!\n"); 3137184610Salfred return (ENOMEM); 3138184610Salfred } 3139184610Salfred if (!(sc->sc_mix_info & SOUND_MASK_VOLUME)) { 3140184610Salfred mix_setparentchild(m, SOUND_MIXER_VOLUME, SOUND_MASK_PCM); 3141184610Salfred mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE); 3142184610Salfred } 3143184610Salfred mix_setdevs(m, sc->sc_mix_info); 3144184610Salfred mix_setrecdevs(m, sc->sc_recsrc_info); 3145184610Salfred return (0); 3146184610Salfred} 3147184610Salfred 3148184610Salfredint 3149184610Salfreduaudio_mixer_uninit_sub(struct uaudio_softc *sc) 3150184610Salfred{ 3151184610Salfred DPRINTF("\n"); 3152184610Salfred 3153184610Salfred usb2_transfer_unsetup(sc->sc_mixer_xfer, 1); 3154184610Salfred 3155184610Salfred return (0); 3156184610Salfred} 3157184610Salfred 3158184610Salfredvoid 3159184610Salfreduaudio_mixer_set(struct uaudio_softc *sc, unsigned type, 3160184610Salfred unsigned left, unsigned right) 3161184610Salfred{ 3162184610Salfred struct uaudio_mixer_node *mc; 3163184610Salfred 3164184610Salfred for (mc = sc->sc_mixer_root; mc; 3165184610Salfred mc = mc->next) { 3166184610Salfred 3167184610Salfred if (mc->ctl == type) { 3168184610Salfred if (mc->nchan == 2) { 3169184610Salfred /* set Right */ 3170184610Salfred uaudio_mixer_ctl_set(sc, mc, 1, (int)(right * 255) / 100); 3171184610Salfred } 3172184610Salfred /* set Left or Mono */ 3173184610Salfred uaudio_mixer_ctl_set(sc, mc, 0, (int)(left * 255) / 100); 3174184610Salfred } 3175184610Salfred } 3176184610Salfred return; 3177184610Salfred} 3178184610Salfred 3179184610Salfreduint32_t 3180184610Salfreduaudio_mixer_setrecsrc(struct uaudio_softc *sc, uint32_t src) 3181184610Salfred{ 3182184610Salfred struct uaudio_mixer_node *mc; 3183184610Salfred uint32_t mask; 3184184610Salfred uint32_t temp; 3185184610Salfred int32_t i; 3186184610Salfred 3187184610Salfred for (mc = sc->sc_mixer_root; mc; 3188184610Salfred mc = mc->next) { 3189184610Salfred 3190184610Salfred if ((mc->ctl == SOUND_MIXER_NRDEVICES) && 3191184610Salfred (mc->type == MIX_SELECTOR)) { 3192184610Salfred 3193184610Salfred /* compute selector mask */ 3194184610Salfred 3195184610Salfred mask = 0; 3196184610Salfred for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { 3197184610Salfred mask |= (1 << mc->slctrtype[i - 1]); 3198184610Salfred } 3199184610Salfred 3200184610Salfred temp = mask & src; 3201184610Salfred if (temp == 0) { 3202184610Salfred continue; 3203184610Salfred } 3204184610Salfred /* find the first set bit */ 3205184610Salfred temp = (-temp) & temp; 3206184610Salfred 3207184610Salfred /* update "src" */ 3208184610Salfred src &= ~mask; 3209184610Salfred src |= temp; 3210184610Salfred 3211184610Salfred for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { 3212184610Salfred if (temp != (1 << mc->slctrtype[i - 1])) { 3213184610Salfred continue; 3214184610Salfred } 3215184610Salfred uaudio_mixer_ctl_set(sc, mc, 0, i); 3216184610Salfred break; 3217184610Salfred } 3218184610Salfred } 3219184610Salfred } 3220184610Salfred return (src); 3221184610Salfred} 3222184610Salfred 3223184610Salfred/*========================================================================* 3224184610Salfred * MIDI support routines 3225184610Salfred *========================================================================*/ 3226184610Salfred 3227184610Salfredstatic void 3228184610Salfredumidi_read_clear_stall_callback(struct usb2_xfer *xfer) 3229184610Salfred{ 3230184610Salfred struct umidi_chan *chan = xfer->priv_sc; 3231184610Salfred struct usb2_xfer *xfer_other = chan->xfer[1]; 3232184610Salfred 3233184610Salfred if (usb2_clear_stall_callback(xfer, xfer_other)) { 3234184610Salfred DPRINTF("stall cleared\n"); 3235184610Salfred chan->flags &= ~UMIDI_FLAG_READ_STALL; 3236184610Salfred usb2_transfer_start(xfer_other); 3237184610Salfred } 3238184610Salfred return; 3239184610Salfred} 3240184610Salfred 3241184610Salfredstatic void 3242184610Salfredumidi_bulk_read_callback(struct usb2_xfer *xfer) 3243184610Salfred{ 3244184610Salfred struct umidi_chan *chan = xfer->priv_sc; 3245184610Salfred struct umidi_sub_chan *sub; 3246184610Salfred uint8_t buf[1]; 3247184610Salfred uint8_t cmd_len; 3248184610Salfred uint8_t cn; 3249184610Salfred uint16_t pos; 3250184610Salfred 3251184610Salfred switch (USB_GET_STATE(xfer)) { 3252184610Salfred case USB_ST_TRANSFERRED: 3253184610Salfred 3254184610Salfred DPRINTF("actlen=%d bytes\n", xfer->actlen); 3255184610Salfred 3256184610Salfred if (xfer->actlen == 0) { 3257184610Salfred /* should not happen */ 3258184610Salfred goto tr_error; 3259184610Salfred } 3260184610Salfred pos = 0; 3261184610Salfred 3262184610Salfred while (xfer->actlen >= 4) { 3263184610Salfred 3264184610Salfred usb2_copy_out(xfer->frbuffers, pos, buf, 1); 3265184610Salfred 3266184610Salfred cmd_len = umidi_cmd_to_len[buf[0] & 0xF]; /* command length */ 3267184610Salfred cn = buf[0] >> 4; /* cable number */ 3268184610Salfred sub = &chan->sub[cn]; 3269184610Salfred 3270184610Salfred if (cmd_len && (cn < chan->max_cable) && sub->read_open) { 3271184610Salfred usb2_fifo_put_data(sub->fifo.fp[USB_FIFO_RX], xfer->frbuffers, 3272184610Salfred pos + 1, cmd_len, 1); 3273184610Salfred } else { 3274184610Salfred /* ignore the command */ 3275184610Salfred } 3276184610Salfred 3277184610Salfred xfer->actlen -= 4; 3278184610Salfred pos += 4; 3279184610Salfred } 3280184610Salfred 3281184610Salfred case USB_ST_SETUP: 3282184610Salfred DPRINTF("start\n"); 3283184610Salfred 3284184610Salfred if (chan->flags & UMIDI_FLAG_READ_STALL) { 3285184610Salfred usb2_transfer_start(chan->xfer[3]); 3286184610Salfred return; 3287184610Salfred } 3288184610Salfred xfer->frlengths[0] = xfer->max_data_length; 3289184610Salfred usb2_start_hardware(xfer); 3290184610Salfred return; 3291184610Salfred 3292184610Salfred default: 3293184610Salfredtr_error: 3294184610Salfred 3295184610Salfred DPRINTF("error=%s\n", usb2_errstr(xfer->error)); 3296184610Salfred 3297184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 3298184610Salfred /* try to clear stall first */ 3299184610Salfred chan->flags |= UMIDI_FLAG_READ_STALL; 3300184610Salfred usb2_transfer_start(chan->xfer[3]); 3301184610Salfred } 3302184610Salfred return; 3303184610Salfred 3304184610Salfred } 3305184610Salfred} 3306184610Salfred 3307184610Salfredstatic void 3308184610Salfredumidi_write_clear_stall_callback(struct usb2_xfer *xfer) 3309184610Salfred{ 3310184610Salfred struct umidi_chan *chan = xfer->priv_sc; 3311184610Salfred struct usb2_xfer *xfer_other = chan->xfer[0]; 3312184610Salfred 3313184610Salfred if (usb2_clear_stall_callback(xfer, xfer_other)) { 3314184610Salfred DPRINTF("stall cleared\n"); 3315184610Salfred chan->flags &= ~UMIDI_FLAG_WRITE_STALL; 3316184610Salfred usb2_transfer_start(xfer_other); 3317184610Salfred } 3318184610Salfred return; 3319184610Salfred} 3320184610Salfred 3321184610Salfred/* 3322184610Salfred * The following statemachine, that converts MIDI commands to 3323184610Salfred * USB MIDI packets, derives from Linux's usbmidi.c, which 3324184610Salfred * was written by "Clemens Ladisch": 3325184610Salfred * 3326184610Salfred * Returns: 3327184610Salfred * 0: No command 3328184610Salfred * Else: Command is complete 3329184610Salfred */ 3330184610Salfredstatic uint8_t 3331184610Salfredumidi_convert_to_usb(struct umidi_sub_chan *sub, uint8_t cn, uint8_t b) 3332184610Salfred{ 3333184610Salfred uint8_t p0 = (cn << 4); 3334184610Salfred 3335184610Salfred if (b >= 0xf8) { 3336184610Salfred sub->temp_0[0] = p0 | 0x0f; 3337184610Salfred sub->temp_0[1] = b; 3338184610Salfred sub->temp_0[2] = 0; 3339184610Salfred sub->temp_0[3] = 0; 3340184610Salfred sub->temp_cmd = sub->temp_0; 3341184610Salfred return (1); 3342184610Salfred 3343184610Salfred } else if (b >= 0xf0) { 3344184610Salfred switch (b) { 3345184610Salfred case 0xf0: /* system exclusive begin */ 3346184610Salfred sub->temp_1[1] = b; 3347184610Salfred sub->state = UMIDI_ST_SYSEX_1; 3348184610Salfred break; 3349184610Salfred case 0xf1: /* MIDI time code */ 3350184610Salfred case 0xf3: /* song select */ 3351184610Salfred sub->temp_1[1] = b; 3352184610Salfred sub->state = UMIDI_ST_1PARAM; 3353184610Salfred break; 3354184610Salfred case 0xf2: /* song position pointer */ 3355184610Salfred sub->temp_1[1] = b; 3356184610Salfred sub->state = UMIDI_ST_2PARAM_1; 3357184610Salfred break; 3358184610Salfred case 0xf4: /* unknown */ 3359184610Salfred case 0xf5: /* unknown */ 3360184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3361184610Salfred break; 3362184610Salfred case 0xf6: /* tune request */ 3363184610Salfred sub->temp_1[0] = p0 | 0x05; 3364184610Salfred sub->temp_1[1] = 0xf6; 3365184610Salfred sub->temp_1[2] = 0; 3366184610Salfred sub->temp_1[3] = 0; 3367184610Salfred sub->temp_cmd = sub->temp_1; 3368184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3369184610Salfred return (1); 3370184610Salfred 3371184610Salfred case 0xf7: /* system exclusive end */ 3372184610Salfred switch (sub->state) { 3373184610Salfred case UMIDI_ST_SYSEX_0: 3374184610Salfred sub->temp_1[0] = p0 | 0x05; 3375184610Salfred sub->temp_1[1] = 0xf7; 3376184610Salfred sub->temp_1[2] = 0; 3377184610Salfred sub->temp_1[3] = 0; 3378184610Salfred sub->temp_cmd = sub->temp_1; 3379184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3380184610Salfred return (1); 3381184610Salfred case UMIDI_ST_SYSEX_1: 3382184610Salfred sub->temp_1[0] = p0 | 0x06; 3383184610Salfred sub->temp_1[2] = 0xf7; 3384184610Salfred sub->temp_1[3] = 0; 3385184610Salfred sub->temp_cmd = sub->temp_1; 3386184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3387184610Salfred return (1); 3388184610Salfred case UMIDI_ST_SYSEX_2: 3389184610Salfred sub->temp_1[0] = p0 | 0x07; 3390184610Salfred sub->temp_1[3] = 0xf7; 3391184610Salfred sub->temp_cmd = sub->temp_1; 3392184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3393184610Salfred return (1); 3394184610Salfred } 3395184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3396184610Salfred break; 3397184610Salfred } 3398184610Salfred } else if (b >= 0x80) { 3399184610Salfred sub->temp_1[1] = b; 3400184610Salfred if ((b >= 0xc0) && (b <= 0xdf)) { 3401184610Salfred sub->state = UMIDI_ST_1PARAM; 3402184610Salfred } else { 3403184610Salfred sub->state = UMIDI_ST_2PARAM_1; 3404184610Salfred } 3405184610Salfred } else { /* b < 0x80 */ 3406184610Salfred switch (sub->state) { 3407184610Salfred case UMIDI_ST_1PARAM: 3408184610Salfred if (sub->temp_1[1] < 0xf0) { 3409184610Salfred p0 |= sub->temp_1[1] >> 4; 3410184610Salfred } else { 3411184610Salfred p0 |= 0x02; 3412184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3413184610Salfred } 3414184610Salfred sub->temp_1[0] = p0; 3415184610Salfred sub->temp_1[2] = b; 3416184610Salfred sub->temp_1[3] = 0; 3417184610Salfred sub->temp_cmd = sub->temp_1; 3418184610Salfred return (1); 3419184610Salfred case UMIDI_ST_2PARAM_1: 3420184610Salfred sub->temp_1[2] = b; 3421184610Salfred sub->state = UMIDI_ST_2PARAM_2; 3422184610Salfred break; 3423184610Salfred case UMIDI_ST_2PARAM_2: 3424184610Salfred if (sub->temp_1[1] < 0xf0) { 3425184610Salfred p0 |= sub->temp_1[1] >> 4; 3426184610Salfred sub->state = UMIDI_ST_2PARAM_1; 3427184610Salfred } else { 3428184610Salfred p0 |= 0x03; 3429184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3430184610Salfred } 3431184610Salfred sub->temp_1[0] = p0; 3432184610Salfred sub->temp_1[3] = b; 3433184610Salfred sub->temp_cmd = sub->temp_1; 3434184610Salfred return (1); 3435184610Salfred case UMIDI_ST_SYSEX_0: 3436184610Salfred sub->temp_1[1] = b; 3437184610Salfred sub->state = UMIDI_ST_SYSEX_1; 3438184610Salfred break; 3439184610Salfred case UMIDI_ST_SYSEX_1: 3440184610Salfred sub->temp_1[2] = b; 3441184610Salfred sub->state = UMIDI_ST_SYSEX_2; 3442184610Salfred break; 3443184610Salfred case UMIDI_ST_SYSEX_2: 3444184610Salfred sub->temp_1[0] = p0 | 0x04; 3445184610Salfred sub->temp_1[3] = b; 3446184610Salfred sub->temp_cmd = sub->temp_1; 3447184610Salfred sub->state = UMIDI_ST_SYSEX_0; 3448184610Salfred return (1); 3449184610Salfred } 3450184610Salfred } 3451184610Salfred return (0); 3452184610Salfred} 3453184610Salfred 3454184610Salfredstatic void 3455184610Salfredumidi_bulk_write_callback(struct usb2_xfer *xfer) 3456184610Salfred{ 3457184610Salfred struct umidi_chan *chan = xfer->priv_sc; 3458184610Salfred struct umidi_sub_chan *sub; 3459184610Salfred uint32_t actlen; 3460184610Salfred uint16_t total_length; 3461184610Salfred uint8_t buf; 3462184610Salfred uint8_t start_cable; 3463184610Salfred uint8_t tr_any; 3464184610Salfred 3465184610Salfred switch (USB_GET_STATE(xfer)) { 3466184610Salfred case USB_ST_TRANSFERRED: 3467184610Salfred DPRINTF("actlen=%d bytes\n", xfer->actlen); 3468184610Salfred 3469184610Salfred case USB_ST_SETUP: 3470184610Salfred 3471184610Salfred DPRINTF("start\n"); 3472184610Salfred 3473184610Salfred if (chan->flags & UMIDI_FLAG_WRITE_STALL) { 3474184610Salfred usb2_transfer_start(chan->xfer[2]); 3475184610Salfred return; 3476184610Salfred } 3477184610Salfred total_length = 0; /* reset */ 3478184610Salfred 3479184610Salfred start_cable = chan->curr_cable; 3480184610Salfred 3481184610Salfred tr_any = 0; 3482184610Salfred 3483184610Salfred while (1) { 3484184610Salfred 3485184610Salfred /* round robin de-queueing */ 3486184610Salfred 3487184610Salfred sub = &chan->sub[chan->curr_cable]; 3488184610Salfred 3489184610Salfred if (sub->write_open) { 3490184610Salfred usb2_fifo_get_data(sub->fifo.fp[USB_FIFO_TX], 3491184610Salfred xfer->frbuffers, total_length, 3492184610Salfred 1, &actlen, 0); 3493184610Salfred } else { 3494184610Salfred actlen = 0; 3495184610Salfred } 3496184610Salfred 3497184610Salfred if (actlen) { 3498184610Salfred usb2_copy_out(xfer->frbuffers, total_length, &buf, 1); 3499184610Salfred 3500184610Salfred tr_any = 1; 3501184610Salfred 3502184610Salfred DPRINTF("byte=0x%02x\n", buf); 3503184610Salfred 3504184610Salfred if (umidi_convert_to_usb(sub, chan->curr_cable, buf)) { 3505184610Salfred 3506184610Salfred DPRINTF("sub= %02x %02x %02x %02x\n", 3507184610Salfred sub->temp_cmd[0], sub->temp_cmd[1], 3508184610Salfred sub->temp_cmd[2], sub->temp_cmd[3]); 3509184610Salfred 3510184610Salfred usb2_copy_in(xfer->frbuffers, total_length, 3511184610Salfred sub->temp_cmd, 4); 3512184610Salfred 3513184610Salfred total_length += 4; 3514184610Salfred 3515184610Salfred if (total_length >= UMIDI_BULK_SIZE) { 3516184610Salfred break; 3517184610Salfred } 3518184610Salfred } else { 3519184610Salfred continue; 3520184610Salfred } 3521184610Salfred } 3522184610Salfred chan->curr_cable++; 3523184610Salfred if (chan->curr_cable >= chan->max_cable) { 3524184610Salfred chan->curr_cable = 0; 3525184610Salfred } 3526184610Salfred if (chan->curr_cable == start_cable) { 3527184610Salfred if (tr_any == 0) { 3528184610Salfred break; 3529184610Salfred } 3530184610Salfred tr_any = 0; 3531184610Salfred } 3532184610Salfred } 3533184610Salfred 3534184610Salfred if (total_length) { 3535184610Salfred xfer->frlengths[0] = total_length; 3536184610Salfred usb2_start_hardware(xfer); 3537184610Salfred } 3538184610Salfred return; 3539184610Salfred 3540184610Salfred default: /* Error */ 3541184610Salfred 3542184610Salfred DPRINTF("error=%s\n", usb2_errstr(xfer->error)); 3543184610Salfred 3544184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 3545184610Salfred /* try to clear stall first */ 3546184610Salfred chan->flags |= UMIDI_FLAG_WRITE_STALL; 3547184610Salfred usb2_transfer_start(chan->xfer[2]); 3548184610Salfred } 3549184610Salfred return; 3550184610Salfred 3551184610Salfred } 3552184610Salfred} 3553184610Salfred 3554184610Salfredstatic struct umidi_sub_chan * 3555184610Salfredumidi_sub_by_fifo(struct usb2_fifo *fifo) 3556184610Salfred{ 3557184610Salfred struct umidi_chan *chan = fifo->priv_sc0; 3558184610Salfred struct umidi_sub_chan *sub; 3559184610Salfred uint32_t n; 3560184610Salfred 3561184610Salfred for (n = 0; n < UMIDI_CABLES_MAX; n++) { 3562184610Salfred sub = &chan->sub[n]; 3563184610Salfred if ((sub->fifo.fp[USB_FIFO_RX] == fifo) || 3564184610Salfred (sub->fifo.fp[USB_FIFO_TX] == fifo)) { 3565184610Salfred return (sub); 3566184610Salfred } 3567184610Salfred } 3568184610Salfred 3569184610Salfred panic("%s:%d cannot find usb2_fifo!\n", 3570184610Salfred __FILE__, __LINE__); 3571184610Salfred 3572184610Salfred return (NULL); 3573184610Salfred} 3574184610Salfred 3575184610Salfredstatic void 3576184610Salfredumidi_start_read(struct usb2_fifo *fifo) 3577184610Salfred{ 3578184610Salfred struct umidi_chan *chan = fifo->priv_sc0; 3579184610Salfred 3580184610Salfred usb2_transfer_start(chan->xfer[1]); 3581184610Salfred return; 3582184610Salfred} 3583184610Salfred 3584184610Salfredstatic void 3585184610Salfredumidi_stop_read(struct usb2_fifo *fifo) 3586184610Salfred{ 3587184610Salfred struct umidi_chan *chan = fifo->priv_sc0; 3588184610Salfred struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo); 3589184610Salfred 3590184610Salfred DPRINTF("\n"); 3591184610Salfred 3592184610Salfred sub->read_open = 0; 3593184610Salfred 3594184610Salfred if (--(chan->read_open_refcount) == 0) { 3595184610Salfred /* 3596184610Salfred * XXX don't stop the read transfer here, hence that causes 3597184610Salfred * problems with some MIDI adapters 3598184610Salfred */ 3599184610Salfred DPRINTF("(stopping read transfer)\n"); 3600184610Salfred } 3601184610Salfred return; 3602184610Salfred} 3603184610Salfred 3604184610Salfredstatic void 3605184610Salfredumidi_start_write(struct usb2_fifo *fifo) 3606184610Salfred{ 3607184610Salfred struct umidi_chan *chan = fifo->priv_sc0; 3608184610Salfred 3609184610Salfred usb2_transfer_start(chan->xfer[0]); 3610184610Salfred return; 3611184610Salfred} 3612184610Salfred 3613184610Salfredstatic void 3614184610Salfredumidi_stop_write(struct usb2_fifo *fifo) 3615184610Salfred{ 3616184610Salfred struct umidi_chan *chan = fifo->priv_sc0; 3617184610Salfred struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo); 3618184610Salfred 3619184610Salfred DPRINTF("\n"); 3620184610Salfred 3621184610Salfred sub->write_open = 0; 3622184610Salfred 3623184610Salfred if (--(chan->write_open_refcount) == 0) { 3624184610Salfred DPRINTF("(stopping write transfer)\n"); 3625184610Salfred usb2_transfer_stop(chan->xfer[2]); 3626184610Salfred usb2_transfer_stop(chan->xfer[0]); 3627184610Salfred } 3628184610Salfred return; 3629184610Salfred} 3630184610Salfred 3631184610Salfredstatic int 3632184610Salfredumidi_open(struct usb2_fifo *fifo, int fflags, struct thread *td) 3633184610Salfred{ 3634184610Salfred struct umidi_chan *chan = fifo->priv_sc0; 3635184610Salfred struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo); 3636184610Salfred 3637184610Salfred if (fflags & FREAD) { 3638184610Salfred if (usb2_fifo_alloc_buffer(fifo, 4, (1024 / 4))) { 3639184610Salfred return (ENOMEM); 3640184610Salfred } 3641184610Salfred mtx_lock(fifo->priv_mtx); 3642184610Salfred chan->read_open_refcount++; 3643184610Salfred sub->read_open = 1; 3644184610Salfred mtx_unlock(fifo->priv_mtx); 3645184610Salfred } 3646184610Salfred if (fflags & FWRITE) { 3647184610Salfred if (usb2_fifo_alloc_buffer(fifo, 32, (1024 / 32))) { 3648184610Salfred return (ENOMEM); 3649184610Salfred } 3650184610Salfred /* clear stall first */ 3651184610Salfred mtx_lock(fifo->priv_mtx); 3652184610Salfred chan->flags |= UMIDI_FLAG_WRITE_STALL; 3653184610Salfred chan->write_open_refcount++; 3654184610Salfred sub->write_open = 1; 3655184610Salfred 3656184610Salfred /* reset */ 3657184610Salfred sub->state = UMIDI_ST_UNKNOWN; 3658184610Salfred mtx_unlock(fifo->priv_mtx); 3659184610Salfred } 3660184610Salfred return (0); /* success */ 3661184610Salfred} 3662184610Salfred 3663184610Salfredstatic void 3664184610Salfredumidi_close(struct usb2_fifo *fifo, int fflags, struct thread *td) 3665184610Salfred{ 3666184610Salfred if (fflags & FREAD) { 3667184610Salfred usb2_fifo_free_buffer(fifo); 3668184610Salfred } 3669184610Salfred if (fflags & FWRITE) { 3670184610Salfred usb2_fifo_free_buffer(fifo); 3671184610Salfred } 3672184610Salfred return; 3673184610Salfred} 3674184610Salfred 3675184610Salfred 3676184610Salfredstatic int 3677184610Salfredumidi_ioctl(struct usb2_fifo *fifo, u_long cmd, void *data, 3678184610Salfred int fflags, struct thread *td) 3679184610Salfred{ 3680184610Salfred return (ENODEV); 3681184610Salfred} 3682184610Salfred 3683184610Salfredstatic void 3684184610Salfredumidi_init(device_t dev) 3685184610Salfred{ 3686184610Salfred struct uaudio_softc *sc = device_get_softc(dev); 3687184610Salfred struct umidi_chan *chan = &sc->sc_midi_chan; 3688184610Salfred 3689184610Salfred mtx_init(&chan->mtx, "umidi lock", NULL, MTX_DEF | MTX_RECURSE); 3690184610Salfred return; 3691184610Salfred} 3692184610Salfred 3693184610Salfredstatic struct usb2_fifo_methods umidi_fifo_methods = { 3694184610Salfred .f_start_read = &umidi_start_read, 3695184610Salfred .f_start_write = &umidi_start_write, 3696184610Salfred .f_stop_read = &umidi_stop_read, 3697184610Salfred .f_stop_write = &umidi_stop_write, 3698184610Salfred .f_open = &umidi_open, 3699184610Salfred .f_close = &umidi_close, 3700184610Salfred .f_ioctl = &umidi_ioctl, 3701184610Salfred .basename[0] = "umidi", 3702184610Salfred}; 3703184610Salfred 3704184610Salfredstatic int32_t 3705184610Salfredumidi_probe(device_t dev) 3706184610Salfred{ 3707184610Salfred struct uaudio_softc *sc = device_get_softc(dev); 3708184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 3709184610Salfred struct umidi_chan *chan = &sc->sc_midi_chan; 3710184610Salfred struct umidi_sub_chan *sub; 3711184610Salfred int unit = device_get_unit(dev); 3712184610Salfred int error; 3713184610Salfred uint32_t n; 3714184610Salfred 3715184610Salfred if (usb2_set_alt_interface_index(sc->sc_udev, chan->iface_index, 3716184610Salfred chan->iface_alt_index)) { 3717184610Salfred DPRINTF("setting of alternate index failed!\n"); 3718184610Salfred goto detach; 3719184610Salfred } 3720184610Salfred usb2_set_parent_iface(sc->sc_udev, chan->iface_index, sc->sc_mixer_iface_index); 3721184610Salfred 3722184610Salfred error = usb2_transfer_setup(uaa->device, &chan->iface_index, 3723184610Salfred chan->xfer, umidi_config, UMIDI_N_TRANSFER, 3724184610Salfred chan, &chan->mtx); 3725184610Salfred if (error) { 3726184610Salfred DPRINTF("error=%s\n", usb2_errstr(error)); 3727184610Salfred goto detach; 3728184610Salfred } 3729184610Salfred if ((chan->max_cable > UMIDI_CABLES_MAX) || 3730184610Salfred (chan->max_cable == 0)) { 3731184610Salfred chan->max_cable = UMIDI_CABLES_MAX; 3732184610Salfred } 3733184610Salfred /* set interface permissions */ 3734184610Salfred usb2_set_iface_perm(sc->sc_udev, chan->iface_index, 3735184610Salfred UID_ROOT, GID_OPERATOR, 0644); 3736184610Salfred 3737184610Salfred for (n = 0; n < chan->max_cable; n++) { 3738184610Salfred 3739184610Salfred sub = &chan->sub[n]; 3740184610Salfred 3741184610Salfred error = usb2_fifo_attach(sc->sc_udev, chan, &chan->mtx, 3742184610Salfred &umidi_fifo_methods, &sub->fifo, unit, n, 3743184610Salfred chan->iface_index); 3744184610Salfred if (error) { 3745184610Salfred goto detach; 3746184610Salfred } 3747184610Salfred } 3748184610Salfred 3749184610Salfred mtx_lock(&chan->mtx); 3750184610Salfred 3751184610Salfred /* clear stall first */ 3752184610Salfred chan->flags |= UMIDI_FLAG_READ_STALL; 3753184610Salfred 3754184610Salfred /* 3755184610Salfred * NOTE: at least one device will not work properly unless 3756184610Salfred * the BULK pipe is open all the time. 3757184610Salfred */ 3758184610Salfred usb2_transfer_start(chan->xfer[1]); 3759184610Salfred 3760184610Salfred mtx_unlock(&chan->mtx); 3761184610Salfred 3762184610Salfred return (0); /* success */ 3763184610Salfred 3764184610Salfreddetach: 3765184610Salfred return (ENXIO); /* failure */ 3766184610Salfred} 3767184610Salfred 3768184610Salfredstatic int32_t 3769184610Salfredumidi_detach(device_t dev) 3770184610Salfred{ 3771184610Salfred struct uaudio_softc *sc = device_get_softc(dev); 3772184610Salfred struct umidi_chan *chan = &sc->sc_midi_chan; 3773184610Salfred uint32_t n; 3774184610Salfred 3775184610Salfred for (n = 0; n < UMIDI_CABLES_MAX; n++) { 3776184610Salfred usb2_fifo_detach(&chan->sub[n].fifo); 3777184610Salfred } 3778184610Salfred 3779184610Salfred mtx_lock(&chan->mtx); 3780184610Salfred 3781184610Salfred usb2_transfer_stop(chan->xfer[3]); 3782184610Salfred usb2_transfer_stop(chan->xfer[1]); 3783184610Salfred 3784184610Salfred mtx_unlock(&chan->mtx); 3785184610Salfred 3786184610Salfred usb2_transfer_unsetup(chan->xfer, UMIDI_N_TRANSFER); 3787184610Salfred 3788184610Salfred mtx_destroy(&chan->mtx); 3789184610Salfred 3790184610Salfred return (0); 3791184610Salfred} 3792184610Salfred 3793184610SalfredDRIVER_MODULE(uaudio, ushub, uaudio_driver, uaudio_devclass, NULL, 0); 3794184610SalfredMODULE_DEPEND(uaudio, usb2_sound, 1, 1, 1); 3795184610SalfredMODULE_DEPEND(uaudio, usb2_core, 1, 1, 1); 3796184610SalfredMODULE_DEPEND(uaudio, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 3797184610SalfredMODULE_VERSION(uaudio, 1); 3798