uaudio.c revision 209452
1184610Salfred/*	$NetBSD: uaudio.c,v 1.91 2004/11/05 17:46:14 kent Exp $	*/
2184610Salfred/*	$FreeBSD: head/sys/dev/sound/usb/uaudio.c 209452 2010-06-22 21:16:18Z thompsa $ */
3184610Salfred
4184610Salfred/*-
5184610Salfred * Copyright (c) 1999 The NetBSD Foundation, Inc.
6184610Salfred * All rights reserved.
7184610Salfred *
8184610Salfred * This code is derived from software contributed to The NetBSD Foundation
9184610Salfred * by Lennart Augustsson (lennart@augustsson.net) at
10184610Salfred * Carlstedt Research & Technology.
11184610Salfred *
12184610Salfred * Redistribution and use in source and binary forms, with or without
13184610Salfred * modification, are permitted provided that the following conditions
14184610Salfred * are met:
15184610Salfred * 1. Redistributions of source code must retain the above copyright
16184610Salfred *    notice, this list of conditions and the following disclaimer.
17184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
18184610Salfred *    notice, this list of conditions and the following disclaimer in the
19184610Salfred *    documentation and/or other materials provided with the distribution.
20184610Salfred *
21184610Salfred * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22184610Salfred * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23184610Salfred * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24184610Salfred * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25184610Salfred * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26184610Salfred * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27184610Salfred * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28184610Salfred * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29184610Salfred * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30184610Salfred * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31184610Salfred * POSSIBILITY OF SUCH DAMAGE.
32184610Salfred */
33184610Salfred
34184610Salfred/*
35184610Salfred * USB audio specs: http://www.usb.org/developers/devclass_docs/audio10.pdf
36184610Salfred *                  http://www.usb.org/developers/devclass_docs/frmts10.pdf
37184610Salfred *                  http://www.usb.org/developers/devclass_docs/termt10.pdf
38184610Salfred */
39184610Salfred
40184610Salfred/*
41184610Salfred * Also merged:
42184610Salfred *  $NetBSD: uaudio.c,v 1.94 2005/01/15 15:19:53 kent Exp $
43184610Salfred *  $NetBSD: uaudio.c,v 1.95 2005/01/16 06:02:19 dsainty Exp $
44184610Salfred *  $NetBSD: uaudio.c,v 1.96 2005/01/16 12:46:00 kent Exp $
45184610Salfred *  $NetBSD: uaudio.c,v 1.97 2005/02/24 08:19:38 martin Exp $
46184610Salfred */
47184610Salfred
48194677Sthompsa#include <sys/stdint.h>
49194677Sthompsa#include <sys/stddef.h>
50194677Sthompsa#include <sys/param.h>
51194677Sthompsa#include <sys/queue.h>
52194677Sthompsa#include <sys/types.h>
53194677Sthompsa#include <sys/systm.h>
54194677Sthompsa#include <sys/kernel.h>
55194677Sthompsa#include <sys/bus.h>
56194677Sthompsa#include <sys/linker_set.h>
57194677Sthompsa#include <sys/module.h>
58194677Sthompsa#include <sys/lock.h>
59194677Sthompsa#include <sys/mutex.h>
60194677Sthompsa#include <sys/condvar.h>
61194677Sthompsa#include <sys/sysctl.h>
62194677Sthompsa#include <sys/sx.h>
63194677Sthompsa#include <sys/unistd.h>
64194677Sthompsa#include <sys/callout.h>
65194677Sthompsa#include <sys/malloc.h>
66194677Sthompsa#include <sys/priv.h>
67194677Sthompsa
68188746Sthompsa#include "usbdevs.h"
69188942Sthompsa#include <dev/usb/usb.h>
70194677Sthompsa#include <dev/usb/usbdi.h>
71194677Sthompsa#include <dev/usb/usbdi_util.h>
72184610Salfred
73184610Salfred#define	USB_DEBUG_VAR uaudio_debug
74188942Sthompsa#include <dev/usb/usb_debug.h>
75184610Salfred
76188942Sthompsa#include <dev/usb/quirk/usb_quirk.h>
77184610Salfred
78184610Salfred#include <sys/reboot.h>			/* for bootverbose */
79184610Salfred
80193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS
81193640Sariff#include "opt_snd.h"
82193640Sariff#endif
83193640Sariff
84184610Salfred#include <dev/sound/pcm/sound.h>
85188957Sthompsa#include <dev/sound/usb/uaudioreg.h>
86188957Sthompsa#include <dev/sound/usb/uaudio.h>
87184610Salfred#include <dev/sound/chip.h>
88184610Salfred#include "feeder_if.h"
89184610Salfred
90200825Sthompsastatic int uaudio_default_rate = 0;		/* use rate list */
91186730Salfredstatic int uaudio_default_bits = 32;
92200825Sthompsastatic int uaudio_default_channels = 0;		/* use default */
93186730Salfred
94207077Sthompsa#ifdef USB_DEBUG
95184610Salfredstatic int uaudio_debug = 0;
96184610Salfred
97192505SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, uaudio, CTLFLAG_RW, 0, "USB uaudio");
98200825Sthompsa
99192505SthompsaSYSCTL_INT(_hw_usb_uaudio, OID_AUTO, debug, CTLFLAG_RW,
100184610Salfred    &uaudio_debug, 0, "uaudio debug level");
101200825Sthompsa
102200825SthompsaTUNABLE_INT("hw.usb.uaudio.default_rate", &uaudio_default_rate);
103192505SthompsaSYSCTL_INT(_hw_usb_uaudio, OID_AUTO, default_rate, CTLFLAG_RW,
104186730Salfred    &uaudio_default_rate, 0, "uaudio default sample rate");
105200825Sthompsa
106200825SthompsaTUNABLE_INT("hw.usb.uaudio.default_bits", &uaudio_default_bits);
107192505SthompsaSYSCTL_INT(_hw_usb_uaudio, OID_AUTO, default_bits, CTLFLAG_RW,
108186730Salfred    &uaudio_default_bits, 0, "uaudio default sample bits");
109200825Sthompsa
110200825SthompsaTUNABLE_INT("hw.usb.uaudio.default_channels", &uaudio_default_channels);
111192505SthompsaSYSCTL_INT(_hw_usb_uaudio, OID_AUTO, default_channels, CTLFLAG_RW,
112186730Salfred    &uaudio_default_channels, 0, "uaudio default sample channels");
113184610Salfred#endif
114184610Salfred
115199060Sthompsa#define	UAUDIO_NFRAMES		64	/* must be factor of 8 due HS-USB */
116184610Salfred#define	UAUDIO_NCHANBUFS        2	/* number of outstanding request */
117184610Salfred#define	UAUDIO_RECURSE_LIMIT   24	/* rounds */
118184610Salfred
119184610Salfred#define	MAKE_WORD(h,l) (((h) << 8) | (l))
120184610Salfred#define	BIT_TEST(bm,bno) (((bm)[(bno) / 8] >> (7 - ((bno) % 8))) & 1)
121193465Sthompsa#define	UAUDIO_MAX_CHAN(x) (x)
122184610Salfred
123184610Salfredstruct uaudio_mixer_node {
124184610Salfred	int32_t	minval;
125184610Salfred	int32_t	maxval;
126184610Salfred#define	MIX_MAX_CHAN 8
127184610Salfred	int32_t	wValue[MIX_MAX_CHAN];	/* using nchan */
128184610Salfred	uint32_t mul;
129184610Salfred	uint32_t ctl;
130184610Salfred
131184610Salfred	uint16_t wData[MIX_MAX_CHAN];	/* using nchan */
132184610Salfred	uint16_t wIndex;
133184610Salfred
134184610Salfred	uint8_t	update[(MIX_MAX_CHAN + 7) / 8];
135184610Salfred	uint8_t	nchan;
136184610Salfred	uint8_t	type;
137184610Salfred#define	MIX_ON_OFF	1
138184610Salfred#define	MIX_SIGNED_16	2
139184610Salfred#define	MIX_UNSIGNED_16	3
140184610Salfred#define	MIX_SIGNED_8	4
141184610Salfred#define	MIX_SELECTOR	5
142184610Salfred#define	MIX_UNKNOWN     6
143184610Salfred#define	MIX_SIZE(n) ((((n) == MIX_SIGNED_16) || \
144184610Salfred		      ((n) == MIX_UNSIGNED_16)) ? 2 : 1)
145184610Salfred#define	MIX_UNSIGNED(n) ((n) == MIX_UNSIGNED_16)
146184610Salfred
147184610Salfred#define	MAX_SELECTOR_INPUT_PIN 256
148184610Salfred	uint8_t	slctrtype[MAX_SELECTOR_INPUT_PIN];
149184610Salfred	uint8_t	class;
150184610Salfred
151184610Salfred	struct uaudio_mixer_node *next;
152184610Salfred};
153184610Salfred
154184610Salfredstruct uaudio_chan {
155184610Salfred	struct pcmchan_caps pcm_cap;	/* capabilities */
156184610Salfred
157184610Salfred	struct snd_dbuf *pcm_buf;
158203678Sbrucec	const struct usb_config *usb_cfg;
159184610Salfred	struct mtx *pcm_mtx;		/* lock protecting this structure */
160184610Salfred	struct uaudio_softc *priv_sc;
161184610Salfred	struct pcm_channel *pcm_ch;
162192984Sthompsa	struct usb_xfer *xfer[UAUDIO_NCHANBUFS];
163203678Sbrucec	const struct usb_audio_streaming_interface_descriptor *p_asid;
164203678Sbrucec	const struct usb_audio_streaming_type1_descriptor *p_asf1d;
165203678Sbrucec	const struct usb_audio_streaming_endpoint_descriptor *p_sed;
166203678Sbrucec	const usb_endpoint_descriptor_audio_t *p_ed1;
167203678Sbrucec	const usb_endpoint_descriptor_audio_t *p_ed2;
168184610Salfred	const struct uaudio_format *p_fmt;
169184610Salfred
170184610Salfred	uint8_t *buf;			/* pointer to buffer */
171184610Salfred	uint8_t *start;			/* upper layer buffer start */
172184610Salfred	uint8_t *end;			/* upper layer buffer end */
173184610Salfred	uint8_t *cur;			/* current position in upper layer
174184610Salfred					 * buffer */
175184610Salfred
176186730Salfred	uint32_t intr_size;		/* in bytes */
177199060Sthompsa	uint32_t intr_frames;		/* in units */
178184610Salfred	uint32_t sample_rate;
179200825Sthompsa	uint32_t frames_per_second;
180200825Sthompsa	uint32_t sample_rem;
181200825Sthompsa	uint32_t sample_curr;
182200825Sthompsa
183184610Salfred	uint32_t format;
184184610Salfred	uint32_t pcm_format[2];
185184610Salfred
186200825Sthompsa	uint16_t bytes_per_frame[2];
187184610Salfred
188200825Sthompsa	uint16_t sample_size;
189200825Sthompsa
190184610Salfred	uint8_t	valid;
191184610Salfred	uint8_t	iface_index;
192184610Salfred	uint8_t	iface_alt_index;
193184610Salfred};
194184610Salfred
195184610Salfred#define	UMIDI_N_TRANSFER    4		/* units */
196184610Salfred#define	UMIDI_CABLES_MAX   16		/* units */
197184610Salfred#define	UMIDI_BULK_SIZE  1024		/* bytes */
198184610Salfred
199184610Salfredstruct umidi_sub_chan {
200192984Sthompsa	struct usb_fifo_sc fifo;
201184610Salfred	uint8_t *temp_cmd;
202184610Salfred	uint8_t	temp_0[4];
203184610Salfred	uint8_t	temp_1[4];
204184610Salfred	uint8_t	state;
205184610Salfred#define	UMIDI_ST_UNKNOWN   0		/* scan for command */
206184610Salfred#define	UMIDI_ST_1PARAM    1
207184610Salfred#define	UMIDI_ST_2PARAM_1  2
208184610Salfred#define	UMIDI_ST_2PARAM_2  3
209184610Salfred#define	UMIDI_ST_SYSEX_0   4
210184610Salfred#define	UMIDI_ST_SYSEX_1   5
211184610Salfred#define	UMIDI_ST_SYSEX_2   6
212184610Salfred
213184610Salfred	uint8_t	read_open:1;
214184610Salfred	uint8_t	write_open:1;
215184610Salfred	uint8_t	unused:6;
216184610Salfred};
217184610Salfred
218184610Salfredstruct umidi_chan {
219184610Salfred
220184610Salfred	struct umidi_sub_chan sub[UMIDI_CABLES_MAX];
221184610Salfred	struct mtx mtx;
222184610Salfred
223192984Sthompsa	struct usb_xfer *xfer[UMIDI_N_TRANSFER];
224184610Salfred
225184610Salfred	uint8_t	iface_index;
226184610Salfred	uint8_t	iface_alt_index;
227184610Salfred
228184610Salfred	uint8_t	flags;
229184610Salfred#define	UMIDI_FLAG_READ_STALL  0x01
230184610Salfred#define	UMIDI_FLAG_WRITE_STALL 0x02
231184610Salfred
232184610Salfred	uint8_t	read_open_refcount;
233184610Salfred	uint8_t	write_open_refcount;
234184610Salfred
235184610Salfred	uint8_t	curr_cable;
236184610Salfred	uint8_t	max_cable;
237184610Salfred	uint8_t	valid;
238184610Salfred};
239184610Salfred
240184610Salfredstruct uaudio_softc {
241184610Salfred	struct sbuf sc_sndstat;
242184610Salfred	struct sndcard_func sc_sndcard_func;
243184610Salfred	struct uaudio_chan sc_rec_chan;
244184610Salfred	struct uaudio_chan sc_play_chan;
245184610Salfred	struct umidi_chan sc_midi_chan;
246184610Salfred
247192984Sthompsa	struct usb_device *sc_udev;
248192984Sthompsa	struct usb_xfer *sc_mixer_xfer[1];
249184610Salfred	struct uaudio_mixer_node *sc_mixer_root;
250184610Salfred	struct uaudio_mixer_node *sc_mixer_curr;
251184610Salfred
252184610Salfred	uint32_t sc_mix_info;
253184610Salfred	uint32_t sc_recsrc_info;
254184610Salfred
255184610Salfred	uint16_t sc_audio_rev;
256184610Salfred	uint16_t sc_mixer_count;
257184610Salfred
258184610Salfred	uint8_t	sc_sndstat_valid;
259184610Salfred	uint8_t	sc_mixer_iface_index;
260184610Salfred	uint8_t	sc_mixer_iface_no;
261184610Salfred	uint8_t	sc_mixer_chan;
262184610Salfred	uint8_t	sc_pcm_registered:1;
263184610Salfred	uint8_t	sc_mixer_init:1;
264184610Salfred	uint8_t	sc_uq_audio_swap_lr:1;
265184610Salfred	uint8_t	sc_uq_au_inp_async:1;
266184610Salfred	uint8_t	sc_uq_au_no_xu:1;
267184610Salfred	uint8_t	sc_uq_bad_adc:1;
268184610Salfred};
269184610Salfred
270184610Salfredstruct uaudio_search_result {
271184610Salfred	uint8_t	bit_input[(256 + 7) / 8];
272184610Salfred	uint8_t	bit_output[(256 + 7) / 8];
273184610Salfred	uint8_t	bit_visited[(256 + 7) / 8];
274184610Salfred	uint8_t	recurse_level;
275184610Salfred	uint8_t	id_max;
276184610Salfred};
277184610Salfred
278184610Salfredstruct uaudio_terminal_node {
279184610Salfred	union {
280192984Sthompsa		const struct usb_descriptor *desc;
281203678Sbrucec		const struct usb_audio_input_terminal *it;
282203678Sbrucec		const struct usb_audio_output_terminal *ot;
283203678Sbrucec		const struct usb_audio_mixer_unit_0 *mu;
284203678Sbrucec		const struct usb_audio_selector_unit *su;
285203678Sbrucec		const struct usb_audio_feature_unit *fu;
286203678Sbrucec		const struct usb_audio_processing_unit_0 *pu;
287203678Sbrucec		const struct usb_audio_extension_unit_0 *eu;
288184610Salfred	}	u;
289184610Salfred	struct uaudio_search_result usr;
290184610Salfred	struct uaudio_terminal_node *root;
291184610Salfred};
292184610Salfred
293184610Salfredstruct uaudio_format {
294184610Salfred	uint16_t wFormat;
295184610Salfred	uint8_t	bPrecision;
296184610Salfred	uint32_t freebsd_fmt;
297184610Salfred	const char *description;
298184610Salfred};
299184610Salfred
300184610Salfredstatic const struct uaudio_format uaudio_formats[] = {
301184610Salfred
302184610Salfred	{UA_FMT_PCM8, 8, AFMT_U8, "8-bit U-LE PCM"},
303184610Salfred	{UA_FMT_PCM8, 16, AFMT_U16_LE, "16-bit U-LE PCM"},
304184610Salfred	{UA_FMT_PCM8, 24, AFMT_U24_LE, "24-bit U-LE PCM"},
305184610Salfred	{UA_FMT_PCM8, 32, AFMT_U32_LE, "32-bit U-LE PCM"},
306184610Salfred
307184610Salfred	{UA_FMT_PCM, 8, AFMT_S8, "8-bit S-LE PCM"},
308184610Salfred	{UA_FMT_PCM, 16, AFMT_S16_LE, "16-bit S-LE PCM"},
309184610Salfred	{UA_FMT_PCM, 24, AFMT_S24_LE, "24-bit S-LE PCM"},
310184610Salfred	{UA_FMT_PCM, 32, AFMT_S32_LE, "32-bit S-LE PCM"},
311184610Salfred
312184610Salfred	{UA_FMT_ALAW, 8, AFMT_A_LAW, "8-bit A-Law"},
313184610Salfred	{UA_FMT_MULAW, 8, AFMT_MU_LAW, "8-bit mu-Law"},
314184610Salfred
315184610Salfred	{0, 0, 0, NULL}
316184610Salfred};
317184610Salfred
318184610Salfred#define	UAC_OUTPUT	0
319184610Salfred#define	UAC_INPUT	1
320184610Salfred#define	UAC_EQUAL	2
321184610Salfred#define	UAC_RECORD	3
322184610Salfred#define	UAC_NCLASSES	4
323184610Salfred
324207077Sthompsa#ifdef USB_DEBUG
325184610Salfredstatic const char *uac_names[] = {
326184610Salfred	"outputs", "inputs", "equalization", "record"
327184610Salfred};
328184610Salfred
329184610Salfred#endif
330184610Salfred
331184610Salfred/* prototypes */
332184610Salfred
333184610Salfredstatic device_probe_t uaudio_probe;
334184610Salfredstatic device_attach_t uaudio_attach;
335184610Salfredstatic device_detach_t uaudio_detach;
336184610Salfred
337193045Sthompsastatic usb_callback_t uaudio_chan_play_callback;
338193045Sthompsastatic usb_callback_t uaudio_chan_record_callback;
339193045Sthompsastatic usb_callback_t uaudio_mixer_write_cfg_callback;
340193045Sthompsastatic usb_callback_t umidi_read_clear_stall_callback;
341193045Sthompsastatic usb_callback_t umidi_bulk_read_callback;
342193045Sthompsastatic usb_callback_t umidi_write_clear_stall_callback;
343193045Sthompsastatic usb_callback_t umidi_bulk_write_callback;
344184610Salfred
345185948Sthompsastatic void	uaudio_chan_fill_info_sub(struct uaudio_softc *,
346200825Sthompsa		    struct usb_device *, uint32_t, uint8_t, uint8_t);
347185948Sthompsastatic void	uaudio_chan_fill_info(struct uaudio_softc *,
348192984Sthompsa		    struct usb_device *);
349185948Sthompsastatic void	uaudio_mixer_add_ctl_sub(struct uaudio_softc *,
350185948Sthompsa		    struct uaudio_mixer_node *);
351185948Sthompsastatic void	uaudio_mixer_add_ctl(struct uaudio_softc *,
352185948Sthompsa		    struct uaudio_mixer_node *);
353185948Sthompsastatic void	uaudio_mixer_add_input(struct uaudio_softc *,
354185948Sthompsa		    const struct uaudio_terminal_node *, int);
355185948Sthompsastatic void	uaudio_mixer_add_output(struct uaudio_softc *,
356185948Sthompsa		    const struct uaudio_terminal_node *, int);
357185948Sthompsastatic void	uaudio_mixer_add_mixer(struct uaudio_softc *,
358185948Sthompsa		    const struct uaudio_terminal_node *, int);
359185948Sthompsastatic void	uaudio_mixer_add_selector(struct uaudio_softc *,
360185948Sthompsa		    const struct uaudio_terminal_node *, int);
361185948Sthompsastatic uint32_t	uaudio_mixer_feature_get_bmaControls(
362203678Sbrucec		    const struct usb_audio_feature_unit *, uint8_t);
363185948Sthompsastatic void	uaudio_mixer_add_feature(struct uaudio_softc *,
364185948Sthompsa		    const struct uaudio_terminal_node *, int);
365185948Sthompsastatic void	uaudio_mixer_add_processing_updown(struct uaudio_softc *,
366185948Sthompsa		    const struct uaudio_terminal_node *, int);
367185948Sthompsastatic void	uaudio_mixer_add_processing(struct uaudio_softc *,
368185948Sthompsa		    const struct uaudio_terminal_node *, int);
369185948Sthompsastatic void	uaudio_mixer_add_extension(struct uaudio_softc *,
370185948Sthompsa		    const struct uaudio_terminal_node *, int);
371203678Sbrucecstatic struct	usb_audio_cluster uaudio_mixer_get_cluster(uint8_t,
372185948Sthompsa		    const struct uaudio_terminal_node *);
373185948Sthompsastatic uint16_t	uaudio_mixer_determine_class(const struct uaudio_terminal_node *,
374185948Sthompsa		    struct uaudio_mixer_node *);
375185948Sthompsastatic uint16_t	uaudio_mixer_feature_name(const struct uaudio_terminal_node *,
376185948Sthompsa		    struct uaudio_mixer_node *);
377185948Sthompsastatic const struct uaudio_terminal_node *uaudio_mixer_get_input(
378185948Sthompsa		    const struct uaudio_terminal_node *, uint8_t);
379185948Sthompsastatic const struct uaudio_terminal_node *uaudio_mixer_get_output(
380185948Sthompsa		    const struct uaudio_terminal_node *, uint8_t);
381185948Sthompsastatic void	uaudio_mixer_find_inputs_sub(struct uaudio_terminal_node *,
382185948Sthompsa		    const uint8_t *, uint8_t, struct uaudio_search_result *);
383185948Sthompsastatic void	uaudio_mixer_find_outputs_sub(struct uaudio_terminal_node *,
384185948Sthompsa		    uint8_t, uint8_t, struct uaudio_search_result *);
385185948Sthompsastatic void	uaudio_mixer_fill_info(struct uaudio_softc *,
386192984Sthompsa		    struct usb_device *, void *);
387192984Sthompsastatic uint16_t	uaudio_mixer_get(struct usb_device *, uint8_t,
388185948Sthompsa		    struct uaudio_mixer_node *);
389185948Sthompsastatic void	uaudio_mixer_ctl_set(struct uaudio_softc *,
390185948Sthompsa		    struct uaudio_mixer_node *, uint8_t, int32_t val);
391193045Sthompsastatic usb_error_t uaudio_set_speed(struct usb_device *, uint8_t, uint32_t);
392185948Sthompsastatic int	uaudio_mixer_signext(uint8_t, int);
393185948Sthompsastatic int	uaudio_mixer_bsd2value(struct uaudio_mixer_node *, int32_t val);
394185948Sthompsastatic const void *uaudio_mixer_verify_desc(const void *, uint32_t);
395185948Sthompsastatic void	uaudio_mixer_init(struct uaudio_softc *);
396185948Sthompsastatic uint8_t	umidi_convert_to_usb(struct umidi_sub_chan *, uint8_t, uint8_t);
397192984Sthompsastatic struct	umidi_sub_chan *umidi_sub_by_fifo(struct usb_fifo *);
398192984Sthompsastatic void	umidi_start_read(struct usb_fifo *);
399192984Sthompsastatic void	umidi_stop_read(struct usb_fifo *);
400192984Sthompsastatic void	umidi_start_write(struct usb_fifo *);
401192984Sthompsastatic void	umidi_stop_write(struct usb_fifo *);
402192984Sthompsastatic int	umidi_open(struct usb_fifo *, int);
403192984Sthompsastatic int	umidi_ioctl(struct usb_fifo *, u_long cmd, void *, int);
404192984Sthompsastatic void	umidi_close(struct usb_fifo *, int);
405185948Sthompsastatic void	umidi_init(device_t dev);
406185948Sthompsastatic int32_t	umidi_probe(device_t dev);
407185948Sthompsastatic int32_t	umidi_detach(device_t dev);
408184610Salfred
409207077Sthompsa#ifdef USB_DEBUG
410185948Sthompsastatic void	uaudio_chan_dump_ep_desc(
411203678Sbrucec		    const usb_endpoint_descriptor_audio_t *);
412185948Sthompsastatic void	uaudio_mixer_dump_cluster(uint8_t,
413185948Sthompsa		    const struct uaudio_terminal_node *);
414185948Sthompsastatic const char *uaudio_mixer_get_terminal_name(uint16_t);
415184610Salfred#endif
416184610Salfred
417192984Sthompsastatic const struct usb_config
418186730Salfred	uaudio_cfg_record[UAUDIO_NCHANBUFS] = {
419184610Salfred	[0] = {
420184610Salfred		.type = UE_ISOCHRONOUS,
421184610Salfred		.endpoint = UE_ADDR_ANY,
422184610Salfred		.direction = UE_DIR_IN,
423190734Sthompsa		.bufsize = 0,	/* use "wMaxPacketSize * frames" */
424199060Sthompsa		.frames = UAUDIO_NFRAMES,
425190734Sthompsa		.flags = {.short_xfer_ok = 1,},
426190734Sthompsa		.callback = &uaudio_chan_record_callback,
427184610Salfred	},
428184610Salfred
429184610Salfred	[1] = {
430184610Salfred		.type = UE_ISOCHRONOUS,
431184610Salfred		.endpoint = UE_ADDR_ANY,
432184610Salfred		.direction = UE_DIR_IN,
433190734Sthompsa		.bufsize = 0,	/* use "wMaxPacketSize * frames" */
434199060Sthompsa		.frames = UAUDIO_NFRAMES,
435190734Sthompsa		.flags = {.short_xfer_ok = 1,},
436190734Sthompsa		.callback = &uaudio_chan_record_callback,
437184610Salfred	},
438184610Salfred};
439184610Salfred
440192984Sthompsastatic const struct usb_config
441186730Salfred	uaudio_cfg_play[UAUDIO_NCHANBUFS] = {
442184610Salfred	[0] = {
443184610Salfred		.type = UE_ISOCHRONOUS,
444184610Salfred		.endpoint = UE_ADDR_ANY,
445184610Salfred		.direction = UE_DIR_OUT,
446190734Sthompsa		.bufsize = 0,	/* use "wMaxPacketSize * frames" */
447199060Sthompsa		.frames = UAUDIO_NFRAMES,
448190734Sthompsa		.flags = {.short_xfer_ok = 1,},
449190734Sthompsa		.callback = &uaudio_chan_play_callback,
450184610Salfred	},
451184610Salfred
452184610Salfred	[1] = {
453184610Salfred		.type = UE_ISOCHRONOUS,
454184610Salfred		.endpoint = UE_ADDR_ANY,
455184610Salfred		.direction = UE_DIR_OUT,
456190734Sthompsa		.bufsize = 0,	/* use "wMaxPacketSize * frames" */
457199060Sthompsa		.frames = UAUDIO_NFRAMES,
458190734Sthompsa		.flags = {.short_xfer_ok = 1,},
459190734Sthompsa		.callback = &uaudio_chan_play_callback,
460184610Salfred	},
461184610Salfred};
462184610Salfred
463192984Sthompsastatic const struct usb_config
464184610Salfred	uaudio_mixer_config[1] = {
465184610Salfred	[0] = {
466184610Salfred		.type = UE_CONTROL,
467184610Salfred		.endpoint = 0x00,	/* Control pipe */
468184610Salfred		.direction = UE_DIR_ANY,
469192984Sthompsa		.bufsize = (sizeof(struct usb_device_request) + 4),
470190734Sthompsa		.callback = &uaudio_mixer_write_cfg_callback,
471190734Sthompsa		.timeout = 1000,	/* 1 second */
472184610Salfred	},
473184610Salfred};
474184610Salfred
475184610Salfredstatic const
476184610Salfreduint8_t	umidi_cmd_to_len[16] = {
477184610Salfred	[0x0] = 0,			/* reserved */
478184610Salfred	[0x1] = 0,			/* reserved */
479184610Salfred	[0x2] = 2,			/* bytes */
480184610Salfred	[0x3] = 3,			/* bytes */
481184610Salfred	[0x4] = 3,			/* bytes */
482184610Salfred	[0x5] = 1,			/* bytes */
483184610Salfred	[0x6] = 2,			/* bytes */
484184610Salfred	[0x7] = 3,			/* bytes */
485184610Salfred	[0x8] = 3,			/* bytes */
486184610Salfred	[0x9] = 3,			/* bytes */
487184610Salfred	[0xA] = 3,			/* bytes */
488184610Salfred	[0xB] = 3,			/* bytes */
489184610Salfred	[0xC] = 2,			/* bytes */
490184610Salfred	[0xD] = 2,			/* bytes */
491184610Salfred	[0xE] = 3,			/* bytes */
492184610Salfred	[0xF] = 1,			/* bytes */
493184610Salfred};
494184610Salfred
495192984Sthompsastatic const struct usb_config
496184610Salfred	umidi_config[UMIDI_N_TRANSFER] = {
497184610Salfred	[0] = {
498184610Salfred		.type = UE_BULK,
499184610Salfred		.endpoint = UE_ADDR_ANY,
500184610Salfred		.direction = UE_DIR_OUT,
501190734Sthompsa		.bufsize = UMIDI_BULK_SIZE,
502190734Sthompsa		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
503190734Sthompsa		.callback = &umidi_bulk_write_callback,
504184610Salfred	},
505184610Salfred
506184610Salfred	[1] = {
507184610Salfred		.type = UE_BULK,
508184610Salfred		.endpoint = UE_ADDR_ANY,
509184610Salfred		.direction = UE_DIR_IN,
510209450Sthompsa		.bufsize = 4,	/* bytes */
511209450Sthompsa		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,.proxy_buffer = 1,},
512190734Sthompsa		.callback = &umidi_bulk_read_callback,
513184610Salfred	},
514184610Salfred
515184610Salfred	[2] = {
516184610Salfred		.type = UE_CONTROL,
517184610Salfred		.endpoint = 0x00,	/* Control pipe */
518184610Salfred		.direction = UE_DIR_ANY,
519192984Sthompsa		.bufsize = sizeof(struct usb_device_request),
520190734Sthompsa		.callback = &umidi_write_clear_stall_callback,
521190734Sthompsa		.timeout = 1000,	/* 1 second */
522190734Sthompsa		.interval = 50,	/* 50ms */
523184610Salfred	},
524184610Salfred
525184610Salfred	[3] = {
526184610Salfred		.type = UE_CONTROL,
527184610Salfred		.endpoint = 0x00,	/* Control pipe */
528184610Salfred		.direction = UE_DIR_ANY,
529192984Sthompsa		.bufsize = sizeof(struct usb_device_request),
530190734Sthompsa		.callback = &umidi_read_clear_stall_callback,
531190734Sthompsa		.timeout = 1000,	/* 1 second */
532190734Sthompsa		.interval = 50,	/* 50ms */
533184610Salfred	},
534184610Salfred};
535184610Salfred
536184610Salfredstatic devclass_t uaudio_devclass;
537184610Salfred
538184610Salfredstatic device_method_t uaudio_methods[] = {
539184610Salfred	DEVMETHOD(device_probe, uaudio_probe),
540184610Salfred	DEVMETHOD(device_attach, uaudio_attach),
541184610Salfred	DEVMETHOD(device_detach, uaudio_detach),
542184610Salfred	DEVMETHOD(device_suspend, bus_generic_suspend),
543184610Salfred	DEVMETHOD(device_resume, bus_generic_resume),
544184610Salfred	DEVMETHOD(device_shutdown, bus_generic_shutdown),
545184610Salfred	DEVMETHOD(bus_print_child, bus_generic_print_child),
546184610Salfred	{0, 0}
547184610Salfred};
548184610Salfred
549184610Salfredstatic driver_t uaudio_driver = {
550184610Salfred	.name = "uaudio",
551184610Salfred	.methods = uaudio_methods,
552184610Salfred	.size = sizeof(struct uaudio_softc),
553184610Salfred};
554184610Salfred
555184610Salfredstatic int
556184610Salfreduaudio_probe(device_t dev)
557184610Salfred{
558192984Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(dev);
559184610Salfred
560192505Sthompsa	if (uaa->usb_mode != USB_MODE_HOST)
561184610Salfred		return (ENXIO);
562188416Sthompsa
563188416Sthompsa	if (uaa->use_generic == 0)
564188416Sthompsa		return (ENXIO);
565188416Sthompsa
566184610Salfred	/* trigger on the control interface */
567184610Salfred
568184610Salfred	if ((uaa->info.bInterfaceClass == UICLASS_AUDIO) &&
569184610Salfred	    (uaa->info.bInterfaceSubClass == UISUBCLASS_AUDIOCONTROL)) {
570194228Sthompsa		if (usb_test_quirk(uaa, UQ_BAD_AUDIO))
571184610Salfred			return (ENXIO);
572184610Salfred		else
573184610Salfred			return (0);
574184610Salfred	}
575199677Sthompsa
576199677Sthompsa	/* check for MIDI stream */
577199677Sthompsa
578199677Sthompsa	if ((uaa->info.bInterfaceClass == UICLASS_AUDIO) &&
579199677Sthompsa	    (uaa->info.bInterfaceSubClass == UISUBCLASS_MIDISTREAM)) {
580199677Sthompsa		return (0);
581199677Sthompsa	}
582184610Salfred	return (ENXIO);
583184610Salfred}
584184610Salfred
585184610Salfredstatic int
586184610Salfreduaudio_attach(device_t dev)
587184610Salfred{
588192984Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(dev);
589184610Salfred	struct uaudio_softc *sc = device_get_softc(dev);
590192984Sthompsa	struct usb_interface_descriptor *id;
591184610Salfred	device_t child;
592184610Salfred
593184610Salfred	sc->sc_play_chan.priv_sc = sc;
594184610Salfred	sc->sc_rec_chan.priv_sc = sc;
595184610Salfred	sc->sc_udev = uaa->device;
596199060Sthompsa	sc->sc_mixer_iface_index = uaa->info.bIfaceIndex;
597199060Sthompsa	sc->sc_mixer_iface_no = uaa->info.bIfaceNum;
598184610Salfred
599194228Sthompsa	if (usb_test_quirk(uaa, UQ_AUDIO_SWAP_LR))
600184610Salfred		sc->sc_uq_audio_swap_lr = 1;
601184610Salfred
602194228Sthompsa	if (usb_test_quirk(uaa, UQ_AU_INP_ASYNC))
603184610Salfred		sc->sc_uq_au_inp_async = 1;
604184610Salfred
605194228Sthompsa	if (usb_test_quirk(uaa, UQ_AU_NO_XU))
606184610Salfred		sc->sc_uq_au_no_xu = 1;
607184610Salfred
608194228Sthompsa	if (usb_test_quirk(uaa, UQ_BAD_ADC))
609184610Salfred		sc->sc_uq_bad_adc = 1;
610184610Salfred
611184610Salfred	umidi_init(dev);
612184610Salfred
613194228Sthompsa	device_set_usb_desc(dev);
614184610Salfred
615194228Sthompsa	id = usbd_get_interface_descriptor(uaa->iface);
616184610Salfred
617184610Salfred	uaudio_chan_fill_info(sc, uaa->device);
618184610Salfred
619184610Salfred	uaudio_mixer_fill_info(sc, uaa->device, id);
620184610Salfred
621184610Salfred	DPRINTF("audio rev %d.%02x\n",
622184610Salfred	    sc->sc_audio_rev >> 8,
623184610Salfred	    sc->sc_audio_rev & 0xff);
624184610Salfred
625184610Salfred	DPRINTF("%d mixer controls\n",
626184610Salfred	    sc->sc_mixer_count);
627184610Salfred
628184610Salfred	if (sc->sc_play_chan.valid) {
629184610Salfred		device_printf(dev, "Play: %d Hz, %d ch, %s format\n",
630184610Salfred		    sc->sc_play_chan.sample_rate,
631184610Salfred		    sc->sc_play_chan.p_asf1d->bNrChannels,
632184610Salfred		    sc->sc_play_chan.p_fmt->description);
633184610Salfred	} else {
634184610Salfred		device_printf(dev, "No playback!\n");
635184610Salfred	}
636184610Salfred
637184610Salfred	if (sc->sc_rec_chan.valid) {
638184610Salfred		device_printf(dev, "Record: %d Hz, %d ch, %s format\n",
639184610Salfred		    sc->sc_rec_chan.sample_rate,
640184610Salfred		    sc->sc_rec_chan.p_asf1d->bNrChannels,
641184610Salfred		    sc->sc_rec_chan.p_fmt->description);
642184610Salfred	} else {
643184610Salfred		device_printf(dev, "No recording!\n");
644184610Salfred	}
645184610Salfred
646184610Salfred	if (sc->sc_midi_chan.valid) {
647184610Salfred
648184610Salfred		if (umidi_probe(dev)) {
649184610Salfred			goto detach;
650184610Salfred		}
651184610Salfred		device_printf(dev, "MIDI sequencer\n");
652184610Salfred	} else {
653184610Salfred		device_printf(dev, "No midi sequencer\n");
654184610Salfred	}
655184610Salfred
656184610Salfred	DPRINTF("doing child attach\n");
657184610Salfred
658184610Salfred	/* attach the children */
659184610Salfred
660184610Salfred	sc->sc_sndcard_func.func = SCF_PCM;
661184610Salfred
662184610Salfred	child = device_add_child(dev, "pcm", -1);
663184610Salfred
664184610Salfred	if (child == NULL) {
665184610Salfred		DPRINTF("out of memory\n");
666184610Salfred		goto detach;
667184610Salfred	}
668184610Salfred	device_set_ivars(child, &sc->sc_sndcard_func);
669184610Salfred
670184610Salfred	if (bus_generic_attach(dev)) {
671184610Salfred		DPRINTF("child attach failed\n");
672184610Salfred		goto detach;
673184610Salfred	}
674184610Salfred	return (0);			/* success */
675184610Salfred
676184610Salfreddetach:
677184610Salfred	uaudio_detach(dev);
678184610Salfred	return (ENXIO);
679184610Salfred}
680184610Salfred
681184610Salfredstatic void
682184610Salfreduaudio_pcm_setflags(device_t dev, uint32_t flags)
683184610Salfred{
684184610Salfred	pcm_setflags(dev, pcm_getflags(dev) | flags);
685184610Salfred}
686184610Salfred
687184610Salfredint
688184610Salfreduaudio_attach_sub(device_t dev, kobj_class_t mixer_class, kobj_class_t chan_class)
689184610Salfred{
690184610Salfred	struct uaudio_softc *sc = device_get_softc(device_get_parent(dev));
691184610Salfred	char status[SND_STATUSLEN];
692184610Salfred
693184610Salfred	uaudio_mixer_init(sc);
694184610Salfred
695184610Salfred	if (sc->sc_uq_audio_swap_lr) {
696184610Salfred		DPRINTF("hardware has swapped left and right\n");
697193640Sariff		/* uaudio_pcm_setflags(dev, SD_F_PSWAPLR); */
698184610Salfred	}
699184610Salfred	if (!(sc->sc_mix_info & SOUND_MASK_PCM)) {
700184610Salfred
701184610Salfred		DPRINTF("emulating master volume\n");
702184610Salfred
703184610Salfred		/*
704184610Salfred		 * Emulate missing pcm mixer controller
705184610Salfred		 * through FEEDER_VOLUME
706184610Salfred		 */
707184610Salfred		uaudio_pcm_setflags(dev, SD_F_SOFTPCMVOL);
708184610Salfred	}
709184610Salfred	if (mixer_init(dev, mixer_class, sc)) {
710184610Salfred		goto detach;
711184610Salfred	}
712184610Salfred	sc->sc_mixer_init = 1;
713184610Salfred
714184610Salfred	snprintf(status, sizeof(status), "at ? %s", PCM_KLDSTRING(snd_uaudio));
715184610Salfred
716184610Salfred	if (pcm_register(dev, sc,
717184610Salfred	    sc->sc_play_chan.valid ? 1 : 0,
718184610Salfred	    sc->sc_rec_chan.valid ? 1 : 0)) {
719184610Salfred		goto detach;
720184610Salfred	}
721193640Sariff
722193640Sariff	uaudio_pcm_setflags(dev, SD_F_MPSAFE);
723184610Salfred	sc->sc_pcm_registered = 1;
724184610Salfred
725184610Salfred	if (sc->sc_play_chan.valid) {
726184610Salfred		pcm_addchan(dev, PCMDIR_PLAY, chan_class, sc);
727184610Salfred	}
728184610Salfred	if (sc->sc_rec_chan.valid) {
729184610Salfred		pcm_addchan(dev, PCMDIR_REC, chan_class, sc);
730184610Salfred	}
731184610Salfred	pcm_setstatus(dev, status);
732184610Salfred
733184610Salfred	return (0);			/* success */
734184610Salfred
735184610Salfreddetach:
736184610Salfred	uaudio_detach_sub(dev);
737184610Salfred	return (ENXIO);
738184610Salfred}
739184610Salfred
740184610Salfredint
741184610Salfreduaudio_detach_sub(device_t dev)
742184610Salfred{
743184610Salfred	struct uaudio_softc *sc = device_get_softc(device_get_parent(dev));
744184610Salfred	int error = 0;
745184610Salfred
746184610Salfredrepeat:
747184610Salfred	if (sc->sc_pcm_registered) {
748184610Salfred		error = pcm_unregister(dev);
749184610Salfred	} else {
750184610Salfred		if (sc->sc_mixer_init) {
751184610Salfred			error = mixer_uninit(dev);
752184610Salfred		}
753184610Salfred	}
754184610Salfred
755184610Salfred	if (error) {
756184610Salfred		device_printf(dev, "Waiting for sound application to exit!\n");
757194228Sthompsa		usb_pause_mtx(NULL, 2 * hz);
758184610Salfred		goto repeat;		/* try again */
759184610Salfred	}
760184610Salfred	return (0);			/* success */
761184610Salfred}
762184610Salfred
763184610Salfredstatic int
764184610Salfreduaudio_detach(device_t dev)
765184610Salfred{
766184610Salfred	struct uaudio_softc *sc = device_get_softc(dev);
767184610Salfred
768184610Salfred	if (bus_generic_detach(dev)) {
769184610Salfred		DPRINTF("detach failed!\n");
770184610Salfred	}
771184610Salfred	sbuf_delete(&sc->sc_sndstat);
772184610Salfred	sc->sc_sndstat_valid = 0;
773184610Salfred
774184610Salfred	umidi_detach(dev);
775184610Salfred
776184610Salfred	return (0);
777184610Salfred}
778184610Salfred
779184610Salfred/*========================================================================*
780184610Salfred * AS - Audio Stream - routines
781184610Salfred *========================================================================*/
782184610Salfred
783207077Sthompsa#ifdef USB_DEBUG
784184610Salfredstatic void
785203678Sbrucecuaudio_chan_dump_ep_desc(const usb_endpoint_descriptor_audio_t *ed)
786184610Salfred{
787184610Salfred	if (ed) {
788184610Salfred		DPRINTF("endpoint=%p bLength=%d bDescriptorType=%d \n"
789184610Salfred		    "bEndpointAddress=%d bmAttributes=0x%x \n"
790184610Salfred		    "wMaxPacketSize=%d bInterval=%d \n"
791184610Salfred		    "bRefresh=%d bSynchAddress=%d\n",
792184610Salfred		    ed, ed->bLength, ed->bDescriptorType,
793184610Salfred		    ed->bEndpointAddress, ed->bmAttributes,
794184610Salfred		    UGETW(ed->wMaxPacketSize), ed->bInterval,
795209452Sthompsa		    UEP_HAS_REFRESH(ed) ? ed->bRefresh : 0,
796209452Sthompsa		    UEP_HAS_SYNCADDR(ed) ? ed->bSynchAddress : 0);
797184610Salfred	}
798184610Salfred}
799184610Salfred
800184610Salfred#endif
801184610Salfred
802184610Salfredstatic void
803192984Sthompsauaudio_chan_fill_info_sub(struct uaudio_softc *sc, struct usb_device *udev,
804200825Sthompsa    uint32_t rate, uint8_t channels, uint8_t bit_resolution)
805184610Salfred{
806192984Sthompsa	struct usb_descriptor *desc = NULL;
807203678Sbrucec	const struct usb_audio_streaming_interface_descriptor *asid = NULL;
808203678Sbrucec	const struct usb_audio_streaming_type1_descriptor *asf1d = NULL;
809203678Sbrucec	const struct usb_audio_streaming_endpoint_descriptor *sed = NULL;
810203678Sbrucec	const usb_endpoint_descriptor_audio_t *ed1 = NULL;
811203678Sbrucec	const usb_endpoint_descriptor_audio_t *ed2 = NULL;
812194228Sthompsa	struct usb_config_descriptor *cd = usbd_get_config_descriptor(udev);
813192984Sthompsa	struct usb_interface_descriptor *id;
814184610Salfred	const struct uaudio_format *p_fmt;
815184610Salfred	struct uaudio_chan *chan;
816184610Salfred	uint16_t curidx = 0xFFFF;
817184610Salfred	uint16_t lastidx = 0xFFFF;
818184610Salfred	uint16_t alt_index = 0;
819184610Salfred	uint16_t wFormat;
820184610Salfred	uint8_t ep_dir;
821184610Salfred	uint8_t bChannels;
822184610Salfred	uint8_t bBitResolution;
823184610Salfred	uint8_t x;
824184610Salfred	uint8_t audio_if = 0;
825184610Salfred
826194228Sthompsa	while ((desc = usb_desc_foreach(cd, desc))) {
827184610Salfred
828184610Salfred		if ((desc->bDescriptorType == UDESC_INTERFACE) &&
829184610Salfred		    (desc->bLength >= sizeof(*id))) {
830184610Salfred
831184610Salfred			id = (void *)desc;
832184610Salfred
833184610Salfred			if (id->bInterfaceNumber != lastidx) {
834184610Salfred				lastidx = id->bInterfaceNumber;
835184610Salfred				curidx++;
836184610Salfred				alt_index = 0;
837184610Salfred
838184610Salfred			} else {
839184610Salfred				alt_index++;
840184610Salfred			}
841184610Salfred
842184610Salfred			if ((id->bInterfaceClass == UICLASS_AUDIO) &&
843184610Salfred			    (id->bInterfaceSubClass == UISUBCLASS_AUDIOSTREAM)) {
844184610Salfred				audio_if = 1;
845184610Salfred			} else {
846184610Salfred				audio_if = 0;
847184610Salfred			}
848184610Salfred
849184610Salfred			if ((id->bInterfaceClass == UICLASS_AUDIO) &&
850184610Salfred			    (id->bInterfaceSubClass == UISUBCLASS_MIDISTREAM)) {
851184610Salfred
852184610Salfred				/*
853184610Salfred				 * XXX could allow multiple MIDI interfaces
854184610Salfred				 * XXX
855184610Salfred				 */
856184610Salfred
857184610Salfred				if ((sc->sc_midi_chan.valid == 0) &&
858194228Sthompsa				    usbd_get_iface(udev, curidx)) {
859184610Salfred					sc->sc_midi_chan.iface_index = curidx;
860184610Salfred					sc->sc_midi_chan.iface_alt_index = alt_index;
861184610Salfred					sc->sc_midi_chan.valid = 1;
862184610Salfred				}
863184610Salfred			}
864184610Salfred			asid = NULL;
865184610Salfred			asf1d = NULL;
866184610Salfred			ed1 = NULL;
867184610Salfred			ed2 = NULL;
868184610Salfred			sed = NULL;
869184610Salfred		}
870184610Salfred		if ((desc->bDescriptorType == UDESC_CS_INTERFACE) &&
871184610Salfred		    (desc->bDescriptorSubtype == AS_GENERAL) &&
872184610Salfred		    (desc->bLength >= sizeof(*asid))) {
873184610Salfred			if (asid == NULL) {
874184610Salfred				asid = (void *)desc;
875184610Salfred			}
876184610Salfred		}
877184610Salfred		if ((desc->bDescriptorType == UDESC_CS_INTERFACE) &&
878184610Salfred		    (desc->bDescriptorSubtype == FORMAT_TYPE) &&
879184610Salfred		    (desc->bLength >= sizeof(*asf1d))) {
880184610Salfred			if (asf1d == NULL) {
881184610Salfred				asf1d = (void *)desc;
882184610Salfred				if (asf1d->bFormatType != FORMAT_TYPE_I) {
883184610Salfred					DPRINTFN(11, "ignored bFormatType = %d\n",
884184610Salfred					    asf1d->bFormatType);
885184610Salfred					asf1d = NULL;
886184610Salfred					continue;
887184610Salfred				}
888184610Salfred				if (asf1d->bLength < (sizeof(*asf1d) +
889184610Salfred				    (asf1d->bSamFreqType == 0) ? 6 :
890184610Salfred				    (asf1d->bSamFreqType * 3))) {
891184610Salfred					DPRINTFN(11, "'asf1d' descriptor is too short\n");
892184610Salfred					asf1d = NULL;
893184610Salfred					continue;
894184610Salfred				}
895184610Salfred			}
896184610Salfred		}
897184610Salfred		if ((desc->bDescriptorType == UDESC_ENDPOINT) &&
898209452Sthompsa		    (desc->bLength >= UEP_MINSIZE)) {
899184610Salfred			if (ed1 == NULL) {
900184610Salfred				ed1 = (void *)desc;
901184610Salfred				if (UE_GET_XFERTYPE(ed1->bmAttributes) != UE_ISOCHRONOUS) {
902184610Salfred					ed1 = NULL;
903184610Salfred				}
904184610Salfred			}
905184610Salfred		}
906184610Salfred		if ((desc->bDescriptorType == UDESC_CS_ENDPOINT) &&
907184610Salfred		    (desc->bDescriptorSubtype == AS_GENERAL) &&
908184610Salfred		    (desc->bLength >= sizeof(*sed))) {
909184610Salfred			if (sed == NULL) {
910184610Salfred				sed = (void *)desc;
911184610Salfred			}
912184610Salfred		}
913184610Salfred		if (audio_if && asid && asf1d && ed1 && sed) {
914184610Salfred
915184610Salfred			ep_dir = UE_GET_DIR(ed1->bEndpointAddress);
916184610Salfred
917209452Sthompsa			/* We ignore sync endpoint information until further. */
918184610Salfred
919184610Salfred			wFormat = UGETW(asid->wFormatTag);
920192929Sthompsa			bChannels = UAUDIO_MAX_CHAN(asf1d->bNrChannels);
921184610Salfred			bBitResolution = asf1d->bBitResolution;
922184610Salfred
923184610Salfred			if (asf1d->bSamFreqType == 0) {
924184610Salfred				DPRINTFN(16, "Sample rate: %d-%dHz\n",
925184610Salfred				    UA_SAMP_LO(asf1d), UA_SAMP_HI(asf1d));
926184610Salfred
927184610Salfred				if ((rate >= UA_SAMP_LO(asf1d)) &&
928184610Salfred				    (rate <= UA_SAMP_HI(asf1d))) {
929184610Salfred					goto found_rate;
930184610Salfred				}
931184610Salfred			} else {
932184610Salfred
933184610Salfred				for (x = 0; x < asf1d->bSamFreqType; x++) {
934184610Salfred					DPRINTFN(16, "Sample rate = %dHz\n",
935184610Salfred					    UA_GETSAMP(asf1d, x));
936184610Salfred
937184610Salfred					if (rate == UA_GETSAMP(asf1d, x)) {
938184610Salfred						goto found_rate;
939184610Salfred					}
940184610Salfred				}
941184610Salfred			}
942184610Salfred
943184610Salfred			audio_if = 0;
944184610Salfred			continue;
945184610Salfred
946184610Salfred	found_rate:
947184610Salfred
948184610Salfred			for (p_fmt = uaudio_formats;
949184610Salfred			    p_fmt->wFormat;
950184610Salfred			    p_fmt++) {
951184610Salfred				if ((p_fmt->wFormat == wFormat) &&
952184610Salfred				    (p_fmt->bPrecision == bBitResolution)) {
953184610Salfred					goto found_format;
954184610Salfred				}
955184610Salfred			}
956184610Salfred
957184610Salfred			audio_if = 0;
958184610Salfred			continue;
959184610Salfred
960184610Salfred	found_format:
961184610Salfred
962184610Salfred			if ((bChannels == channels) &&
963184610Salfred			    (bBitResolution == bit_resolution)) {
964184610Salfred
965184610Salfred				chan = (ep_dir == UE_DIR_IN) ?
966184610Salfred				    &sc->sc_rec_chan :
967184610Salfred				    &sc->sc_play_chan;
968184610Salfred
969194228Sthompsa				if ((chan->valid == 0) && usbd_get_iface(udev, curidx)) {
970184610Salfred
971184610Salfred					chan->valid = 1;
972207077Sthompsa#ifdef USB_DEBUG
973184610Salfred					uaudio_chan_dump_ep_desc(ed1);
974184610Salfred					uaudio_chan_dump_ep_desc(ed2);
975184610Salfred
976184610Salfred					if (sed->bmAttributes & UA_SED_FREQ_CONTROL) {
977184610Salfred						DPRINTFN(2, "FREQ_CONTROL\n");
978184610Salfred					}
979184610Salfred					if (sed->bmAttributes & UA_SED_PITCH_CONTROL) {
980184610Salfred						DPRINTFN(2, "PITCH_CONTROL\n");
981184610Salfred					}
982184610Salfred#endif
983184610Salfred					DPRINTF("Sample rate = %dHz, channels = %d, "
984184610Salfred					    "bits = %d, format = %s\n", rate, channels,
985184610Salfred					    bit_resolution, p_fmt->description);
986184610Salfred
987184610Salfred					chan->sample_rate = rate;
988184610Salfred					chan->p_asid = asid;
989184610Salfred					chan->p_asf1d = asf1d;
990184610Salfred					chan->p_ed1 = ed1;
991184610Salfred					chan->p_ed2 = ed2;
992184610Salfred					chan->p_fmt = p_fmt;
993184610Salfred					chan->p_sed = sed;
994184610Salfred					chan->iface_index = curidx;
995184610Salfred					chan->iface_alt_index = alt_index;
996184610Salfred
997186730Salfred					if (ep_dir == UE_DIR_IN)
998203678Sbrucec						chan->usb_cfg =
999186730Salfred						    uaudio_cfg_record;
1000186730Salfred					else
1001203678Sbrucec						chan->usb_cfg =
1002186730Salfred						    uaudio_cfg_play;
1003184610Salfred
1004200825Sthompsa					chan->sample_size = ((
1005192929Sthompsa					    UAUDIO_MAX_CHAN(chan->p_asf1d->bNrChannels) *
1006184610Salfred					    chan->p_asf1d->bBitResolution) / 8);
1007184610Salfred
1008184610Salfred					if (sc->sc_sndstat_valid) {
1009184610Salfred						sbuf_printf(&sc->sc_sndstat, "\n\t"
1010184610Salfred						    "mode %d.%d:(%s) %dch, %d/%dbit, %s, %dHz",
1011184610Salfred						    curidx, alt_index,
1012184610Salfred						    (ep_dir == UE_DIR_IN) ? "input" : "output",
1013184610Salfred						    asf1d->bNrChannels, asf1d->bBitResolution,
1014184610Salfred						    asf1d->bSubFrameSize * 8,
1015184610Salfred						    p_fmt->description, rate);
1016184610Salfred					}
1017184610Salfred				}
1018184610Salfred			}
1019184610Salfred			audio_if = 0;
1020184610Salfred			continue;
1021184610Salfred		}
1022184610Salfred	}
1023184610Salfred}
1024184610Salfred
1025200825Sthompsa/* This structure defines all the supported rates. */
1026200825Sthompsa
1027200825Sthompsastatic const uint32_t uaudio_rate_list[] = {
1028200825Sthompsa	96000,
1029200825Sthompsa	88000,
1030200825Sthompsa	80000,
1031200825Sthompsa	72000,
1032200825Sthompsa	64000,
1033200825Sthompsa	56000,
1034200825Sthompsa	48000,
1035200825Sthompsa	44100,
1036200825Sthompsa	40000,
1037200825Sthompsa	32000,
1038200825Sthompsa	24000,
1039200825Sthompsa	22050,
1040200825Sthompsa	16000,
1041200825Sthompsa	11025,
1042200825Sthompsa	8000,
1043200825Sthompsa	0
1044200825Sthompsa};
1045200825Sthompsa
1046184610Salfredstatic void
1047192984Sthompsauaudio_chan_fill_info(struct uaudio_softc *sc, struct usb_device *udev)
1048184610Salfred{
1049184610Salfred	uint32_t rate = uaudio_default_rate;
1050200825Sthompsa	uint8_t z;
1051184610Salfred	uint8_t bits = uaudio_default_bits;
1052184610Salfred	uint8_t y;
1053184610Salfred	uint8_t channels = uaudio_default_channels;
1054184610Salfred	uint8_t x;
1055184610Salfred
1056184610Salfred	bits -= (bits % 8);
1057186730Salfred	if ((bits == 0) || (bits > 32)) {
1058186730Salfred		/* set a valid value */
1059186730Salfred		bits = 32;
1060186730Salfred	}
1061200825Sthompsa	if (channels == 0) {
1062200825Sthompsa		switch (usbd_get_speed(udev)) {
1063200825Sthompsa		case USB_SPEED_LOW:
1064200825Sthompsa		case USB_SPEED_FULL:
1065200825Sthompsa			/*
1066200825Sthompsa			 * Due to high bandwidth usage and problems
1067200825Sthompsa			 * with HIGH-speed split transactions we
1068200825Sthompsa			 * disable surround setups on FULL-speed USB
1069200825Sthompsa			 * by default
1070200825Sthompsa			 */
1071200825Sthompsa			channels = 2;
1072200825Sthompsa			break;
1073200825Sthompsa		default:
1074200825Sthompsa			channels = 16;
1075200825Sthompsa			break;
1076200825Sthompsa		}
1077200825Sthompsa	} else if (channels > 16) {
1078200825Sthompsa		channels = 16;
1079186730Salfred	}
1080184610Salfred	if (sbuf_new(&sc->sc_sndstat, NULL, 4096, SBUF_AUTOEXTEND)) {
1081184610Salfred		sc->sc_sndstat_valid = 1;
1082184610Salfred	}
1083184610Salfred	/* try to search for a valid config */
1084184610Salfred
1085184610Salfred	for (x = channels; x; x--) {
1086184610Salfred		for (y = bits; y; y -= 8) {
1087184610Salfred
1088200825Sthompsa			/* try user defined rate, if any */
1089200825Sthompsa			if (rate != 0)
1090200825Sthompsa				uaudio_chan_fill_info_sub(sc, udev, rate, x, y);
1091200825Sthompsa
1092200825Sthompsa			/* try find a matching rate, if any */
1093200825Sthompsa			for (z = 0; uaudio_rate_list[z]; z++) {
1094200825Sthompsa				uaudio_chan_fill_info_sub(sc, udev, uaudio_rate_list[z], x, y);
1095200825Sthompsa
1096184610Salfred				if (sc->sc_rec_chan.valid &&
1097184610Salfred				    sc->sc_play_chan.valid) {
1098184610Salfred					goto done;
1099184610Salfred				}
1100184610Salfred			}
1101184610Salfred		}
1102184610Salfred	}
1103184610Salfred
1104184610Salfreddone:
1105184610Salfred	if (sc->sc_sndstat_valid) {
1106184610Salfred		sbuf_finish(&sc->sc_sndstat);
1107184610Salfred	}
1108184610Salfred}
1109184610Salfred
1110184610Salfredstatic void
1111194677Sthompsauaudio_chan_play_callback(struct usb_xfer *xfer, usb_error_t error)
1112184610Salfred{
1113194677Sthompsa	struct uaudio_chan *ch = usbd_xfer_softc(xfer);
1114194677Sthompsa	struct usb_page_cache *pc;
1115186730Salfred	uint32_t total;
1116184610Salfred	uint32_t blockcount;
1117184610Salfred	uint32_t n;
1118184610Salfred	uint32_t offset;
1119200825Sthompsa	int actlen;
1120200825Sthompsa	int sumlen;
1121184610Salfred
1122194677Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
1123194677Sthompsa
1124199060Sthompsa	if (ch->end == ch->start) {
1125199060Sthompsa		DPRINTF("no buffer!\n");
1126199060Sthompsa		return;
1127199060Sthompsa	}
1128199060Sthompsa
1129184610Salfred	switch (USB_GET_STATE(xfer)) {
1130184610Salfred	case USB_ST_TRANSFERRED:
1131184610Salfredtr_transferred:
1132194677Sthompsa		if (actlen < sumlen) {
1133184610Salfred			DPRINTF("short transfer, "
1134200825Sthompsa			    "%d of %d bytes\n", actlen, sumlen);
1135184610Salfred		}
1136184610Salfred		chn_intr(ch->pcm_ch);
1137184610Salfred
1138184610Salfred	case USB_ST_SETUP:
1139200825Sthompsa		if (ch->bytes_per_frame[1] > usbd_xfer_max_framelen(xfer)) {
1140184610Salfred			DPRINTF("bytes per transfer, %d, "
1141184610Salfred			    "exceeds maximum, %d!\n",
1142200825Sthompsa			    ch->bytes_per_frame[1],
1143194677Sthompsa			    usbd_xfer_max_framelen(xfer));
1144184610Salfred			break;
1145184610Salfred		}
1146200825Sthompsa
1147200825Sthompsa		blockcount = ch->intr_frames;
1148200825Sthompsa
1149200825Sthompsa		/* setup number of frames */
1150194677Sthompsa		usbd_xfer_set_frames(xfer, blockcount);
1151184610Salfred
1152200825Sthompsa		/* reset total length */
1153200825Sthompsa		total = 0;
1154200825Sthompsa
1155200825Sthompsa		/* setup frame lengths */
1156200825Sthompsa		for (n = 0; n != blockcount; n++) {
1157200825Sthompsa			ch->sample_curr += ch->sample_rem;
1158200825Sthompsa			if (ch->sample_curr >= ch->frames_per_second) {
1159200825Sthompsa				ch->sample_curr -= ch->frames_per_second;
1160200825Sthompsa				usbd_xfer_set_frame_len(xfer, n, ch->bytes_per_frame[1]);
1161200825Sthompsa				total += ch->bytes_per_frame[1];
1162200825Sthompsa			} else {
1163200825Sthompsa				usbd_xfer_set_frame_len(xfer, n, ch->bytes_per_frame[0]);
1164200825Sthompsa				total += ch->bytes_per_frame[0];
1165200825Sthompsa			}
1166200825Sthompsa		}
1167200825Sthompsa
1168184610Salfred		DPRINTFN(6, "transfer %d bytes\n", total);
1169184610Salfred
1170184610Salfred		offset = 0;
1171184610Salfred
1172194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
1173184610Salfred		while (total > 0) {
1174184610Salfred
1175184610Salfred			n = (ch->end - ch->cur);
1176184610Salfred			if (n > total) {
1177184610Salfred				n = total;
1178184610Salfred			}
1179194677Sthompsa			usbd_copy_in(pc, offset, ch->cur, n);
1180184610Salfred
1181184610Salfred			total -= n;
1182184610Salfred			ch->cur += n;
1183184610Salfred			offset += n;
1184184610Salfred
1185184610Salfred			if (ch->cur >= ch->end) {
1186184610Salfred				ch->cur = ch->start;
1187184610Salfred			}
1188184610Salfred		}
1189184610Salfred
1190194228Sthompsa		usbd_transfer_submit(xfer);
1191184610Salfred		break;
1192184610Salfred
1193184610Salfred	default:			/* Error */
1194194677Sthompsa		if (error == USB_ERR_CANCELLED) {
1195184610Salfred			break;
1196184610Salfred		}
1197184610Salfred		goto tr_transferred;
1198184610Salfred	}
1199184610Salfred}
1200184610Salfred
1201184610Salfredstatic void
1202194677Sthompsauaudio_chan_record_callback(struct usb_xfer *xfer, usb_error_t error)
1203184610Salfred{
1204194677Sthompsa	struct uaudio_chan *ch = usbd_xfer_softc(xfer);
1205194677Sthompsa	struct usb_page_cache *pc;
1206184610Salfred	uint32_t n;
1207184610Salfred	uint32_t m;
1208184610Salfred	uint32_t blockcount;
1209184610Salfred	uint32_t offset0;
1210184610Salfred	uint32_t offset1;
1211199060Sthompsa	uint32_t mfl;
1212194677Sthompsa	int len;
1213199060Sthompsa	int actlen;
1214199060Sthompsa	int nframes;
1215184610Salfred
1216194677Sthompsa	usbd_xfer_status(xfer, &actlen, NULL, NULL, &nframes);
1217199060Sthompsa	mfl = usbd_xfer_max_framelen(xfer);
1218194677Sthompsa
1219199060Sthompsa	if (ch->end == ch->start) {
1220199060Sthompsa		DPRINTF("no buffer!\n");
1221199060Sthompsa		return;
1222199060Sthompsa	}
1223199060Sthompsa
1224184610Salfred	switch (USB_GET_STATE(xfer)) {
1225184610Salfred	case USB_ST_TRANSFERRED:
1226184610Salfred
1227200825Sthompsa		DPRINTFN(6, "transferred %d bytes\n", actlen);
1228200825Sthompsa
1229184610Salfred		offset0 = 0;
1230199060Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
1231184610Salfred
1232194677Sthompsa		for (n = 0; n != nframes; n++) {
1233184610Salfred
1234184610Salfred			offset1 = offset0;
1235194682Sthompsa			len = usbd_xfer_frame_len(xfer, n);
1236184610Salfred
1237194677Sthompsa			while (len > 0) {
1238184610Salfred
1239184610Salfred				m = (ch->end - ch->cur);
1240184610Salfred
1241194677Sthompsa				if (m > len) {
1242194677Sthompsa					m = len;
1243184610Salfred				}
1244194677Sthompsa				usbd_copy_out(pc, offset1, ch->cur, m);
1245184610Salfred
1246194677Sthompsa				len -= m;
1247184610Salfred				offset1 += m;
1248184610Salfred				ch->cur += m;
1249184610Salfred
1250184610Salfred				if (ch->cur >= ch->end) {
1251184610Salfred					ch->cur = ch->start;
1252184610Salfred				}
1253184610Salfred			}
1254184610Salfred
1255199060Sthompsa			offset0 += mfl;
1256184610Salfred		}
1257184610Salfred
1258184610Salfred		chn_intr(ch->pcm_ch);
1259184610Salfred
1260184610Salfred	case USB_ST_SETUP:
1261199060Sthompsatr_setup:
1262200825Sthompsa		blockcount = ch->intr_frames;
1263200825Sthompsa
1264194677Sthompsa		usbd_xfer_set_frames(xfer, blockcount);
1265194677Sthompsa		for (n = 0; n < blockcount; n++) {
1266199060Sthompsa			usbd_xfer_set_frame_len(xfer, n, mfl);
1267184610Salfred		}
1268184610Salfred
1269194228Sthompsa		usbd_transfer_submit(xfer);
1270199060Sthompsa		break;
1271184610Salfred
1272184610Salfred	default:			/* Error */
1273194677Sthompsa		if (error == USB_ERR_CANCELLED) {
1274199060Sthompsa			break;
1275184610Salfred		}
1276199060Sthompsa		goto tr_setup;
1277184610Salfred	}
1278184610Salfred}
1279184610Salfred
1280184610Salfredvoid   *
1281184610Salfreduaudio_chan_init(struct uaudio_softc *sc, struct snd_dbuf *b,
1282184610Salfred    struct pcm_channel *c, int dir)
1283184610Salfred{
1284184610Salfred	struct uaudio_chan *ch = ((dir == PCMDIR_PLAY) ?
1285184610Salfred	    &sc->sc_play_chan : &sc->sc_rec_chan);
1286186730Salfred	uint32_t buf_size;
1287199060Sthompsa	uint32_t frames;
1288200825Sthompsa	uint32_t format;
1289200825Sthompsa	uint16_t fps;
1290184610Salfred	uint8_t endpoint;
1291199060Sthompsa	uint8_t blocks;
1292184610Salfred	uint8_t iface_index;
1293184610Salfred	uint8_t alt_index;
1294199060Sthompsa	uint8_t fps_shift;
1295193045Sthompsa	usb_error_t err;
1296184610Salfred
1297200825Sthompsa	fps = usbd_get_isoc_fps(sc->sc_udev);
1298200825Sthompsa
1299200825Sthompsa	if (fps < 8000) {
1300199060Sthompsa		/* FULL speed USB */
1301199060Sthompsa		frames = 8;
1302199060Sthompsa	} else {
1303199060Sthompsa		/* HIGH speed USB */
1304199060Sthompsa		frames = UAUDIO_NFRAMES;
1305199060Sthompsa	}
1306199060Sthompsa
1307184610Salfred	/* setup play/record format */
1308184610Salfred
1309184610Salfred	ch->pcm_cap.fmtlist = ch->pcm_format;
1310184610Salfred
1311184610Salfred	ch->pcm_format[0] = 0;
1312184610Salfred	ch->pcm_format[1] = 0;
1313184610Salfred
1314184610Salfred	ch->pcm_cap.minspeed = ch->sample_rate;
1315184610Salfred	ch->pcm_cap.maxspeed = ch->sample_rate;
1316184610Salfred
1317199576Sthompsa	/* setup mutex and PCM channel */
1318199576Sthompsa
1319199576Sthompsa	ch->pcm_ch = c;
1320199576Sthompsa	ch->pcm_mtx = c->lock;
1321199576Sthompsa
1322200825Sthompsa	format = ch->p_fmt->freebsd_fmt;
1323184610Salfred
1324200825Sthompsa	switch (ch->p_asf1d->bNrChannels) {
1325200825Sthompsa	case 2:
1326200825Sthompsa		/* stereo */
1327200825Sthompsa		format = SND_FORMAT(format, 2, 0);
1328200825Sthompsa		break;
1329200825Sthompsa	case 1:
1330200825Sthompsa		/* mono */
1331200825Sthompsa		format = SND_FORMAT(format, 1, 0);
1332200825Sthompsa		break;
1333200825Sthompsa	default:
1334200825Sthompsa		/* surround and more */
1335200825Sthompsa		format = feeder_matrix_default_format(
1336200825Sthompsa		    SND_FORMAT(format, ch->p_asf1d->bNrChannels, 0));
1337200825Sthompsa		break;
1338200825Sthompsa	}
1339200825Sthompsa
1340200825Sthompsa	ch->pcm_cap.fmtlist[0] = format;
1341184610Salfred	ch->pcm_cap.fmtlist[1] = 0;
1342184610Salfred
1343200825Sthompsa	/* check if format is not supported */
1344200825Sthompsa
1345200825Sthompsa	if (format == 0) {
1346200825Sthompsa		DPRINTF("The selected audio format is not supported\n");
1347200825Sthompsa		goto error;
1348200825Sthompsa	}
1349200825Sthompsa
1350184610Salfred	/* set alternate interface corresponding to the mode */
1351184610Salfred
1352184610Salfred	endpoint = ch->p_ed1->bEndpointAddress;
1353184610Salfred	iface_index = ch->iface_index;
1354184610Salfred	alt_index = ch->iface_alt_index;
1355184610Salfred
1356184610Salfred	DPRINTF("endpoint=0x%02x, speed=%d, iface=%d alt=%d\n",
1357184610Salfred	    endpoint, ch->sample_rate, iface_index, alt_index);
1358184610Salfred
1359194228Sthompsa	err = usbd_set_alt_interface_index(sc->sc_udev, iface_index, alt_index);
1360184610Salfred	if (err) {
1361184610Salfred		DPRINTF("setting of alternate index failed: %s!\n",
1362194228Sthompsa		    usbd_errstr(err));
1363184610Salfred		goto error;
1364184610Salfred	}
1365194228Sthompsa	usbd_set_parent_iface(sc->sc_udev, iface_index, sc->sc_mixer_iface_index);
1366184610Salfred
1367184610Salfred	/*
1368184610Salfred	 * If just one sampling rate is supported,
1369184610Salfred	 * no need to call "uaudio_set_speed()".
1370184610Salfred	 * Roland SD-90 freezes by a SAMPLING_FREQ_CONTROL request.
1371184610Salfred	 */
1372184610Salfred	if (ch->p_asf1d->bSamFreqType != 1) {
1373184610Salfred		if (uaudio_set_speed(sc->sc_udev, endpoint, ch->sample_rate)) {
1374184610Salfred			/*
1375184610Salfred			 * If the endpoint is adaptive setting the speed may
1376184610Salfred			 * fail.
1377184610Salfred			 */
1378184610Salfred			DPRINTF("setting of sample rate failed! (continuing anyway)\n");
1379184610Salfred		}
1380184610Salfred	}
1381194228Sthompsa	if (usbd_transfer_setup(sc->sc_udev, &iface_index, ch->xfer,
1382203678Sbrucec	    ch->usb_cfg, UAUDIO_NCHANBUFS, ch, ch->pcm_mtx)) {
1383184610Salfred		DPRINTF("could not allocate USB transfers!\n");
1384184610Salfred		goto error;
1385184610Salfred	}
1386199060Sthompsa
1387199060Sthompsa	fps_shift = usbd_xfer_get_fps_shift(ch->xfer[0]);
1388199060Sthompsa
1389200825Sthompsa	/* down shift number of frames per second, if any */
1390200825Sthompsa	fps >>= fps_shift;
1391200825Sthompsa	frames >>= fps_shift;
1392200825Sthompsa
1393200825Sthompsa	/* bytes per frame should not be zero */
1394200825Sthompsa	ch->bytes_per_frame[0] = ((ch->sample_rate / fps) * ch->sample_size);
1395200825Sthompsa	ch->bytes_per_frame[1] = (((ch->sample_rate + fps - 1) / fps) * ch->sample_size);
1396200825Sthompsa
1397200825Sthompsa	/* setup data rate dithering, if any */
1398200825Sthompsa	ch->frames_per_second = fps;
1399200825Sthompsa	ch->sample_rem = ch->sample_rate % fps;
1400200825Sthompsa	ch->sample_curr = 0;
1401200825Sthompsa	ch->frames_per_second = fps;
1402200825Sthompsa
1403200825Sthompsa	/* compute required buffer size */
1404200825Sthompsa	buf_size = (ch->bytes_per_frame[1] * frames);
1405200825Sthompsa
1406199060Sthompsa	ch->intr_size = buf_size;
1407200825Sthompsa	ch->intr_frames = frames;
1408199060Sthompsa
1409200825Sthompsa	DPRINTF("fps=%d sample_rem=%d\n", fps, ch->sample_rem);
1410200825Sthompsa
1411199060Sthompsa	if (ch->intr_frames == 0) {
1412199060Sthompsa		DPRINTF("frame shift is too high!\n");
1413199060Sthompsa		goto error;
1414199060Sthompsa	}
1415199060Sthompsa
1416199060Sthompsa	/* setup double buffering */
1417199060Sthompsa	buf_size *= 2;
1418199060Sthompsa	blocks = 2;
1419199060Sthompsa
1420199060Sthompsa	ch->buf = malloc(buf_size, M_DEVBUF, M_WAITOK | M_ZERO);
1421199060Sthompsa	if (ch->buf == NULL)
1422199060Sthompsa		goto error;
1423199060Sthompsa	if (sndbuf_setup(b, ch->buf, buf_size) != 0)
1424199060Sthompsa		goto error;
1425199060Sthompsa	if (sndbuf_resize(b, blocks, ch->intr_size))
1426199060Sthompsa		goto error;
1427199060Sthompsa
1428199060Sthompsa	ch->start = ch->buf;
1429199060Sthompsa	ch->end = ch->buf + buf_size;
1430199060Sthompsa	ch->cur = ch->buf;
1431199060Sthompsa	ch->pcm_buf = b;
1432199060Sthompsa
1433199060Sthompsa	if (ch->pcm_mtx == NULL) {
1434199060Sthompsa		DPRINTF("ERROR: PCM channels does not have a mutex!\n");
1435199060Sthompsa		goto error;
1436199060Sthompsa	}
1437199060Sthompsa
1438184610Salfred	return (ch);
1439184610Salfred
1440184610Salfrederror:
1441184610Salfred	uaudio_chan_free(ch);
1442184610Salfred	return (NULL);
1443184610Salfred}
1444184610Salfred
1445184610Salfredint
1446184610Salfreduaudio_chan_free(struct uaudio_chan *ch)
1447184610Salfred{
1448184610Salfred	if (ch->buf != NULL) {
1449184610Salfred		free(ch->buf, M_DEVBUF);
1450184610Salfred		ch->buf = NULL;
1451184610Salfred	}
1452194228Sthompsa	usbd_transfer_unsetup(ch->xfer, UAUDIO_NCHANBUFS);
1453184610Salfred
1454184610Salfred	ch->valid = 0;
1455184610Salfred
1456184610Salfred	return (0);
1457184610Salfred}
1458184610Salfred
1459184610Salfredint
1460184610Salfreduaudio_chan_set_param_blocksize(struct uaudio_chan *ch, uint32_t blocksize)
1461184610Salfred{
1462199060Sthompsa	return (ch->intr_size);
1463184610Salfred}
1464184610Salfred
1465184610Salfredint
1466184610Salfreduaudio_chan_set_param_fragments(struct uaudio_chan *ch, uint32_t blocksize,
1467184610Salfred    uint32_t blockcount)
1468184610Salfred{
1469184610Salfred	return (1);
1470184610Salfred}
1471184610Salfred
1472184610Salfredint
1473184610Salfreduaudio_chan_set_param_speed(struct uaudio_chan *ch, uint32_t speed)
1474184610Salfred{
1475184610Salfred	if (speed != ch->sample_rate) {
1476184610Salfred		DPRINTF("rate conversion required\n");
1477184610Salfred	}
1478184610Salfred	return (ch->sample_rate);
1479184610Salfred}
1480184610Salfred
1481184610Salfredint
1482184610Salfreduaudio_chan_getptr(struct uaudio_chan *ch)
1483184610Salfred{
1484184610Salfred	return (ch->cur - ch->start);
1485184610Salfred}
1486184610Salfred
1487184610Salfredstruct pcmchan_caps *
1488184610Salfreduaudio_chan_getcaps(struct uaudio_chan *ch)
1489184610Salfred{
1490184610Salfred	return (&ch->pcm_cap);
1491184610Salfred}
1492184610Salfred
1493193640Sariffstatic struct pcmchan_matrix uaudio_chan_matrix_swap_2_0 = {
1494193640Sariff	.id = SND_CHN_MATRIX_DRV,
1495193640Sariff	.channels = 2,
1496193640Sariff	.ext = 0,
1497193640Sariff	.map = {
1498193640Sariff		/* Right */
1499193640Sariff		[0] = {
1500193640Sariff			.type = SND_CHN_T_FR,
1501193640Sariff			.members =
1502193640Sariff			    SND_CHN_T_MASK_FR | SND_CHN_T_MASK_FC |
1503193640Sariff			    SND_CHN_T_MASK_LF | SND_CHN_T_MASK_BR |
1504193640Sariff			    SND_CHN_T_MASK_BC | SND_CHN_T_MASK_SR
1505193640Sariff		},
1506193640Sariff		/* Left */
1507193640Sariff		[1] = {
1508193640Sariff			.type = SND_CHN_T_FL,
1509193640Sariff			.members =
1510193640Sariff			    SND_CHN_T_MASK_FL | SND_CHN_T_MASK_FC |
1511193640Sariff			    SND_CHN_T_MASK_LF | SND_CHN_T_MASK_BL |
1512193640Sariff			    SND_CHN_T_MASK_BC | SND_CHN_T_MASK_SL
1513193640Sariff		},
1514193640Sariff		[2] = {
1515193640Sariff			.type = SND_CHN_T_MAX,
1516193640Sariff			.members = 0
1517193640Sariff		}
1518193640Sariff	},
1519193640Sariff	.mask = SND_CHN_T_MASK_FR | SND_CHN_T_MASK_FL,
1520193640Sariff	.offset = {  1,  0, -1, -1, -1, -1, -1, -1, -1,
1521193640Sariff		    -1, -1, -1, -1, -1, -1, -1, -1, -1  }
1522193640Sariff};
1523193640Sariff
1524193640Sariffstruct pcmchan_matrix *
1525193640Sariffuaudio_chan_getmatrix(struct uaudio_chan *ch, uint32_t format)
1526193640Sariff{
1527193640Sariff	struct uaudio_softc *sc;
1528193640Sariff
1529193640Sariff	sc = ch->priv_sc;
1530193640Sariff
1531193640Sariff	if (sc != NULL && sc->sc_uq_audio_swap_lr != 0 &&
1532193640Sariff	    AFMT_CHANNEL(format) == 2)
1533193640Sariff		return (&uaudio_chan_matrix_swap_2_0);
1534193640Sariff
1535193640Sariff	return (feeder_matrix_format_map(format));
1536193640Sariff}
1537193640Sariff
1538184610Salfredint
1539184610Salfreduaudio_chan_set_param_format(struct uaudio_chan *ch, uint32_t format)
1540184610Salfred{
1541184610Salfred	ch->format = format;
1542184610Salfred	return (0);
1543184610Salfred}
1544184610Salfred
1545184610Salfredint
1546184610Salfreduaudio_chan_start(struct uaudio_chan *ch)
1547184610Salfred{
1548184610Salfred	ch->cur = ch->start;
1549184610Salfred
1550184610Salfred#if (UAUDIO_NCHANBUFS != 2)
1551184610Salfred#error "please update code"
1552184610Salfred#endif
1553184610Salfred	if (ch->xfer[0]) {
1554194228Sthompsa		usbd_transfer_start(ch->xfer[0]);
1555184610Salfred	}
1556184610Salfred	if (ch->xfer[1]) {
1557194228Sthompsa		usbd_transfer_start(ch->xfer[1]);
1558184610Salfred	}
1559184610Salfred	return (0);
1560184610Salfred}
1561184610Salfred
1562184610Salfredint
1563184610Salfreduaudio_chan_stop(struct uaudio_chan *ch)
1564184610Salfred{
1565184610Salfred#if (UAUDIO_NCHANBUFS != 2)
1566184610Salfred#error "please update code"
1567184610Salfred#endif
1568194228Sthompsa	usbd_transfer_stop(ch->xfer[0]);
1569194228Sthompsa	usbd_transfer_stop(ch->xfer[1]);
1570184610Salfred	return (0);
1571184610Salfred}
1572184610Salfred
1573184610Salfred/*========================================================================*
1574184610Salfred * AC - Audio Controller - routines
1575184610Salfred *========================================================================*/
1576184610Salfred
1577184610Salfredstatic void
1578184610Salfreduaudio_mixer_add_ctl_sub(struct uaudio_softc *sc, struct uaudio_mixer_node *mc)
1579184610Salfred{
1580184610Salfred	struct uaudio_mixer_node *p_mc_new =
1581184610Salfred	malloc(sizeof(*p_mc_new), M_USBDEV, M_WAITOK);
1582184610Salfred
1583184610Salfred	if (p_mc_new) {
1584184610Salfred		bcopy(mc, p_mc_new, sizeof(*p_mc_new));
1585184610Salfred		p_mc_new->next = sc->sc_mixer_root;
1586184610Salfred		sc->sc_mixer_root = p_mc_new;
1587184610Salfred		sc->sc_mixer_count++;
1588184610Salfred	} else {
1589184610Salfred		DPRINTF("out of memory\n");
1590184610Salfred	}
1591184610Salfred}
1592184610Salfred
1593184610Salfredstatic void
1594184610Salfreduaudio_mixer_add_ctl(struct uaudio_softc *sc, struct uaudio_mixer_node *mc)
1595184610Salfred{
1596184610Salfred	int32_t res;
1597184610Salfred
1598184610Salfred	if (mc->class < UAC_NCLASSES) {
1599184610Salfred		DPRINTF("adding %s.%d\n",
1600184610Salfred		    uac_names[mc->class], mc->ctl);
1601184610Salfred	} else {
1602184610Salfred		DPRINTF("adding %d\n", mc->ctl);
1603184610Salfred	}
1604184610Salfred
1605184610Salfred	if (mc->type == MIX_ON_OFF) {
1606184610Salfred		mc->minval = 0;
1607184610Salfred		mc->maxval = 1;
1608184610Salfred	} else if (mc->type == MIX_SELECTOR) {
1609184610Salfred	} else {
1610184610Salfred
1611184610Salfred		/* determine min and max values */
1612184610Salfred
1613184610Salfred		mc->minval = uaudio_mixer_get(sc->sc_udev, GET_MIN, mc);
1614184610Salfred
1615184610Salfred		mc->minval = uaudio_mixer_signext(mc->type, mc->minval);
1616184610Salfred
1617184610Salfred		mc->maxval = uaudio_mixer_get(sc->sc_udev, GET_MAX, mc);
1618184610Salfred
1619199060Sthompsa		mc->maxval = uaudio_mixer_signext(mc->type, mc->maxval);
1620184610Salfred
1621199060Sthompsa		/* check if max and min was swapped */
1622199060Sthompsa
1623199060Sthompsa		if (mc->maxval < mc->minval) {
1624199060Sthompsa			res = mc->maxval;
1625199060Sthompsa			mc->maxval = mc->minval;
1626199060Sthompsa			mc->minval = res;
1627199060Sthompsa		}
1628199060Sthompsa
1629199060Sthompsa		/* compute value range */
1630184610Salfred		mc->mul = mc->maxval - mc->minval;
1631199060Sthompsa		if (mc->mul == 0)
1632184610Salfred			mc->mul = 1;
1633199060Sthompsa
1634199060Sthompsa		/* compute value alignment */
1635184610Salfred		res = uaudio_mixer_get(sc->sc_udev, GET_RES, mc);
1636199576Sthompsa
1637199576Sthompsa		DPRINTF("Resolution = %d\n", (int)res);
1638184610Salfred	}
1639184610Salfred
1640184610Salfred	uaudio_mixer_add_ctl_sub(sc, mc);
1641184610Salfred
1642207077Sthompsa#ifdef USB_DEBUG
1643184610Salfred	if (uaudio_debug > 2) {
1644184610Salfred		uint8_t i;
1645184610Salfred
1646184610Salfred		for (i = 0; i < mc->nchan; i++) {
1647184610Salfred			DPRINTF("[mix] wValue=%04x\n", mc->wValue[0]);
1648184610Salfred		}
1649184610Salfred		DPRINTF("[mix] wIndex=%04x type=%d ctl='%d' "
1650184610Salfred		    "min=%d max=%d\n",
1651184610Salfred		    mc->wIndex, mc->type, mc->ctl,
1652184610Salfred		    mc->minval, mc->maxval);
1653184610Salfred	}
1654184610Salfred#endif
1655184610Salfred}
1656184610Salfred
1657184610Salfredstatic void
1658184610Salfreduaudio_mixer_add_input(struct uaudio_softc *sc,
1659184610Salfred    const struct uaudio_terminal_node *iot, int id)
1660184610Salfred{
1661207077Sthompsa#ifdef USB_DEBUG
1662203678Sbrucec	const struct usb_audio_input_terminal *d = iot[id].u.it;
1663184610Salfred
1664184610Salfred	DPRINTFN(3, "bTerminalId=%d wTerminalType=0x%04x "
1665184610Salfred	    "bAssocTerminal=%d bNrChannels=%d wChannelConfig=%d "
1666184610Salfred	    "iChannelNames=%d\n",
1667184610Salfred	    d->bTerminalId, UGETW(d->wTerminalType), d->bAssocTerminal,
1668184610Salfred	    d->bNrChannels, UGETW(d->wChannelConfig),
1669184610Salfred	    d->iChannelNames);
1670184610Salfred#endif
1671184610Salfred}
1672184610Salfred
1673184610Salfredstatic void
1674184610Salfreduaudio_mixer_add_output(struct uaudio_softc *sc,
1675184610Salfred    const struct uaudio_terminal_node *iot, int id)
1676184610Salfred{
1677207077Sthompsa#ifdef USB_DEBUG
1678203678Sbrucec	const struct usb_audio_output_terminal *d = iot[id].u.ot;
1679184610Salfred
1680184610Salfred	DPRINTFN(3, "bTerminalId=%d wTerminalType=0x%04x "
1681184610Salfred	    "bAssocTerminal=%d bSourceId=%d iTerminal=%d\n",
1682184610Salfred	    d->bTerminalId, UGETW(d->wTerminalType), d->bAssocTerminal,
1683184610Salfred	    d->bSourceId, d->iTerminal);
1684184610Salfred#endif
1685184610Salfred}
1686184610Salfred
1687184610Salfredstatic void
1688184610Salfreduaudio_mixer_add_mixer(struct uaudio_softc *sc,
1689184610Salfred    const struct uaudio_terminal_node *iot, int id)
1690184610Salfred{
1691184610Salfred	struct uaudio_mixer_node mix;
1692184610Salfred
1693203678Sbrucec	const struct usb_audio_mixer_unit_0 *d0 = iot[id].u.mu;
1694203678Sbrucec	const struct usb_audio_mixer_unit_1 *d1;
1695184610Salfred
1696184610Salfred	uint32_t bno;			/* bit number */
1697184610Salfred	uint32_t p;			/* bit number accumulator */
1698184610Salfred	uint32_t mo;			/* matching outputs */
1699184610Salfred	uint32_t mc;			/* matching channels */
1700184610Salfred	uint32_t ichs;			/* input channels */
1701184610Salfred	uint32_t ochs;			/* output channels */
1702184610Salfred	uint32_t c;
1703184610Salfred	uint32_t chs;			/* channels */
1704184610Salfred	uint32_t i;
1705184610Salfred	uint32_t o;
1706184610Salfred
1707184610Salfred	DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n",
1708184610Salfred	    d0->bUnitId, d0->bNrInPins);
1709184610Salfred
1710184610Salfred	/* compute the number of input channels */
1711184610Salfred
1712184610Salfred	ichs = 0;
1713184610Salfred	for (i = 0; i < d0->bNrInPins; i++) {
1714184610Salfred		ichs += (uaudio_mixer_get_cluster(d0->baSourceId[i], iot)
1715184610Salfred		    .bNrChannels);
1716184610Salfred	}
1717184610Salfred
1718184610Salfred	d1 = (const void *)(d0->baSourceId + d0->bNrInPins);
1719184610Salfred
1720184610Salfred	/* and the number of output channels */
1721184610Salfred
1722184610Salfred	ochs = d1->bNrChannels;
1723184610Salfred
1724184610Salfred	DPRINTFN(3, "ichs=%d ochs=%d\n", ichs, ochs);
1725184610Salfred
1726184610Salfred	bzero(&mix, sizeof(mix));
1727184610Salfred
1728184610Salfred	mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no);
1729184610Salfred	uaudio_mixer_determine_class(&iot[id], &mix);
1730184610Salfred	mix.type = MIX_SIGNED_16;
1731184610Salfred
1732184610Salfred	if (uaudio_mixer_verify_desc(d0, ((ichs * ochs) + 7) / 8) == NULL) {
1733184610Salfred		return;
1734184610Salfred	}
1735184610Salfred	for (p = i = 0; i < d0->bNrInPins; i++) {
1736184610Salfred		chs = uaudio_mixer_get_cluster(d0->baSourceId[i], iot).bNrChannels;
1737184610Salfred		mc = 0;
1738184610Salfred		for (c = 0; c < chs; c++) {
1739184610Salfred			mo = 0;
1740184610Salfred			for (o = 0; o < ochs; o++) {
1741184610Salfred				bno = ((p + c) * ochs) + o;
1742184610Salfred				if (BIT_TEST(d1->bmControls, bno)) {
1743184610Salfred					mo++;
1744184610Salfred				}
1745184610Salfred			}
1746184610Salfred			if (mo == 1) {
1747184610Salfred				mc++;
1748184610Salfred			}
1749184610Salfred		}
1750184610Salfred		if ((mc == chs) && (chs <= MIX_MAX_CHAN)) {
1751184610Salfred
1752184610Salfred			/* repeat bit-scan */
1753184610Salfred
1754184610Salfred			mc = 0;
1755184610Salfred			for (c = 0; c < chs; c++) {
1756184610Salfred				for (o = 0; o < ochs; o++) {
1757184610Salfred					bno = ((p + c) * ochs) + o;
1758184610Salfred					if (BIT_TEST(d1->bmControls, bno)) {
1759184610Salfred						mix.wValue[mc++] = MAKE_WORD(p + c + 1, o + 1);
1760184610Salfred					}
1761184610Salfred				}
1762184610Salfred			}
1763184610Salfred			mix.nchan = chs;
1764184610Salfred			uaudio_mixer_add_ctl(sc, &mix);
1765184610Salfred		} else {
1766184610Salfred			/* XXX */
1767184610Salfred		}
1768184610Salfred		p += chs;
1769184610Salfred	}
1770184610Salfred}
1771184610Salfred
1772184610Salfredstatic void
1773184610Salfreduaudio_mixer_add_selector(struct uaudio_softc *sc,
1774184610Salfred    const struct uaudio_terminal_node *iot, int id)
1775184610Salfred{
1776203678Sbrucec	const struct usb_audio_selector_unit *d = iot[id].u.su;
1777184610Salfred	struct uaudio_mixer_node mix;
1778184610Salfred	uint16_t i;
1779184610Salfred
1780184610Salfred	DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n",
1781184610Salfred	    d->bUnitId, d->bNrInPins);
1782184610Salfred
1783184610Salfred	if (d->bNrInPins == 0) {
1784184610Salfred		return;
1785184610Salfred	}
1786184610Salfred	bzero(&mix, sizeof(mix));
1787184610Salfred
1788184610Salfred	mix.wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no);
1789184610Salfred	mix.wValue[0] = MAKE_WORD(0, 0);
1790184610Salfred	uaudio_mixer_determine_class(&iot[id], &mix);
1791184610Salfred	mix.nchan = 1;
1792184610Salfred	mix.type = MIX_SELECTOR;
1793184610Salfred
1794184610Salfred	mix.ctl = SOUND_MIXER_NRDEVICES;
1795184610Salfred	mix.minval = 1;
1796184610Salfred	mix.maxval = d->bNrInPins;
1797184610Salfred
1798184610Salfred	if (mix.maxval > MAX_SELECTOR_INPUT_PIN) {
1799184610Salfred		mix.maxval = MAX_SELECTOR_INPUT_PIN;
1800184610Salfred	}
1801184610Salfred	mix.mul = (mix.maxval - mix.minval);
1802184610Salfred	for (i = 0; i < MAX_SELECTOR_INPUT_PIN; i++) {
1803184610Salfred		mix.slctrtype[i] = SOUND_MIXER_NRDEVICES;
1804184610Salfred	}
1805184610Salfred
1806184610Salfred	for (i = 0; i < mix.maxval; i++) {
1807184610Salfred		mix.slctrtype[i] = uaudio_mixer_feature_name
1808184610Salfred		    (&iot[d->baSourceId[i]], &mix);
1809184610Salfred	}
1810184610Salfred
1811184610Salfred	mix.class = 0;			/* not used */
1812184610Salfred
1813184610Salfred	uaudio_mixer_add_ctl(sc, &mix);
1814184610Salfred}
1815184610Salfred
1816184610Salfredstatic uint32_t
1817203678Sbrucecuaudio_mixer_feature_get_bmaControls(const struct usb_audio_feature_unit *d,
1818184610Salfred    uint8_t index)
1819184610Salfred{
1820184610Salfred	uint32_t temp = 0;
1821184610Salfred	uint32_t offset = (index * d->bControlSize);
1822184610Salfred
1823184610Salfred	if (d->bControlSize > 0) {
1824184610Salfred		temp |= d->bmaControls[offset];
1825184610Salfred		if (d->bControlSize > 1) {
1826184610Salfred			temp |= d->bmaControls[offset + 1] << 8;
1827184610Salfred			if (d->bControlSize > 2) {
1828184610Salfred				temp |= d->bmaControls[offset + 2] << 16;
1829184610Salfred				if (d->bControlSize > 3) {
1830184610Salfred					temp |= d->bmaControls[offset + 3] << 24;
1831184610Salfred				}
1832184610Salfred			}
1833184610Salfred		}
1834184610Salfred	}
1835184610Salfred	return (temp);
1836184610Salfred}
1837184610Salfred
1838184610Salfredstatic void
1839184610Salfreduaudio_mixer_add_feature(struct uaudio_softc *sc,
1840184610Salfred    const struct uaudio_terminal_node *iot, int id)
1841184610Salfred{
1842203678Sbrucec	const struct usb_audio_feature_unit *d = iot[id].u.fu;
1843184610Salfred	struct uaudio_mixer_node mix;
1844184610Salfred	uint32_t fumask;
1845184610Salfred	uint32_t mmask;
1846184610Salfred	uint32_t cmask;
1847184610Salfred	uint16_t mixernumber;
1848184610Salfred	uint8_t nchan;
1849184610Salfred	uint8_t chan;
1850184610Salfred	uint8_t ctl;
1851184610Salfred	uint8_t i;
1852184610Salfred
1853184610Salfred	if (d->bControlSize == 0) {
1854184610Salfred		return;
1855184610Salfred	}
1856184610Salfred	bzero(&mix, sizeof(mix));
1857184610Salfred
1858184610Salfred	nchan = (d->bLength - 7) / d->bControlSize;
1859184610Salfred	mmask = uaudio_mixer_feature_get_bmaControls(d, 0);
1860184610Salfred	cmask = 0;
1861184610Salfred
1862184610Salfred	if (nchan == 0) {
1863184610Salfred		return;
1864184610Salfred	}
1865184610Salfred	/* figure out what we can control */
1866184610Salfred
1867184610Salfred	for (chan = 1; chan < nchan; chan++) {
1868184610Salfred		DPRINTFN(10, "chan=%d mask=%x\n",
1869184610Salfred		    chan, uaudio_mixer_feature_get_bmaControls(d, chan));
1870184610Salfred
1871184610Salfred		cmask |= uaudio_mixer_feature_get_bmaControls(d, chan);
1872184610Salfred	}
1873184610Salfred
1874184610Salfred	if (nchan > MIX_MAX_CHAN) {
1875184610Salfred		nchan = MIX_MAX_CHAN;
1876184610Salfred	}
1877184610Salfred	mix.wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no);
1878184610Salfred
1879184610Salfred	for (ctl = 1; ctl <= LOUDNESS_CONTROL; ctl++) {
1880184610Salfred
1881184610Salfred		fumask = FU_MASK(ctl);
1882184610Salfred
1883184610Salfred		DPRINTFN(5, "ctl=%d fumask=0x%04x\n",
1884184610Salfred		    ctl, fumask);
1885184610Salfred
1886184610Salfred		if (mmask & fumask) {
1887184610Salfred			mix.nchan = 1;
1888184610Salfred			mix.wValue[0] = MAKE_WORD(ctl, 0);
1889184610Salfred		} else if (cmask & fumask) {
1890184610Salfred			mix.nchan = nchan - 1;
1891184610Salfred			for (i = 1; i < nchan; i++) {
1892184610Salfred				if (uaudio_mixer_feature_get_bmaControls(d, i) & fumask)
1893184610Salfred					mix.wValue[i - 1] = MAKE_WORD(ctl, i);
1894184610Salfred				else
1895184610Salfred					mix.wValue[i - 1] = -1;
1896184610Salfred			}
1897184610Salfred		} else {
1898184610Salfred			continue;
1899184610Salfred		}
1900184610Salfred
1901184610Salfred		mixernumber = uaudio_mixer_feature_name(&iot[id], &mix);
1902184610Salfred
1903184610Salfred		switch (ctl) {
1904184610Salfred		case MUTE_CONTROL:
1905184610Salfred			mix.type = MIX_ON_OFF;
1906184610Salfred			mix.ctl = SOUND_MIXER_NRDEVICES;
1907184610Salfred			break;
1908184610Salfred
1909184610Salfred		case VOLUME_CONTROL:
1910184610Salfred			mix.type = MIX_SIGNED_16;
1911184610Salfred			mix.ctl = mixernumber;
1912184610Salfred			break;
1913184610Salfred
1914184610Salfred		case BASS_CONTROL:
1915184610Salfred			mix.type = MIX_SIGNED_8;
1916184610Salfred			mix.ctl = SOUND_MIXER_BASS;
1917184610Salfred			break;
1918184610Salfred
1919184610Salfred		case MID_CONTROL:
1920184610Salfred			mix.type = MIX_SIGNED_8;
1921184610Salfred			mix.ctl = SOUND_MIXER_NRDEVICES;	/* XXXXX */
1922184610Salfred			break;
1923184610Salfred
1924184610Salfred		case TREBLE_CONTROL:
1925184610Salfred			mix.type = MIX_SIGNED_8;
1926184610Salfred			mix.ctl = SOUND_MIXER_TREBLE;
1927184610Salfred			break;
1928184610Salfred
1929184610Salfred		case GRAPHIC_EQUALIZER_CONTROL:
1930184610Salfred			continue;	/* XXX don't add anything */
1931184610Salfred			break;
1932184610Salfred
1933184610Salfred		case AGC_CONTROL:
1934184610Salfred			mix.type = MIX_ON_OFF;
1935184610Salfred			mix.ctl = SOUND_MIXER_NRDEVICES;	/* XXXXX */
1936184610Salfred			break;
1937184610Salfred
1938184610Salfred		case DELAY_CONTROL:
1939184610Salfred			mix.type = MIX_UNSIGNED_16;
1940184610Salfred			mix.ctl = SOUND_MIXER_NRDEVICES;	/* XXXXX */
1941184610Salfred			break;
1942184610Salfred
1943184610Salfred		case BASS_BOOST_CONTROL:
1944184610Salfred			mix.type = MIX_ON_OFF;
1945184610Salfred			mix.ctl = SOUND_MIXER_NRDEVICES;	/* XXXXX */
1946184610Salfred			break;
1947184610Salfred
1948184610Salfred		case LOUDNESS_CONTROL:
1949184610Salfred			mix.type = MIX_ON_OFF;
1950184610Salfred			mix.ctl = SOUND_MIXER_LOUD;	/* Is this correct ? */
1951184610Salfred			break;
1952184610Salfred
1953184610Salfred		default:
1954184610Salfred			mix.type = MIX_UNKNOWN;
1955184610Salfred			break;
1956184610Salfred		}
1957184610Salfred
1958184610Salfred		if (mix.type != MIX_UNKNOWN) {
1959184610Salfred			uaudio_mixer_add_ctl(sc, &mix);
1960184610Salfred		}
1961184610Salfred	}
1962184610Salfred}
1963184610Salfred
1964184610Salfredstatic void
1965184610Salfreduaudio_mixer_add_processing_updown(struct uaudio_softc *sc,
1966184610Salfred    const struct uaudio_terminal_node *iot, int id)
1967184610Salfred{
1968203678Sbrucec	const struct usb_audio_processing_unit_0 *d0 = iot[id].u.pu;
1969203678Sbrucec	const struct usb_audio_processing_unit_1 *d1 =
1970184610Salfred	(const void *)(d0->baSourceId + d0->bNrInPins);
1971203678Sbrucec	const struct usb_audio_processing_unit_updown *ud =
1972184610Salfred	(const void *)(d1->bmControls + d1->bControlSize);
1973184610Salfred	struct uaudio_mixer_node mix;
1974184610Salfred	uint8_t i;
1975184610Salfred
1976184610Salfred	if (uaudio_mixer_verify_desc(d0, sizeof(*ud)) == NULL) {
1977184610Salfred		return;
1978184610Salfred	}
1979184610Salfred	if (uaudio_mixer_verify_desc(d0, sizeof(*ud) + (2 * ud->bNrModes))
1980184610Salfred	    == NULL) {
1981184610Salfred		return;
1982184610Salfred	}
1983184610Salfred	DPRINTFN(3, "bUnitId=%d bNrModes=%d\n",
1984184610Salfred	    d0->bUnitId, ud->bNrModes);
1985184610Salfred
1986184610Salfred	if (!(d1->bmControls[0] & UA_PROC_MASK(UD_MODE_SELECT_CONTROL))) {
1987184610Salfred		DPRINTF("no mode select\n");
1988184610Salfred		return;
1989184610Salfred	}
1990184610Salfred	bzero(&mix, sizeof(mix));
1991184610Salfred
1992184610Salfred	mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no);
1993184610Salfred	mix.nchan = 1;
1994184610Salfred	mix.wValue[0] = MAKE_WORD(UD_MODE_SELECT_CONTROL, 0);
1995184610Salfred	uaudio_mixer_determine_class(&iot[id], &mix);
1996184610Salfred	mix.type = MIX_ON_OFF;		/* XXX */
1997184610Salfred
1998184610Salfred	for (i = 0; i < ud->bNrModes; i++) {
1999184610Salfred		DPRINTFN(3, "i=%d bm=0x%x\n", i, UGETW(ud->waModes[i]));
2000184610Salfred		/* XXX */
2001184610Salfred	}
2002184610Salfred
2003184610Salfred	uaudio_mixer_add_ctl(sc, &mix);
2004184610Salfred}
2005184610Salfred
2006184610Salfredstatic void
2007184610Salfreduaudio_mixer_add_processing(struct uaudio_softc *sc,
2008184610Salfred    const struct uaudio_terminal_node *iot, int id)
2009184610Salfred{
2010203678Sbrucec	const struct usb_audio_processing_unit_0 *d0 = iot[id].u.pu;
2011203678Sbrucec	const struct usb_audio_processing_unit_1 *d1 =
2012184610Salfred	(const void *)(d0->baSourceId + d0->bNrInPins);
2013184610Salfred	struct uaudio_mixer_node mix;
2014184610Salfred	uint16_t ptype;
2015184610Salfred
2016184610Salfred	bzero(&mix, sizeof(mix));
2017184610Salfred
2018184610Salfred	ptype = UGETW(d0->wProcessType);
2019184610Salfred
2020184610Salfred	DPRINTFN(3, "wProcessType=%d bUnitId=%d "
2021184610Salfred	    "bNrInPins=%d\n", ptype, d0->bUnitId, d0->bNrInPins);
2022184610Salfred
2023184610Salfred	if (d1->bControlSize == 0) {
2024184610Salfred		return;
2025184610Salfred	}
2026184610Salfred	if (d1->bmControls[0] & UA_PROC_ENABLE_MASK) {
2027184610Salfred		mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no);
2028184610Salfred		mix.nchan = 1;
2029184610Salfred		mix.wValue[0] = MAKE_WORD(XX_ENABLE_CONTROL, 0);
2030184610Salfred		uaudio_mixer_determine_class(&iot[id], &mix);
2031184610Salfred		mix.type = MIX_ON_OFF;
2032184610Salfred		uaudio_mixer_add_ctl(sc, &mix);
2033184610Salfred	}
2034184610Salfred	switch (ptype) {
2035184610Salfred	case UPDOWNMIX_PROCESS:
2036184610Salfred		uaudio_mixer_add_processing_updown(sc, iot, id);
2037184610Salfred		break;
2038184610Salfred
2039184610Salfred	case DOLBY_PROLOGIC_PROCESS:
2040184610Salfred	case P3D_STEREO_EXTENDER_PROCESS:
2041184610Salfred	case REVERBATION_PROCESS:
2042184610Salfred	case CHORUS_PROCESS:
2043184610Salfred	case DYN_RANGE_COMP_PROCESS:
2044184610Salfred	default:
2045184610Salfred		DPRINTF("unit %d, type=%d is not implemented\n",
2046184610Salfred		    d0->bUnitId, ptype);
2047184610Salfred		break;
2048184610Salfred	}
2049184610Salfred}
2050184610Salfred
2051184610Salfredstatic void
2052184610Salfreduaudio_mixer_add_extension(struct uaudio_softc *sc,
2053184610Salfred    const struct uaudio_terminal_node *iot, int id)
2054184610Salfred{
2055203678Sbrucec	const struct usb_audio_extension_unit_0 *d0 = iot[id].u.eu;
2056203678Sbrucec	const struct usb_audio_extension_unit_1 *d1 =
2057184610Salfred	(const void *)(d0->baSourceId + d0->bNrInPins);
2058184610Salfred	struct uaudio_mixer_node mix;
2059184610Salfred
2060184610Salfred	DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n",
2061184610Salfred	    d0->bUnitId, d0->bNrInPins);
2062184610Salfred
2063184610Salfred	if (sc->sc_uq_au_no_xu) {
2064184610Salfred		return;
2065184610Salfred	}
2066184610Salfred	if (d1->bControlSize == 0) {
2067184610Salfred		return;
2068184610Salfred	}
2069184610Salfred	if (d1->bmControls[0] & UA_EXT_ENABLE_MASK) {
2070184610Salfred
2071184610Salfred		bzero(&mix, sizeof(mix));
2072184610Salfred
2073184610Salfred		mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no);
2074184610Salfred		mix.nchan = 1;
2075184610Salfred		mix.wValue[0] = MAKE_WORD(UA_EXT_ENABLE, 0);
2076184610Salfred		uaudio_mixer_determine_class(&iot[id], &mix);
2077184610Salfred		mix.type = MIX_ON_OFF;
2078184610Salfred
2079184610Salfred		uaudio_mixer_add_ctl(sc, &mix);
2080184610Salfred	}
2081184610Salfred}
2082184610Salfred
2083184610Salfredstatic const void *
2084184610Salfreduaudio_mixer_verify_desc(const void *arg, uint32_t len)
2085184610Salfred{
2086203678Sbrucec	const struct usb_audio_mixer_unit_1 *d1;
2087203678Sbrucec	const struct usb_audio_extension_unit_1 *e1;
2088203678Sbrucec	const struct usb_audio_processing_unit_1 *u1;
2089184610Salfred
2090184610Salfred	union {
2091192984Sthompsa		const struct usb_descriptor *desc;
2092203678Sbrucec		const struct usb_audio_input_terminal *it;
2093203678Sbrucec		const struct usb_audio_output_terminal *ot;
2094203678Sbrucec		const struct usb_audio_mixer_unit_0 *mu;
2095203678Sbrucec		const struct usb_audio_selector_unit *su;
2096203678Sbrucec		const struct usb_audio_feature_unit *fu;
2097203678Sbrucec		const struct usb_audio_processing_unit_0 *pu;
2098203678Sbrucec		const struct usb_audio_extension_unit_0 *eu;
2099184610Salfred	}     u;
2100184610Salfred
2101184610Salfred	u.desc = arg;
2102184610Salfred
2103184610Salfred	if (u.desc == NULL) {
2104184610Salfred		goto error;
2105184610Salfred	}
2106184610Salfred	if (u.desc->bDescriptorType != UDESC_CS_INTERFACE) {
2107184610Salfred		goto error;
2108184610Salfred	}
2109184610Salfred	switch (u.desc->bDescriptorSubtype) {
2110184610Salfred	case UDESCSUB_AC_INPUT:
2111184610Salfred		len += sizeof(*u.it);
2112184610Salfred		break;
2113184610Salfred
2114184610Salfred	case UDESCSUB_AC_OUTPUT:
2115184610Salfred		len += sizeof(*u.ot);
2116184610Salfred		break;
2117184610Salfred
2118184610Salfred	case UDESCSUB_AC_MIXER:
2119184610Salfred		len += sizeof(*u.mu);
2120184610Salfred
2121184610Salfred		if (u.desc->bLength < len) {
2122184610Salfred			goto error;
2123184610Salfred		}
2124184610Salfred		len += u.mu->bNrInPins;
2125184610Salfred
2126184610Salfred		if (u.desc->bLength < len) {
2127184610Salfred			goto error;
2128184610Salfred		}
2129184610Salfred		d1 = (const void *)(u.mu->baSourceId + u.mu->bNrInPins);
2130184610Salfred
2131184610Salfred		len += sizeof(*d1);
2132184610Salfred		break;
2133184610Salfred
2134184610Salfred	case UDESCSUB_AC_SELECTOR:
2135184610Salfred		len += sizeof(*u.su);
2136184610Salfred
2137184610Salfred		if (u.desc->bLength < len) {
2138184610Salfred			goto error;
2139184610Salfred		}
2140184610Salfred		len += u.su->bNrInPins;
2141184610Salfred		break;
2142184610Salfred
2143184610Salfred	case UDESCSUB_AC_FEATURE:
2144184610Salfred		len += (sizeof(*u.fu) + 1);
2145184610Salfred		break;
2146184610Salfred
2147184610Salfred	case UDESCSUB_AC_PROCESSING:
2148184610Salfred		len += sizeof(*u.pu);
2149184610Salfred
2150184610Salfred		if (u.desc->bLength < len) {
2151184610Salfred			goto error;
2152184610Salfred		}
2153184610Salfred		len += u.pu->bNrInPins;
2154184610Salfred
2155184610Salfred		if (u.desc->bLength < len) {
2156184610Salfred			goto error;
2157184610Salfred		}
2158184610Salfred		u1 = (const void *)(u.pu->baSourceId + u.pu->bNrInPins);
2159184610Salfred
2160184610Salfred		len += sizeof(*u1);
2161184610Salfred
2162184610Salfred		if (u.desc->bLength < len) {
2163184610Salfred			goto error;
2164184610Salfred		}
2165184610Salfred		len += u1->bControlSize;
2166184610Salfred
2167184610Salfred		break;
2168184610Salfred
2169184610Salfred	case UDESCSUB_AC_EXTENSION:
2170184610Salfred		len += sizeof(*u.eu);
2171184610Salfred
2172184610Salfred		if (u.desc->bLength < len) {
2173184610Salfred			goto error;
2174184610Salfred		}
2175184610Salfred		len += u.eu->bNrInPins;
2176184610Salfred
2177184610Salfred		if (u.desc->bLength < len) {
2178184610Salfred			goto error;
2179184610Salfred		}
2180184610Salfred		e1 = (const void *)(u.eu->baSourceId + u.eu->bNrInPins);
2181184610Salfred
2182184610Salfred		len += sizeof(*e1);
2183184610Salfred
2184184610Salfred		if (u.desc->bLength < len) {
2185184610Salfred			goto error;
2186184610Salfred		}
2187184610Salfred		len += e1->bControlSize;
2188184610Salfred		break;
2189184610Salfred
2190184610Salfred	default:
2191184610Salfred		goto error;
2192184610Salfred	}
2193184610Salfred
2194184610Salfred	if (u.desc->bLength < len) {
2195184610Salfred		goto error;
2196184610Salfred	}
2197184610Salfred	return (u.desc);
2198184610Salfred
2199184610Salfrederror:
2200184610Salfred	if (u.desc) {
2201184610Salfred		DPRINTF("invalid descriptor, type=%d, "
2202184610Salfred		    "sub_type=%d, len=%d of %d bytes\n",
2203184610Salfred		    u.desc->bDescriptorType,
2204184610Salfred		    u.desc->bDescriptorSubtype,
2205184610Salfred		    u.desc->bLength, len);
2206184610Salfred	}
2207184610Salfred	return (NULL);
2208184610Salfred}
2209184610Salfred
2210207077Sthompsa#ifdef USB_DEBUG
2211184610Salfredstatic void
2212184610Salfreduaudio_mixer_dump_cluster(uint8_t id, const struct uaudio_terminal_node *iot)
2213184610Salfred{
2214184610Salfred	static const char *channel_names[16] = {
2215184610Salfred		"LEFT", "RIGHT", "CENTER", "LFE",
2216184610Salfred		"LEFT_SURROUND", "RIGHT_SURROUND", "LEFT_CENTER", "RIGHT_CENTER",
2217184610Salfred		"SURROUND", "LEFT_SIDE", "RIGHT_SIDE", "TOP",
2218184610Salfred		"RESERVED12", "RESERVED13", "RESERVED14", "RESERVED15",
2219184610Salfred	};
2220184610Salfred	uint16_t cc;
2221184610Salfred	uint8_t i;
2222203678Sbrucec	const struct usb_audio_cluster cl = uaudio_mixer_get_cluster(id, iot);
2223184610Salfred
2224184610Salfred	cc = UGETW(cl.wChannelConfig);
2225184610Salfred
2226184610Salfred	DPRINTF("cluster: bNrChannels=%u iChannelNames=%u wChannelConfig="
2227184610Salfred	    "0x%04x:\n", cl.iChannelNames, cl.bNrChannels, cc);
2228184610Salfred
2229184610Salfred	for (i = 0; cc; i++) {
2230184610Salfred		if (cc & 1) {
2231184610Salfred			DPRINTF(" - %s\n", channel_names[i]);
2232184610Salfred		}
2233184610Salfred		cc >>= 1;
2234184610Salfred	}
2235184610Salfred}
2236184610Salfred
2237184610Salfred#endif
2238184610Salfred
2239203678Sbrucecstatic struct usb_audio_cluster
2240184610Salfreduaudio_mixer_get_cluster(uint8_t id, const struct uaudio_terminal_node *iot)
2241184610Salfred{
2242203678Sbrucec	struct usb_audio_cluster r;
2243192984Sthompsa	const struct usb_descriptor *dp;
2244184610Salfred	uint8_t i;
2245184610Salfred
2246184610Salfred	for (i = 0; i < UAUDIO_RECURSE_LIMIT; i++) {	/* avoid infinite loops */
2247184610Salfred		dp = iot[id].u.desc;
2248184610Salfred		if (dp == NULL) {
2249184610Salfred			goto error;
2250184610Salfred		}
2251184610Salfred		switch (dp->bDescriptorSubtype) {
2252184610Salfred		case UDESCSUB_AC_INPUT:
2253184610Salfred			r.bNrChannels = iot[id].u.it->bNrChannels;
2254184610Salfred			r.wChannelConfig[0] = iot[id].u.it->wChannelConfig[0];
2255184610Salfred			r.wChannelConfig[1] = iot[id].u.it->wChannelConfig[1];
2256184610Salfred			r.iChannelNames = iot[id].u.it->iChannelNames;
2257184610Salfred			goto done;
2258184610Salfred
2259184610Salfred		case UDESCSUB_AC_OUTPUT:
2260184610Salfred			id = iot[id].u.ot->bSourceId;
2261184610Salfred			break;
2262184610Salfred
2263184610Salfred		case UDESCSUB_AC_MIXER:
2264203678Sbrucec			r = *(const struct usb_audio_cluster *)
2265184610Salfred			    &iot[id].u.mu->baSourceId[iot[id].u.mu->
2266184610Salfred			    bNrInPins];
2267184610Salfred			goto done;
2268184610Salfred
2269184610Salfred		case UDESCSUB_AC_SELECTOR:
2270184610Salfred			if (iot[id].u.su->bNrInPins > 0) {
2271184610Salfred				/* XXX This is not really right */
2272184610Salfred				id = iot[id].u.su->baSourceId[0];
2273184610Salfred			}
2274184610Salfred			break;
2275184610Salfred
2276184610Salfred		case UDESCSUB_AC_FEATURE:
2277184610Salfred			id = iot[id].u.fu->bSourceId;
2278184610Salfred			break;
2279184610Salfred
2280184610Salfred		case UDESCSUB_AC_PROCESSING:
2281203678Sbrucec			r = *((const struct usb_audio_cluster *)
2282184610Salfred			    &iot[id].u.pu->baSourceId[iot[id].u.pu->
2283184610Salfred			    bNrInPins]);
2284184610Salfred			goto done;
2285184610Salfred
2286184610Salfred		case UDESCSUB_AC_EXTENSION:
2287203678Sbrucec			r = *((const struct usb_audio_cluster *)
2288184610Salfred			    &iot[id].u.eu->baSourceId[iot[id].u.eu->
2289184610Salfred			    bNrInPins]);
2290184610Salfred			goto done;
2291184610Salfred
2292184610Salfred		default:
2293184610Salfred			goto error;
2294184610Salfred		}
2295184610Salfred	}
2296184610Salfrederror:
2297184610Salfred	DPRINTF("bad data\n");
2298184610Salfred	bzero(&r, sizeof(r));
2299184610Salfreddone:
2300184610Salfred	return (r);
2301184610Salfred}
2302184610Salfred
2303207077Sthompsa#ifdef USB_DEBUG
2304184610Salfred
2305184610Salfredstruct uaudio_tt_to_string {
2306184610Salfred	uint16_t terminal_type;
2307184610Salfred	const char *desc;
2308184610Salfred};
2309184610Salfred
2310184610Salfredstatic const struct uaudio_tt_to_string uaudio_tt_to_string[] = {
2311184610Salfred
2312184610Salfred	/* USB terminal types */
2313184610Salfred	{UAT_UNDEFINED, "UAT_UNDEFINED"},
2314184610Salfred	{UAT_STREAM, "UAT_STREAM"},
2315184610Salfred	{UAT_VENDOR, "UAT_VENDOR"},
2316184610Salfred
2317184610Salfred	/* input terminal types */
2318184610Salfred	{UATI_UNDEFINED, "UATI_UNDEFINED"},
2319184610Salfred	{UATI_MICROPHONE, "UATI_MICROPHONE"},
2320184610Salfred	{UATI_DESKMICROPHONE, "UATI_DESKMICROPHONE"},
2321184610Salfred	{UATI_PERSONALMICROPHONE, "UATI_PERSONALMICROPHONE"},
2322184610Salfred	{UATI_OMNIMICROPHONE, "UATI_OMNIMICROPHONE"},
2323184610Salfred	{UATI_MICROPHONEARRAY, "UATI_MICROPHONEARRAY"},
2324184610Salfred	{UATI_PROCMICROPHONEARR, "UATI_PROCMICROPHONEARR"},
2325184610Salfred
2326184610Salfred	/* output terminal types */
2327184610Salfred	{UATO_UNDEFINED, "UATO_UNDEFINED"},
2328184610Salfred	{UATO_SPEAKER, "UATO_SPEAKER"},
2329184610Salfred	{UATO_HEADPHONES, "UATO_HEADPHONES"},
2330184610Salfred	{UATO_DISPLAYAUDIO, "UATO_DISPLAYAUDIO"},
2331184610Salfred	{UATO_DESKTOPSPEAKER, "UATO_DESKTOPSPEAKER"},
2332184610Salfred	{UATO_ROOMSPEAKER, "UATO_ROOMSPEAKER"},
2333184610Salfred	{UATO_COMMSPEAKER, "UATO_COMMSPEAKER"},
2334184610Salfred	{UATO_SUBWOOFER, "UATO_SUBWOOFER"},
2335184610Salfred
2336184610Salfred	/* bidir terminal types */
2337184610Salfred	{UATB_UNDEFINED, "UATB_UNDEFINED"},
2338184610Salfred	{UATB_HANDSET, "UATB_HANDSET"},
2339184610Salfred	{UATB_HEADSET, "UATB_HEADSET"},
2340184610Salfred	{UATB_SPEAKERPHONE, "UATB_SPEAKERPHONE"},
2341184610Salfred	{UATB_SPEAKERPHONEESUP, "UATB_SPEAKERPHONEESUP"},
2342184610Salfred	{UATB_SPEAKERPHONEECANC, "UATB_SPEAKERPHONEECANC"},
2343184610Salfred
2344184610Salfred	/* telephony terminal types */
2345184610Salfred	{UATT_UNDEFINED, "UATT_UNDEFINED"},
2346184610Salfred	{UATT_PHONELINE, "UATT_PHONELINE"},
2347184610Salfred	{UATT_TELEPHONE, "UATT_TELEPHONE"},
2348184610Salfred	{UATT_DOWNLINEPHONE, "UATT_DOWNLINEPHONE"},
2349184610Salfred
2350184610Salfred	/* external terminal types */
2351184610Salfred	{UATE_UNDEFINED, "UATE_UNDEFINED"},
2352184610Salfred	{UATE_ANALOGCONN, "UATE_ANALOGCONN"},
2353184610Salfred	{UATE_LINECONN, "UATE_LINECONN"},
2354184610Salfred	{UATE_LEGACYCONN, "UATE_LEGACYCONN"},
2355184610Salfred	{UATE_DIGITALAUIFC, "UATE_DIGITALAUIFC"},
2356184610Salfred	{UATE_SPDIF, "UATE_SPDIF"},
2357184610Salfred	{UATE_1394DA, "UATE_1394DA"},
2358184610Salfred	{UATE_1394DV, "UATE_1394DV"},
2359184610Salfred
2360184610Salfred	/* embedded function terminal types */
2361184610Salfred	{UATF_UNDEFINED, "UATF_UNDEFINED"},
2362184610Salfred	{UATF_CALIBNOISE, "UATF_CALIBNOISE"},
2363184610Salfred	{UATF_EQUNOISE, "UATF_EQUNOISE"},
2364184610Salfred	{UATF_CDPLAYER, "UATF_CDPLAYER"},
2365184610Salfred	{UATF_DAT, "UATF_DAT"},
2366184610Salfred	{UATF_DCC, "UATF_DCC"},
2367184610Salfred	{UATF_MINIDISK, "UATF_MINIDISK"},
2368184610Salfred	{UATF_ANALOGTAPE, "UATF_ANALOGTAPE"},
2369184610Salfred	{UATF_PHONOGRAPH, "UATF_PHONOGRAPH"},
2370184610Salfred	{UATF_VCRAUDIO, "UATF_VCRAUDIO"},
2371184610Salfred	{UATF_VIDEODISCAUDIO, "UATF_VIDEODISCAUDIO"},
2372184610Salfred	{UATF_DVDAUDIO, "UATF_DVDAUDIO"},
2373184610Salfred	{UATF_TVTUNERAUDIO, "UATF_TVTUNERAUDIO"},
2374184610Salfred	{UATF_SATELLITE, "UATF_SATELLITE"},
2375184610Salfred	{UATF_CABLETUNER, "UATF_CABLETUNER"},
2376184610Salfred	{UATF_DSS, "UATF_DSS"},
2377184610Salfred	{UATF_RADIORECV, "UATF_RADIORECV"},
2378184610Salfred	{UATF_RADIOXMIT, "UATF_RADIOXMIT"},
2379184610Salfred	{UATF_MULTITRACK, "UATF_MULTITRACK"},
2380184610Salfred	{UATF_SYNTHESIZER, "UATF_SYNTHESIZER"},
2381184610Salfred
2382184610Salfred	/* unknown */
2383184610Salfred	{0x0000, "UNKNOWN"},
2384184610Salfred};
2385184610Salfred
2386184610Salfredstatic const char *
2387184610Salfreduaudio_mixer_get_terminal_name(uint16_t terminal_type)
2388184610Salfred{
2389184610Salfred	const struct uaudio_tt_to_string *uat = uaudio_tt_to_string;
2390184610Salfred
2391184610Salfred	while (uat->terminal_type) {
2392184610Salfred		if (uat->terminal_type == terminal_type) {
2393184610Salfred			break;
2394184610Salfred		}
2395184610Salfred		uat++;
2396184610Salfred	}
2397184610Salfred	if (uat->terminal_type == 0) {
2398184610Salfred		DPRINTF("unknown terminal type (0x%04x)", terminal_type);
2399184610Salfred	}
2400184610Salfred	return (uat->desc);
2401184610Salfred}
2402184610Salfred
2403184610Salfred#endif
2404184610Salfred
2405184610Salfredstatic uint16_t
2406184610Salfreduaudio_mixer_determine_class(const struct uaudio_terminal_node *iot,
2407184610Salfred    struct uaudio_mixer_node *mix)
2408184610Salfred{
2409184610Salfred	uint16_t terminal_type = 0x0000;
2410184610Salfred	const struct uaudio_terminal_node *input[2];
2411184610Salfred	const struct uaudio_terminal_node *output[2];
2412184610Salfred
2413184610Salfred	input[0] = uaudio_mixer_get_input(iot, 0);
2414184610Salfred	input[1] = uaudio_mixer_get_input(iot, 1);
2415184610Salfred
2416184610Salfred	output[0] = uaudio_mixer_get_output(iot, 0);
2417184610Salfred	output[1] = uaudio_mixer_get_output(iot, 1);
2418184610Salfred
2419184610Salfred	/*
2420184610Salfred	 * check if there is only
2421184610Salfred	 * one output terminal:
2422184610Salfred	 */
2423184610Salfred	if (output[0] && (!output[1])) {
2424184610Salfred		terminal_type = UGETW(output[0]->u.ot->wTerminalType);
2425184610Salfred	}
2426184610Salfred	/*
2427184610Salfred	 * If the only output terminal is USB,
2428184610Salfred	 * the class is UAC_RECORD.
2429184610Salfred	 */
2430184610Salfred	if ((terminal_type & 0xff00) == (UAT_UNDEFINED & 0xff00)) {
2431184610Salfred
2432184610Salfred		mix->class = UAC_RECORD;
2433184610Salfred		if (input[0] && (!input[1])) {
2434184610Salfred			terminal_type = UGETW(input[0]->u.it->wTerminalType);
2435184610Salfred		} else {
2436184610Salfred			terminal_type = 0;
2437184610Salfred		}
2438184610Salfred		goto done;
2439184610Salfred	}
2440184610Salfred	/*
2441184610Salfred	 * if the unit is connected to just
2442184610Salfred	 * one input terminal, the
2443184610Salfred	 * class is UAC_INPUT:
2444184610Salfred	 */
2445184610Salfred	if (input[0] && (!input[1])) {
2446184610Salfred		mix->class = UAC_INPUT;
2447184610Salfred		terminal_type = UGETW(input[0]->u.it->wTerminalType);
2448184610Salfred		goto done;
2449184610Salfred	}
2450184610Salfred	/*
2451184610Salfred	 * Otherwise, the class is UAC_OUTPUT.
2452184610Salfred	 */
2453184610Salfred	mix->class = UAC_OUTPUT;
2454184610Salfreddone:
2455184610Salfred	return (terminal_type);
2456184610Salfred}
2457184610Salfred
2458184610Salfredstruct uaudio_tt_to_feature {
2459184610Salfred	uint16_t terminal_type;
2460184610Salfred	uint16_t feature;
2461184610Salfred};
2462184610Salfred
2463184610Salfredstatic const struct uaudio_tt_to_feature uaudio_tt_to_feature[] = {
2464184610Salfred
2465184610Salfred	{UAT_STREAM, SOUND_MIXER_PCM},
2466184610Salfred
2467184610Salfred	{UATI_MICROPHONE, SOUND_MIXER_MIC},
2468184610Salfred	{UATI_DESKMICROPHONE, SOUND_MIXER_MIC},
2469184610Salfred	{UATI_PERSONALMICROPHONE, SOUND_MIXER_MIC},
2470184610Salfred	{UATI_OMNIMICROPHONE, SOUND_MIXER_MIC},
2471184610Salfred	{UATI_MICROPHONEARRAY, SOUND_MIXER_MIC},
2472184610Salfred	{UATI_PROCMICROPHONEARR, SOUND_MIXER_MIC},
2473184610Salfred
2474184610Salfred	{UATO_SPEAKER, SOUND_MIXER_SPEAKER},
2475184610Salfred	{UATO_DESKTOPSPEAKER, SOUND_MIXER_SPEAKER},
2476184610Salfred	{UATO_ROOMSPEAKER, SOUND_MIXER_SPEAKER},
2477184610Salfred	{UATO_COMMSPEAKER, SOUND_MIXER_SPEAKER},
2478184610Salfred
2479184610Salfred	{UATE_ANALOGCONN, SOUND_MIXER_LINE},
2480184610Salfred	{UATE_LINECONN, SOUND_MIXER_LINE},
2481184610Salfred	{UATE_LEGACYCONN, SOUND_MIXER_LINE},
2482184610Salfred
2483184610Salfred	{UATE_DIGITALAUIFC, SOUND_MIXER_ALTPCM},
2484184610Salfred	{UATE_SPDIF, SOUND_MIXER_ALTPCM},
2485184610Salfred	{UATE_1394DA, SOUND_MIXER_ALTPCM},
2486184610Salfred	{UATE_1394DV, SOUND_MIXER_ALTPCM},
2487184610Salfred
2488184610Salfred	{UATF_CDPLAYER, SOUND_MIXER_CD},
2489184610Salfred
2490184610Salfred	{UATF_SYNTHESIZER, SOUND_MIXER_SYNTH},
2491184610Salfred
2492184610Salfred	{UATF_VIDEODISCAUDIO, SOUND_MIXER_VIDEO},
2493184610Salfred	{UATF_DVDAUDIO, SOUND_MIXER_VIDEO},
2494184610Salfred	{UATF_TVTUNERAUDIO, SOUND_MIXER_VIDEO},
2495184610Salfred
2496184610Salfred	/* telephony terminal types */
2497184610Salfred	{UATT_UNDEFINED, SOUND_MIXER_PHONEIN},	/* SOUND_MIXER_PHONEOUT */
2498184610Salfred	{UATT_PHONELINE, SOUND_MIXER_PHONEIN},	/* SOUND_MIXER_PHONEOUT */
2499184610Salfred	{UATT_TELEPHONE, SOUND_MIXER_PHONEIN},	/* SOUND_MIXER_PHONEOUT */
2500184610Salfred	{UATT_DOWNLINEPHONE, SOUND_MIXER_PHONEIN},	/* SOUND_MIXER_PHONEOUT */
2501184610Salfred
2502184610Salfred	{UATF_RADIORECV, SOUND_MIXER_RADIO},
2503184610Salfred	{UATF_RADIOXMIT, SOUND_MIXER_RADIO},
2504184610Salfred
2505184610Salfred	{UAT_UNDEFINED, SOUND_MIXER_VOLUME},
2506184610Salfred	{UAT_VENDOR, SOUND_MIXER_VOLUME},
2507184610Salfred	{UATI_UNDEFINED, SOUND_MIXER_VOLUME},
2508184610Salfred
2509184610Salfred	/* output terminal types */
2510184610Salfred	{UATO_UNDEFINED, SOUND_MIXER_VOLUME},
2511184610Salfred	{UATO_DISPLAYAUDIO, SOUND_MIXER_VOLUME},
2512184610Salfred	{UATO_SUBWOOFER, SOUND_MIXER_VOLUME},
2513184610Salfred	{UATO_HEADPHONES, SOUND_MIXER_VOLUME},
2514184610Salfred
2515184610Salfred	/* bidir terminal types */
2516184610Salfred	{UATB_UNDEFINED, SOUND_MIXER_VOLUME},
2517184610Salfred	{UATB_HANDSET, SOUND_MIXER_VOLUME},
2518184610Salfred	{UATB_HEADSET, SOUND_MIXER_VOLUME},
2519184610Salfred	{UATB_SPEAKERPHONE, SOUND_MIXER_VOLUME},
2520184610Salfred	{UATB_SPEAKERPHONEESUP, SOUND_MIXER_VOLUME},
2521184610Salfred	{UATB_SPEAKERPHONEECANC, SOUND_MIXER_VOLUME},
2522184610Salfred
2523184610Salfred	/* external terminal types */
2524184610Salfred	{UATE_UNDEFINED, SOUND_MIXER_VOLUME},
2525184610Salfred
2526184610Salfred	/* embedded function terminal types */
2527184610Salfred	{UATF_UNDEFINED, SOUND_MIXER_VOLUME},
2528184610Salfred	{UATF_CALIBNOISE, SOUND_MIXER_VOLUME},
2529184610Salfred	{UATF_EQUNOISE, SOUND_MIXER_VOLUME},
2530184610Salfred	{UATF_DAT, SOUND_MIXER_VOLUME},
2531184610Salfred	{UATF_DCC, SOUND_MIXER_VOLUME},
2532184610Salfred	{UATF_MINIDISK, SOUND_MIXER_VOLUME},
2533184610Salfred	{UATF_ANALOGTAPE, SOUND_MIXER_VOLUME},
2534184610Salfred	{UATF_PHONOGRAPH, SOUND_MIXER_VOLUME},
2535184610Salfred	{UATF_VCRAUDIO, SOUND_MIXER_VOLUME},
2536184610Salfred	{UATF_SATELLITE, SOUND_MIXER_VOLUME},
2537184610Salfred	{UATF_CABLETUNER, SOUND_MIXER_VOLUME},
2538184610Salfred	{UATF_DSS, SOUND_MIXER_VOLUME},
2539184610Salfred	{UATF_MULTITRACK, SOUND_MIXER_VOLUME},
2540184610Salfred	{0xffff, SOUND_MIXER_VOLUME},
2541184610Salfred
2542184610Salfred	/* default */
2543184610Salfred	{0x0000, SOUND_MIXER_VOLUME},
2544184610Salfred};
2545184610Salfred
2546184610Salfredstatic uint16_t
2547184610Salfreduaudio_mixer_feature_name(const struct uaudio_terminal_node *iot,
2548184610Salfred    struct uaudio_mixer_node *mix)
2549184610Salfred{
2550184610Salfred	const struct uaudio_tt_to_feature *uat = uaudio_tt_to_feature;
2551184610Salfred	uint16_t terminal_type = uaudio_mixer_determine_class(iot, mix);
2552184610Salfred
2553184610Salfred	if ((mix->class == UAC_RECORD) && (terminal_type == 0)) {
2554184610Salfred		return (SOUND_MIXER_IMIX);
2555184610Salfred	}
2556184610Salfred	while (uat->terminal_type) {
2557184610Salfred		if (uat->terminal_type == terminal_type) {
2558184610Salfred			break;
2559184610Salfred		}
2560184610Salfred		uat++;
2561184610Salfred	}
2562184610Salfred
2563184610Salfred	DPRINTF("terminal_type=%s (0x%04x) -> %d\n",
2564184610Salfred	    uaudio_mixer_get_terminal_name(terminal_type),
2565184610Salfred	    terminal_type, uat->feature);
2566184610Salfred
2567184610Salfred	return (uat->feature);
2568184610Salfred}
2569184610Salfred
2570184610Salfredconst static struct uaudio_terminal_node *
2571184610Salfreduaudio_mixer_get_input(const struct uaudio_terminal_node *iot, uint8_t index)
2572184610Salfred{
2573184610Salfred	struct uaudio_terminal_node *root = iot->root;
2574184610Salfred	uint8_t n;
2575184610Salfred
2576184610Salfred	n = iot->usr.id_max;
2577184610Salfred	do {
2578184610Salfred		if (iot->usr.bit_input[n / 8] & (1 << (n % 8))) {
2579184610Salfred			if (!index--) {
2580184610Salfred				return (root + n);
2581184610Salfred			}
2582184610Salfred		}
2583184610Salfred	} while (n--);
2584184610Salfred
2585184610Salfred	return (NULL);
2586184610Salfred}
2587184610Salfred
2588184610Salfredconst static struct uaudio_terminal_node *
2589184610Salfreduaudio_mixer_get_output(const struct uaudio_terminal_node *iot, uint8_t index)
2590184610Salfred{
2591184610Salfred	struct uaudio_terminal_node *root = iot->root;
2592184610Salfred	uint8_t n;
2593184610Salfred
2594184610Salfred	n = iot->usr.id_max;
2595184610Salfred	do {
2596184610Salfred		if (iot->usr.bit_output[n / 8] & (1 << (n % 8))) {
2597184610Salfred			if (!index--) {
2598184610Salfred				return (root + n);
2599184610Salfred			}
2600184610Salfred		}
2601184610Salfred	} while (n--);
2602184610Salfred
2603184610Salfred	return (NULL);
2604184610Salfred}
2605184610Salfred
2606184610Salfredstatic void
2607184610Salfreduaudio_mixer_find_inputs_sub(struct uaudio_terminal_node *root,
2608184610Salfred    const uint8_t *p_id, uint8_t n_id,
2609184610Salfred    struct uaudio_search_result *info)
2610184610Salfred{
2611184610Salfred	struct uaudio_terminal_node *iot;
2612184610Salfred	uint8_t n;
2613184610Salfred	uint8_t i;
2614184610Salfred
2615184610Salfred	if (info->recurse_level >= UAUDIO_RECURSE_LIMIT) {
2616184610Salfred		return;
2617184610Salfred	}
2618184610Salfred	info->recurse_level++;
2619184610Salfred
2620184610Salfred	for (n = 0; n < n_id; n++) {
2621184610Salfred
2622184610Salfred		i = p_id[n];
2623184610Salfred
2624184610Salfred		if (info->bit_visited[i / 8] & (1 << (i % 8))) {
2625184610Salfred			/* don't go into a circle */
2626184610Salfred			DPRINTF("avoided going into a circle at id=%d!\n", i);
2627184610Salfred			continue;
2628184610Salfred		} else {
2629184610Salfred			info->bit_visited[i / 8] |= (1 << (i % 8));
2630184610Salfred		}
2631184610Salfred
2632184610Salfred		iot = (root + i);
2633184610Salfred
2634184610Salfred		if (iot->u.desc == NULL) {
2635184610Salfred			continue;
2636184610Salfred		}
2637184610Salfred		switch (iot->u.desc->bDescriptorSubtype) {
2638184610Salfred		case UDESCSUB_AC_INPUT:
2639184610Salfred			info->bit_input[i / 8] |= (1 << (i % 8));
2640184610Salfred			break;
2641184610Salfred
2642184610Salfred		case UDESCSUB_AC_FEATURE:
2643184610Salfred			uaudio_mixer_find_inputs_sub
2644184610Salfred			    (root, &iot->u.fu->bSourceId, 1, info);
2645184610Salfred			break;
2646184610Salfred
2647184610Salfred		case UDESCSUB_AC_OUTPUT:
2648184610Salfred			uaudio_mixer_find_inputs_sub
2649184610Salfred			    (root, &iot->u.ot->bSourceId, 1, info);
2650184610Salfred			break;
2651184610Salfred
2652184610Salfred		case UDESCSUB_AC_MIXER:
2653184610Salfred			uaudio_mixer_find_inputs_sub
2654184610Salfred			    (root, iot->u.mu->baSourceId,
2655184610Salfred			    iot->u.mu->bNrInPins, info);
2656184610Salfred			break;
2657184610Salfred
2658184610Salfred		case UDESCSUB_AC_SELECTOR:
2659184610Salfred			uaudio_mixer_find_inputs_sub
2660184610Salfred			    (root, iot->u.su->baSourceId,
2661184610Salfred			    iot->u.su->bNrInPins, info);
2662184610Salfred			break;
2663184610Salfred
2664184610Salfred		case UDESCSUB_AC_PROCESSING:
2665184610Salfred			uaudio_mixer_find_inputs_sub
2666184610Salfred			    (root, iot->u.pu->baSourceId,
2667184610Salfred			    iot->u.pu->bNrInPins, info);
2668184610Salfred			break;
2669184610Salfred
2670184610Salfred		case UDESCSUB_AC_EXTENSION:
2671184610Salfred			uaudio_mixer_find_inputs_sub
2672184610Salfred			    (root, iot->u.eu->baSourceId,
2673184610Salfred			    iot->u.eu->bNrInPins, info);
2674184610Salfred			break;
2675184610Salfred
2676184610Salfred		case UDESCSUB_AC_HEADER:
2677184610Salfred		default:
2678184610Salfred			break;
2679184610Salfred		}
2680184610Salfred	}
2681184610Salfred	info->recurse_level--;
2682184610Salfred}
2683184610Salfred
2684184610Salfredstatic void
2685184610Salfreduaudio_mixer_find_outputs_sub(struct uaudio_terminal_node *root, uint8_t id,
2686184610Salfred    uint8_t n_id, struct uaudio_search_result *info)
2687184610Salfred{
2688184610Salfred	struct uaudio_terminal_node *iot = (root + id);
2689184610Salfred	uint8_t j;
2690184610Salfred
2691184610Salfred	j = n_id;
2692184610Salfred	do {
2693184610Salfred		if ((j != id) && ((root + j)->u.desc) &&
2694184610Salfred		    ((root + j)->u.desc->bDescriptorSubtype == UDESCSUB_AC_OUTPUT)) {
2695184610Salfred
2696184610Salfred			/*
2697184610Salfred			 * "j" (output) <--- virtual wire <--- "id" (input)
2698184610Salfred			 *
2699184610Salfred			 * if "j" has "id" on the input, then "id" have "j" on
2700184610Salfred			 * the output, because they are connected:
2701184610Salfred			 */
2702184610Salfred			if ((root + j)->usr.bit_input[id / 8] & (1 << (id % 8))) {
2703184610Salfred				iot->usr.bit_output[j / 8] |= (1 << (j % 8));
2704184610Salfred			}
2705184610Salfred		}
2706184610Salfred	} while (j--);
2707184610Salfred}
2708184610Salfred
2709184610Salfredstatic void
2710192984Sthompsauaudio_mixer_fill_info(struct uaudio_softc *sc, struct usb_device *udev,
2711184610Salfred    void *desc)
2712184610Salfred{
2713203678Sbrucec	const struct usb_audio_control_descriptor *acdp;
2714194228Sthompsa	struct usb_config_descriptor *cd = usbd_get_config_descriptor(udev);
2715192984Sthompsa	const struct usb_descriptor *dp;
2716203678Sbrucec	const struct usb_audio_unit *au;
2717184610Salfred	struct uaudio_terminal_node *iot = NULL;
2718184610Salfred	uint16_t wTotalLen;
2719184610Salfred	uint8_t ID_max = 0;		/* inclusive */
2720184610Salfred	uint8_t i;
2721184610Salfred
2722194228Sthompsa	desc = usb_desc_foreach(cd, desc);
2723184610Salfred
2724184610Salfred	if (desc == NULL) {
2725184610Salfred		DPRINTF("no Audio Control header\n");
2726184610Salfred		goto done;
2727184610Salfred	}
2728184610Salfred	acdp = desc;
2729184610Salfred
2730184610Salfred	if ((acdp->bLength < sizeof(*acdp)) ||
2731184610Salfred	    (acdp->bDescriptorType != UDESC_CS_INTERFACE) ||
2732184610Salfred	    (acdp->bDescriptorSubtype != UDESCSUB_AC_HEADER)) {
2733184610Salfred		DPRINTF("invalid Audio Control header\n");
2734184610Salfred		goto done;
2735184610Salfred	}
2736186730Salfred	/* "wTotalLen" is allowed to be corrupt */
2737186730Salfred	wTotalLen = UGETW(acdp->wTotalLength) - acdp->bLength;
2738186730Salfred
2739186730Salfred	/* get USB audio revision */
2740184610Salfred	sc->sc_audio_rev = UGETW(acdp->bcdADC);
2741184610Salfred
2742184610Salfred	DPRINTFN(3, "found AC header, vers=%03x, len=%d\n",
2743184610Salfred	    sc->sc_audio_rev, wTotalLen);
2744184610Salfred
2745184610Salfred	if (sc->sc_audio_rev != UAUDIO_VERSION) {
2746184610Salfred
2747184610Salfred		if (sc->sc_uq_bad_adc) {
2748184610Salfred
2749184610Salfred		} else {
2750184610Salfred			DPRINTF("invalid audio version\n");
2751184610Salfred			goto done;
2752184610Salfred		}
2753184610Salfred	}
2754184610Salfred	iot = malloc(sizeof(struct uaudio_terminal_node) * 256, M_TEMP,
2755184610Salfred	    M_WAITOK | M_ZERO);
2756184610Salfred
2757184610Salfred	if (iot == NULL) {
2758184610Salfred		DPRINTF("no memory!\n");
2759184610Salfred		goto done;
2760184610Salfred	}
2761194228Sthompsa	while ((desc = usb_desc_foreach(cd, desc))) {
2762184610Salfred
2763184610Salfred		dp = desc;
2764184610Salfred
2765184610Salfred		if (dp->bLength > wTotalLen) {
2766184610Salfred			break;
2767184610Salfred		} else {
2768184610Salfred			wTotalLen -= dp->bLength;
2769184610Salfred		}
2770184610Salfred
2771184610Salfred		au = uaudio_mixer_verify_desc(dp, 0);
2772184610Salfred
2773184610Salfred		if (au) {
2774184610Salfred			iot[au->bUnitId].u.desc = (const void *)au;
2775184610Salfred			if (au->bUnitId > ID_max) {
2776184610Salfred				ID_max = au->bUnitId;
2777184610Salfred			}
2778184610Salfred		}
2779184610Salfred	}
2780184610Salfred
2781184610Salfred	DPRINTF("Maximum ID=%d\n", ID_max);
2782184610Salfred
2783184610Salfred	/*
2784184610Salfred	 * determine sourcing inputs for
2785184610Salfred	 * all nodes in the tree:
2786184610Salfred	 */
2787184610Salfred	i = ID_max;
2788184610Salfred	do {
2789184610Salfred		uaudio_mixer_find_inputs_sub(iot, &i, 1, &((iot + i)->usr));
2790184610Salfred	} while (i--);
2791184610Salfred
2792184610Salfred	/*
2793184610Salfred	 * determine outputs for
2794184610Salfred	 * all nodes in the tree:
2795184610Salfred	 */
2796184610Salfred	i = ID_max;
2797184610Salfred	do {
2798184610Salfred		uaudio_mixer_find_outputs_sub(iot, i, ID_max, &((iot + i)->usr));
2799184610Salfred	} while (i--);
2800184610Salfred
2801184610Salfred	/* set "id_max" and "root" */
2802184610Salfred
2803184610Salfred	i = ID_max;
2804184610Salfred	do {
2805184610Salfred		(iot + i)->usr.id_max = ID_max;
2806184610Salfred		(iot + i)->root = iot;
2807184610Salfred	} while (i--);
2808184610Salfred
2809207077Sthompsa#ifdef USB_DEBUG
2810184610Salfred	i = ID_max;
2811184610Salfred	do {
2812184610Salfred		uint8_t j;
2813184610Salfred
2814184610Salfred		if (iot[i].u.desc == NULL) {
2815184610Salfred			continue;
2816184610Salfred		}
2817184610Salfred		DPRINTF("id %d:\n", i);
2818184610Salfred
2819184610Salfred		switch (iot[i].u.desc->bDescriptorSubtype) {
2820184610Salfred		case UDESCSUB_AC_INPUT:
2821184610Salfred			DPRINTF(" - AC_INPUT type=%s\n",
2822184610Salfred			    uaudio_mixer_get_terminal_name
2823184610Salfred			    (UGETW(iot[i].u.it->wTerminalType)));
2824184610Salfred			uaudio_mixer_dump_cluster(i, iot);
2825184610Salfred			break;
2826184610Salfred
2827184610Salfred		case UDESCSUB_AC_OUTPUT:
2828184610Salfred			DPRINTF(" - AC_OUTPUT type=%s "
2829184610Salfred			    "src=%d\n", uaudio_mixer_get_terminal_name
2830184610Salfred			    (UGETW(iot[i].u.ot->wTerminalType)),
2831184610Salfred			    iot[i].u.ot->bSourceId);
2832184610Salfred			break;
2833184610Salfred
2834184610Salfred		case UDESCSUB_AC_MIXER:
2835184610Salfred			DPRINTF(" - AC_MIXER src:\n");
2836184610Salfred			for (j = 0; j < iot[i].u.mu->bNrInPins; j++) {
2837184610Salfred				DPRINTF("   - %d\n", iot[i].u.mu->baSourceId[j]);
2838184610Salfred			}
2839184610Salfred			uaudio_mixer_dump_cluster(i, iot);
2840184610Salfred			break;
2841184610Salfred
2842184610Salfred		case UDESCSUB_AC_SELECTOR:
2843184610Salfred			DPRINTF(" - AC_SELECTOR src:\n");
2844184610Salfred			for (j = 0; j < iot[i].u.su->bNrInPins; j++) {
2845184610Salfred				DPRINTF("   - %d\n", iot[i].u.su->baSourceId[j]);
2846184610Salfred			}
2847184610Salfred			break;
2848184610Salfred
2849184610Salfred		case UDESCSUB_AC_FEATURE:
2850184610Salfred			DPRINTF(" - AC_FEATURE src=%d\n", iot[i].u.fu->bSourceId);
2851184610Salfred			break;
2852184610Salfred
2853184610Salfred		case UDESCSUB_AC_PROCESSING:
2854184610Salfred			DPRINTF(" - AC_PROCESSING src:\n");
2855184610Salfred			for (j = 0; j < iot[i].u.pu->bNrInPins; j++) {
2856184610Salfred				DPRINTF("   - %d\n", iot[i].u.pu->baSourceId[j]);
2857184610Salfred			}
2858184610Salfred			uaudio_mixer_dump_cluster(i, iot);
2859184610Salfred			break;
2860184610Salfred
2861184610Salfred		case UDESCSUB_AC_EXTENSION:
2862184610Salfred			DPRINTF(" - AC_EXTENSION src:\n");
2863184610Salfred			for (j = 0; j < iot[i].u.eu->bNrInPins; j++) {
2864184610Salfred				DPRINTF("%d ", iot[i].u.eu->baSourceId[j]);
2865184610Salfred			}
2866184610Salfred			uaudio_mixer_dump_cluster(i, iot);
2867184610Salfred			break;
2868184610Salfred
2869184610Salfred		default:
2870184610Salfred			DPRINTF("unknown audio control (subtype=%d)\n",
2871184610Salfred			    iot[i].u.desc->bDescriptorSubtype);
2872184610Salfred		}
2873184610Salfred
2874184610Salfred		DPRINTF("Inputs to this ID are:\n");
2875184610Salfred
2876184610Salfred		j = ID_max;
2877184610Salfred		do {
2878184610Salfred			if (iot[i].usr.bit_input[j / 8] & (1 << (j % 8))) {
2879184610Salfred				DPRINTF("  -- ID=%d\n", j);
2880184610Salfred			}
2881184610Salfred		} while (j--);
2882184610Salfred
2883184610Salfred		DPRINTF("Outputs from this ID are:\n");
2884184610Salfred
2885184610Salfred		j = ID_max;
2886184610Salfred		do {
2887184610Salfred			if (iot[i].usr.bit_output[j / 8] & (1 << (j % 8))) {
2888184610Salfred				DPRINTF("  -- ID=%d\n", j);
2889184610Salfred			}
2890184610Salfred		} while (j--);
2891184610Salfred
2892184610Salfred	} while (i--);
2893184610Salfred#endif
2894184610Salfred
2895184610Salfred	/*
2896184610Salfred	 * scan the config to create a linked
2897184610Salfred	 * list of "mixer" nodes:
2898184610Salfred	 */
2899184610Salfred
2900184610Salfred	i = ID_max;
2901184610Salfred	do {
2902184610Salfred		dp = iot[i].u.desc;
2903184610Salfred
2904184610Salfred		if (dp == NULL) {
2905184610Salfred			continue;
2906184610Salfred		}
2907184610Salfred		DPRINTFN(11, "id=%d subtype=%d\n",
2908184610Salfred		    i, dp->bDescriptorSubtype);
2909184610Salfred
2910184610Salfred		switch (dp->bDescriptorSubtype) {
2911184610Salfred		case UDESCSUB_AC_HEADER:
2912184610Salfred			DPRINTF("unexpected AC header\n");
2913184610Salfred			break;
2914184610Salfred
2915184610Salfred		case UDESCSUB_AC_INPUT:
2916184610Salfred			uaudio_mixer_add_input(sc, iot, i);
2917184610Salfred			break;
2918184610Salfred
2919184610Salfred		case UDESCSUB_AC_OUTPUT:
2920184610Salfred			uaudio_mixer_add_output(sc, iot, i);
2921184610Salfred			break;
2922184610Salfred
2923184610Salfred		case UDESCSUB_AC_MIXER:
2924184610Salfred			uaudio_mixer_add_mixer(sc, iot, i);
2925184610Salfred			break;
2926184610Salfred
2927184610Salfred		case UDESCSUB_AC_SELECTOR:
2928184610Salfred			uaudio_mixer_add_selector(sc, iot, i);
2929184610Salfred			break;
2930184610Salfred
2931184610Salfred		case UDESCSUB_AC_FEATURE:
2932184610Salfred			uaudio_mixer_add_feature(sc, iot, i);
2933184610Salfred			break;
2934184610Salfred
2935184610Salfred		case UDESCSUB_AC_PROCESSING:
2936184610Salfred			uaudio_mixer_add_processing(sc, iot, i);
2937184610Salfred			break;
2938184610Salfred
2939184610Salfred		case UDESCSUB_AC_EXTENSION:
2940184610Salfred			uaudio_mixer_add_extension(sc, iot, i);
2941184610Salfred			break;
2942184610Salfred
2943184610Salfred		default:
2944184610Salfred			DPRINTF("bad AC desc subtype=0x%02x\n",
2945184610Salfred			    dp->bDescriptorSubtype);
2946184610Salfred			break;
2947184610Salfred		}
2948184610Salfred
2949184610Salfred	} while (i--);
2950184610Salfred
2951184610Salfreddone:
2952184610Salfred	if (iot) {
2953184610Salfred		free(iot, M_TEMP);
2954184610Salfred	}
2955184610Salfred}
2956184610Salfred
2957184610Salfredstatic uint16_t
2958192984Sthompsauaudio_mixer_get(struct usb_device *udev, uint8_t what,
2959184610Salfred    struct uaudio_mixer_node *mc)
2960184610Salfred{
2961192984Sthompsa	struct usb_device_request req;
2962184610Salfred	uint16_t val;
2963184610Salfred	uint16_t len = MIX_SIZE(mc->type);
2964184610Salfred	uint8_t data[4];
2965193045Sthompsa	usb_error_t err;
2966184610Salfred
2967184610Salfred	if (mc->wValue[0] == -1) {
2968184610Salfred		return (0);
2969184610Salfred	}
2970184610Salfred	req.bmRequestType = UT_READ_CLASS_INTERFACE;
2971184610Salfred	req.bRequest = what;
2972184610Salfred	USETW(req.wValue, mc->wValue[0]);
2973184610Salfred	USETW(req.wIndex, mc->wIndex);
2974184610Salfred	USETW(req.wLength, len);
2975184610Salfred
2976196487Salfred	err = usbd_do_request(udev, NULL, &req, data);
2977184610Salfred	if (err) {
2978194228Sthompsa		DPRINTF("err=%s\n", usbd_errstr(err));
2979184610Salfred		return (0);
2980184610Salfred	}
2981184610Salfred	if (len < 1) {
2982184610Salfred		data[0] = 0;
2983184610Salfred	}
2984184610Salfred	if (len < 2) {
2985184610Salfred		data[1] = 0;
2986184610Salfred	}
2987184610Salfred	val = (data[0] | (data[1] << 8));
2988184610Salfred
2989184610Salfred	DPRINTFN(3, "val=%d\n", val);
2990184610Salfred
2991184610Salfred	return (val);
2992184610Salfred}
2993184610Salfred
2994184610Salfredstatic void
2995194677Sthompsauaudio_mixer_write_cfg_callback(struct usb_xfer *xfer, usb_error_t error)
2996184610Salfred{
2997192984Sthompsa	struct usb_device_request req;
2998194677Sthompsa	struct uaudio_softc *sc = usbd_xfer_softc(xfer);
2999184610Salfred	struct uaudio_mixer_node *mc = sc->sc_mixer_curr;
3000194677Sthompsa	struct usb_page_cache *pc;
3001184610Salfred	uint16_t len;
3002184610Salfred	uint8_t repeat = 1;
3003184610Salfred	uint8_t update;
3004184610Salfred	uint8_t chan;
3005184610Salfred	uint8_t buf[2];
3006184610Salfred
3007187165Sthompsa	DPRINTF("\n");
3008187165Sthompsa
3009184610Salfred	switch (USB_GET_STATE(xfer)) {
3010184610Salfred	case USB_ST_TRANSFERRED:
3011184610Salfredtr_transferred:
3012184610Salfred	case USB_ST_SETUP:
3013184610Salfredtr_setup:
3014184610Salfred
3015184610Salfred		if (mc == NULL) {
3016184610Salfred			mc = sc->sc_mixer_root;
3017184610Salfred			sc->sc_mixer_curr = mc;
3018184610Salfred			sc->sc_mixer_chan = 0;
3019184610Salfred			repeat = 0;
3020184610Salfred		}
3021184610Salfred		while (mc) {
3022184610Salfred			while (sc->sc_mixer_chan < mc->nchan) {
3023184610Salfred
3024184610Salfred				len = MIX_SIZE(mc->type);
3025184610Salfred
3026184610Salfred				chan = sc->sc_mixer_chan;
3027184610Salfred
3028184610Salfred				sc->sc_mixer_chan++;
3029184610Salfred
3030184610Salfred				update = ((mc->update[chan / 8] & (1 << (chan % 8))) &&
3031184610Salfred				    (mc->wValue[chan] != -1));
3032184610Salfred
3033184610Salfred				mc->update[chan / 8] &= ~(1 << (chan % 8));
3034184610Salfred
3035184610Salfred				if (update) {
3036184610Salfred
3037184610Salfred					req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
3038184610Salfred					req.bRequest = SET_CUR;
3039184610Salfred					USETW(req.wValue, mc->wValue[chan]);
3040184610Salfred					USETW(req.wIndex, mc->wIndex);
3041184610Salfred					USETW(req.wLength, len);
3042184610Salfred
3043184610Salfred					if (len > 0) {
3044184610Salfred						buf[0] = (mc->wData[chan] & 0xFF);
3045184610Salfred					}
3046184610Salfred					if (len > 1) {
3047184610Salfred						buf[1] = (mc->wData[chan] >> 8) & 0xFF;
3048184610Salfred					}
3049194677Sthompsa					pc = usbd_xfer_get_frame(xfer, 0);
3050194677Sthompsa					usbd_copy_in(pc, 0, &req, sizeof(req));
3051194677Sthompsa					pc = usbd_xfer_get_frame(xfer, 1);
3052194677Sthompsa					usbd_copy_in(pc, 0, buf, len);
3053184610Salfred
3054194677Sthompsa					usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
3055194677Sthompsa					usbd_xfer_set_frame_len(xfer, 1, len);
3056194677Sthompsa					usbd_xfer_set_frames(xfer, len ? 2 : 1);
3057194228Sthompsa					usbd_transfer_submit(xfer);
3058184610Salfred					return;
3059184610Salfred				}
3060184610Salfred			}
3061184610Salfred
3062184610Salfred			mc = mc->next;
3063184610Salfred			sc->sc_mixer_curr = mc;
3064184610Salfred			sc->sc_mixer_chan = 0;
3065184610Salfred		}
3066184610Salfred
3067184610Salfred		if (repeat) {
3068184610Salfred			goto tr_setup;
3069184610Salfred		}
3070187165Sthompsa		break;
3071184610Salfred
3072184610Salfred	default:			/* Error */
3073194677Sthompsa		DPRINTF("error=%s\n", usbd_errstr(error));
3074194677Sthompsa		if (error == USB_ERR_CANCELLED) {
3075187165Sthompsa			/* do nothing - we are detaching */
3076187165Sthompsa			break;
3077187165Sthompsa		}
3078184610Salfred		goto tr_transferred;
3079184610Salfred	}
3080184610Salfred}
3081184610Salfred
3082193045Sthompsastatic usb_error_t
3083192984Sthompsauaudio_set_speed(struct usb_device *udev, uint8_t endpt, uint32_t speed)
3084184610Salfred{
3085192984Sthompsa	struct usb_device_request req;
3086184610Salfred	uint8_t data[3];
3087184610Salfred
3088184610Salfred	DPRINTFN(6, "endpt=%d speed=%u\n", endpt, speed);
3089184610Salfred
3090184610Salfred	req.bmRequestType = UT_WRITE_CLASS_ENDPOINT;
3091184610Salfred	req.bRequest = SET_CUR;
3092184610Salfred	USETW2(req.wValue, SAMPLING_FREQ_CONTROL, 0);
3093184610Salfred	USETW(req.wIndex, endpt);
3094184610Salfred	USETW(req.wLength, 3);
3095184610Salfred	data[0] = speed;
3096184610Salfred	data[1] = speed >> 8;
3097184610Salfred	data[2] = speed >> 16;
3098184610Salfred
3099196487Salfred	return (usbd_do_request(udev, NULL, &req, data));
3100184610Salfred}
3101184610Salfred
3102184610Salfredstatic int
3103184610Salfreduaudio_mixer_signext(uint8_t type, int val)
3104184610Salfred{
3105184610Salfred	if (!MIX_UNSIGNED(type)) {
3106184610Salfred		if (MIX_SIZE(type) == 2) {
3107184610Salfred			val = (int16_t)val;
3108184610Salfred		} else {
3109184610Salfred			val = (int8_t)val;
3110184610Salfred		}
3111184610Salfred	}
3112184610Salfred	return (val);
3113184610Salfred}
3114184610Salfred
3115184610Salfredstatic int
3116184610Salfreduaudio_mixer_bsd2value(struct uaudio_mixer_node *mc, int32_t val)
3117184610Salfred{
3118184610Salfred	if (mc->type == MIX_ON_OFF) {
3119184610Salfred		val = (val != 0);
3120184610Salfred	} else if (mc->type == MIX_SELECTOR) {
3121184610Salfred		if ((val < mc->minval) ||
3122184610Salfred		    (val > mc->maxval)) {
3123184610Salfred			val = mc->minval;
3124184610Salfred		}
3125184610Salfred	} else {
3126199060Sthompsa
3127199060Sthompsa		/* compute actual volume */
3128199060Sthompsa		val = (val * mc->mul) / 255;
3129199060Sthompsa
3130199060Sthompsa		/* add lower offset */
3131199060Sthompsa		val = val + mc->minval;
3132199060Sthompsa
3133199060Sthompsa		/* make sure we don't write a value out of range */
3134199060Sthompsa		if (val > mc->maxval)
3135199060Sthompsa			val = mc->maxval;
3136199060Sthompsa		else if (val < mc->minval)
3137199060Sthompsa			val = mc->minval;
3138184610Salfred	}
3139184610Salfred
3140185087Salfred	DPRINTFN(6, "type=0x%03x val=%d min=%d max=%d val=%d\n",
3141185087Salfred	    mc->type, val, mc->minval, mc->maxval, val);
3142184610Salfred	return (val);
3143184610Salfred}
3144184610Salfred
3145184610Salfredstatic void
3146184610Salfreduaudio_mixer_ctl_set(struct uaudio_softc *sc, struct uaudio_mixer_node *mc,
3147184610Salfred    uint8_t chan, int32_t val)
3148184610Salfred{
3149184610Salfred	val = uaudio_mixer_bsd2value(mc, val);
3150184610Salfred
3151184610Salfred	mc->update[chan / 8] |= (1 << (chan % 8));
3152184610Salfred	mc->wData[chan] = val;
3153184610Salfred
3154184610Salfred	/* start the transfer, if not already started */
3155184610Salfred
3156194228Sthompsa	usbd_transfer_start(sc->sc_mixer_xfer[0]);
3157184610Salfred}
3158184610Salfred
3159184610Salfredstatic void
3160184610Salfreduaudio_mixer_init(struct uaudio_softc *sc)
3161184610Salfred{
3162184610Salfred	struct uaudio_mixer_node *mc;
3163184610Salfred	int32_t i;
3164184610Salfred
3165184610Salfred	for (mc = sc->sc_mixer_root; mc;
3166184610Salfred	    mc = mc->next) {
3167184610Salfred
3168184610Salfred		if (mc->ctl != SOUND_MIXER_NRDEVICES) {
3169184610Salfred			/*
3170184610Salfred			 * Set device mask bits. See
3171184610Salfred			 * /usr/include/machine/soundcard.h
3172184610Salfred			 */
3173184610Salfred			sc->sc_mix_info |= (1 << mc->ctl);
3174184610Salfred		}
3175184610Salfred		if ((mc->ctl == SOUND_MIXER_NRDEVICES) &&
3176184610Salfred		    (mc->type == MIX_SELECTOR)) {
3177184610Salfred
3178184610Salfred			for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) {
3179184610Salfred				if (mc->slctrtype[i - 1] == SOUND_MIXER_NRDEVICES) {
3180184610Salfred					continue;
3181184610Salfred				}
3182184610Salfred				sc->sc_recsrc_info |= 1 << mc->slctrtype[i - 1];
3183184610Salfred			}
3184184610Salfred		}
3185184610Salfred	}
3186184610Salfred}
3187184610Salfred
3188184610Salfredint
3189184610Salfreduaudio_mixer_init_sub(struct uaudio_softc *sc, struct snd_mixer *m)
3190184610Salfred{
3191184610Salfred	DPRINTF("\n");
3192184610Salfred
3193194228Sthompsa	if (usbd_transfer_setup(sc->sc_udev, &sc->sc_mixer_iface_index,
3194184610Salfred	    sc->sc_mixer_xfer, uaudio_mixer_config, 1, sc,
3195184610Salfred	    mixer_get_lock(m))) {
3196184610Salfred		DPRINTFN(0, "could not allocate USB "
3197184610Salfred		    "transfer for audio mixer!\n");
3198184610Salfred		return (ENOMEM);
3199184610Salfred	}
3200184610Salfred	if (!(sc->sc_mix_info & SOUND_MASK_VOLUME)) {
3201184610Salfred		mix_setparentchild(m, SOUND_MIXER_VOLUME, SOUND_MASK_PCM);
3202184610Salfred		mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE);
3203184610Salfred	}
3204184610Salfred	mix_setdevs(m, sc->sc_mix_info);
3205184610Salfred	mix_setrecdevs(m, sc->sc_recsrc_info);
3206184610Salfred	return (0);
3207184610Salfred}
3208184610Salfred
3209184610Salfredint
3210184610Salfreduaudio_mixer_uninit_sub(struct uaudio_softc *sc)
3211184610Salfred{
3212184610Salfred	DPRINTF("\n");
3213184610Salfred
3214194228Sthompsa	usbd_transfer_unsetup(sc->sc_mixer_xfer, 1);
3215184610Salfred
3216184610Salfred	return (0);
3217184610Salfred}
3218184610Salfred
3219184610Salfredvoid
3220184610Salfreduaudio_mixer_set(struct uaudio_softc *sc, unsigned type,
3221184610Salfred    unsigned left, unsigned right)
3222184610Salfred{
3223184610Salfred	struct uaudio_mixer_node *mc;
3224184610Salfred
3225184610Salfred	for (mc = sc->sc_mixer_root; mc;
3226184610Salfred	    mc = mc->next) {
3227184610Salfred
3228184610Salfred		if (mc->ctl == type) {
3229184610Salfred			if (mc->nchan == 2) {
3230184610Salfred				/* set Right */
3231184610Salfred				uaudio_mixer_ctl_set(sc, mc, 1, (int)(right * 255) / 100);
3232184610Salfred			}
3233184610Salfred			/* set Left or Mono */
3234184610Salfred			uaudio_mixer_ctl_set(sc, mc, 0, (int)(left * 255) / 100);
3235184610Salfred		}
3236184610Salfred	}
3237184610Salfred}
3238184610Salfred
3239184610Salfreduint32_t
3240184610Salfreduaudio_mixer_setrecsrc(struct uaudio_softc *sc, uint32_t src)
3241184610Salfred{
3242184610Salfred	struct uaudio_mixer_node *mc;
3243184610Salfred	uint32_t mask;
3244184610Salfred	uint32_t temp;
3245184610Salfred	int32_t i;
3246184610Salfred
3247184610Salfred	for (mc = sc->sc_mixer_root; mc;
3248184610Salfred	    mc = mc->next) {
3249184610Salfred
3250184610Salfred		if ((mc->ctl == SOUND_MIXER_NRDEVICES) &&
3251184610Salfred		    (mc->type == MIX_SELECTOR)) {
3252184610Salfred
3253184610Salfred			/* compute selector mask */
3254184610Salfred
3255184610Salfred			mask = 0;
3256184610Salfred			for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) {
3257184610Salfred				mask |= (1 << mc->slctrtype[i - 1]);
3258184610Salfred			}
3259184610Salfred
3260184610Salfred			temp = mask & src;
3261184610Salfred			if (temp == 0) {
3262184610Salfred				continue;
3263184610Salfred			}
3264184610Salfred			/* find the first set bit */
3265184610Salfred			temp = (-temp) & temp;
3266184610Salfred
3267184610Salfred			/* update "src" */
3268184610Salfred			src &= ~mask;
3269184610Salfred			src |= temp;
3270184610Salfred
3271184610Salfred			for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) {
3272184610Salfred				if (temp != (1 << mc->slctrtype[i - 1])) {
3273184610Salfred					continue;
3274184610Salfred				}
3275184610Salfred				uaudio_mixer_ctl_set(sc, mc, 0, i);
3276184610Salfred				break;
3277184610Salfred			}
3278184610Salfred		}
3279184610Salfred	}
3280184610Salfred	return (src);
3281184610Salfred}
3282184610Salfred
3283184610Salfred/*========================================================================*
3284184610Salfred * MIDI support routines
3285184610Salfred *========================================================================*/
3286184610Salfred
3287184610Salfredstatic void
3288194677Sthompsaumidi_read_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error)
3289184610Salfred{
3290194677Sthompsa	struct umidi_chan *chan = usbd_xfer_softc(xfer);
3291192984Sthompsa	struct usb_xfer *xfer_other = chan->xfer[1];
3292184610Salfred
3293194228Sthompsa	if (usbd_clear_stall_callback(xfer, xfer_other)) {
3294184610Salfred		DPRINTF("stall cleared\n");
3295184610Salfred		chan->flags &= ~UMIDI_FLAG_READ_STALL;
3296194228Sthompsa		usbd_transfer_start(xfer_other);
3297184610Salfred	}
3298184610Salfred}
3299184610Salfred
3300184610Salfredstatic void
3301194677Sthompsaumidi_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
3302184610Salfred{
3303194677Sthompsa	struct umidi_chan *chan = usbd_xfer_softc(xfer);
3304184610Salfred	struct umidi_sub_chan *sub;
3305194677Sthompsa	struct usb_page_cache *pc;
3306184610Salfred	uint8_t buf[1];
3307184610Salfred	uint8_t cmd_len;
3308184610Salfred	uint8_t cn;
3309184610Salfred	uint16_t pos;
3310194677Sthompsa	int actlen;
3311184610Salfred
3312194677Sthompsa	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
3313194677Sthompsa
3314184610Salfred	switch (USB_GET_STATE(xfer)) {
3315184610Salfred	case USB_ST_TRANSFERRED:
3316184610Salfred
3317194677Sthompsa		DPRINTF("actlen=%d bytes\n", actlen);
3318184610Salfred
3319184610Salfred		pos = 0;
3320194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
3321184610Salfred
3322194677Sthompsa		while (actlen >= 4) {
3323184610Salfred
3324194677Sthompsa			usbd_copy_out(pc, pos, buf, 1);
3325184610Salfred
3326184610Salfred			cmd_len = umidi_cmd_to_len[buf[0] & 0xF];	/* command length */
3327184610Salfred			cn = buf[0] >> 4;	/* cable number */
3328184610Salfred			sub = &chan->sub[cn];
3329184610Salfred
3330184610Salfred			if (cmd_len && (cn < chan->max_cable) && sub->read_open) {
3331194677Sthompsa				usb_fifo_put_data(sub->fifo.fp[USB_FIFO_RX], pc,
3332184610Salfred				    pos + 1, cmd_len, 1);
3333184610Salfred			} else {
3334184610Salfred				/* ignore the command */
3335184610Salfred			}
3336184610Salfred
3337194677Sthompsa			actlen -= 4;
3338184610Salfred			pos += 4;
3339184610Salfred		}
3340184610Salfred
3341184610Salfred	case USB_ST_SETUP:
3342184610Salfred		DPRINTF("start\n");
3343184610Salfred
3344184610Salfred		if (chan->flags & UMIDI_FLAG_READ_STALL) {
3345194228Sthompsa			usbd_transfer_start(chan->xfer[3]);
3346184610Salfred			return;
3347184610Salfred		}
3348194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
3349194228Sthompsa		usbd_transfer_submit(xfer);
3350184610Salfred		return;
3351184610Salfred
3352184610Salfred	default:
3353194677Sthompsa		DPRINTF("error=%s\n", usbd_errstr(error));
3354184610Salfred
3355194677Sthompsa		if (error != USB_ERR_CANCELLED) {
3356184610Salfred			/* try to clear stall first */
3357184610Salfred			chan->flags |= UMIDI_FLAG_READ_STALL;
3358194228Sthompsa			usbd_transfer_start(chan->xfer[3]);
3359184610Salfred		}
3360184610Salfred		return;
3361184610Salfred
3362184610Salfred	}
3363184610Salfred}
3364184610Salfred
3365184610Salfredstatic void
3366194677Sthompsaumidi_write_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error)
3367184610Salfred{
3368194677Sthompsa	struct umidi_chan *chan = usbd_xfer_softc(xfer);
3369192984Sthompsa	struct usb_xfer *xfer_other = chan->xfer[0];
3370184610Salfred
3371194228Sthompsa	if (usbd_clear_stall_callback(xfer, xfer_other)) {
3372184610Salfred		DPRINTF("stall cleared\n");
3373184610Salfred		chan->flags &= ~UMIDI_FLAG_WRITE_STALL;
3374194228Sthompsa		usbd_transfer_start(xfer_other);
3375184610Salfred	}
3376184610Salfred}
3377184610Salfred
3378184610Salfred/*
3379184610Salfred * The following statemachine, that converts MIDI commands to
3380184610Salfred * USB MIDI packets, derives from Linux's usbmidi.c, which
3381184610Salfred * was written by "Clemens Ladisch":
3382184610Salfred *
3383184610Salfred * Returns:
3384184610Salfred *    0: No command
3385184610Salfred * Else: Command is complete
3386184610Salfred */
3387184610Salfredstatic uint8_t
3388184610Salfredumidi_convert_to_usb(struct umidi_sub_chan *sub, uint8_t cn, uint8_t b)
3389184610Salfred{
3390184610Salfred	uint8_t p0 = (cn << 4);
3391184610Salfred
3392184610Salfred	if (b >= 0xf8) {
3393184610Salfred		sub->temp_0[0] = p0 | 0x0f;
3394184610Salfred		sub->temp_0[1] = b;
3395184610Salfred		sub->temp_0[2] = 0;
3396184610Salfred		sub->temp_0[3] = 0;
3397184610Salfred		sub->temp_cmd = sub->temp_0;
3398184610Salfred		return (1);
3399184610Salfred
3400184610Salfred	} else if (b >= 0xf0) {
3401184610Salfred		switch (b) {
3402184610Salfred		case 0xf0:		/* system exclusive begin */
3403184610Salfred			sub->temp_1[1] = b;
3404184610Salfred			sub->state = UMIDI_ST_SYSEX_1;
3405184610Salfred			break;
3406184610Salfred		case 0xf1:		/* MIDI time code */
3407184610Salfred		case 0xf3:		/* song select */
3408184610Salfred			sub->temp_1[1] = b;
3409184610Salfred			sub->state = UMIDI_ST_1PARAM;
3410184610Salfred			break;
3411184610Salfred		case 0xf2:		/* song position pointer */
3412184610Salfred			sub->temp_1[1] = b;
3413184610Salfred			sub->state = UMIDI_ST_2PARAM_1;
3414184610Salfred			break;
3415184610Salfred		case 0xf4:		/* unknown */
3416184610Salfred		case 0xf5:		/* unknown */
3417184610Salfred			sub->state = UMIDI_ST_UNKNOWN;
3418184610Salfred			break;
3419184610Salfred		case 0xf6:		/* tune request */
3420184610Salfred			sub->temp_1[0] = p0 | 0x05;
3421184610Salfred			sub->temp_1[1] = 0xf6;
3422184610Salfred			sub->temp_1[2] = 0;
3423184610Salfred			sub->temp_1[3] = 0;
3424184610Salfred			sub->temp_cmd = sub->temp_1;
3425184610Salfred			sub->state = UMIDI_ST_UNKNOWN;
3426184610Salfred			return (1);
3427184610Salfred
3428184610Salfred		case 0xf7:		/* system exclusive end */
3429184610Salfred			switch (sub->state) {
3430184610Salfred			case UMIDI_ST_SYSEX_0:
3431184610Salfred				sub->temp_1[0] = p0 | 0x05;
3432184610Salfred				sub->temp_1[1] = 0xf7;
3433184610Salfred				sub->temp_1[2] = 0;
3434184610Salfred				sub->temp_1[3] = 0;
3435184610Salfred				sub->temp_cmd = sub->temp_1;
3436184610Salfred				sub->state = UMIDI_ST_UNKNOWN;
3437184610Salfred				return (1);
3438184610Salfred			case UMIDI_ST_SYSEX_1:
3439184610Salfred				sub->temp_1[0] = p0 | 0x06;
3440184610Salfred				sub->temp_1[2] = 0xf7;
3441184610Salfred				sub->temp_1[3] = 0;
3442184610Salfred				sub->temp_cmd = sub->temp_1;
3443184610Salfred				sub->state = UMIDI_ST_UNKNOWN;
3444184610Salfred				return (1);
3445184610Salfred			case UMIDI_ST_SYSEX_2:
3446184610Salfred				sub->temp_1[0] = p0 | 0x07;
3447184610Salfred				sub->temp_1[3] = 0xf7;
3448184610Salfred				sub->temp_cmd = sub->temp_1;
3449184610Salfred				sub->state = UMIDI_ST_UNKNOWN;
3450184610Salfred				return (1);
3451184610Salfred			}
3452184610Salfred			sub->state = UMIDI_ST_UNKNOWN;
3453184610Salfred			break;
3454184610Salfred		}
3455184610Salfred	} else if (b >= 0x80) {
3456184610Salfred		sub->temp_1[1] = b;
3457184610Salfred		if ((b >= 0xc0) && (b <= 0xdf)) {
3458184610Salfred			sub->state = UMIDI_ST_1PARAM;
3459184610Salfred		} else {
3460184610Salfred			sub->state = UMIDI_ST_2PARAM_1;
3461184610Salfred		}
3462184610Salfred	} else {			/* b < 0x80 */
3463184610Salfred		switch (sub->state) {
3464184610Salfred		case UMIDI_ST_1PARAM:
3465184610Salfred			if (sub->temp_1[1] < 0xf0) {
3466184610Salfred				p0 |= sub->temp_1[1] >> 4;
3467184610Salfred			} else {
3468184610Salfred				p0 |= 0x02;
3469184610Salfred				sub->state = UMIDI_ST_UNKNOWN;
3470184610Salfred			}
3471184610Salfred			sub->temp_1[0] = p0;
3472184610Salfred			sub->temp_1[2] = b;
3473184610Salfred			sub->temp_1[3] = 0;
3474184610Salfred			sub->temp_cmd = sub->temp_1;
3475184610Salfred			return (1);
3476184610Salfred		case UMIDI_ST_2PARAM_1:
3477184610Salfred			sub->temp_1[2] = b;
3478184610Salfred			sub->state = UMIDI_ST_2PARAM_2;
3479184610Salfred			break;
3480184610Salfred		case UMIDI_ST_2PARAM_2:
3481184610Salfred			if (sub->temp_1[1] < 0xf0) {
3482184610Salfred				p0 |= sub->temp_1[1] >> 4;
3483184610Salfred				sub->state = UMIDI_ST_2PARAM_1;
3484184610Salfred			} else {
3485184610Salfred				p0 |= 0x03;
3486184610Salfred				sub->state = UMIDI_ST_UNKNOWN;
3487184610Salfred			}
3488184610Salfred			sub->temp_1[0] = p0;
3489184610Salfred			sub->temp_1[3] = b;
3490184610Salfred			sub->temp_cmd = sub->temp_1;
3491184610Salfred			return (1);
3492184610Salfred		case UMIDI_ST_SYSEX_0:
3493184610Salfred			sub->temp_1[1] = b;
3494184610Salfred			sub->state = UMIDI_ST_SYSEX_1;
3495184610Salfred			break;
3496184610Salfred		case UMIDI_ST_SYSEX_1:
3497184610Salfred			sub->temp_1[2] = b;
3498184610Salfred			sub->state = UMIDI_ST_SYSEX_2;
3499184610Salfred			break;
3500184610Salfred		case UMIDI_ST_SYSEX_2:
3501184610Salfred			sub->temp_1[0] = p0 | 0x04;
3502184610Salfred			sub->temp_1[3] = b;
3503184610Salfred			sub->temp_cmd = sub->temp_1;
3504184610Salfred			sub->state = UMIDI_ST_SYSEX_0;
3505184610Salfred			return (1);
3506184610Salfred		}
3507184610Salfred	}
3508184610Salfred	return (0);
3509184610Salfred}
3510184610Salfred
3511184610Salfredstatic void
3512194677Sthompsaumidi_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
3513184610Salfred{
3514194677Sthompsa	struct umidi_chan *chan = usbd_xfer_softc(xfer);
3515184610Salfred	struct umidi_sub_chan *sub;
3516194677Sthompsa	struct usb_page_cache *pc;
3517184610Salfred	uint32_t actlen;
3518184610Salfred	uint16_t total_length;
3519184610Salfred	uint8_t buf;
3520184610Salfred	uint8_t start_cable;
3521184610Salfred	uint8_t tr_any;
3522194677Sthompsa	int len;
3523184610Salfred
3524194677Sthompsa	usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
3525194677Sthompsa
3526184610Salfred	switch (USB_GET_STATE(xfer)) {
3527184610Salfred	case USB_ST_TRANSFERRED:
3528194677Sthompsa		DPRINTF("actlen=%d bytes\n", len);
3529184610Salfred
3530184610Salfred	case USB_ST_SETUP:
3531184610Salfred
3532184610Salfred		DPRINTF("start\n");
3533184610Salfred
3534184610Salfred		if (chan->flags & UMIDI_FLAG_WRITE_STALL) {
3535194228Sthompsa			usbd_transfer_start(chan->xfer[2]);
3536184610Salfred			return;
3537184610Salfred		}
3538184610Salfred		total_length = 0;	/* reset */
3539184610Salfred		start_cable = chan->curr_cable;
3540184610Salfred		tr_any = 0;
3541194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
3542184610Salfred
3543184610Salfred		while (1) {
3544184610Salfred
3545184610Salfred			/* round robin de-queueing */
3546184610Salfred
3547184610Salfred			sub = &chan->sub[chan->curr_cable];
3548184610Salfred
3549184610Salfred			if (sub->write_open) {
3550194228Sthompsa				usb_fifo_get_data(sub->fifo.fp[USB_FIFO_TX],
3551194677Sthompsa				    pc, total_length, 1, &actlen, 0);
3552184610Salfred			} else {
3553184610Salfred				actlen = 0;
3554184610Salfred			}
3555184610Salfred
3556184610Salfred			if (actlen) {
3557194677Sthompsa				usbd_copy_out(pc, total_length, &buf, 1);
3558184610Salfred
3559184610Salfred				tr_any = 1;
3560184610Salfred
3561184610Salfred				DPRINTF("byte=0x%02x\n", buf);
3562184610Salfred
3563184610Salfred				if (umidi_convert_to_usb(sub, chan->curr_cable, buf)) {
3564184610Salfred
3565184610Salfred					DPRINTF("sub= %02x %02x %02x %02x\n",
3566184610Salfred					    sub->temp_cmd[0], sub->temp_cmd[1],
3567184610Salfred					    sub->temp_cmd[2], sub->temp_cmd[3]);
3568184610Salfred
3569194677Sthompsa					usbd_copy_in(pc, total_length,
3570184610Salfred					    sub->temp_cmd, 4);
3571184610Salfred
3572184610Salfred					total_length += 4;
3573184610Salfred
3574184610Salfred					if (total_length >= UMIDI_BULK_SIZE) {
3575184610Salfred						break;
3576184610Salfred					}
3577184610Salfred				} else {
3578184610Salfred					continue;
3579184610Salfred				}
3580184610Salfred			}
3581184610Salfred			chan->curr_cable++;
3582184610Salfred			if (chan->curr_cable >= chan->max_cable) {
3583184610Salfred				chan->curr_cable = 0;
3584184610Salfred			}
3585184610Salfred			if (chan->curr_cable == start_cable) {
3586184610Salfred				if (tr_any == 0) {
3587184610Salfred					break;
3588184610Salfred				}
3589184610Salfred				tr_any = 0;
3590184610Salfred			}
3591184610Salfred		}
3592184610Salfred
3593184610Salfred		if (total_length) {
3594194677Sthompsa			usbd_xfer_set_frame_len(xfer, 0, total_length);
3595194228Sthompsa			usbd_transfer_submit(xfer);
3596184610Salfred		}
3597184610Salfred		return;
3598184610Salfred
3599184610Salfred	default:			/* Error */
3600184610Salfred
3601194677Sthompsa		DPRINTF("error=%s\n", usbd_errstr(error));
3602184610Salfred
3603194677Sthompsa		if (error != USB_ERR_CANCELLED) {
3604184610Salfred			/* try to clear stall first */
3605184610Salfred			chan->flags |= UMIDI_FLAG_WRITE_STALL;
3606194228Sthompsa			usbd_transfer_start(chan->xfer[2]);
3607184610Salfred		}
3608184610Salfred		return;
3609184610Salfred
3610184610Salfred	}
3611184610Salfred}
3612184610Salfred
3613184610Salfredstatic struct umidi_sub_chan *
3614192984Sthompsaumidi_sub_by_fifo(struct usb_fifo *fifo)
3615184610Salfred{
3616194677Sthompsa	struct umidi_chan *chan = usb_fifo_softc(fifo);
3617184610Salfred	struct umidi_sub_chan *sub;
3618184610Salfred	uint32_t n;
3619184610Salfred
3620184610Salfred	for (n = 0; n < UMIDI_CABLES_MAX; n++) {
3621184610Salfred		sub = &chan->sub[n];
3622184610Salfred		if ((sub->fifo.fp[USB_FIFO_RX] == fifo) ||
3623184610Salfred		    (sub->fifo.fp[USB_FIFO_TX] == fifo)) {
3624184610Salfred			return (sub);
3625184610Salfred		}
3626184610Salfred	}
3627184610Salfred
3628192984Sthompsa	panic("%s:%d cannot find usb_fifo!\n",
3629184610Salfred	    __FILE__, __LINE__);
3630184610Salfred
3631184610Salfred	return (NULL);
3632184610Salfred}
3633184610Salfred
3634184610Salfredstatic void
3635192984Sthompsaumidi_start_read(struct usb_fifo *fifo)
3636184610Salfred{
3637194677Sthompsa	struct umidi_chan *chan = usb_fifo_softc(fifo);
3638184610Salfred
3639194228Sthompsa	usbd_transfer_start(chan->xfer[1]);
3640184610Salfred}
3641184610Salfred
3642184610Salfredstatic void
3643192984Sthompsaumidi_stop_read(struct usb_fifo *fifo)
3644184610Salfred{
3645194677Sthompsa	struct umidi_chan *chan = usb_fifo_softc(fifo);
3646184610Salfred	struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo);
3647184610Salfred
3648184610Salfred	DPRINTF("\n");
3649184610Salfred
3650184610Salfred	sub->read_open = 0;
3651184610Salfred
3652184610Salfred	if (--(chan->read_open_refcount) == 0) {
3653184610Salfred		/*
3654184610Salfred		 * XXX don't stop the read transfer here, hence that causes
3655184610Salfred		 * problems with some MIDI adapters
3656184610Salfred		 */
3657184610Salfred		DPRINTF("(stopping read transfer)\n");
3658184610Salfred	}
3659184610Salfred}
3660184610Salfred
3661184610Salfredstatic void
3662192984Sthompsaumidi_start_write(struct usb_fifo *fifo)
3663184610Salfred{
3664194677Sthompsa	struct umidi_chan *chan = usb_fifo_softc(fifo);
3665184610Salfred
3666194228Sthompsa	usbd_transfer_start(chan->xfer[0]);
3667184610Salfred}
3668184610Salfred
3669184610Salfredstatic void
3670192984Sthompsaumidi_stop_write(struct usb_fifo *fifo)
3671184610Salfred{
3672194677Sthompsa	struct umidi_chan *chan = usb_fifo_softc(fifo);
3673184610Salfred	struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo);
3674184610Salfred
3675184610Salfred	DPRINTF("\n");
3676184610Salfred
3677184610Salfred	sub->write_open = 0;
3678184610Salfred
3679184610Salfred	if (--(chan->write_open_refcount) == 0) {
3680184610Salfred		DPRINTF("(stopping write transfer)\n");
3681194228Sthompsa		usbd_transfer_stop(chan->xfer[2]);
3682194228Sthompsa		usbd_transfer_stop(chan->xfer[0]);
3683184610Salfred	}
3684184610Salfred}
3685184610Salfred
3686184610Salfredstatic int
3687192984Sthompsaumidi_open(struct usb_fifo *fifo, int fflags)
3688184610Salfred{
3689194677Sthompsa	struct umidi_chan *chan = usb_fifo_softc(fifo);
3690184610Salfred	struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo);
3691184610Salfred
3692184610Salfred	if (fflags & FREAD) {
3693194228Sthompsa		if (usb_fifo_alloc_buffer(fifo, 4, (1024 / 4))) {
3694184610Salfred			return (ENOMEM);
3695184610Salfred		}
3696195120Sthompsa		mtx_lock(&chan->mtx);
3697184610Salfred		chan->read_open_refcount++;
3698184610Salfred		sub->read_open = 1;
3699195120Sthompsa		mtx_unlock(&chan->mtx);
3700184610Salfred	}
3701184610Salfred	if (fflags & FWRITE) {
3702194228Sthompsa		if (usb_fifo_alloc_buffer(fifo, 32, (1024 / 32))) {
3703184610Salfred			return (ENOMEM);
3704184610Salfred		}
3705184610Salfred		/* clear stall first */
3706195120Sthompsa		mtx_lock(&chan->mtx);
3707184610Salfred		chan->flags |= UMIDI_FLAG_WRITE_STALL;
3708184610Salfred		chan->write_open_refcount++;
3709184610Salfred		sub->write_open = 1;
3710184610Salfred
3711184610Salfred		/* reset */
3712184610Salfred		sub->state = UMIDI_ST_UNKNOWN;
3713195120Sthompsa		mtx_unlock(&chan->mtx);
3714184610Salfred	}
3715184610Salfred	return (0);			/* success */
3716184610Salfred}
3717184610Salfred
3718184610Salfredstatic void
3719192984Sthompsaumidi_close(struct usb_fifo *fifo, int fflags)
3720184610Salfred{
3721184610Salfred	if (fflags & FREAD) {
3722194228Sthompsa		usb_fifo_free_buffer(fifo);
3723184610Salfred	}
3724184610Salfred	if (fflags & FWRITE) {
3725194228Sthompsa		usb_fifo_free_buffer(fifo);
3726184610Salfred	}
3727184610Salfred}
3728184610Salfred
3729184610Salfred
3730184610Salfredstatic int
3731192984Sthompsaumidi_ioctl(struct usb_fifo *fifo, u_long cmd, void *data,
3732189110Sthompsa    int fflags)
3733184610Salfred{
3734184610Salfred	return (ENODEV);
3735184610Salfred}
3736184610Salfred
3737184610Salfredstatic void
3738184610Salfredumidi_init(device_t dev)
3739184610Salfred{
3740184610Salfred	struct uaudio_softc *sc = device_get_softc(dev);
3741184610Salfred	struct umidi_chan *chan = &sc->sc_midi_chan;
3742184610Salfred
3743184610Salfred	mtx_init(&chan->mtx, "umidi lock", NULL, MTX_DEF | MTX_RECURSE);
3744184610Salfred}
3745184610Salfred
3746192984Sthompsastatic struct usb_fifo_methods umidi_fifo_methods = {
3747184610Salfred	.f_start_read = &umidi_start_read,
3748184610Salfred	.f_start_write = &umidi_start_write,
3749184610Salfred	.f_stop_read = &umidi_stop_read,
3750184610Salfred	.f_stop_write = &umidi_stop_write,
3751184610Salfred	.f_open = &umidi_open,
3752184610Salfred	.f_close = &umidi_close,
3753184610Salfred	.f_ioctl = &umidi_ioctl,
3754184610Salfred	.basename[0] = "umidi",
3755184610Salfred};
3756184610Salfred
3757184610Salfredstatic int32_t
3758184610Salfredumidi_probe(device_t dev)
3759184610Salfred{
3760184610Salfred	struct uaudio_softc *sc = device_get_softc(dev);
3761192984Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(dev);
3762184610Salfred	struct umidi_chan *chan = &sc->sc_midi_chan;
3763184610Salfred	struct umidi_sub_chan *sub;
3764184610Salfred	int unit = device_get_unit(dev);
3765184610Salfred	int error;
3766184610Salfred	uint32_t n;
3767184610Salfred
3768194228Sthompsa	if (usbd_set_alt_interface_index(sc->sc_udev, chan->iface_index,
3769184610Salfred	    chan->iface_alt_index)) {
3770184610Salfred		DPRINTF("setting of alternate index failed!\n");
3771184610Salfred		goto detach;
3772184610Salfred	}
3773194228Sthompsa	usbd_set_parent_iface(sc->sc_udev, chan->iface_index, sc->sc_mixer_iface_index);
3774184610Salfred
3775194228Sthompsa	error = usbd_transfer_setup(uaa->device, &chan->iface_index,
3776184610Salfred	    chan->xfer, umidi_config, UMIDI_N_TRANSFER,
3777184610Salfred	    chan, &chan->mtx);
3778184610Salfred	if (error) {
3779194228Sthompsa		DPRINTF("error=%s\n", usbd_errstr(error));
3780184610Salfred		goto detach;
3781184610Salfred	}
3782184610Salfred	if ((chan->max_cable > UMIDI_CABLES_MAX) ||
3783184610Salfred	    (chan->max_cable == 0)) {
3784184610Salfred		chan->max_cable = UMIDI_CABLES_MAX;
3785184610Salfred	}
3786184610Salfred
3787184610Salfred	for (n = 0; n < chan->max_cable; n++) {
3788184610Salfred
3789184610Salfred		sub = &chan->sub[n];
3790184610Salfred
3791194228Sthompsa		error = usb_fifo_attach(sc->sc_udev, chan, &chan->mtx,
3792184610Salfred		    &umidi_fifo_methods, &sub->fifo, unit, n,
3793189110Sthompsa		    chan->iface_index,
3794189110Sthompsa		    UID_ROOT, GID_OPERATOR, 0644);
3795184610Salfred		if (error) {
3796184610Salfred			goto detach;
3797184610Salfred		}
3798184610Salfred	}
3799184610Salfred
3800184610Salfred	mtx_lock(&chan->mtx);
3801184610Salfred
3802184610Salfred	/* clear stall first */
3803184610Salfred	chan->flags |= UMIDI_FLAG_READ_STALL;
3804184610Salfred
3805184610Salfred	/*
3806184610Salfred	 * NOTE: at least one device will not work properly unless
3807184610Salfred	 * the BULK pipe is open all the time.
3808184610Salfred	 */
3809194228Sthompsa	usbd_transfer_start(chan->xfer[1]);
3810184610Salfred
3811184610Salfred	mtx_unlock(&chan->mtx);
3812184610Salfred
3813184610Salfred	return (0);			/* success */
3814184610Salfred
3815184610Salfreddetach:
3816184610Salfred	return (ENXIO);			/* failure */
3817184610Salfred}
3818184610Salfred
3819184610Salfredstatic int32_t
3820184610Salfredumidi_detach(device_t dev)
3821184610Salfred{
3822184610Salfred	struct uaudio_softc *sc = device_get_softc(dev);
3823184610Salfred	struct umidi_chan *chan = &sc->sc_midi_chan;
3824184610Salfred	uint32_t n;
3825184610Salfred
3826184610Salfred	for (n = 0; n < UMIDI_CABLES_MAX; n++) {
3827194228Sthompsa		usb_fifo_detach(&chan->sub[n].fifo);
3828184610Salfred	}
3829184610Salfred
3830184610Salfred	mtx_lock(&chan->mtx);
3831184610Salfred
3832194228Sthompsa	usbd_transfer_stop(chan->xfer[3]);
3833194228Sthompsa	usbd_transfer_stop(chan->xfer[1]);
3834184610Salfred
3835184610Salfred	mtx_unlock(&chan->mtx);
3836184610Salfred
3837194228Sthompsa	usbd_transfer_unsetup(chan->xfer, UMIDI_N_TRANSFER);
3838184610Salfred
3839184610Salfred	mtx_destroy(&chan->mtx);
3840184610Salfred
3841184610Salfred	return (0);
3842184610Salfred}
3843184610Salfred
3844189275SthompsaDRIVER_MODULE(uaudio, uhub, uaudio_driver, uaudio_devclass, NULL, 0);
3845188942SthompsaMODULE_DEPEND(uaudio, usb, 1, 1, 1);
3846184610SalfredMODULE_DEPEND(uaudio, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
3847184610SalfredMODULE_VERSION(uaudio, 1);
3848