uaudio.c revision 209450
1184610Salfred/*	$NetBSD: uaudio.c,v 1.91 2004/11/05 17:46:14 kent Exp $	*/
2184610Salfred/*	$FreeBSD: head/sys/dev/sound/usb/uaudio.c 209450 2010-06-22 21:13:36Z 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,
795184610Salfred		    ed->bRefresh, ed->bSynchAddress);
796184610Salfred	}
797184610Salfred}
798184610Salfred
799184610Salfred#endif
800184610Salfred
801184610Salfredstatic void
802192984Sthompsauaudio_chan_fill_info_sub(struct uaudio_softc *sc, struct usb_device *udev,
803200825Sthompsa    uint32_t rate, uint8_t channels, uint8_t bit_resolution)
804184610Salfred{
805192984Sthompsa	struct usb_descriptor *desc = NULL;
806203678Sbrucec	const struct usb_audio_streaming_interface_descriptor *asid = NULL;
807203678Sbrucec	const struct usb_audio_streaming_type1_descriptor *asf1d = NULL;
808203678Sbrucec	const struct usb_audio_streaming_endpoint_descriptor *sed = NULL;
809203678Sbrucec	const usb_endpoint_descriptor_audio_t *ed1 = NULL;
810203678Sbrucec	const usb_endpoint_descriptor_audio_t *ed2 = NULL;
811194228Sthompsa	struct usb_config_descriptor *cd = usbd_get_config_descriptor(udev);
812192984Sthompsa	struct usb_interface_descriptor *id;
813184610Salfred	const struct uaudio_format *p_fmt;
814184610Salfred	struct uaudio_chan *chan;
815184610Salfred	uint16_t curidx = 0xFFFF;
816184610Salfred	uint16_t lastidx = 0xFFFF;
817184610Salfred	uint16_t alt_index = 0;
818184610Salfred	uint16_t wFormat;
819184610Salfred	uint8_t ep_dir;
820184610Salfred	uint8_t ep_type;
821184610Salfred	uint8_t ep_sync;
822184610Salfred	uint8_t bChannels;
823184610Salfred	uint8_t bBitResolution;
824184610Salfred	uint8_t x;
825184610Salfred	uint8_t audio_if = 0;
826184610Salfred
827194228Sthompsa	while ((desc = usb_desc_foreach(cd, desc))) {
828184610Salfred
829184610Salfred		if ((desc->bDescriptorType == UDESC_INTERFACE) &&
830184610Salfred		    (desc->bLength >= sizeof(*id))) {
831184610Salfred
832184610Salfred			id = (void *)desc;
833184610Salfred
834184610Salfred			if (id->bInterfaceNumber != lastidx) {
835184610Salfred				lastidx = id->bInterfaceNumber;
836184610Salfred				curidx++;
837184610Salfred				alt_index = 0;
838184610Salfred
839184610Salfred			} else {
840184610Salfred				alt_index++;
841184610Salfred			}
842184610Salfred
843184610Salfred			if ((id->bInterfaceClass == UICLASS_AUDIO) &&
844184610Salfred			    (id->bInterfaceSubClass == UISUBCLASS_AUDIOSTREAM)) {
845184610Salfred				audio_if = 1;
846184610Salfred			} else {
847184610Salfred				audio_if = 0;
848184610Salfred			}
849184610Salfred
850184610Salfred			if ((id->bInterfaceClass == UICLASS_AUDIO) &&
851184610Salfred			    (id->bInterfaceSubClass == UISUBCLASS_MIDISTREAM)) {
852184610Salfred
853184610Salfred				/*
854184610Salfred				 * XXX could allow multiple MIDI interfaces
855184610Salfred				 * XXX
856184610Salfred				 */
857184610Salfred
858184610Salfred				if ((sc->sc_midi_chan.valid == 0) &&
859194228Sthompsa				    usbd_get_iface(udev, curidx)) {
860184610Salfred					sc->sc_midi_chan.iface_index = curidx;
861184610Salfred					sc->sc_midi_chan.iface_alt_index = alt_index;
862184610Salfred					sc->sc_midi_chan.valid = 1;
863184610Salfred				}
864184610Salfred			}
865184610Salfred			asid = NULL;
866184610Salfred			asf1d = NULL;
867184610Salfred			ed1 = NULL;
868184610Salfred			ed2 = NULL;
869184610Salfred			sed = NULL;
870184610Salfred		}
871184610Salfred		if ((desc->bDescriptorType == UDESC_CS_INTERFACE) &&
872184610Salfred		    (desc->bDescriptorSubtype == AS_GENERAL) &&
873184610Salfred		    (desc->bLength >= sizeof(*asid))) {
874184610Salfred			if (asid == NULL) {
875184610Salfred				asid = (void *)desc;
876184610Salfred			}
877184610Salfred		}
878184610Salfred		if ((desc->bDescriptorType == UDESC_CS_INTERFACE) &&
879184610Salfred		    (desc->bDescriptorSubtype == FORMAT_TYPE) &&
880184610Salfred		    (desc->bLength >= sizeof(*asf1d))) {
881184610Salfred			if (asf1d == NULL) {
882184610Salfred				asf1d = (void *)desc;
883184610Salfred				if (asf1d->bFormatType != FORMAT_TYPE_I) {
884184610Salfred					DPRINTFN(11, "ignored bFormatType = %d\n",
885184610Salfred					    asf1d->bFormatType);
886184610Salfred					asf1d = NULL;
887184610Salfred					continue;
888184610Salfred				}
889184610Salfred				if (asf1d->bLength < (sizeof(*asf1d) +
890184610Salfred				    (asf1d->bSamFreqType == 0) ? 6 :
891184610Salfred				    (asf1d->bSamFreqType * 3))) {
892184610Salfred					DPRINTFN(11, "'asf1d' descriptor is too short\n");
893184610Salfred					asf1d = NULL;
894184610Salfred					continue;
895184610Salfred				}
896184610Salfred			}
897184610Salfred		}
898184610Salfred		if ((desc->bDescriptorType == UDESC_ENDPOINT) &&
899184610Salfred		    (desc->bLength >= sizeof(*ed1))) {
900184610Salfred			if (ed1 == NULL) {
901184610Salfred				ed1 = (void *)desc;
902184610Salfred				if (UE_GET_XFERTYPE(ed1->bmAttributes) != UE_ISOCHRONOUS) {
903184610Salfred					ed1 = NULL;
904184610Salfred				}
905184610Salfred			} else {
906184610Salfred				if (ed2 == NULL) {
907184610Salfred					ed2 = (void *)desc;
908184610Salfred					if (UE_GET_XFERTYPE(ed2->bmAttributes) != UE_ISOCHRONOUS) {
909184610Salfred						ed2 = NULL;
910184610Salfred						continue;
911184610Salfred					}
912184610Salfred					if (ed2->bSynchAddress != 0) {
913184610Salfred						DPRINTFN(11, "invalid endpoint: bSynchAddress != 0\n");
914184610Salfred						ed2 = NULL;
915184610Salfred						continue;
916184610Salfred					}
917184610Salfred					if (ed2->bEndpointAddress != ed1->bSynchAddress) {
918184610Salfred						DPRINTFN(11, "invalid endpoint addresses: "
919184610Salfred						    "ep[0]->bSynchAddress=0x%x "
920184610Salfred						    "ep[1]->bEndpointAddress=0x%x\n",
921184610Salfred						    ed1->bSynchAddress,
922184610Salfred						    ed2->bEndpointAddress);
923184610Salfred						ed2 = NULL;
924184610Salfred						continue;
925184610Salfred					}
926184610Salfred				}
927184610Salfred			}
928184610Salfred		}
929184610Salfred		if ((desc->bDescriptorType == UDESC_CS_ENDPOINT) &&
930184610Salfred		    (desc->bDescriptorSubtype == AS_GENERAL) &&
931184610Salfred		    (desc->bLength >= sizeof(*sed))) {
932184610Salfred			if (sed == NULL) {
933184610Salfred				sed = (void *)desc;
934184610Salfred			}
935184610Salfred		}
936184610Salfred		if (audio_if && asid && asf1d && ed1 && sed) {
937184610Salfred
938184610Salfred			ep_dir = UE_GET_DIR(ed1->bEndpointAddress);
939184610Salfred			ep_type = UE_GET_ISO_TYPE(ed1->bmAttributes);
940184610Salfred			ep_sync = 0;
941184610Salfred
942184610Salfred			if ((sc->sc_uq_au_inp_async) &&
943184610Salfred			    (ep_dir == UE_DIR_IN) && (ep_type == UE_ISO_ADAPT)) {
944184610Salfred				ep_type = UE_ISO_ASYNC;
945184610Salfred			}
946184610Salfred			if ((ep_dir == UE_DIR_IN) && (ep_type == UE_ISO_ADAPT)) {
947184610Salfred				ep_sync = 1;
948184610Salfred			}
949184610Salfred			if ((ep_dir != UE_DIR_IN) && (ep_type == UE_ISO_ASYNC)) {
950184610Salfred				ep_sync = 1;
951184610Salfred			}
952184610Salfred			/* Ignore sync endpoint information until further. */
953184610Salfred#if 0
954184610Salfred			if (ep_sync && (!ed2)) {
955184610Salfred				continue;
956184610Salfred			}
957184610Salfred			/*
958184610Salfred			 * we can't handle endpoints that need a sync pipe
959184610Salfred			 * yet
960184610Salfred			 */
961184610Salfred
962184610Salfred			if (ep_sync) {
963184610Salfred				DPRINTF("skipped sync interface\n");
964184610Salfred				audio_if = 0;
965184610Salfred				continue;
966184610Salfred			}
967184610Salfred#endif
968184610Salfred
969184610Salfred			wFormat = UGETW(asid->wFormatTag);
970192929Sthompsa			bChannels = UAUDIO_MAX_CHAN(asf1d->bNrChannels);
971184610Salfred			bBitResolution = asf1d->bBitResolution;
972184610Salfred
973184610Salfred			if (asf1d->bSamFreqType == 0) {
974184610Salfred				DPRINTFN(16, "Sample rate: %d-%dHz\n",
975184610Salfred				    UA_SAMP_LO(asf1d), UA_SAMP_HI(asf1d));
976184610Salfred
977184610Salfred				if ((rate >= UA_SAMP_LO(asf1d)) &&
978184610Salfred				    (rate <= UA_SAMP_HI(asf1d))) {
979184610Salfred					goto found_rate;
980184610Salfred				}
981184610Salfred			} else {
982184610Salfred
983184610Salfred				for (x = 0; x < asf1d->bSamFreqType; x++) {
984184610Salfred					DPRINTFN(16, "Sample rate = %dHz\n",
985184610Salfred					    UA_GETSAMP(asf1d, x));
986184610Salfred
987184610Salfred					if (rate == UA_GETSAMP(asf1d, x)) {
988184610Salfred						goto found_rate;
989184610Salfred					}
990184610Salfred				}
991184610Salfred			}
992184610Salfred
993184610Salfred			audio_if = 0;
994184610Salfred			continue;
995184610Salfred
996184610Salfred	found_rate:
997184610Salfred
998184610Salfred			for (p_fmt = uaudio_formats;
999184610Salfred			    p_fmt->wFormat;
1000184610Salfred			    p_fmt++) {
1001184610Salfred				if ((p_fmt->wFormat == wFormat) &&
1002184610Salfred				    (p_fmt->bPrecision == bBitResolution)) {
1003184610Salfred					goto found_format;
1004184610Salfred				}
1005184610Salfred			}
1006184610Salfred
1007184610Salfred			audio_if = 0;
1008184610Salfred			continue;
1009184610Salfred
1010184610Salfred	found_format:
1011184610Salfred
1012184610Salfred			if ((bChannels == channels) &&
1013184610Salfred			    (bBitResolution == bit_resolution)) {
1014184610Salfred
1015184610Salfred				chan = (ep_dir == UE_DIR_IN) ?
1016184610Salfred				    &sc->sc_rec_chan :
1017184610Salfred				    &sc->sc_play_chan;
1018184610Salfred
1019194228Sthompsa				if ((chan->valid == 0) && usbd_get_iface(udev, curidx)) {
1020184610Salfred
1021184610Salfred					chan->valid = 1;
1022207077Sthompsa#ifdef USB_DEBUG
1023184610Salfred					uaudio_chan_dump_ep_desc(ed1);
1024184610Salfred					uaudio_chan_dump_ep_desc(ed2);
1025184610Salfred
1026184610Salfred					if (sed->bmAttributes & UA_SED_FREQ_CONTROL) {
1027184610Salfred						DPRINTFN(2, "FREQ_CONTROL\n");
1028184610Salfred					}
1029184610Salfred					if (sed->bmAttributes & UA_SED_PITCH_CONTROL) {
1030184610Salfred						DPRINTFN(2, "PITCH_CONTROL\n");
1031184610Salfred					}
1032184610Salfred#endif
1033184610Salfred					DPRINTF("Sample rate = %dHz, channels = %d, "
1034184610Salfred					    "bits = %d, format = %s\n", rate, channels,
1035184610Salfred					    bit_resolution, p_fmt->description);
1036184610Salfred
1037184610Salfred					chan->sample_rate = rate;
1038184610Salfred					chan->p_asid = asid;
1039184610Salfred					chan->p_asf1d = asf1d;
1040184610Salfred					chan->p_ed1 = ed1;
1041184610Salfred					chan->p_ed2 = ed2;
1042184610Salfred					chan->p_fmt = p_fmt;
1043184610Salfred					chan->p_sed = sed;
1044184610Salfred					chan->iface_index = curidx;
1045184610Salfred					chan->iface_alt_index = alt_index;
1046184610Salfred
1047186730Salfred					if (ep_dir == UE_DIR_IN)
1048203678Sbrucec						chan->usb_cfg =
1049186730Salfred						    uaudio_cfg_record;
1050186730Salfred					else
1051203678Sbrucec						chan->usb_cfg =
1052186730Salfred						    uaudio_cfg_play;
1053184610Salfred
1054200825Sthompsa					chan->sample_size = ((
1055192929Sthompsa					    UAUDIO_MAX_CHAN(chan->p_asf1d->bNrChannels) *
1056184610Salfred					    chan->p_asf1d->bBitResolution) / 8);
1057184610Salfred
1058184610Salfred					if (sc->sc_sndstat_valid) {
1059184610Salfred						sbuf_printf(&sc->sc_sndstat, "\n\t"
1060184610Salfred						    "mode %d.%d:(%s) %dch, %d/%dbit, %s, %dHz",
1061184610Salfred						    curidx, alt_index,
1062184610Salfred						    (ep_dir == UE_DIR_IN) ? "input" : "output",
1063184610Salfred						    asf1d->bNrChannels, asf1d->bBitResolution,
1064184610Salfred						    asf1d->bSubFrameSize * 8,
1065184610Salfred						    p_fmt->description, rate);
1066184610Salfred					}
1067184610Salfred				}
1068184610Salfred			}
1069184610Salfred			audio_if = 0;
1070184610Salfred			continue;
1071184610Salfred		}
1072184610Salfred	}
1073184610Salfred}
1074184610Salfred
1075200825Sthompsa/* This structure defines all the supported rates. */
1076200825Sthompsa
1077200825Sthompsastatic const uint32_t uaudio_rate_list[] = {
1078200825Sthompsa	96000,
1079200825Sthompsa	88000,
1080200825Sthompsa	80000,
1081200825Sthompsa	72000,
1082200825Sthompsa	64000,
1083200825Sthompsa	56000,
1084200825Sthompsa	48000,
1085200825Sthompsa	44100,
1086200825Sthompsa	40000,
1087200825Sthompsa	32000,
1088200825Sthompsa	24000,
1089200825Sthompsa	22050,
1090200825Sthompsa	16000,
1091200825Sthompsa	11025,
1092200825Sthompsa	8000,
1093200825Sthompsa	0
1094200825Sthompsa};
1095200825Sthompsa
1096184610Salfredstatic void
1097192984Sthompsauaudio_chan_fill_info(struct uaudio_softc *sc, struct usb_device *udev)
1098184610Salfred{
1099184610Salfred	uint32_t rate = uaudio_default_rate;
1100200825Sthompsa	uint8_t z;
1101184610Salfred	uint8_t bits = uaudio_default_bits;
1102184610Salfred	uint8_t y;
1103184610Salfred	uint8_t channels = uaudio_default_channels;
1104184610Salfred	uint8_t x;
1105184610Salfred
1106184610Salfred	bits -= (bits % 8);
1107186730Salfred	if ((bits == 0) || (bits > 32)) {
1108186730Salfred		/* set a valid value */
1109186730Salfred		bits = 32;
1110186730Salfred	}
1111200825Sthompsa	if (channels == 0) {
1112200825Sthompsa		switch (usbd_get_speed(udev)) {
1113200825Sthompsa		case USB_SPEED_LOW:
1114200825Sthompsa		case USB_SPEED_FULL:
1115200825Sthompsa			/*
1116200825Sthompsa			 * Due to high bandwidth usage and problems
1117200825Sthompsa			 * with HIGH-speed split transactions we
1118200825Sthompsa			 * disable surround setups on FULL-speed USB
1119200825Sthompsa			 * by default
1120200825Sthompsa			 */
1121200825Sthompsa			channels = 2;
1122200825Sthompsa			break;
1123200825Sthompsa		default:
1124200825Sthompsa			channels = 16;
1125200825Sthompsa			break;
1126200825Sthompsa		}
1127200825Sthompsa	} else if (channels > 16) {
1128200825Sthompsa		channels = 16;
1129186730Salfred	}
1130184610Salfred	if (sbuf_new(&sc->sc_sndstat, NULL, 4096, SBUF_AUTOEXTEND)) {
1131184610Salfred		sc->sc_sndstat_valid = 1;
1132184610Salfred	}
1133184610Salfred	/* try to search for a valid config */
1134184610Salfred
1135184610Salfred	for (x = channels; x; x--) {
1136184610Salfred		for (y = bits; y; y -= 8) {
1137184610Salfred
1138200825Sthompsa			/* try user defined rate, if any */
1139200825Sthompsa			if (rate != 0)
1140200825Sthompsa				uaudio_chan_fill_info_sub(sc, udev, rate, x, y);
1141200825Sthompsa
1142200825Sthompsa			/* try find a matching rate, if any */
1143200825Sthompsa			for (z = 0; uaudio_rate_list[z]; z++) {
1144200825Sthompsa				uaudio_chan_fill_info_sub(sc, udev, uaudio_rate_list[z], x, y);
1145200825Sthompsa
1146184610Salfred				if (sc->sc_rec_chan.valid &&
1147184610Salfred				    sc->sc_play_chan.valid) {
1148184610Salfred					goto done;
1149184610Salfred				}
1150184610Salfred			}
1151184610Salfred		}
1152184610Salfred	}
1153184610Salfred
1154184610Salfreddone:
1155184610Salfred	if (sc->sc_sndstat_valid) {
1156184610Salfred		sbuf_finish(&sc->sc_sndstat);
1157184610Salfred	}
1158184610Salfred}
1159184610Salfred
1160184610Salfredstatic void
1161194677Sthompsauaudio_chan_play_callback(struct usb_xfer *xfer, usb_error_t error)
1162184610Salfred{
1163194677Sthompsa	struct uaudio_chan *ch = usbd_xfer_softc(xfer);
1164194677Sthompsa	struct usb_page_cache *pc;
1165186730Salfred	uint32_t total;
1166184610Salfred	uint32_t blockcount;
1167184610Salfred	uint32_t n;
1168184610Salfred	uint32_t offset;
1169200825Sthompsa	int actlen;
1170200825Sthompsa	int sumlen;
1171184610Salfred
1172194677Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
1173194677Sthompsa
1174199060Sthompsa	if (ch->end == ch->start) {
1175199060Sthompsa		DPRINTF("no buffer!\n");
1176199060Sthompsa		return;
1177199060Sthompsa	}
1178199060Sthompsa
1179184610Salfred	switch (USB_GET_STATE(xfer)) {
1180184610Salfred	case USB_ST_TRANSFERRED:
1181184610Salfredtr_transferred:
1182194677Sthompsa		if (actlen < sumlen) {
1183184610Salfred			DPRINTF("short transfer, "
1184200825Sthompsa			    "%d of %d bytes\n", actlen, sumlen);
1185184610Salfred		}
1186184610Salfred		chn_intr(ch->pcm_ch);
1187184610Salfred
1188184610Salfred	case USB_ST_SETUP:
1189200825Sthompsa		if (ch->bytes_per_frame[1] > usbd_xfer_max_framelen(xfer)) {
1190184610Salfred			DPRINTF("bytes per transfer, %d, "
1191184610Salfred			    "exceeds maximum, %d!\n",
1192200825Sthompsa			    ch->bytes_per_frame[1],
1193194677Sthompsa			    usbd_xfer_max_framelen(xfer));
1194184610Salfred			break;
1195184610Salfred		}
1196200825Sthompsa
1197200825Sthompsa		blockcount = ch->intr_frames;
1198200825Sthompsa
1199200825Sthompsa		/* setup number of frames */
1200194677Sthompsa		usbd_xfer_set_frames(xfer, blockcount);
1201184610Salfred
1202200825Sthompsa		/* reset total length */
1203200825Sthompsa		total = 0;
1204200825Sthompsa
1205200825Sthompsa		/* setup frame lengths */
1206200825Sthompsa		for (n = 0; n != blockcount; n++) {
1207200825Sthompsa			ch->sample_curr += ch->sample_rem;
1208200825Sthompsa			if (ch->sample_curr >= ch->frames_per_second) {
1209200825Sthompsa				ch->sample_curr -= ch->frames_per_second;
1210200825Sthompsa				usbd_xfer_set_frame_len(xfer, n, ch->bytes_per_frame[1]);
1211200825Sthompsa				total += ch->bytes_per_frame[1];
1212200825Sthompsa			} else {
1213200825Sthompsa				usbd_xfer_set_frame_len(xfer, n, ch->bytes_per_frame[0]);
1214200825Sthompsa				total += ch->bytes_per_frame[0];
1215200825Sthompsa			}
1216200825Sthompsa		}
1217200825Sthompsa
1218184610Salfred		DPRINTFN(6, "transfer %d bytes\n", total);
1219184610Salfred
1220184610Salfred		offset = 0;
1221184610Salfred
1222194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
1223184610Salfred		while (total > 0) {
1224184610Salfred
1225184610Salfred			n = (ch->end - ch->cur);
1226184610Salfred			if (n > total) {
1227184610Salfred				n = total;
1228184610Salfred			}
1229194677Sthompsa			usbd_copy_in(pc, offset, ch->cur, n);
1230184610Salfred
1231184610Salfred			total -= n;
1232184610Salfred			ch->cur += n;
1233184610Salfred			offset += n;
1234184610Salfred
1235184610Salfred			if (ch->cur >= ch->end) {
1236184610Salfred				ch->cur = ch->start;
1237184610Salfred			}
1238184610Salfred		}
1239184610Salfred
1240194228Sthompsa		usbd_transfer_submit(xfer);
1241184610Salfred		break;
1242184610Salfred
1243184610Salfred	default:			/* Error */
1244194677Sthompsa		if (error == USB_ERR_CANCELLED) {
1245184610Salfred			break;
1246184610Salfred		}
1247184610Salfred		goto tr_transferred;
1248184610Salfred	}
1249184610Salfred}
1250184610Salfred
1251184610Salfredstatic void
1252194677Sthompsauaudio_chan_record_callback(struct usb_xfer *xfer, usb_error_t error)
1253184610Salfred{
1254194677Sthompsa	struct uaudio_chan *ch = usbd_xfer_softc(xfer);
1255194677Sthompsa	struct usb_page_cache *pc;
1256184610Salfred	uint32_t n;
1257184610Salfred	uint32_t m;
1258184610Salfred	uint32_t blockcount;
1259184610Salfred	uint32_t offset0;
1260184610Salfred	uint32_t offset1;
1261199060Sthompsa	uint32_t mfl;
1262194677Sthompsa	int len;
1263199060Sthompsa	int actlen;
1264199060Sthompsa	int nframes;
1265184610Salfred
1266194677Sthompsa	usbd_xfer_status(xfer, &actlen, NULL, NULL, &nframes);
1267199060Sthompsa	mfl = usbd_xfer_max_framelen(xfer);
1268194677Sthompsa
1269199060Sthompsa	if (ch->end == ch->start) {
1270199060Sthompsa		DPRINTF("no buffer!\n");
1271199060Sthompsa		return;
1272199060Sthompsa	}
1273199060Sthompsa
1274184610Salfred	switch (USB_GET_STATE(xfer)) {
1275184610Salfred	case USB_ST_TRANSFERRED:
1276184610Salfred
1277200825Sthompsa		DPRINTFN(6, "transferred %d bytes\n", actlen);
1278200825Sthompsa
1279184610Salfred		offset0 = 0;
1280199060Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
1281184610Salfred
1282194677Sthompsa		for (n = 0; n != nframes; n++) {
1283184610Salfred
1284184610Salfred			offset1 = offset0;
1285194682Sthompsa			len = usbd_xfer_frame_len(xfer, n);
1286184610Salfred
1287194677Sthompsa			while (len > 0) {
1288184610Salfred
1289184610Salfred				m = (ch->end - ch->cur);
1290184610Salfred
1291194677Sthompsa				if (m > len) {
1292194677Sthompsa					m = len;
1293184610Salfred				}
1294194677Sthompsa				usbd_copy_out(pc, offset1, ch->cur, m);
1295184610Salfred
1296194677Sthompsa				len -= m;
1297184610Salfred				offset1 += m;
1298184610Salfred				ch->cur += m;
1299184610Salfred
1300184610Salfred				if (ch->cur >= ch->end) {
1301184610Salfred					ch->cur = ch->start;
1302184610Salfred				}
1303184610Salfred			}
1304184610Salfred
1305199060Sthompsa			offset0 += mfl;
1306184610Salfred		}
1307184610Salfred
1308184610Salfred		chn_intr(ch->pcm_ch);
1309184610Salfred
1310184610Salfred	case USB_ST_SETUP:
1311199060Sthompsatr_setup:
1312200825Sthompsa		blockcount = ch->intr_frames;
1313200825Sthompsa
1314194677Sthompsa		usbd_xfer_set_frames(xfer, blockcount);
1315194677Sthompsa		for (n = 0; n < blockcount; n++) {
1316199060Sthompsa			usbd_xfer_set_frame_len(xfer, n, mfl);
1317184610Salfred		}
1318184610Salfred
1319194228Sthompsa		usbd_transfer_submit(xfer);
1320199060Sthompsa		break;
1321184610Salfred
1322184610Salfred	default:			/* Error */
1323194677Sthompsa		if (error == USB_ERR_CANCELLED) {
1324199060Sthompsa			break;
1325184610Salfred		}
1326199060Sthompsa		goto tr_setup;
1327184610Salfred	}
1328184610Salfred}
1329184610Salfred
1330184610Salfredvoid   *
1331184610Salfreduaudio_chan_init(struct uaudio_softc *sc, struct snd_dbuf *b,
1332184610Salfred    struct pcm_channel *c, int dir)
1333184610Salfred{
1334184610Salfred	struct uaudio_chan *ch = ((dir == PCMDIR_PLAY) ?
1335184610Salfred	    &sc->sc_play_chan : &sc->sc_rec_chan);
1336186730Salfred	uint32_t buf_size;
1337199060Sthompsa	uint32_t frames;
1338200825Sthompsa	uint32_t format;
1339200825Sthompsa	uint16_t fps;
1340184610Salfred	uint8_t endpoint;
1341199060Sthompsa	uint8_t blocks;
1342184610Salfred	uint8_t iface_index;
1343184610Salfred	uint8_t alt_index;
1344199060Sthompsa	uint8_t fps_shift;
1345193045Sthompsa	usb_error_t err;
1346184610Salfred
1347200825Sthompsa	fps = usbd_get_isoc_fps(sc->sc_udev);
1348200825Sthompsa
1349200825Sthompsa	if (fps < 8000) {
1350199060Sthompsa		/* FULL speed USB */
1351199060Sthompsa		frames = 8;
1352199060Sthompsa	} else {
1353199060Sthompsa		/* HIGH speed USB */
1354199060Sthompsa		frames = UAUDIO_NFRAMES;
1355199060Sthompsa	}
1356199060Sthompsa
1357184610Salfred	/* setup play/record format */
1358184610Salfred
1359184610Salfred	ch->pcm_cap.fmtlist = ch->pcm_format;
1360184610Salfred
1361184610Salfred	ch->pcm_format[0] = 0;
1362184610Salfred	ch->pcm_format[1] = 0;
1363184610Salfred
1364184610Salfred	ch->pcm_cap.minspeed = ch->sample_rate;
1365184610Salfred	ch->pcm_cap.maxspeed = ch->sample_rate;
1366184610Salfred
1367199576Sthompsa	/* setup mutex and PCM channel */
1368199576Sthompsa
1369199576Sthompsa	ch->pcm_ch = c;
1370199576Sthompsa	ch->pcm_mtx = c->lock;
1371199576Sthompsa
1372200825Sthompsa	format = ch->p_fmt->freebsd_fmt;
1373184610Salfred
1374200825Sthompsa	switch (ch->p_asf1d->bNrChannels) {
1375200825Sthompsa	case 2:
1376200825Sthompsa		/* stereo */
1377200825Sthompsa		format = SND_FORMAT(format, 2, 0);
1378200825Sthompsa		break;
1379200825Sthompsa	case 1:
1380200825Sthompsa		/* mono */
1381200825Sthompsa		format = SND_FORMAT(format, 1, 0);
1382200825Sthompsa		break;
1383200825Sthompsa	default:
1384200825Sthompsa		/* surround and more */
1385200825Sthompsa		format = feeder_matrix_default_format(
1386200825Sthompsa		    SND_FORMAT(format, ch->p_asf1d->bNrChannels, 0));
1387200825Sthompsa		break;
1388200825Sthompsa	}
1389200825Sthompsa
1390200825Sthompsa	ch->pcm_cap.fmtlist[0] = format;
1391184610Salfred	ch->pcm_cap.fmtlist[1] = 0;
1392184610Salfred
1393200825Sthompsa	/* check if format is not supported */
1394200825Sthompsa
1395200825Sthompsa	if (format == 0) {
1396200825Sthompsa		DPRINTF("The selected audio format is not supported\n");
1397200825Sthompsa		goto error;
1398200825Sthompsa	}
1399200825Sthompsa
1400184610Salfred	/* set alternate interface corresponding to the mode */
1401184610Salfred
1402184610Salfred	endpoint = ch->p_ed1->bEndpointAddress;
1403184610Salfred	iface_index = ch->iface_index;
1404184610Salfred	alt_index = ch->iface_alt_index;
1405184610Salfred
1406184610Salfred	DPRINTF("endpoint=0x%02x, speed=%d, iface=%d alt=%d\n",
1407184610Salfred	    endpoint, ch->sample_rate, iface_index, alt_index);
1408184610Salfred
1409194228Sthompsa	err = usbd_set_alt_interface_index(sc->sc_udev, iface_index, alt_index);
1410184610Salfred	if (err) {
1411184610Salfred		DPRINTF("setting of alternate index failed: %s!\n",
1412194228Sthompsa		    usbd_errstr(err));
1413184610Salfred		goto error;
1414184610Salfred	}
1415194228Sthompsa	usbd_set_parent_iface(sc->sc_udev, iface_index, sc->sc_mixer_iface_index);
1416184610Salfred
1417184610Salfred	/*
1418184610Salfred	 * If just one sampling rate is supported,
1419184610Salfred	 * no need to call "uaudio_set_speed()".
1420184610Salfred	 * Roland SD-90 freezes by a SAMPLING_FREQ_CONTROL request.
1421184610Salfred	 */
1422184610Salfred	if (ch->p_asf1d->bSamFreqType != 1) {
1423184610Salfred		if (uaudio_set_speed(sc->sc_udev, endpoint, ch->sample_rate)) {
1424184610Salfred			/*
1425184610Salfred			 * If the endpoint is adaptive setting the speed may
1426184610Salfred			 * fail.
1427184610Salfred			 */
1428184610Salfred			DPRINTF("setting of sample rate failed! (continuing anyway)\n");
1429184610Salfred		}
1430184610Salfred	}
1431194228Sthompsa	if (usbd_transfer_setup(sc->sc_udev, &iface_index, ch->xfer,
1432203678Sbrucec	    ch->usb_cfg, UAUDIO_NCHANBUFS, ch, ch->pcm_mtx)) {
1433184610Salfred		DPRINTF("could not allocate USB transfers!\n");
1434184610Salfred		goto error;
1435184610Salfred	}
1436199060Sthompsa
1437199060Sthompsa	fps_shift = usbd_xfer_get_fps_shift(ch->xfer[0]);
1438199060Sthompsa
1439200825Sthompsa	/* down shift number of frames per second, if any */
1440200825Sthompsa	fps >>= fps_shift;
1441200825Sthompsa	frames >>= fps_shift;
1442200825Sthompsa
1443200825Sthompsa	/* bytes per frame should not be zero */
1444200825Sthompsa	ch->bytes_per_frame[0] = ((ch->sample_rate / fps) * ch->sample_size);
1445200825Sthompsa	ch->bytes_per_frame[1] = (((ch->sample_rate + fps - 1) / fps) * ch->sample_size);
1446200825Sthompsa
1447200825Sthompsa	/* setup data rate dithering, if any */
1448200825Sthompsa	ch->frames_per_second = fps;
1449200825Sthompsa	ch->sample_rem = ch->sample_rate % fps;
1450200825Sthompsa	ch->sample_curr = 0;
1451200825Sthompsa	ch->frames_per_second = fps;
1452200825Sthompsa
1453200825Sthompsa	/* compute required buffer size */
1454200825Sthompsa	buf_size = (ch->bytes_per_frame[1] * frames);
1455200825Sthompsa
1456199060Sthompsa	ch->intr_size = buf_size;
1457200825Sthompsa	ch->intr_frames = frames;
1458199060Sthompsa
1459200825Sthompsa	DPRINTF("fps=%d sample_rem=%d\n", fps, ch->sample_rem);
1460200825Sthompsa
1461199060Sthompsa	if (ch->intr_frames == 0) {
1462199060Sthompsa		DPRINTF("frame shift is too high!\n");
1463199060Sthompsa		goto error;
1464199060Sthompsa	}
1465199060Sthompsa
1466199060Sthompsa	/* setup double buffering */
1467199060Sthompsa	buf_size *= 2;
1468199060Sthompsa	blocks = 2;
1469199060Sthompsa
1470199060Sthompsa	ch->buf = malloc(buf_size, M_DEVBUF, M_WAITOK | M_ZERO);
1471199060Sthompsa	if (ch->buf == NULL)
1472199060Sthompsa		goto error;
1473199060Sthompsa	if (sndbuf_setup(b, ch->buf, buf_size) != 0)
1474199060Sthompsa		goto error;
1475199060Sthompsa	if (sndbuf_resize(b, blocks, ch->intr_size))
1476199060Sthompsa		goto error;
1477199060Sthompsa
1478199060Sthompsa	ch->start = ch->buf;
1479199060Sthompsa	ch->end = ch->buf + buf_size;
1480199060Sthompsa	ch->cur = ch->buf;
1481199060Sthompsa	ch->pcm_buf = b;
1482199060Sthompsa
1483199060Sthompsa	if (ch->pcm_mtx == NULL) {
1484199060Sthompsa		DPRINTF("ERROR: PCM channels does not have a mutex!\n");
1485199060Sthompsa		goto error;
1486199060Sthompsa	}
1487199060Sthompsa
1488184610Salfred	return (ch);
1489184610Salfred
1490184610Salfrederror:
1491184610Salfred	uaudio_chan_free(ch);
1492184610Salfred	return (NULL);
1493184610Salfred}
1494184610Salfred
1495184610Salfredint
1496184610Salfreduaudio_chan_free(struct uaudio_chan *ch)
1497184610Salfred{
1498184610Salfred	if (ch->buf != NULL) {
1499184610Salfred		free(ch->buf, M_DEVBUF);
1500184610Salfred		ch->buf = NULL;
1501184610Salfred	}
1502194228Sthompsa	usbd_transfer_unsetup(ch->xfer, UAUDIO_NCHANBUFS);
1503184610Salfred
1504184610Salfred	ch->valid = 0;
1505184610Salfred
1506184610Salfred	return (0);
1507184610Salfred}
1508184610Salfred
1509184610Salfredint
1510184610Salfreduaudio_chan_set_param_blocksize(struct uaudio_chan *ch, uint32_t blocksize)
1511184610Salfred{
1512199060Sthompsa	return (ch->intr_size);
1513184610Salfred}
1514184610Salfred
1515184610Salfredint
1516184610Salfreduaudio_chan_set_param_fragments(struct uaudio_chan *ch, uint32_t blocksize,
1517184610Salfred    uint32_t blockcount)
1518184610Salfred{
1519184610Salfred	return (1);
1520184610Salfred}
1521184610Salfred
1522184610Salfredint
1523184610Salfreduaudio_chan_set_param_speed(struct uaudio_chan *ch, uint32_t speed)
1524184610Salfred{
1525184610Salfred	if (speed != ch->sample_rate) {
1526184610Salfred		DPRINTF("rate conversion required\n");
1527184610Salfred	}
1528184610Salfred	return (ch->sample_rate);
1529184610Salfred}
1530184610Salfred
1531184610Salfredint
1532184610Salfreduaudio_chan_getptr(struct uaudio_chan *ch)
1533184610Salfred{
1534184610Salfred	return (ch->cur - ch->start);
1535184610Salfred}
1536184610Salfred
1537184610Salfredstruct pcmchan_caps *
1538184610Salfreduaudio_chan_getcaps(struct uaudio_chan *ch)
1539184610Salfred{
1540184610Salfred	return (&ch->pcm_cap);
1541184610Salfred}
1542184610Salfred
1543193640Sariffstatic struct pcmchan_matrix uaudio_chan_matrix_swap_2_0 = {
1544193640Sariff	.id = SND_CHN_MATRIX_DRV,
1545193640Sariff	.channels = 2,
1546193640Sariff	.ext = 0,
1547193640Sariff	.map = {
1548193640Sariff		/* Right */
1549193640Sariff		[0] = {
1550193640Sariff			.type = SND_CHN_T_FR,
1551193640Sariff			.members =
1552193640Sariff			    SND_CHN_T_MASK_FR | SND_CHN_T_MASK_FC |
1553193640Sariff			    SND_CHN_T_MASK_LF | SND_CHN_T_MASK_BR |
1554193640Sariff			    SND_CHN_T_MASK_BC | SND_CHN_T_MASK_SR
1555193640Sariff		},
1556193640Sariff		/* Left */
1557193640Sariff		[1] = {
1558193640Sariff			.type = SND_CHN_T_FL,
1559193640Sariff			.members =
1560193640Sariff			    SND_CHN_T_MASK_FL | SND_CHN_T_MASK_FC |
1561193640Sariff			    SND_CHN_T_MASK_LF | SND_CHN_T_MASK_BL |
1562193640Sariff			    SND_CHN_T_MASK_BC | SND_CHN_T_MASK_SL
1563193640Sariff		},
1564193640Sariff		[2] = {
1565193640Sariff			.type = SND_CHN_T_MAX,
1566193640Sariff			.members = 0
1567193640Sariff		}
1568193640Sariff	},
1569193640Sariff	.mask = SND_CHN_T_MASK_FR | SND_CHN_T_MASK_FL,
1570193640Sariff	.offset = {  1,  0, -1, -1, -1, -1, -1, -1, -1,
1571193640Sariff		    -1, -1, -1, -1, -1, -1, -1, -1, -1  }
1572193640Sariff};
1573193640Sariff
1574193640Sariffstruct pcmchan_matrix *
1575193640Sariffuaudio_chan_getmatrix(struct uaudio_chan *ch, uint32_t format)
1576193640Sariff{
1577193640Sariff	struct uaudio_softc *sc;
1578193640Sariff
1579193640Sariff	sc = ch->priv_sc;
1580193640Sariff
1581193640Sariff	if (sc != NULL && sc->sc_uq_audio_swap_lr != 0 &&
1582193640Sariff	    AFMT_CHANNEL(format) == 2)
1583193640Sariff		return (&uaudio_chan_matrix_swap_2_0);
1584193640Sariff
1585193640Sariff	return (feeder_matrix_format_map(format));
1586193640Sariff}
1587193640Sariff
1588184610Salfredint
1589184610Salfreduaudio_chan_set_param_format(struct uaudio_chan *ch, uint32_t format)
1590184610Salfred{
1591184610Salfred	ch->format = format;
1592184610Salfred	return (0);
1593184610Salfred}
1594184610Salfred
1595184610Salfredint
1596184610Salfreduaudio_chan_start(struct uaudio_chan *ch)
1597184610Salfred{
1598184610Salfred	ch->cur = ch->start;
1599184610Salfred
1600184610Salfred#if (UAUDIO_NCHANBUFS != 2)
1601184610Salfred#error "please update code"
1602184610Salfred#endif
1603184610Salfred	if (ch->xfer[0]) {
1604194228Sthompsa		usbd_transfer_start(ch->xfer[0]);
1605184610Salfred	}
1606184610Salfred	if (ch->xfer[1]) {
1607194228Sthompsa		usbd_transfer_start(ch->xfer[1]);
1608184610Salfred	}
1609184610Salfred	return (0);
1610184610Salfred}
1611184610Salfred
1612184610Salfredint
1613184610Salfreduaudio_chan_stop(struct uaudio_chan *ch)
1614184610Salfred{
1615184610Salfred#if (UAUDIO_NCHANBUFS != 2)
1616184610Salfred#error "please update code"
1617184610Salfred#endif
1618194228Sthompsa	usbd_transfer_stop(ch->xfer[0]);
1619194228Sthompsa	usbd_transfer_stop(ch->xfer[1]);
1620184610Salfred	return (0);
1621184610Salfred}
1622184610Salfred
1623184610Salfred/*========================================================================*
1624184610Salfred * AC - Audio Controller - routines
1625184610Salfred *========================================================================*/
1626184610Salfred
1627184610Salfredstatic void
1628184610Salfreduaudio_mixer_add_ctl_sub(struct uaudio_softc *sc, struct uaudio_mixer_node *mc)
1629184610Salfred{
1630184610Salfred	struct uaudio_mixer_node *p_mc_new =
1631184610Salfred	malloc(sizeof(*p_mc_new), M_USBDEV, M_WAITOK);
1632184610Salfred
1633184610Salfred	if (p_mc_new) {
1634184610Salfred		bcopy(mc, p_mc_new, sizeof(*p_mc_new));
1635184610Salfred		p_mc_new->next = sc->sc_mixer_root;
1636184610Salfred		sc->sc_mixer_root = p_mc_new;
1637184610Salfred		sc->sc_mixer_count++;
1638184610Salfred	} else {
1639184610Salfred		DPRINTF("out of memory\n");
1640184610Salfred	}
1641184610Salfred}
1642184610Salfred
1643184610Salfredstatic void
1644184610Salfreduaudio_mixer_add_ctl(struct uaudio_softc *sc, struct uaudio_mixer_node *mc)
1645184610Salfred{
1646184610Salfred	int32_t res;
1647184610Salfred
1648184610Salfred	if (mc->class < UAC_NCLASSES) {
1649184610Salfred		DPRINTF("adding %s.%d\n",
1650184610Salfred		    uac_names[mc->class], mc->ctl);
1651184610Salfred	} else {
1652184610Salfred		DPRINTF("adding %d\n", mc->ctl);
1653184610Salfred	}
1654184610Salfred
1655184610Salfred	if (mc->type == MIX_ON_OFF) {
1656184610Salfred		mc->minval = 0;
1657184610Salfred		mc->maxval = 1;
1658184610Salfred	} else if (mc->type == MIX_SELECTOR) {
1659184610Salfred	} else {
1660184610Salfred
1661184610Salfred		/* determine min and max values */
1662184610Salfred
1663184610Salfred		mc->minval = uaudio_mixer_get(sc->sc_udev, GET_MIN, mc);
1664184610Salfred
1665184610Salfred		mc->minval = uaudio_mixer_signext(mc->type, mc->minval);
1666184610Salfred
1667184610Salfred		mc->maxval = uaudio_mixer_get(sc->sc_udev, GET_MAX, mc);
1668184610Salfred
1669199060Sthompsa		mc->maxval = uaudio_mixer_signext(mc->type, mc->maxval);
1670184610Salfred
1671199060Sthompsa		/* check if max and min was swapped */
1672199060Sthompsa
1673199060Sthompsa		if (mc->maxval < mc->minval) {
1674199060Sthompsa			res = mc->maxval;
1675199060Sthompsa			mc->maxval = mc->minval;
1676199060Sthompsa			mc->minval = res;
1677199060Sthompsa		}
1678199060Sthompsa
1679199060Sthompsa		/* compute value range */
1680184610Salfred		mc->mul = mc->maxval - mc->minval;
1681199060Sthompsa		if (mc->mul == 0)
1682184610Salfred			mc->mul = 1;
1683199060Sthompsa
1684199060Sthompsa		/* compute value alignment */
1685184610Salfred		res = uaudio_mixer_get(sc->sc_udev, GET_RES, mc);
1686199576Sthompsa
1687199576Sthompsa		DPRINTF("Resolution = %d\n", (int)res);
1688184610Salfred	}
1689184610Salfred
1690184610Salfred	uaudio_mixer_add_ctl_sub(sc, mc);
1691184610Salfred
1692207077Sthompsa#ifdef USB_DEBUG
1693184610Salfred	if (uaudio_debug > 2) {
1694184610Salfred		uint8_t i;
1695184610Salfred
1696184610Salfred		for (i = 0; i < mc->nchan; i++) {
1697184610Salfred			DPRINTF("[mix] wValue=%04x\n", mc->wValue[0]);
1698184610Salfred		}
1699184610Salfred		DPRINTF("[mix] wIndex=%04x type=%d ctl='%d' "
1700184610Salfred		    "min=%d max=%d\n",
1701184610Salfred		    mc->wIndex, mc->type, mc->ctl,
1702184610Salfred		    mc->minval, mc->maxval);
1703184610Salfred	}
1704184610Salfred#endif
1705184610Salfred}
1706184610Salfred
1707184610Salfredstatic void
1708184610Salfreduaudio_mixer_add_input(struct uaudio_softc *sc,
1709184610Salfred    const struct uaudio_terminal_node *iot, int id)
1710184610Salfred{
1711207077Sthompsa#ifdef USB_DEBUG
1712203678Sbrucec	const struct usb_audio_input_terminal *d = iot[id].u.it;
1713184610Salfred
1714184610Salfred	DPRINTFN(3, "bTerminalId=%d wTerminalType=0x%04x "
1715184610Salfred	    "bAssocTerminal=%d bNrChannels=%d wChannelConfig=%d "
1716184610Salfred	    "iChannelNames=%d\n",
1717184610Salfred	    d->bTerminalId, UGETW(d->wTerminalType), d->bAssocTerminal,
1718184610Salfred	    d->bNrChannels, UGETW(d->wChannelConfig),
1719184610Salfred	    d->iChannelNames);
1720184610Salfred#endif
1721184610Salfred}
1722184610Salfred
1723184610Salfredstatic void
1724184610Salfreduaudio_mixer_add_output(struct uaudio_softc *sc,
1725184610Salfred    const struct uaudio_terminal_node *iot, int id)
1726184610Salfred{
1727207077Sthompsa#ifdef USB_DEBUG
1728203678Sbrucec	const struct usb_audio_output_terminal *d = iot[id].u.ot;
1729184610Salfred
1730184610Salfred	DPRINTFN(3, "bTerminalId=%d wTerminalType=0x%04x "
1731184610Salfred	    "bAssocTerminal=%d bSourceId=%d iTerminal=%d\n",
1732184610Salfred	    d->bTerminalId, UGETW(d->wTerminalType), d->bAssocTerminal,
1733184610Salfred	    d->bSourceId, d->iTerminal);
1734184610Salfred#endif
1735184610Salfred}
1736184610Salfred
1737184610Salfredstatic void
1738184610Salfreduaudio_mixer_add_mixer(struct uaudio_softc *sc,
1739184610Salfred    const struct uaudio_terminal_node *iot, int id)
1740184610Salfred{
1741184610Salfred	struct uaudio_mixer_node mix;
1742184610Salfred
1743203678Sbrucec	const struct usb_audio_mixer_unit_0 *d0 = iot[id].u.mu;
1744203678Sbrucec	const struct usb_audio_mixer_unit_1 *d1;
1745184610Salfred
1746184610Salfred	uint32_t bno;			/* bit number */
1747184610Salfred	uint32_t p;			/* bit number accumulator */
1748184610Salfred	uint32_t mo;			/* matching outputs */
1749184610Salfred	uint32_t mc;			/* matching channels */
1750184610Salfred	uint32_t ichs;			/* input channels */
1751184610Salfred	uint32_t ochs;			/* output channels */
1752184610Salfred	uint32_t c;
1753184610Salfred	uint32_t chs;			/* channels */
1754184610Salfred	uint32_t i;
1755184610Salfred	uint32_t o;
1756184610Salfred
1757184610Salfred	DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n",
1758184610Salfred	    d0->bUnitId, d0->bNrInPins);
1759184610Salfred
1760184610Salfred	/* compute the number of input channels */
1761184610Salfred
1762184610Salfred	ichs = 0;
1763184610Salfred	for (i = 0; i < d0->bNrInPins; i++) {
1764184610Salfred		ichs += (uaudio_mixer_get_cluster(d0->baSourceId[i], iot)
1765184610Salfred		    .bNrChannels);
1766184610Salfred	}
1767184610Salfred
1768184610Salfred	d1 = (const void *)(d0->baSourceId + d0->bNrInPins);
1769184610Salfred
1770184610Salfred	/* and the number of output channels */
1771184610Salfred
1772184610Salfred	ochs = d1->bNrChannels;
1773184610Salfred
1774184610Salfred	DPRINTFN(3, "ichs=%d ochs=%d\n", ichs, ochs);
1775184610Salfred
1776184610Salfred	bzero(&mix, sizeof(mix));
1777184610Salfred
1778184610Salfred	mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no);
1779184610Salfred	uaudio_mixer_determine_class(&iot[id], &mix);
1780184610Salfred	mix.type = MIX_SIGNED_16;
1781184610Salfred
1782184610Salfred	if (uaudio_mixer_verify_desc(d0, ((ichs * ochs) + 7) / 8) == NULL) {
1783184610Salfred		return;
1784184610Salfred	}
1785184610Salfred	for (p = i = 0; i < d0->bNrInPins; i++) {
1786184610Salfred		chs = uaudio_mixer_get_cluster(d0->baSourceId[i], iot).bNrChannels;
1787184610Salfred		mc = 0;
1788184610Salfred		for (c = 0; c < chs; c++) {
1789184610Salfred			mo = 0;
1790184610Salfred			for (o = 0; o < ochs; o++) {
1791184610Salfred				bno = ((p + c) * ochs) + o;
1792184610Salfred				if (BIT_TEST(d1->bmControls, bno)) {
1793184610Salfred					mo++;
1794184610Salfred				}
1795184610Salfred			}
1796184610Salfred			if (mo == 1) {
1797184610Salfred				mc++;
1798184610Salfred			}
1799184610Salfred		}
1800184610Salfred		if ((mc == chs) && (chs <= MIX_MAX_CHAN)) {
1801184610Salfred
1802184610Salfred			/* repeat bit-scan */
1803184610Salfred
1804184610Salfred			mc = 0;
1805184610Salfred			for (c = 0; c < chs; c++) {
1806184610Salfred				for (o = 0; o < ochs; o++) {
1807184610Salfred					bno = ((p + c) * ochs) + o;
1808184610Salfred					if (BIT_TEST(d1->bmControls, bno)) {
1809184610Salfred						mix.wValue[mc++] = MAKE_WORD(p + c + 1, o + 1);
1810184610Salfred					}
1811184610Salfred				}
1812184610Salfred			}
1813184610Salfred			mix.nchan = chs;
1814184610Salfred			uaudio_mixer_add_ctl(sc, &mix);
1815184610Salfred		} else {
1816184610Salfred			/* XXX */
1817184610Salfred		}
1818184610Salfred		p += chs;
1819184610Salfred	}
1820184610Salfred}
1821184610Salfred
1822184610Salfredstatic void
1823184610Salfreduaudio_mixer_add_selector(struct uaudio_softc *sc,
1824184610Salfred    const struct uaudio_terminal_node *iot, int id)
1825184610Salfred{
1826203678Sbrucec	const struct usb_audio_selector_unit *d = iot[id].u.su;
1827184610Salfred	struct uaudio_mixer_node mix;
1828184610Salfred	uint16_t i;
1829184610Salfred
1830184610Salfred	DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n",
1831184610Salfred	    d->bUnitId, d->bNrInPins);
1832184610Salfred
1833184610Salfred	if (d->bNrInPins == 0) {
1834184610Salfred		return;
1835184610Salfred	}
1836184610Salfred	bzero(&mix, sizeof(mix));
1837184610Salfred
1838184610Salfred	mix.wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no);
1839184610Salfred	mix.wValue[0] = MAKE_WORD(0, 0);
1840184610Salfred	uaudio_mixer_determine_class(&iot[id], &mix);
1841184610Salfred	mix.nchan = 1;
1842184610Salfred	mix.type = MIX_SELECTOR;
1843184610Salfred
1844184610Salfred	mix.ctl = SOUND_MIXER_NRDEVICES;
1845184610Salfred	mix.minval = 1;
1846184610Salfred	mix.maxval = d->bNrInPins;
1847184610Salfred
1848184610Salfred	if (mix.maxval > MAX_SELECTOR_INPUT_PIN) {
1849184610Salfred		mix.maxval = MAX_SELECTOR_INPUT_PIN;
1850184610Salfred	}
1851184610Salfred	mix.mul = (mix.maxval - mix.minval);
1852184610Salfred	for (i = 0; i < MAX_SELECTOR_INPUT_PIN; i++) {
1853184610Salfred		mix.slctrtype[i] = SOUND_MIXER_NRDEVICES;
1854184610Salfred	}
1855184610Salfred
1856184610Salfred	for (i = 0; i < mix.maxval; i++) {
1857184610Salfred		mix.slctrtype[i] = uaudio_mixer_feature_name
1858184610Salfred		    (&iot[d->baSourceId[i]], &mix);
1859184610Salfred	}
1860184610Salfred
1861184610Salfred	mix.class = 0;			/* not used */
1862184610Salfred
1863184610Salfred	uaudio_mixer_add_ctl(sc, &mix);
1864184610Salfred}
1865184610Salfred
1866184610Salfredstatic uint32_t
1867203678Sbrucecuaudio_mixer_feature_get_bmaControls(const struct usb_audio_feature_unit *d,
1868184610Salfred    uint8_t index)
1869184610Salfred{
1870184610Salfred	uint32_t temp = 0;
1871184610Salfred	uint32_t offset = (index * d->bControlSize);
1872184610Salfred
1873184610Salfred	if (d->bControlSize > 0) {
1874184610Salfred		temp |= d->bmaControls[offset];
1875184610Salfred		if (d->bControlSize > 1) {
1876184610Salfred			temp |= d->bmaControls[offset + 1] << 8;
1877184610Salfred			if (d->bControlSize > 2) {
1878184610Salfred				temp |= d->bmaControls[offset + 2] << 16;
1879184610Salfred				if (d->bControlSize > 3) {
1880184610Salfred					temp |= d->bmaControls[offset + 3] << 24;
1881184610Salfred				}
1882184610Salfred			}
1883184610Salfred		}
1884184610Salfred	}
1885184610Salfred	return (temp);
1886184610Salfred}
1887184610Salfred
1888184610Salfredstatic void
1889184610Salfreduaudio_mixer_add_feature(struct uaudio_softc *sc,
1890184610Salfred    const struct uaudio_terminal_node *iot, int id)
1891184610Salfred{
1892203678Sbrucec	const struct usb_audio_feature_unit *d = iot[id].u.fu;
1893184610Salfred	struct uaudio_mixer_node mix;
1894184610Salfred	uint32_t fumask;
1895184610Salfred	uint32_t mmask;
1896184610Salfred	uint32_t cmask;
1897184610Salfred	uint16_t mixernumber;
1898184610Salfred	uint8_t nchan;
1899184610Salfred	uint8_t chan;
1900184610Salfred	uint8_t ctl;
1901184610Salfred	uint8_t i;
1902184610Salfred
1903184610Salfred	if (d->bControlSize == 0) {
1904184610Salfred		return;
1905184610Salfred	}
1906184610Salfred	bzero(&mix, sizeof(mix));
1907184610Salfred
1908184610Salfred	nchan = (d->bLength - 7) / d->bControlSize;
1909184610Salfred	mmask = uaudio_mixer_feature_get_bmaControls(d, 0);
1910184610Salfred	cmask = 0;
1911184610Salfred
1912184610Salfred	if (nchan == 0) {
1913184610Salfred		return;
1914184610Salfred	}
1915184610Salfred	/* figure out what we can control */
1916184610Salfred
1917184610Salfred	for (chan = 1; chan < nchan; chan++) {
1918184610Salfred		DPRINTFN(10, "chan=%d mask=%x\n",
1919184610Salfred		    chan, uaudio_mixer_feature_get_bmaControls(d, chan));
1920184610Salfred
1921184610Salfred		cmask |= uaudio_mixer_feature_get_bmaControls(d, chan);
1922184610Salfred	}
1923184610Salfred
1924184610Salfred	if (nchan > MIX_MAX_CHAN) {
1925184610Salfred		nchan = MIX_MAX_CHAN;
1926184610Salfred	}
1927184610Salfred	mix.wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no);
1928184610Salfred
1929184610Salfred	for (ctl = 1; ctl <= LOUDNESS_CONTROL; ctl++) {
1930184610Salfred
1931184610Salfred		fumask = FU_MASK(ctl);
1932184610Salfred
1933184610Salfred		DPRINTFN(5, "ctl=%d fumask=0x%04x\n",
1934184610Salfred		    ctl, fumask);
1935184610Salfred
1936184610Salfred		if (mmask & fumask) {
1937184610Salfred			mix.nchan = 1;
1938184610Salfred			mix.wValue[0] = MAKE_WORD(ctl, 0);
1939184610Salfred		} else if (cmask & fumask) {
1940184610Salfred			mix.nchan = nchan - 1;
1941184610Salfred			for (i = 1; i < nchan; i++) {
1942184610Salfred				if (uaudio_mixer_feature_get_bmaControls(d, i) & fumask)
1943184610Salfred					mix.wValue[i - 1] = MAKE_WORD(ctl, i);
1944184610Salfred				else
1945184610Salfred					mix.wValue[i - 1] = -1;
1946184610Salfred			}
1947184610Salfred		} else {
1948184610Salfred			continue;
1949184610Salfred		}
1950184610Salfred
1951184610Salfred		mixernumber = uaudio_mixer_feature_name(&iot[id], &mix);
1952184610Salfred
1953184610Salfred		switch (ctl) {
1954184610Salfred		case MUTE_CONTROL:
1955184610Salfred			mix.type = MIX_ON_OFF;
1956184610Salfred			mix.ctl = SOUND_MIXER_NRDEVICES;
1957184610Salfred			break;
1958184610Salfred
1959184610Salfred		case VOLUME_CONTROL:
1960184610Salfred			mix.type = MIX_SIGNED_16;
1961184610Salfred			mix.ctl = mixernumber;
1962184610Salfred			break;
1963184610Salfred
1964184610Salfred		case BASS_CONTROL:
1965184610Salfred			mix.type = MIX_SIGNED_8;
1966184610Salfred			mix.ctl = SOUND_MIXER_BASS;
1967184610Salfred			break;
1968184610Salfred
1969184610Salfred		case MID_CONTROL:
1970184610Salfred			mix.type = MIX_SIGNED_8;
1971184610Salfred			mix.ctl = SOUND_MIXER_NRDEVICES;	/* XXXXX */
1972184610Salfred			break;
1973184610Salfred
1974184610Salfred		case TREBLE_CONTROL:
1975184610Salfred			mix.type = MIX_SIGNED_8;
1976184610Salfred			mix.ctl = SOUND_MIXER_TREBLE;
1977184610Salfred			break;
1978184610Salfred
1979184610Salfred		case GRAPHIC_EQUALIZER_CONTROL:
1980184610Salfred			continue;	/* XXX don't add anything */
1981184610Salfred			break;
1982184610Salfred
1983184610Salfred		case AGC_CONTROL:
1984184610Salfred			mix.type = MIX_ON_OFF;
1985184610Salfred			mix.ctl = SOUND_MIXER_NRDEVICES;	/* XXXXX */
1986184610Salfred			break;
1987184610Salfred
1988184610Salfred		case DELAY_CONTROL:
1989184610Salfred			mix.type = MIX_UNSIGNED_16;
1990184610Salfred			mix.ctl = SOUND_MIXER_NRDEVICES;	/* XXXXX */
1991184610Salfred			break;
1992184610Salfred
1993184610Salfred		case BASS_BOOST_CONTROL:
1994184610Salfred			mix.type = MIX_ON_OFF;
1995184610Salfred			mix.ctl = SOUND_MIXER_NRDEVICES;	/* XXXXX */
1996184610Salfred			break;
1997184610Salfred
1998184610Salfred		case LOUDNESS_CONTROL:
1999184610Salfred			mix.type = MIX_ON_OFF;
2000184610Salfred			mix.ctl = SOUND_MIXER_LOUD;	/* Is this correct ? */
2001184610Salfred			break;
2002184610Salfred
2003184610Salfred		default:
2004184610Salfred			mix.type = MIX_UNKNOWN;
2005184610Salfred			break;
2006184610Salfred		}
2007184610Salfred
2008184610Salfred		if (mix.type != MIX_UNKNOWN) {
2009184610Salfred			uaudio_mixer_add_ctl(sc, &mix);
2010184610Salfred		}
2011184610Salfred	}
2012184610Salfred}
2013184610Salfred
2014184610Salfredstatic void
2015184610Salfreduaudio_mixer_add_processing_updown(struct uaudio_softc *sc,
2016184610Salfred    const struct uaudio_terminal_node *iot, int id)
2017184610Salfred{
2018203678Sbrucec	const struct usb_audio_processing_unit_0 *d0 = iot[id].u.pu;
2019203678Sbrucec	const struct usb_audio_processing_unit_1 *d1 =
2020184610Salfred	(const void *)(d0->baSourceId + d0->bNrInPins);
2021203678Sbrucec	const struct usb_audio_processing_unit_updown *ud =
2022184610Salfred	(const void *)(d1->bmControls + d1->bControlSize);
2023184610Salfred	struct uaudio_mixer_node mix;
2024184610Salfred	uint8_t i;
2025184610Salfred
2026184610Salfred	if (uaudio_mixer_verify_desc(d0, sizeof(*ud)) == NULL) {
2027184610Salfred		return;
2028184610Salfred	}
2029184610Salfred	if (uaudio_mixer_verify_desc(d0, sizeof(*ud) + (2 * ud->bNrModes))
2030184610Salfred	    == NULL) {
2031184610Salfred		return;
2032184610Salfred	}
2033184610Salfred	DPRINTFN(3, "bUnitId=%d bNrModes=%d\n",
2034184610Salfred	    d0->bUnitId, ud->bNrModes);
2035184610Salfred
2036184610Salfred	if (!(d1->bmControls[0] & UA_PROC_MASK(UD_MODE_SELECT_CONTROL))) {
2037184610Salfred		DPRINTF("no mode select\n");
2038184610Salfred		return;
2039184610Salfred	}
2040184610Salfred	bzero(&mix, sizeof(mix));
2041184610Salfred
2042184610Salfred	mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no);
2043184610Salfred	mix.nchan = 1;
2044184610Salfred	mix.wValue[0] = MAKE_WORD(UD_MODE_SELECT_CONTROL, 0);
2045184610Salfred	uaudio_mixer_determine_class(&iot[id], &mix);
2046184610Salfred	mix.type = MIX_ON_OFF;		/* XXX */
2047184610Salfred
2048184610Salfred	for (i = 0; i < ud->bNrModes; i++) {
2049184610Salfred		DPRINTFN(3, "i=%d bm=0x%x\n", i, UGETW(ud->waModes[i]));
2050184610Salfred		/* XXX */
2051184610Salfred	}
2052184610Salfred
2053184610Salfred	uaudio_mixer_add_ctl(sc, &mix);
2054184610Salfred}
2055184610Salfred
2056184610Salfredstatic void
2057184610Salfreduaudio_mixer_add_processing(struct uaudio_softc *sc,
2058184610Salfred    const struct uaudio_terminal_node *iot, int id)
2059184610Salfred{
2060203678Sbrucec	const struct usb_audio_processing_unit_0 *d0 = iot[id].u.pu;
2061203678Sbrucec	const struct usb_audio_processing_unit_1 *d1 =
2062184610Salfred	(const void *)(d0->baSourceId + d0->bNrInPins);
2063184610Salfred	struct uaudio_mixer_node mix;
2064184610Salfred	uint16_t ptype;
2065184610Salfred
2066184610Salfred	bzero(&mix, sizeof(mix));
2067184610Salfred
2068184610Salfred	ptype = UGETW(d0->wProcessType);
2069184610Salfred
2070184610Salfred	DPRINTFN(3, "wProcessType=%d bUnitId=%d "
2071184610Salfred	    "bNrInPins=%d\n", ptype, d0->bUnitId, d0->bNrInPins);
2072184610Salfred
2073184610Salfred	if (d1->bControlSize == 0) {
2074184610Salfred		return;
2075184610Salfred	}
2076184610Salfred	if (d1->bmControls[0] & UA_PROC_ENABLE_MASK) {
2077184610Salfred		mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no);
2078184610Salfred		mix.nchan = 1;
2079184610Salfred		mix.wValue[0] = MAKE_WORD(XX_ENABLE_CONTROL, 0);
2080184610Salfred		uaudio_mixer_determine_class(&iot[id], &mix);
2081184610Salfred		mix.type = MIX_ON_OFF;
2082184610Salfred		uaudio_mixer_add_ctl(sc, &mix);
2083184610Salfred	}
2084184610Salfred	switch (ptype) {
2085184610Salfred	case UPDOWNMIX_PROCESS:
2086184610Salfred		uaudio_mixer_add_processing_updown(sc, iot, id);
2087184610Salfred		break;
2088184610Salfred
2089184610Salfred	case DOLBY_PROLOGIC_PROCESS:
2090184610Salfred	case P3D_STEREO_EXTENDER_PROCESS:
2091184610Salfred	case REVERBATION_PROCESS:
2092184610Salfred	case CHORUS_PROCESS:
2093184610Salfred	case DYN_RANGE_COMP_PROCESS:
2094184610Salfred	default:
2095184610Salfred		DPRINTF("unit %d, type=%d is not implemented\n",
2096184610Salfred		    d0->bUnitId, ptype);
2097184610Salfred		break;
2098184610Salfred	}
2099184610Salfred}
2100184610Salfred
2101184610Salfredstatic void
2102184610Salfreduaudio_mixer_add_extension(struct uaudio_softc *sc,
2103184610Salfred    const struct uaudio_terminal_node *iot, int id)
2104184610Salfred{
2105203678Sbrucec	const struct usb_audio_extension_unit_0 *d0 = iot[id].u.eu;
2106203678Sbrucec	const struct usb_audio_extension_unit_1 *d1 =
2107184610Salfred	(const void *)(d0->baSourceId + d0->bNrInPins);
2108184610Salfred	struct uaudio_mixer_node mix;
2109184610Salfred
2110184610Salfred	DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n",
2111184610Salfred	    d0->bUnitId, d0->bNrInPins);
2112184610Salfred
2113184610Salfred	if (sc->sc_uq_au_no_xu) {
2114184610Salfred		return;
2115184610Salfred	}
2116184610Salfred	if (d1->bControlSize == 0) {
2117184610Salfred		return;
2118184610Salfred	}
2119184610Salfred	if (d1->bmControls[0] & UA_EXT_ENABLE_MASK) {
2120184610Salfred
2121184610Salfred		bzero(&mix, sizeof(mix));
2122184610Salfred
2123184610Salfred		mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no);
2124184610Salfred		mix.nchan = 1;
2125184610Salfred		mix.wValue[0] = MAKE_WORD(UA_EXT_ENABLE, 0);
2126184610Salfred		uaudio_mixer_determine_class(&iot[id], &mix);
2127184610Salfred		mix.type = MIX_ON_OFF;
2128184610Salfred
2129184610Salfred		uaudio_mixer_add_ctl(sc, &mix);
2130184610Salfred	}
2131184610Salfred}
2132184610Salfred
2133184610Salfredstatic const void *
2134184610Salfreduaudio_mixer_verify_desc(const void *arg, uint32_t len)
2135184610Salfred{
2136203678Sbrucec	const struct usb_audio_mixer_unit_1 *d1;
2137203678Sbrucec	const struct usb_audio_extension_unit_1 *e1;
2138203678Sbrucec	const struct usb_audio_processing_unit_1 *u1;
2139184610Salfred
2140184610Salfred	union {
2141192984Sthompsa		const struct usb_descriptor *desc;
2142203678Sbrucec		const struct usb_audio_input_terminal *it;
2143203678Sbrucec		const struct usb_audio_output_terminal *ot;
2144203678Sbrucec		const struct usb_audio_mixer_unit_0 *mu;
2145203678Sbrucec		const struct usb_audio_selector_unit *su;
2146203678Sbrucec		const struct usb_audio_feature_unit *fu;
2147203678Sbrucec		const struct usb_audio_processing_unit_0 *pu;
2148203678Sbrucec		const struct usb_audio_extension_unit_0 *eu;
2149184610Salfred	}     u;
2150184610Salfred
2151184610Salfred	u.desc = arg;
2152184610Salfred
2153184610Salfred	if (u.desc == NULL) {
2154184610Salfred		goto error;
2155184610Salfred	}
2156184610Salfred	if (u.desc->bDescriptorType != UDESC_CS_INTERFACE) {
2157184610Salfred		goto error;
2158184610Salfred	}
2159184610Salfred	switch (u.desc->bDescriptorSubtype) {
2160184610Salfred	case UDESCSUB_AC_INPUT:
2161184610Salfred		len += sizeof(*u.it);
2162184610Salfred		break;
2163184610Salfred
2164184610Salfred	case UDESCSUB_AC_OUTPUT:
2165184610Salfred		len += sizeof(*u.ot);
2166184610Salfred		break;
2167184610Salfred
2168184610Salfred	case UDESCSUB_AC_MIXER:
2169184610Salfred		len += sizeof(*u.mu);
2170184610Salfred
2171184610Salfred		if (u.desc->bLength < len) {
2172184610Salfred			goto error;
2173184610Salfred		}
2174184610Salfred		len += u.mu->bNrInPins;
2175184610Salfred
2176184610Salfred		if (u.desc->bLength < len) {
2177184610Salfred			goto error;
2178184610Salfred		}
2179184610Salfred		d1 = (const void *)(u.mu->baSourceId + u.mu->bNrInPins);
2180184610Salfred
2181184610Salfred		len += sizeof(*d1);
2182184610Salfred		break;
2183184610Salfred
2184184610Salfred	case UDESCSUB_AC_SELECTOR:
2185184610Salfred		len += sizeof(*u.su);
2186184610Salfred
2187184610Salfred		if (u.desc->bLength < len) {
2188184610Salfred			goto error;
2189184610Salfred		}
2190184610Salfred		len += u.su->bNrInPins;
2191184610Salfred		break;
2192184610Salfred
2193184610Salfred	case UDESCSUB_AC_FEATURE:
2194184610Salfred		len += (sizeof(*u.fu) + 1);
2195184610Salfred		break;
2196184610Salfred
2197184610Salfred	case UDESCSUB_AC_PROCESSING:
2198184610Salfred		len += sizeof(*u.pu);
2199184610Salfred
2200184610Salfred		if (u.desc->bLength < len) {
2201184610Salfred			goto error;
2202184610Salfred		}
2203184610Salfred		len += u.pu->bNrInPins;
2204184610Salfred
2205184610Salfred		if (u.desc->bLength < len) {
2206184610Salfred			goto error;
2207184610Salfred		}
2208184610Salfred		u1 = (const void *)(u.pu->baSourceId + u.pu->bNrInPins);
2209184610Salfred
2210184610Salfred		len += sizeof(*u1);
2211184610Salfred
2212184610Salfred		if (u.desc->bLength < len) {
2213184610Salfred			goto error;
2214184610Salfred		}
2215184610Salfred		len += u1->bControlSize;
2216184610Salfred
2217184610Salfred		break;
2218184610Salfred
2219184610Salfred	case UDESCSUB_AC_EXTENSION:
2220184610Salfred		len += sizeof(*u.eu);
2221184610Salfred
2222184610Salfred		if (u.desc->bLength < len) {
2223184610Salfred			goto error;
2224184610Salfred		}
2225184610Salfred		len += u.eu->bNrInPins;
2226184610Salfred
2227184610Salfred		if (u.desc->bLength < len) {
2228184610Salfred			goto error;
2229184610Salfred		}
2230184610Salfred		e1 = (const void *)(u.eu->baSourceId + u.eu->bNrInPins);
2231184610Salfred
2232184610Salfred		len += sizeof(*e1);
2233184610Salfred
2234184610Salfred		if (u.desc->bLength < len) {
2235184610Salfred			goto error;
2236184610Salfred		}
2237184610Salfred		len += e1->bControlSize;
2238184610Salfred		break;
2239184610Salfred
2240184610Salfred	default:
2241184610Salfred		goto error;
2242184610Salfred	}
2243184610Salfred
2244184610Salfred	if (u.desc->bLength < len) {
2245184610Salfred		goto error;
2246184610Salfred	}
2247184610Salfred	return (u.desc);
2248184610Salfred
2249184610Salfrederror:
2250184610Salfred	if (u.desc) {
2251184610Salfred		DPRINTF("invalid descriptor, type=%d, "
2252184610Salfred		    "sub_type=%d, len=%d of %d bytes\n",
2253184610Salfred		    u.desc->bDescriptorType,
2254184610Salfred		    u.desc->bDescriptorSubtype,
2255184610Salfred		    u.desc->bLength, len);
2256184610Salfred	}
2257184610Salfred	return (NULL);
2258184610Salfred}
2259184610Salfred
2260207077Sthompsa#ifdef USB_DEBUG
2261184610Salfredstatic void
2262184610Salfreduaudio_mixer_dump_cluster(uint8_t id, const struct uaudio_terminal_node *iot)
2263184610Salfred{
2264184610Salfred	static const char *channel_names[16] = {
2265184610Salfred		"LEFT", "RIGHT", "CENTER", "LFE",
2266184610Salfred		"LEFT_SURROUND", "RIGHT_SURROUND", "LEFT_CENTER", "RIGHT_CENTER",
2267184610Salfred		"SURROUND", "LEFT_SIDE", "RIGHT_SIDE", "TOP",
2268184610Salfred		"RESERVED12", "RESERVED13", "RESERVED14", "RESERVED15",
2269184610Salfred	};
2270184610Salfred	uint16_t cc;
2271184610Salfred	uint8_t i;
2272203678Sbrucec	const struct usb_audio_cluster cl = uaudio_mixer_get_cluster(id, iot);
2273184610Salfred
2274184610Salfred	cc = UGETW(cl.wChannelConfig);
2275184610Salfred
2276184610Salfred	DPRINTF("cluster: bNrChannels=%u iChannelNames=%u wChannelConfig="
2277184610Salfred	    "0x%04x:\n", cl.iChannelNames, cl.bNrChannels, cc);
2278184610Salfred
2279184610Salfred	for (i = 0; cc; i++) {
2280184610Salfred		if (cc & 1) {
2281184610Salfred			DPRINTF(" - %s\n", channel_names[i]);
2282184610Salfred		}
2283184610Salfred		cc >>= 1;
2284184610Salfred	}
2285184610Salfred}
2286184610Salfred
2287184610Salfred#endif
2288184610Salfred
2289203678Sbrucecstatic struct usb_audio_cluster
2290184610Salfreduaudio_mixer_get_cluster(uint8_t id, const struct uaudio_terminal_node *iot)
2291184610Salfred{
2292203678Sbrucec	struct usb_audio_cluster r;
2293192984Sthompsa	const struct usb_descriptor *dp;
2294184610Salfred	uint8_t i;
2295184610Salfred
2296184610Salfred	for (i = 0; i < UAUDIO_RECURSE_LIMIT; i++) {	/* avoid infinite loops */
2297184610Salfred		dp = iot[id].u.desc;
2298184610Salfred		if (dp == NULL) {
2299184610Salfred			goto error;
2300184610Salfred		}
2301184610Salfred		switch (dp->bDescriptorSubtype) {
2302184610Salfred		case UDESCSUB_AC_INPUT:
2303184610Salfred			r.bNrChannels = iot[id].u.it->bNrChannels;
2304184610Salfred			r.wChannelConfig[0] = iot[id].u.it->wChannelConfig[0];
2305184610Salfred			r.wChannelConfig[1] = iot[id].u.it->wChannelConfig[1];
2306184610Salfred			r.iChannelNames = iot[id].u.it->iChannelNames;
2307184610Salfred			goto done;
2308184610Salfred
2309184610Salfred		case UDESCSUB_AC_OUTPUT:
2310184610Salfred			id = iot[id].u.ot->bSourceId;
2311184610Salfred			break;
2312184610Salfred
2313184610Salfred		case UDESCSUB_AC_MIXER:
2314203678Sbrucec			r = *(const struct usb_audio_cluster *)
2315184610Salfred			    &iot[id].u.mu->baSourceId[iot[id].u.mu->
2316184610Salfred			    bNrInPins];
2317184610Salfred			goto done;
2318184610Salfred
2319184610Salfred		case UDESCSUB_AC_SELECTOR:
2320184610Salfred			if (iot[id].u.su->bNrInPins > 0) {
2321184610Salfred				/* XXX This is not really right */
2322184610Salfred				id = iot[id].u.su->baSourceId[0];
2323184610Salfred			}
2324184610Salfred			break;
2325184610Salfred
2326184610Salfred		case UDESCSUB_AC_FEATURE:
2327184610Salfred			id = iot[id].u.fu->bSourceId;
2328184610Salfred			break;
2329184610Salfred
2330184610Salfred		case UDESCSUB_AC_PROCESSING:
2331203678Sbrucec			r = *((const struct usb_audio_cluster *)
2332184610Salfred			    &iot[id].u.pu->baSourceId[iot[id].u.pu->
2333184610Salfred			    bNrInPins]);
2334184610Salfred			goto done;
2335184610Salfred
2336184610Salfred		case UDESCSUB_AC_EXTENSION:
2337203678Sbrucec			r = *((const struct usb_audio_cluster *)
2338184610Salfred			    &iot[id].u.eu->baSourceId[iot[id].u.eu->
2339184610Salfred			    bNrInPins]);
2340184610Salfred			goto done;
2341184610Salfred
2342184610Salfred		default:
2343184610Salfred			goto error;
2344184610Salfred		}
2345184610Salfred	}
2346184610Salfrederror:
2347184610Salfred	DPRINTF("bad data\n");
2348184610Salfred	bzero(&r, sizeof(r));
2349184610Salfreddone:
2350184610Salfred	return (r);
2351184610Salfred}
2352184610Salfred
2353207077Sthompsa#ifdef USB_DEBUG
2354184610Salfred
2355184610Salfredstruct uaudio_tt_to_string {
2356184610Salfred	uint16_t terminal_type;
2357184610Salfred	const char *desc;
2358184610Salfred};
2359184610Salfred
2360184610Salfredstatic const struct uaudio_tt_to_string uaudio_tt_to_string[] = {
2361184610Salfred
2362184610Salfred	/* USB terminal types */
2363184610Salfred	{UAT_UNDEFINED, "UAT_UNDEFINED"},
2364184610Salfred	{UAT_STREAM, "UAT_STREAM"},
2365184610Salfred	{UAT_VENDOR, "UAT_VENDOR"},
2366184610Salfred
2367184610Salfred	/* input terminal types */
2368184610Salfred	{UATI_UNDEFINED, "UATI_UNDEFINED"},
2369184610Salfred	{UATI_MICROPHONE, "UATI_MICROPHONE"},
2370184610Salfred	{UATI_DESKMICROPHONE, "UATI_DESKMICROPHONE"},
2371184610Salfred	{UATI_PERSONALMICROPHONE, "UATI_PERSONALMICROPHONE"},
2372184610Salfred	{UATI_OMNIMICROPHONE, "UATI_OMNIMICROPHONE"},
2373184610Salfred	{UATI_MICROPHONEARRAY, "UATI_MICROPHONEARRAY"},
2374184610Salfred	{UATI_PROCMICROPHONEARR, "UATI_PROCMICROPHONEARR"},
2375184610Salfred
2376184610Salfred	/* output terminal types */
2377184610Salfred	{UATO_UNDEFINED, "UATO_UNDEFINED"},
2378184610Salfred	{UATO_SPEAKER, "UATO_SPEAKER"},
2379184610Salfred	{UATO_HEADPHONES, "UATO_HEADPHONES"},
2380184610Salfred	{UATO_DISPLAYAUDIO, "UATO_DISPLAYAUDIO"},
2381184610Salfred	{UATO_DESKTOPSPEAKER, "UATO_DESKTOPSPEAKER"},
2382184610Salfred	{UATO_ROOMSPEAKER, "UATO_ROOMSPEAKER"},
2383184610Salfred	{UATO_COMMSPEAKER, "UATO_COMMSPEAKER"},
2384184610Salfred	{UATO_SUBWOOFER, "UATO_SUBWOOFER"},
2385184610Salfred
2386184610Salfred	/* bidir terminal types */
2387184610Salfred	{UATB_UNDEFINED, "UATB_UNDEFINED"},
2388184610Salfred	{UATB_HANDSET, "UATB_HANDSET"},
2389184610Salfred	{UATB_HEADSET, "UATB_HEADSET"},
2390184610Salfred	{UATB_SPEAKERPHONE, "UATB_SPEAKERPHONE"},
2391184610Salfred	{UATB_SPEAKERPHONEESUP, "UATB_SPEAKERPHONEESUP"},
2392184610Salfred	{UATB_SPEAKERPHONEECANC, "UATB_SPEAKERPHONEECANC"},
2393184610Salfred
2394184610Salfred	/* telephony terminal types */
2395184610Salfred	{UATT_UNDEFINED, "UATT_UNDEFINED"},
2396184610Salfred	{UATT_PHONELINE, "UATT_PHONELINE"},
2397184610Salfred	{UATT_TELEPHONE, "UATT_TELEPHONE"},
2398184610Salfred	{UATT_DOWNLINEPHONE, "UATT_DOWNLINEPHONE"},
2399184610Salfred
2400184610Salfred	/* external terminal types */
2401184610Salfred	{UATE_UNDEFINED, "UATE_UNDEFINED"},
2402184610Salfred	{UATE_ANALOGCONN, "UATE_ANALOGCONN"},
2403184610Salfred	{UATE_LINECONN, "UATE_LINECONN"},
2404184610Salfred	{UATE_LEGACYCONN, "UATE_LEGACYCONN"},
2405184610Salfred	{UATE_DIGITALAUIFC, "UATE_DIGITALAUIFC"},
2406184610Salfred	{UATE_SPDIF, "UATE_SPDIF"},
2407184610Salfred	{UATE_1394DA, "UATE_1394DA"},
2408184610Salfred	{UATE_1394DV, "UATE_1394DV"},
2409184610Salfred
2410184610Salfred	/* embedded function terminal types */
2411184610Salfred	{UATF_UNDEFINED, "UATF_UNDEFINED"},
2412184610Salfred	{UATF_CALIBNOISE, "UATF_CALIBNOISE"},
2413184610Salfred	{UATF_EQUNOISE, "UATF_EQUNOISE"},
2414184610Salfred	{UATF_CDPLAYER, "UATF_CDPLAYER"},
2415184610Salfred	{UATF_DAT, "UATF_DAT"},
2416184610Salfred	{UATF_DCC, "UATF_DCC"},
2417184610Salfred	{UATF_MINIDISK, "UATF_MINIDISK"},
2418184610Salfred	{UATF_ANALOGTAPE, "UATF_ANALOGTAPE"},
2419184610Salfred	{UATF_PHONOGRAPH, "UATF_PHONOGRAPH"},
2420184610Salfred	{UATF_VCRAUDIO, "UATF_VCRAUDIO"},
2421184610Salfred	{UATF_VIDEODISCAUDIO, "UATF_VIDEODISCAUDIO"},
2422184610Salfred	{UATF_DVDAUDIO, "UATF_DVDAUDIO"},
2423184610Salfred	{UATF_TVTUNERAUDIO, "UATF_TVTUNERAUDIO"},
2424184610Salfred	{UATF_SATELLITE, "UATF_SATELLITE"},
2425184610Salfred	{UATF_CABLETUNER, "UATF_CABLETUNER"},
2426184610Salfred	{UATF_DSS, "UATF_DSS"},
2427184610Salfred	{UATF_RADIORECV, "UATF_RADIORECV"},
2428184610Salfred	{UATF_RADIOXMIT, "UATF_RADIOXMIT"},
2429184610Salfred	{UATF_MULTITRACK, "UATF_MULTITRACK"},
2430184610Salfred	{UATF_SYNTHESIZER, "UATF_SYNTHESIZER"},
2431184610Salfred
2432184610Salfred	/* unknown */
2433184610Salfred	{0x0000, "UNKNOWN"},
2434184610Salfred};
2435184610Salfred
2436184610Salfredstatic const char *
2437184610Salfreduaudio_mixer_get_terminal_name(uint16_t terminal_type)
2438184610Salfred{
2439184610Salfred	const struct uaudio_tt_to_string *uat = uaudio_tt_to_string;
2440184610Salfred
2441184610Salfred	while (uat->terminal_type) {
2442184610Salfred		if (uat->terminal_type == terminal_type) {
2443184610Salfred			break;
2444184610Salfred		}
2445184610Salfred		uat++;
2446184610Salfred	}
2447184610Salfred	if (uat->terminal_type == 0) {
2448184610Salfred		DPRINTF("unknown terminal type (0x%04x)", terminal_type);
2449184610Salfred	}
2450184610Salfred	return (uat->desc);
2451184610Salfred}
2452184610Salfred
2453184610Salfred#endif
2454184610Salfred
2455184610Salfredstatic uint16_t
2456184610Salfreduaudio_mixer_determine_class(const struct uaudio_terminal_node *iot,
2457184610Salfred    struct uaudio_mixer_node *mix)
2458184610Salfred{
2459184610Salfred	uint16_t terminal_type = 0x0000;
2460184610Salfred	const struct uaudio_terminal_node *input[2];
2461184610Salfred	const struct uaudio_terminal_node *output[2];
2462184610Salfred
2463184610Salfred	input[0] = uaudio_mixer_get_input(iot, 0);
2464184610Salfred	input[1] = uaudio_mixer_get_input(iot, 1);
2465184610Salfred
2466184610Salfred	output[0] = uaudio_mixer_get_output(iot, 0);
2467184610Salfred	output[1] = uaudio_mixer_get_output(iot, 1);
2468184610Salfred
2469184610Salfred	/*
2470184610Salfred	 * check if there is only
2471184610Salfred	 * one output terminal:
2472184610Salfred	 */
2473184610Salfred	if (output[0] && (!output[1])) {
2474184610Salfred		terminal_type = UGETW(output[0]->u.ot->wTerminalType);
2475184610Salfred	}
2476184610Salfred	/*
2477184610Salfred	 * If the only output terminal is USB,
2478184610Salfred	 * the class is UAC_RECORD.
2479184610Salfred	 */
2480184610Salfred	if ((terminal_type & 0xff00) == (UAT_UNDEFINED & 0xff00)) {
2481184610Salfred
2482184610Salfred		mix->class = UAC_RECORD;
2483184610Salfred		if (input[0] && (!input[1])) {
2484184610Salfred			terminal_type = UGETW(input[0]->u.it->wTerminalType);
2485184610Salfred		} else {
2486184610Salfred			terminal_type = 0;
2487184610Salfred		}
2488184610Salfred		goto done;
2489184610Salfred	}
2490184610Salfred	/*
2491184610Salfred	 * if the unit is connected to just
2492184610Salfred	 * one input terminal, the
2493184610Salfred	 * class is UAC_INPUT:
2494184610Salfred	 */
2495184610Salfred	if (input[0] && (!input[1])) {
2496184610Salfred		mix->class = UAC_INPUT;
2497184610Salfred		terminal_type = UGETW(input[0]->u.it->wTerminalType);
2498184610Salfred		goto done;
2499184610Salfred	}
2500184610Salfred	/*
2501184610Salfred	 * Otherwise, the class is UAC_OUTPUT.
2502184610Salfred	 */
2503184610Salfred	mix->class = UAC_OUTPUT;
2504184610Salfreddone:
2505184610Salfred	return (terminal_type);
2506184610Salfred}
2507184610Salfred
2508184610Salfredstruct uaudio_tt_to_feature {
2509184610Salfred	uint16_t terminal_type;
2510184610Salfred	uint16_t feature;
2511184610Salfred};
2512184610Salfred
2513184610Salfredstatic const struct uaudio_tt_to_feature uaudio_tt_to_feature[] = {
2514184610Salfred
2515184610Salfred	{UAT_STREAM, SOUND_MIXER_PCM},
2516184610Salfred
2517184610Salfred	{UATI_MICROPHONE, SOUND_MIXER_MIC},
2518184610Salfred	{UATI_DESKMICROPHONE, SOUND_MIXER_MIC},
2519184610Salfred	{UATI_PERSONALMICROPHONE, SOUND_MIXER_MIC},
2520184610Salfred	{UATI_OMNIMICROPHONE, SOUND_MIXER_MIC},
2521184610Salfred	{UATI_MICROPHONEARRAY, SOUND_MIXER_MIC},
2522184610Salfred	{UATI_PROCMICROPHONEARR, SOUND_MIXER_MIC},
2523184610Salfred
2524184610Salfred	{UATO_SPEAKER, SOUND_MIXER_SPEAKER},
2525184610Salfred	{UATO_DESKTOPSPEAKER, SOUND_MIXER_SPEAKER},
2526184610Salfred	{UATO_ROOMSPEAKER, SOUND_MIXER_SPEAKER},
2527184610Salfred	{UATO_COMMSPEAKER, SOUND_MIXER_SPEAKER},
2528184610Salfred
2529184610Salfred	{UATE_ANALOGCONN, SOUND_MIXER_LINE},
2530184610Salfred	{UATE_LINECONN, SOUND_MIXER_LINE},
2531184610Salfred	{UATE_LEGACYCONN, SOUND_MIXER_LINE},
2532184610Salfred
2533184610Salfred	{UATE_DIGITALAUIFC, SOUND_MIXER_ALTPCM},
2534184610Salfred	{UATE_SPDIF, SOUND_MIXER_ALTPCM},
2535184610Salfred	{UATE_1394DA, SOUND_MIXER_ALTPCM},
2536184610Salfred	{UATE_1394DV, SOUND_MIXER_ALTPCM},
2537184610Salfred
2538184610Salfred	{UATF_CDPLAYER, SOUND_MIXER_CD},
2539184610Salfred
2540184610Salfred	{UATF_SYNTHESIZER, SOUND_MIXER_SYNTH},
2541184610Salfred
2542184610Salfred	{UATF_VIDEODISCAUDIO, SOUND_MIXER_VIDEO},
2543184610Salfred	{UATF_DVDAUDIO, SOUND_MIXER_VIDEO},
2544184610Salfred	{UATF_TVTUNERAUDIO, SOUND_MIXER_VIDEO},
2545184610Salfred
2546184610Salfred	/* telephony terminal types */
2547184610Salfred	{UATT_UNDEFINED, SOUND_MIXER_PHONEIN},	/* SOUND_MIXER_PHONEOUT */
2548184610Salfred	{UATT_PHONELINE, SOUND_MIXER_PHONEIN},	/* SOUND_MIXER_PHONEOUT */
2549184610Salfred	{UATT_TELEPHONE, SOUND_MIXER_PHONEIN},	/* SOUND_MIXER_PHONEOUT */
2550184610Salfred	{UATT_DOWNLINEPHONE, SOUND_MIXER_PHONEIN},	/* SOUND_MIXER_PHONEOUT */
2551184610Salfred
2552184610Salfred	{UATF_RADIORECV, SOUND_MIXER_RADIO},
2553184610Salfred	{UATF_RADIOXMIT, SOUND_MIXER_RADIO},
2554184610Salfred
2555184610Salfred	{UAT_UNDEFINED, SOUND_MIXER_VOLUME},
2556184610Salfred	{UAT_VENDOR, SOUND_MIXER_VOLUME},
2557184610Salfred	{UATI_UNDEFINED, SOUND_MIXER_VOLUME},
2558184610Salfred
2559184610Salfred	/* output terminal types */
2560184610Salfred	{UATO_UNDEFINED, SOUND_MIXER_VOLUME},
2561184610Salfred	{UATO_DISPLAYAUDIO, SOUND_MIXER_VOLUME},
2562184610Salfred	{UATO_SUBWOOFER, SOUND_MIXER_VOLUME},
2563184610Salfred	{UATO_HEADPHONES, SOUND_MIXER_VOLUME},
2564184610Salfred
2565184610Salfred	/* bidir terminal types */
2566184610Salfred	{UATB_UNDEFINED, SOUND_MIXER_VOLUME},
2567184610Salfred	{UATB_HANDSET, SOUND_MIXER_VOLUME},
2568184610Salfred	{UATB_HEADSET, SOUND_MIXER_VOLUME},
2569184610Salfred	{UATB_SPEAKERPHONE, SOUND_MIXER_VOLUME},
2570184610Salfred	{UATB_SPEAKERPHONEESUP, SOUND_MIXER_VOLUME},
2571184610Salfred	{UATB_SPEAKERPHONEECANC, SOUND_MIXER_VOLUME},
2572184610Salfred
2573184610Salfred	/* external terminal types */
2574184610Salfred	{UATE_UNDEFINED, SOUND_MIXER_VOLUME},
2575184610Salfred
2576184610Salfred	/* embedded function terminal types */
2577184610Salfred	{UATF_UNDEFINED, SOUND_MIXER_VOLUME},
2578184610Salfred	{UATF_CALIBNOISE, SOUND_MIXER_VOLUME},
2579184610Salfred	{UATF_EQUNOISE, SOUND_MIXER_VOLUME},
2580184610Salfred	{UATF_DAT, SOUND_MIXER_VOLUME},
2581184610Salfred	{UATF_DCC, SOUND_MIXER_VOLUME},
2582184610Salfred	{UATF_MINIDISK, SOUND_MIXER_VOLUME},
2583184610Salfred	{UATF_ANALOGTAPE, SOUND_MIXER_VOLUME},
2584184610Salfred	{UATF_PHONOGRAPH, SOUND_MIXER_VOLUME},
2585184610Salfred	{UATF_VCRAUDIO, SOUND_MIXER_VOLUME},
2586184610Salfred	{UATF_SATELLITE, SOUND_MIXER_VOLUME},
2587184610Salfred	{UATF_CABLETUNER, SOUND_MIXER_VOLUME},
2588184610Salfred	{UATF_DSS, SOUND_MIXER_VOLUME},
2589184610Salfred	{UATF_MULTITRACK, SOUND_MIXER_VOLUME},
2590184610Salfred	{0xffff, SOUND_MIXER_VOLUME},
2591184610Salfred
2592184610Salfred	/* default */
2593184610Salfred	{0x0000, SOUND_MIXER_VOLUME},
2594184610Salfred};
2595184610Salfred
2596184610Salfredstatic uint16_t
2597184610Salfreduaudio_mixer_feature_name(const struct uaudio_terminal_node *iot,
2598184610Salfred    struct uaudio_mixer_node *mix)
2599184610Salfred{
2600184610Salfred	const struct uaudio_tt_to_feature *uat = uaudio_tt_to_feature;
2601184610Salfred	uint16_t terminal_type = uaudio_mixer_determine_class(iot, mix);
2602184610Salfred
2603184610Salfred	if ((mix->class == UAC_RECORD) && (terminal_type == 0)) {
2604184610Salfred		return (SOUND_MIXER_IMIX);
2605184610Salfred	}
2606184610Salfred	while (uat->terminal_type) {
2607184610Salfred		if (uat->terminal_type == terminal_type) {
2608184610Salfred			break;
2609184610Salfred		}
2610184610Salfred		uat++;
2611184610Salfred	}
2612184610Salfred
2613184610Salfred	DPRINTF("terminal_type=%s (0x%04x) -> %d\n",
2614184610Salfred	    uaudio_mixer_get_terminal_name(terminal_type),
2615184610Salfred	    terminal_type, uat->feature);
2616184610Salfred
2617184610Salfred	return (uat->feature);
2618184610Salfred}
2619184610Salfred
2620184610Salfredconst static struct uaudio_terminal_node *
2621184610Salfreduaudio_mixer_get_input(const struct uaudio_terminal_node *iot, uint8_t index)
2622184610Salfred{
2623184610Salfred	struct uaudio_terminal_node *root = iot->root;
2624184610Salfred	uint8_t n;
2625184610Salfred
2626184610Salfred	n = iot->usr.id_max;
2627184610Salfred	do {
2628184610Salfred		if (iot->usr.bit_input[n / 8] & (1 << (n % 8))) {
2629184610Salfred			if (!index--) {
2630184610Salfred				return (root + n);
2631184610Salfred			}
2632184610Salfred		}
2633184610Salfred	} while (n--);
2634184610Salfred
2635184610Salfred	return (NULL);
2636184610Salfred}
2637184610Salfred
2638184610Salfredconst static struct uaudio_terminal_node *
2639184610Salfreduaudio_mixer_get_output(const struct uaudio_terminal_node *iot, uint8_t index)
2640184610Salfred{
2641184610Salfred	struct uaudio_terminal_node *root = iot->root;
2642184610Salfred	uint8_t n;
2643184610Salfred
2644184610Salfred	n = iot->usr.id_max;
2645184610Salfred	do {
2646184610Salfred		if (iot->usr.bit_output[n / 8] & (1 << (n % 8))) {
2647184610Salfred			if (!index--) {
2648184610Salfred				return (root + n);
2649184610Salfred			}
2650184610Salfred		}
2651184610Salfred	} while (n--);
2652184610Salfred
2653184610Salfred	return (NULL);
2654184610Salfred}
2655184610Salfred
2656184610Salfredstatic void
2657184610Salfreduaudio_mixer_find_inputs_sub(struct uaudio_terminal_node *root,
2658184610Salfred    const uint8_t *p_id, uint8_t n_id,
2659184610Salfred    struct uaudio_search_result *info)
2660184610Salfred{
2661184610Salfred	struct uaudio_terminal_node *iot;
2662184610Salfred	uint8_t n;
2663184610Salfred	uint8_t i;
2664184610Salfred
2665184610Salfred	if (info->recurse_level >= UAUDIO_RECURSE_LIMIT) {
2666184610Salfred		return;
2667184610Salfred	}
2668184610Salfred	info->recurse_level++;
2669184610Salfred
2670184610Salfred	for (n = 0; n < n_id; n++) {
2671184610Salfred
2672184610Salfred		i = p_id[n];
2673184610Salfred
2674184610Salfred		if (info->bit_visited[i / 8] & (1 << (i % 8))) {
2675184610Salfred			/* don't go into a circle */
2676184610Salfred			DPRINTF("avoided going into a circle at id=%d!\n", i);
2677184610Salfred			continue;
2678184610Salfred		} else {
2679184610Salfred			info->bit_visited[i / 8] |= (1 << (i % 8));
2680184610Salfred		}
2681184610Salfred
2682184610Salfred		iot = (root + i);
2683184610Salfred
2684184610Salfred		if (iot->u.desc == NULL) {
2685184610Salfred			continue;
2686184610Salfred		}
2687184610Salfred		switch (iot->u.desc->bDescriptorSubtype) {
2688184610Salfred		case UDESCSUB_AC_INPUT:
2689184610Salfred			info->bit_input[i / 8] |= (1 << (i % 8));
2690184610Salfred			break;
2691184610Salfred
2692184610Salfred		case UDESCSUB_AC_FEATURE:
2693184610Salfred			uaudio_mixer_find_inputs_sub
2694184610Salfred			    (root, &iot->u.fu->bSourceId, 1, info);
2695184610Salfred			break;
2696184610Salfred
2697184610Salfred		case UDESCSUB_AC_OUTPUT:
2698184610Salfred			uaudio_mixer_find_inputs_sub
2699184610Salfred			    (root, &iot->u.ot->bSourceId, 1, info);
2700184610Salfred			break;
2701184610Salfred
2702184610Salfred		case UDESCSUB_AC_MIXER:
2703184610Salfred			uaudio_mixer_find_inputs_sub
2704184610Salfred			    (root, iot->u.mu->baSourceId,
2705184610Salfred			    iot->u.mu->bNrInPins, info);
2706184610Salfred			break;
2707184610Salfred
2708184610Salfred		case UDESCSUB_AC_SELECTOR:
2709184610Salfred			uaudio_mixer_find_inputs_sub
2710184610Salfred			    (root, iot->u.su->baSourceId,
2711184610Salfred			    iot->u.su->bNrInPins, info);
2712184610Salfred			break;
2713184610Salfred
2714184610Salfred		case UDESCSUB_AC_PROCESSING:
2715184610Salfred			uaudio_mixer_find_inputs_sub
2716184610Salfred			    (root, iot->u.pu->baSourceId,
2717184610Salfred			    iot->u.pu->bNrInPins, info);
2718184610Salfred			break;
2719184610Salfred
2720184610Salfred		case UDESCSUB_AC_EXTENSION:
2721184610Salfred			uaudio_mixer_find_inputs_sub
2722184610Salfred			    (root, iot->u.eu->baSourceId,
2723184610Salfred			    iot->u.eu->bNrInPins, info);
2724184610Salfred			break;
2725184610Salfred
2726184610Salfred		case UDESCSUB_AC_HEADER:
2727184610Salfred		default:
2728184610Salfred			break;
2729184610Salfred		}
2730184610Salfred	}
2731184610Salfred	info->recurse_level--;
2732184610Salfred}
2733184610Salfred
2734184610Salfredstatic void
2735184610Salfreduaudio_mixer_find_outputs_sub(struct uaudio_terminal_node *root, uint8_t id,
2736184610Salfred    uint8_t n_id, struct uaudio_search_result *info)
2737184610Salfred{
2738184610Salfred	struct uaudio_terminal_node *iot = (root + id);
2739184610Salfred	uint8_t j;
2740184610Salfred
2741184610Salfred	j = n_id;
2742184610Salfred	do {
2743184610Salfred		if ((j != id) && ((root + j)->u.desc) &&
2744184610Salfred		    ((root + j)->u.desc->bDescriptorSubtype == UDESCSUB_AC_OUTPUT)) {
2745184610Salfred
2746184610Salfred			/*
2747184610Salfred			 * "j" (output) <--- virtual wire <--- "id" (input)
2748184610Salfred			 *
2749184610Salfred			 * if "j" has "id" on the input, then "id" have "j" on
2750184610Salfred			 * the output, because they are connected:
2751184610Salfred			 */
2752184610Salfred			if ((root + j)->usr.bit_input[id / 8] & (1 << (id % 8))) {
2753184610Salfred				iot->usr.bit_output[j / 8] |= (1 << (j % 8));
2754184610Salfred			}
2755184610Salfred		}
2756184610Salfred	} while (j--);
2757184610Salfred}
2758184610Salfred
2759184610Salfredstatic void
2760192984Sthompsauaudio_mixer_fill_info(struct uaudio_softc *sc, struct usb_device *udev,
2761184610Salfred    void *desc)
2762184610Salfred{
2763203678Sbrucec	const struct usb_audio_control_descriptor *acdp;
2764194228Sthompsa	struct usb_config_descriptor *cd = usbd_get_config_descriptor(udev);
2765192984Sthompsa	const struct usb_descriptor *dp;
2766203678Sbrucec	const struct usb_audio_unit *au;
2767184610Salfred	struct uaudio_terminal_node *iot = NULL;
2768184610Salfred	uint16_t wTotalLen;
2769184610Salfred	uint8_t ID_max = 0;		/* inclusive */
2770184610Salfred	uint8_t i;
2771184610Salfred
2772194228Sthompsa	desc = usb_desc_foreach(cd, desc);
2773184610Salfred
2774184610Salfred	if (desc == NULL) {
2775184610Salfred		DPRINTF("no Audio Control header\n");
2776184610Salfred		goto done;
2777184610Salfred	}
2778184610Salfred	acdp = desc;
2779184610Salfred
2780184610Salfred	if ((acdp->bLength < sizeof(*acdp)) ||
2781184610Salfred	    (acdp->bDescriptorType != UDESC_CS_INTERFACE) ||
2782184610Salfred	    (acdp->bDescriptorSubtype != UDESCSUB_AC_HEADER)) {
2783184610Salfred		DPRINTF("invalid Audio Control header\n");
2784184610Salfred		goto done;
2785184610Salfred	}
2786186730Salfred	/* "wTotalLen" is allowed to be corrupt */
2787186730Salfred	wTotalLen = UGETW(acdp->wTotalLength) - acdp->bLength;
2788186730Salfred
2789186730Salfred	/* get USB audio revision */
2790184610Salfred	sc->sc_audio_rev = UGETW(acdp->bcdADC);
2791184610Salfred
2792184610Salfred	DPRINTFN(3, "found AC header, vers=%03x, len=%d\n",
2793184610Salfred	    sc->sc_audio_rev, wTotalLen);
2794184610Salfred
2795184610Salfred	if (sc->sc_audio_rev != UAUDIO_VERSION) {
2796184610Salfred
2797184610Salfred		if (sc->sc_uq_bad_adc) {
2798184610Salfred
2799184610Salfred		} else {
2800184610Salfred			DPRINTF("invalid audio version\n");
2801184610Salfred			goto done;
2802184610Salfred		}
2803184610Salfred	}
2804184610Salfred	iot = malloc(sizeof(struct uaudio_terminal_node) * 256, M_TEMP,
2805184610Salfred	    M_WAITOK | M_ZERO);
2806184610Salfred
2807184610Salfred	if (iot == NULL) {
2808184610Salfred		DPRINTF("no memory!\n");
2809184610Salfred		goto done;
2810184610Salfred	}
2811194228Sthompsa	while ((desc = usb_desc_foreach(cd, desc))) {
2812184610Salfred
2813184610Salfred		dp = desc;
2814184610Salfred
2815184610Salfred		if (dp->bLength > wTotalLen) {
2816184610Salfred			break;
2817184610Salfred		} else {
2818184610Salfred			wTotalLen -= dp->bLength;
2819184610Salfred		}
2820184610Salfred
2821184610Salfred		au = uaudio_mixer_verify_desc(dp, 0);
2822184610Salfred
2823184610Salfred		if (au) {
2824184610Salfred			iot[au->bUnitId].u.desc = (const void *)au;
2825184610Salfred			if (au->bUnitId > ID_max) {
2826184610Salfred				ID_max = au->bUnitId;
2827184610Salfred			}
2828184610Salfred		}
2829184610Salfred	}
2830184610Salfred
2831184610Salfred	DPRINTF("Maximum ID=%d\n", ID_max);
2832184610Salfred
2833184610Salfred	/*
2834184610Salfred	 * determine sourcing inputs for
2835184610Salfred	 * all nodes in the tree:
2836184610Salfred	 */
2837184610Salfred	i = ID_max;
2838184610Salfred	do {
2839184610Salfred		uaudio_mixer_find_inputs_sub(iot, &i, 1, &((iot + i)->usr));
2840184610Salfred	} while (i--);
2841184610Salfred
2842184610Salfred	/*
2843184610Salfred	 * determine outputs for
2844184610Salfred	 * all nodes in the tree:
2845184610Salfred	 */
2846184610Salfred	i = ID_max;
2847184610Salfred	do {
2848184610Salfred		uaudio_mixer_find_outputs_sub(iot, i, ID_max, &((iot + i)->usr));
2849184610Salfred	} while (i--);
2850184610Salfred
2851184610Salfred	/* set "id_max" and "root" */
2852184610Salfred
2853184610Salfred	i = ID_max;
2854184610Salfred	do {
2855184610Salfred		(iot + i)->usr.id_max = ID_max;
2856184610Salfred		(iot + i)->root = iot;
2857184610Salfred	} while (i--);
2858184610Salfred
2859207077Sthompsa#ifdef USB_DEBUG
2860184610Salfred	i = ID_max;
2861184610Salfred	do {
2862184610Salfred		uint8_t j;
2863184610Salfred
2864184610Salfred		if (iot[i].u.desc == NULL) {
2865184610Salfred			continue;
2866184610Salfred		}
2867184610Salfred		DPRINTF("id %d:\n", i);
2868184610Salfred
2869184610Salfred		switch (iot[i].u.desc->bDescriptorSubtype) {
2870184610Salfred		case UDESCSUB_AC_INPUT:
2871184610Salfred			DPRINTF(" - AC_INPUT type=%s\n",
2872184610Salfred			    uaudio_mixer_get_terminal_name
2873184610Salfred			    (UGETW(iot[i].u.it->wTerminalType)));
2874184610Salfred			uaudio_mixer_dump_cluster(i, iot);
2875184610Salfred			break;
2876184610Salfred
2877184610Salfred		case UDESCSUB_AC_OUTPUT:
2878184610Salfred			DPRINTF(" - AC_OUTPUT type=%s "
2879184610Salfred			    "src=%d\n", uaudio_mixer_get_terminal_name
2880184610Salfred			    (UGETW(iot[i].u.ot->wTerminalType)),
2881184610Salfred			    iot[i].u.ot->bSourceId);
2882184610Salfred			break;
2883184610Salfred
2884184610Salfred		case UDESCSUB_AC_MIXER:
2885184610Salfred			DPRINTF(" - AC_MIXER src:\n");
2886184610Salfred			for (j = 0; j < iot[i].u.mu->bNrInPins; j++) {
2887184610Salfred				DPRINTF("   - %d\n", iot[i].u.mu->baSourceId[j]);
2888184610Salfred			}
2889184610Salfred			uaudio_mixer_dump_cluster(i, iot);
2890184610Salfred			break;
2891184610Salfred
2892184610Salfred		case UDESCSUB_AC_SELECTOR:
2893184610Salfred			DPRINTF(" - AC_SELECTOR src:\n");
2894184610Salfred			for (j = 0; j < iot[i].u.su->bNrInPins; j++) {
2895184610Salfred				DPRINTF("   - %d\n", iot[i].u.su->baSourceId[j]);
2896184610Salfred			}
2897184610Salfred			break;
2898184610Salfred
2899184610Salfred		case UDESCSUB_AC_FEATURE:
2900184610Salfred			DPRINTF(" - AC_FEATURE src=%d\n", iot[i].u.fu->bSourceId);
2901184610Salfred			break;
2902184610Salfred
2903184610Salfred		case UDESCSUB_AC_PROCESSING:
2904184610Salfred			DPRINTF(" - AC_PROCESSING src:\n");
2905184610Salfred			for (j = 0; j < iot[i].u.pu->bNrInPins; j++) {
2906184610Salfred				DPRINTF("   - %d\n", iot[i].u.pu->baSourceId[j]);
2907184610Salfred			}
2908184610Salfred			uaudio_mixer_dump_cluster(i, iot);
2909184610Salfred			break;
2910184610Salfred
2911184610Salfred		case UDESCSUB_AC_EXTENSION:
2912184610Salfred			DPRINTF(" - AC_EXTENSION src:\n");
2913184610Salfred			for (j = 0; j < iot[i].u.eu->bNrInPins; j++) {
2914184610Salfred				DPRINTF("%d ", iot[i].u.eu->baSourceId[j]);
2915184610Salfred			}
2916184610Salfred			uaudio_mixer_dump_cluster(i, iot);
2917184610Salfred			break;
2918184610Salfred
2919184610Salfred		default:
2920184610Salfred			DPRINTF("unknown audio control (subtype=%d)\n",
2921184610Salfred			    iot[i].u.desc->bDescriptorSubtype);
2922184610Salfred		}
2923184610Salfred
2924184610Salfred		DPRINTF("Inputs to this ID are:\n");
2925184610Salfred
2926184610Salfred		j = ID_max;
2927184610Salfred		do {
2928184610Salfred			if (iot[i].usr.bit_input[j / 8] & (1 << (j % 8))) {
2929184610Salfred				DPRINTF("  -- ID=%d\n", j);
2930184610Salfred			}
2931184610Salfred		} while (j--);
2932184610Salfred
2933184610Salfred		DPRINTF("Outputs from this ID are:\n");
2934184610Salfred
2935184610Salfred		j = ID_max;
2936184610Salfred		do {
2937184610Salfred			if (iot[i].usr.bit_output[j / 8] & (1 << (j % 8))) {
2938184610Salfred				DPRINTF("  -- ID=%d\n", j);
2939184610Salfred			}
2940184610Salfred		} while (j--);
2941184610Salfred
2942184610Salfred	} while (i--);
2943184610Salfred#endif
2944184610Salfred
2945184610Salfred	/*
2946184610Salfred	 * scan the config to create a linked
2947184610Salfred	 * list of "mixer" nodes:
2948184610Salfred	 */
2949184610Salfred
2950184610Salfred	i = ID_max;
2951184610Salfred	do {
2952184610Salfred		dp = iot[i].u.desc;
2953184610Salfred
2954184610Salfred		if (dp == NULL) {
2955184610Salfred			continue;
2956184610Salfred		}
2957184610Salfred		DPRINTFN(11, "id=%d subtype=%d\n",
2958184610Salfred		    i, dp->bDescriptorSubtype);
2959184610Salfred
2960184610Salfred		switch (dp->bDescriptorSubtype) {
2961184610Salfred		case UDESCSUB_AC_HEADER:
2962184610Salfred			DPRINTF("unexpected AC header\n");
2963184610Salfred			break;
2964184610Salfred
2965184610Salfred		case UDESCSUB_AC_INPUT:
2966184610Salfred			uaudio_mixer_add_input(sc, iot, i);
2967184610Salfred			break;
2968184610Salfred
2969184610Salfred		case UDESCSUB_AC_OUTPUT:
2970184610Salfred			uaudio_mixer_add_output(sc, iot, i);
2971184610Salfred			break;
2972184610Salfred
2973184610Salfred		case UDESCSUB_AC_MIXER:
2974184610Salfred			uaudio_mixer_add_mixer(sc, iot, i);
2975184610Salfred			break;
2976184610Salfred
2977184610Salfred		case UDESCSUB_AC_SELECTOR:
2978184610Salfred			uaudio_mixer_add_selector(sc, iot, i);
2979184610Salfred			break;
2980184610Salfred
2981184610Salfred		case UDESCSUB_AC_FEATURE:
2982184610Salfred			uaudio_mixer_add_feature(sc, iot, i);
2983184610Salfred			break;
2984184610Salfred
2985184610Salfred		case UDESCSUB_AC_PROCESSING:
2986184610Salfred			uaudio_mixer_add_processing(sc, iot, i);
2987184610Salfred			break;
2988184610Salfred
2989184610Salfred		case UDESCSUB_AC_EXTENSION:
2990184610Salfred			uaudio_mixer_add_extension(sc, iot, i);
2991184610Salfred			break;
2992184610Salfred
2993184610Salfred		default:
2994184610Salfred			DPRINTF("bad AC desc subtype=0x%02x\n",
2995184610Salfred			    dp->bDescriptorSubtype);
2996184610Salfred			break;
2997184610Salfred		}
2998184610Salfred
2999184610Salfred	} while (i--);
3000184610Salfred
3001184610Salfreddone:
3002184610Salfred	if (iot) {
3003184610Salfred		free(iot, M_TEMP);
3004184610Salfred	}
3005184610Salfred}
3006184610Salfred
3007184610Salfredstatic uint16_t
3008192984Sthompsauaudio_mixer_get(struct usb_device *udev, uint8_t what,
3009184610Salfred    struct uaudio_mixer_node *mc)
3010184610Salfred{
3011192984Sthompsa	struct usb_device_request req;
3012184610Salfred	uint16_t val;
3013184610Salfred	uint16_t len = MIX_SIZE(mc->type);
3014184610Salfred	uint8_t data[4];
3015193045Sthompsa	usb_error_t err;
3016184610Salfred
3017184610Salfred	if (mc->wValue[0] == -1) {
3018184610Salfred		return (0);
3019184610Salfred	}
3020184610Salfred	req.bmRequestType = UT_READ_CLASS_INTERFACE;
3021184610Salfred	req.bRequest = what;
3022184610Salfred	USETW(req.wValue, mc->wValue[0]);
3023184610Salfred	USETW(req.wIndex, mc->wIndex);
3024184610Salfred	USETW(req.wLength, len);
3025184610Salfred
3026196487Salfred	err = usbd_do_request(udev, NULL, &req, data);
3027184610Salfred	if (err) {
3028194228Sthompsa		DPRINTF("err=%s\n", usbd_errstr(err));
3029184610Salfred		return (0);
3030184610Salfred	}
3031184610Salfred	if (len < 1) {
3032184610Salfred		data[0] = 0;
3033184610Salfred	}
3034184610Salfred	if (len < 2) {
3035184610Salfred		data[1] = 0;
3036184610Salfred	}
3037184610Salfred	val = (data[0] | (data[1] << 8));
3038184610Salfred
3039184610Salfred	DPRINTFN(3, "val=%d\n", val);
3040184610Salfred
3041184610Salfred	return (val);
3042184610Salfred}
3043184610Salfred
3044184610Salfredstatic void
3045194677Sthompsauaudio_mixer_write_cfg_callback(struct usb_xfer *xfer, usb_error_t error)
3046184610Salfred{
3047192984Sthompsa	struct usb_device_request req;
3048194677Sthompsa	struct uaudio_softc *sc = usbd_xfer_softc(xfer);
3049184610Salfred	struct uaudio_mixer_node *mc = sc->sc_mixer_curr;
3050194677Sthompsa	struct usb_page_cache *pc;
3051184610Salfred	uint16_t len;
3052184610Salfred	uint8_t repeat = 1;
3053184610Salfred	uint8_t update;
3054184610Salfred	uint8_t chan;
3055184610Salfred	uint8_t buf[2];
3056184610Salfred
3057187165Sthompsa	DPRINTF("\n");
3058187165Sthompsa
3059184610Salfred	switch (USB_GET_STATE(xfer)) {
3060184610Salfred	case USB_ST_TRANSFERRED:
3061184610Salfredtr_transferred:
3062184610Salfred	case USB_ST_SETUP:
3063184610Salfredtr_setup:
3064184610Salfred
3065184610Salfred		if (mc == NULL) {
3066184610Salfred			mc = sc->sc_mixer_root;
3067184610Salfred			sc->sc_mixer_curr = mc;
3068184610Salfred			sc->sc_mixer_chan = 0;
3069184610Salfred			repeat = 0;
3070184610Salfred		}
3071184610Salfred		while (mc) {
3072184610Salfred			while (sc->sc_mixer_chan < mc->nchan) {
3073184610Salfred
3074184610Salfred				len = MIX_SIZE(mc->type);
3075184610Salfred
3076184610Salfred				chan = sc->sc_mixer_chan;
3077184610Salfred
3078184610Salfred				sc->sc_mixer_chan++;
3079184610Salfred
3080184610Salfred				update = ((mc->update[chan / 8] & (1 << (chan % 8))) &&
3081184610Salfred				    (mc->wValue[chan] != -1));
3082184610Salfred
3083184610Salfred				mc->update[chan / 8] &= ~(1 << (chan % 8));
3084184610Salfred
3085184610Salfred				if (update) {
3086184610Salfred
3087184610Salfred					req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
3088184610Salfred					req.bRequest = SET_CUR;
3089184610Salfred					USETW(req.wValue, mc->wValue[chan]);
3090184610Salfred					USETW(req.wIndex, mc->wIndex);
3091184610Salfred					USETW(req.wLength, len);
3092184610Salfred
3093184610Salfred					if (len > 0) {
3094184610Salfred						buf[0] = (mc->wData[chan] & 0xFF);
3095184610Salfred					}
3096184610Salfred					if (len > 1) {
3097184610Salfred						buf[1] = (mc->wData[chan] >> 8) & 0xFF;
3098184610Salfred					}
3099194677Sthompsa					pc = usbd_xfer_get_frame(xfer, 0);
3100194677Sthompsa					usbd_copy_in(pc, 0, &req, sizeof(req));
3101194677Sthompsa					pc = usbd_xfer_get_frame(xfer, 1);
3102194677Sthompsa					usbd_copy_in(pc, 0, buf, len);
3103184610Salfred
3104194677Sthompsa					usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
3105194677Sthompsa					usbd_xfer_set_frame_len(xfer, 1, len);
3106194677Sthompsa					usbd_xfer_set_frames(xfer, len ? 2 : 1);
3107194228Sthompsa					usbd_transfer_submit(xfer);
3108184610Salfred					return;
3109184610Salfred				}
3110184610Salfred			}
3111184610Salfred
3112184610Salfred			mc = mc->next;
3113184610Salfred			sc->sc_mixer_curr = mc;
3114184610Salfred			sc->sc_mixer_chan = 0;
3115184610Salfred		}
3116184610Salfred
3117184610Salfred		if (repeat) {
3118184610Salfred			goto tr_setup;
3119184610Salfred		}
3120187165Sthompsa		break;
3121184610Salfred
3122184610Salfred	default:			/* Error */
3123194677Sthompsa		DPRINTF("error=%s\n", usbd_errstr(error));
3124194677Sthompsa		if (error == USB_ERR_CANCELLED) {
3125187165Sthompsa			/* do nothing - we are detaching */
3126187165Sthompsa			break;
3127187165Sthompsa		}
3128184610Salfred		goto tr_transferred;
3129184610Salfred	}
3130184610Salfred}
3131184610Salfred
3132193045Sthompsastatic usb_error_t
3133192984Sthompsauaudio_set_speed(struct usb_device *udev, uint8_t endpt, uint32_t speed)
3134184610Salfred{
3135192984Sthompsa	struct usb_device_request req;
3136184610Salfred	uint8_t data[3];
3137184610Salfred
3138184610Salfred	DPRINTFN(6, "endpt=%d speed=%u\n", endpt, speed);
3139184610Salfred
3140184610Salfred	req.bmRequestType = UT_WRITE_CLASS_ENDPOINT;
3141184610Salfred	req.bRequest = SET_CUR;
3142184610Salfred	USETW2(req.wValue, SAMPLING_FREQ_CONTROL, 0);
3143184610Salfred	USETW(req.wIndex, endpt);
3144184610Salfred	USETW(req.wLength, 3);
3145184610Salfred	data[0] = speed;
3146184610Salfred	data[1] = speed >> 8;
3147184610Salfred	data[2] = speed >> 16;
3148184610Salfred
3149196487Salfred	return (usbd_do_request(udev, NULL, &req, data));
3150184610Salfred}
3151184610Salfred
3152184610Salfredstatic int
3153184610Salfreduaudio_mixer_signext(uint8_t type, int val)
3154184610Salfred{
3155184610Salfred	if (!MIX_UNSIGNED(type)) {
3156184610Salfred		if (MIX_SIZE(type) == 2) {
3157184610Salfred			val = (int16_t)val;
3158184610Salfred		} else {
3159184610Salfred			val = (int8_t)val;
3160184610Salfred		}
3161184610Salfred	}
3162184610Salfred	return (val);
3163184610Salfred}
3164184610Salfred
3165184610Salfredstatic int
3166184610Salfreduaudio_mixer_bsd2value(struct uaudio_mixer_node *mc, int32_t val)
3167184610Salfred{
3168184610Salfred	if (mc->type == MIX_ON_OFF) {
3169184610Salfred		val = (val != 0);
3170184610Salfred	} else if (mc->type == MIX_SELECTOR) {
3171184610Salfred		if ((val < mc->minval) ||
3172184610Salfred		    (val > mc->maxval)) {
3173184610Salfred			val = mc->minval;
3174184610Salfred		}
3175184610Salfred	} else {
3176199060Sthompsa
3177199060Sthompsa		/* compute actual volume */
3178199060Sthompsa		val = (val * mc->mul) / 255;
3179199060Sthompsa
3180199060Sthompsa		/* add lower offset */
3181199060Sthompsa		val = val + mc->minval;
3182199060Sthompsa
3183199060Sthompsa		/* make sure we don't write a value out of range */
3184199060Sthompsa		if (val > mc->maxval)
3185199060Sthompsa			val = mc->maxval;
3186199060Sthompsa		else if (val < mc->minval)
3187199060Sthompsa			val = mc->minval;
3188184610Salfred	}
3189184610Salfred
3190185087Salfred	DPRINTFN(6, "type=0x%03x val=%d min=%d max=%d val=%d\n",
3191185087Salfred	    mc->type, val, mc->minval, mc->maxval, val);
3192184610Salfred	return (val);
3193184610Salfred}
3194184610Salfred
3195184610Salfredstatic void
3196184610Salfreduaudio_mixer_ctl_set(struct uaudio_softc *sc, struct uaudio_mixer_node *mc,
3197184610Salfred    uint8_t chan, int32_t val)
3198184610Salfred{
3199184610Salfred	val = uaudio_mixer_bsd2value(mc, val);
3200184610Salfred
3201184610Salfred	mc->update[chan / 8] |= (1 << (chan % 8));
3202184610Salfred	mc->wData[chan] = val;
3203184610Salfred
3204184610Salfred	/* start the transfer, if not already started */
3205184610Salfred
3206194228Sthompsa	usbd_transfer_start(sc->sc_mixer_xfer[0]);
3207184610Salfred}
3208184610Salfred
3209184610Salfredstatic void
3210184610Salfreduaudio_mixer_init(struct uaudio_softc *sc)
3211184610Salfred{
3212184610Salfred	struct uaudio_mixer_node *mc;
3213184610Salfred	int32_t i;
3214184610Salfred
3215184610Salfred	for (mc = sc->sc_mixer_root; mc;
3216184610Salfred	    mc = mc->next) {
3217184610Salfred
3218184610Salfred		if (mc->ctl != SOUND_MIXER_NRDEVICES) {
3219184610Salfred			/*
3220184610Salfred			 * Set device mask bits. See
3221184610Salfred			 * /usr/include/machine/soundcard.h
3222184610Salfred			 */
3223184610Salfred			sc->sc_mix_info |= (1 << mc->ctl);
3224184610Salfred		}
3225184610Salfred		if ((mc->ctl == SOUND_MIXER_NRDEVICES) &&
3226184610Salfred		    (mc->type == MIX_SELECTOR)) {
3227184610Salfred
3228184610Salfred			for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) {
3229184610Salfred				if (mc->slctrtype[i - 1] == SOUND_MIXER_NRDEVICES) {
3230184610Salfred					continue;
3231184610Salfred				}
3232184610Salfred				sc->sc_recsrc_info |= 1 << mc->slctrtype[i - 1];
3233184610Salfred			}
3234184610Salfred		}
3235184610Salfred	}
3236184610Salfred}
3237184610Salfred
3238184610Salfredint
3239184610Salfreduaudio_mixer_init_sub(struct uaudio_softc *sc, struct snd_mixer *m)
3240184610Salfred{
3241184610Salfred	DPRINTF("\n");
3242184610Salfred
3243194228Sthompsa	if (usbd_transfer_setup(sc->sc_udev, &sc->sc_mixer_iface_index,
3244184610Salfred	    sc->sc_mixer_xfer, uaudio_mixer_config, 1, sc,
3245184610Salfred	    mixer_get_lock(m))) {
3246184610Salfred		DPRINTFN(0, "could not allocate USB "
3247184610Salfred		    "transfer for audio mixer!\n");
3248184610Salfred		return (ENOMEM);
3249184610Salfred	}
3250184610Salfred	if (!(sc->sc_mix_info & SOUND_MASK_VOLUME)) {
3251184610Salfred		mix_setparentchild(m, SOUND_MIXER_VOLUME, SOUND_MASK_PCM);
3252184610Salfred		mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE);
3253184610Salfred	}
3254184610Salfred	mix_setdevs(m, sc->sc_mix_info);
3255184610Salfred	mix_setrecdevs(m, sc->sc_recsrc_info);
3256184610Salfred	return (0);
3257184610Salfred}
3258184610Salfred
3259184610Salfredint
3260184610Salfreduaudio_mixer_uninit_sub(struct uaudio_softc *sc)
3261184610Salfred{
3262184610Salfred	DPRINTF("\n");
3263184610Salfred
3264194228Sthompsa	usbd_transfer_unsetup(sc->sc_mixer_xfer, 1);
3265184610Salfred
3266184610Salfred	return (0);
3267184610Salfred}
3268184610Salfred
3269184610Salfredvoid
3270184610Salfreduaudio_mixer_set(struct uaudio_softc *sc, unsigned type,
3271184610Salfred    unsigned left, unsigned right)
3272184610Salfred{
3273184610Salfred	struct uaudio_mixer_node *mc;
3274184610Salfred
3275184610Salfred	for (mc = sc->sc_mixer_root; mc;
3276184610Salfred	    mc = mc->next) {
3277184610Salfred
3278184610Salfred		if (mc->ctl == type) {
3279184610Salfred			if (mc->nchan == 2) {
3280184610Salfred				/* set Right */
3281184610Salfred				uaudio_mixer_ctl_set(sc, mc, 1, (int)(right * 255) / 100);
3282184610Salfred			}
3283184610Salfred			/* set Left or Mono */
3284184610Salfred			uaudio_mixer_ctl_set(sc, mc, 0, (int)(left * 255) / 100);
3285184610Salfred		}
3286184610Salfred	}
3287184610Salfred}
3288184610Salfred
3289184610Salfreduint32_t
3290184610Salfreduaudio_mixer_setrecsrc(struct uaudio_softc *sc, uint32_t src)
3291184610Salfred{
3292184610Salfred	struct uaudio_mixer_node *mc;
3293184610Salfred	uint32_t mask;
3294184610Salfred	uint32_t temp;
3295184610Salfred	int32_t i;
3296184610Salfred
3297184610Salfred	for (mc = sc->sc_mixer_root; mc;
3298184610Salfred	    mc = mc->next) {
3299184610Salfred
3300184610Salfred		if ((mc->ctl == SOUND_MIXER_NRDEVICES) &&
3301184610Salfred		    (mc->type == MIX_SELECTOR)) {
3302184610Salfred
3303184610Salfred			/* compute selector mask */
3304184610Salfred
3305184610Salfred			mask = 0;
3306184610Salfred			for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) {
3307184610Salfred				mask |= (1 << mc->slctrtype[i - 1]);
3308184610Salfred			}
3309184610Salfred
3310184610Salfred			temp = mask & src;
3311184610Salfred			if (temp == 0) {
3312184610Salfred				continue;
3313184610Salfred			}
3314184610Salfred			/* find the first set bit */
3315184610Salfred			temp = (-temp) & temp;
3316184610Salfred
3317184610Salfred			/* update "src" */
3318184610Salfred			src &= ~mask;
3319184610Salfred			src |= temp;
3320184610Salfred
3321184610Salfred			for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) {
3322184610Salfred				if (temp != (1 << mc->slctrtype[i - 1])) {
3323184610Salfred					continue;
3324184610Salfred				}
3325184610Salfred				uaudio_mixer_ctl_set(sc, mc, 0, i);
3326184610Salfred				break;
3327184610Salfred			}
3328184610Salfred		}
3329184610Salfred	}
3330184610Salfred	return (src);
3331184610Salfred}
3332184610Salfred
3333184610Salfred/*========================================================================*
3334184610Salfred * MIDI support routines
3335184610Salfred *========================================================================*/
3336184610Salfred
3337184610Salfredstatic void
3338194677Sthompsaumidi_read_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error)
3339184610Salfred{
3340194677Sthompsa	struct umidi_chan *chan = usbd_xfer_softc(xfer);
3341192984Sthompsa	struct usb_xfer *xfer_other = chan->xfer[1];
3342184610Salfred
3343194228Sthompsa	if (usbd_clear_stall_callback(xfer, xfer_other)) {
3344184610Salfred		DPRINTF("stall cleared\n");
3345184610Salfred		chan->flags &= ~UMIDI_FLAG_READ_STALL;
3346194228Sthompsa		usbd_transfer_start(xfer_other);
3347184610Salfred	}
3348184610Salfred}
3349184610Salfred
3350184610Salfredstatic void
3351194677Sthompsaumidi_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
3352184610Salfred{
3353194677Sthompsa	struct umidi_chan *chan = usbd_xfer_softc(xfer);
3354184610Salfred	struct umidi_sub_chan *sub;
3355194677Sthompsa	struct usb_page_cache *pc;
3356184610Salfred	uint8_t buf[1];
3357184610Salfred	uint8_t cmd_len;
3358184610Salfred	uint8_t cn;
3359184610Salfred	uint16_t pos;
3360194677Sthompsa	int actlen;
3361184610Salfred
3362194677Sthompsa	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
3363194677Sthompsa
3364184610Salfred	switch (USB_GET_STATE(xfer)) {
3365184610Salfred	case USB_ST_TRANSFERRED:
3366184610Salfred
3367194677Sthompsa		DPRINTF("actlen=%d bytes\n", actlen);
3368184610Salfred
3369184610Salfred		pos = 0;
3370194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
3371184610Salfred
3372194677Sthompsa		while (actlen >= 4) {
3373184610Salfred
3374194677Sthompsa			usbd_copy_out(pc, pos, buf, 1);
3375184610Salfred
3376184610Salfred			cmd_len = umidi_cmd_to_len[buf[0] & 0xF];	/* command length */
3377184610Salfred			cn = buf[0] >> 4;	/* cable number */
3378184610Salfred			sub = &chan->sub[cn];
3379184610Salfred
3380184610Salfred			if (cmd_len && (cn < chan->max_cable) && sub->read_open) {
3381194677Sthompsa				usb_fifo_put_data(sub->fifo.fp[USB_FIFO_RX], pc,
3382184610Salfred				    pos + 1, cmd_len, 1);
3383184610Salfred			} else {
3384184610Salfred				/* ignore the command */
3385184610Salfred			}
3386184610Salfred
3387194677Sthompsa			actlen -= 4;
3388184610Salfred			pos += 4;
3389184610Salfred		}
3390184610Salfred
3391184610Salfred	case USB_ST_SETUP:
3392184610Salfred		DPRINTF("start\n");
3393184610Salfred
3394184610Salfred		if (chan->flags & UMIDI_FLAG_READ_STALL) {
3395194228Sthompsa			usbd_transfer_start(chan->xfer[3]);
3396184610Salfred			return;
3397184610Salfred		}
3398194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
3399194228Sthompsa		usbd_transfer_submit(xfer);
3400184610Salfred		return;
3401184610Salfred
3402184610Salfred	default:
3403194677Sthompsa		DPRINTF("error=%s\n", usbd_errstr(error));
3404184610Salfred
3405194677Sthompsa		if (error != USB_ERR_CANCELLED) {
3406184610Salfred			/* try to clear stall first */
3407184610Salfred			chan->flags |= UMIDI_FLAG_READ_STALL;
3408194228Sthompsa			usbd_transfer_start(chan->xfer[3]);
3409184610Salfred		}
3410184610Salfred		return;
3411184610Salfred
3412184610Salfred	}
3413184610Salfred}
3414184610Salfred
3415184610Salfredstatic void
3416194677Sthompsaumidi_write_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error)
3417184610Salfred{
3418194677Sthompsa	struct umidi_chan *chan = usbd_xfer_softc(xfer);
3419192984Sthompsa	struct usb_xfer *xfer_other = chan->xfer[0];
3420184610Salfred
3421194228Sthompsa	if (usbd_clear_stall_callback(xfer, xfer_other)) {
3422184610Salfred		DPRINTF("stall cleared\n");
3423184610Salfred		chan->flags &= ~UMIDI_FLAG_WRITE_STALL;
3424194228Sthompsa		usbd_transfer_start(xfer_other);
3425184610Salfred	}
3426184610Salfred}
3427184610Salfred
3428184610Salfred/*
3429184610Salfred * The following statemachine, that converts MIDI commands to
3430184610Salfred * USB MIDI packets, derives from Linux's usbmidi.c, which
3431184610Salfred * was written by "Clemens Ladisch":
3432184610Salfred *
3433184610Salfred * Returns:
3434184610Salfred *    0: No command
3435184610Salfred * Else: Command is complete
3436184610Salfred */
3437184610Salfredstatic uint8_t
3438184610Salfredumidi_convert_to_usb(struct umidi_sub_chan *sub, uint8_t cn, uint8_t b)
3439184610Salfred{
3440184610Salfred	uint8_t p0 = (cn << 4);
3441184610Salfred
3442184610Salfred	if (b >= 0xf8) {
3443184610Salfred		sub->temp_0[0] = p0 | 0x0f;
3444184610Salfred		sub->temp_0[1] = b;
3445184610Salfred		sub->temp_0[2] = 0;
3446184610Salfred		sub->temp_0[3] = 0;
3447184610Salfred		sub->temp_cmd = sub->temp_0;
3448184610Salfred		return (1);
3449184610Salfred
3450184610Salfred	} else if (b >= 0xf0) {
3451184610Salfred		switch (b) {
3452184610Salfred		case 0xf0:		/* system exclusive begin */
3453184610Salfred			sub->temp_1[1] = b;
3454184610Salfred			sub->state = UMIDI_ST_SYSEX_1;
3455184610Salfred			break;
3456184610Salfred		case 0xf1:		/* MIDI time code */
3457184610Salfred		case 0xf3:		/* song select */
3458184610Salfred			sub->temp_1[1] = b;
3459184610Salfred			sub->state = UMIDI_ST_1PARAM;
3460184610Salfred			break;
3461184610Salfred		case 0xf2:		/* song position pointer */
3462184610Salfred			sub->temp_1[1] = b;
3463184610Salfred			sub->state = UMIDI_ST_2PARAM_1;
3464184610Salfred			break;
3465184610Salfred		case 0xf4:		/* unknown */
3466184610Salfred		case 0xf5:		/* unknown */
3467184610Salfred			sub->state = UMIDI_ST_UNKNOWN;
3468184610Salfred			break;
3469184610Salfred		case 0xf6:		/* tune request */
3470184610Salfred			sub->temp_1[0] = p0 | 0x05;
3471184610Salfred			sub->temp_1[1] = 0xf6;
3472184610Salfred			sub->temp_1[2] = 0;
3473184610Salfred			sub->temp_1[3] = 0;
3474184610Salfred			sub->temp_cmd = sub->temp_1;
3475184610Salfred			sub->state = UMIDI_ST_UNKNOWN;
3476184610Salfred			return (1);
3477184610Salfred
3478184610Salfred		case 0xf7:		/* system exclusive end */
3479184610Salfred			switch (sub->state) {
3480184610Salfred			case UMIDI_ST_SYSEX_0:
3481184610Salfred				sub->temp_1[0] = p0 | 0x05;
3482184610Salfred				sub->temp_1[1] = 0xf7;
3483184610Salfred				sub->temp_1[2] = 0;
3484184610Salfred				sub->temp_1[3] = 0;
3485184610Salfred				sub->temp_cmd = sub->temp_1;
3486184610Salfred				sub->state = UMIDI_ST_UNKNOWN;
3487184610Salfred				return (1);
3488184610Salfred			case UMIDI_ST_SYSEX_1:
3489184610Salfred				sub->temp_1[0] = p0 | 0x06;
3490184610Salfred				sub->temp_1[2] = 0xf7;
3491184610Salfred				sub->temp_1[3] = 0;
3492184610Salfred				sub->temp_cmd = sub->temp_1;
3493184610Salfred				sub->state = UMIDI_ST_UNKNOWN;
3494184610Salfred				return (1);
3495184610Salfred			case UMIDI_ST_SYSEX_2:
3496184610Salfred				sub->temp_1[0] = p0 | 0x07;
3497184610Salfred				sub->temp_1[3] = 0xf7;
3498184610Salfred				sub->temp_cmd = sub->temp_1;
3499184610Salfred				sub->state = UMIDI_ST_UNKNOWN;
3500184610Salfred				return (1);
3501184610Salfred			}
3502184610Salfred			sub->state = UMIDI_ST_UNKNOWN;
3503184610Salfred			break;
3504184610Salfred		}
3505184610Salfred	} else if (b >= 0x80) {
3506184610Salfred		sub->temp_1[1] = b;
3507184610Salfred		if ((b >= 0xc0) && (b <= 0xdf)) {
3508184610Salfred			sub->state = UMIDI_ST_1PARAM;
3509184610Salfred		} else {
3510184610Salfred			sub->state = UMIDI_ST_2PARAM_1;
3511184610Salfred		}
3512184610Salfred	} else {			/* b < 0x80 */
3513184610Salfred		switch (sub->state) {
3514184610Salfred		case UMIDI_ST_1PARAM:
3515184610Salfred			if (sub->temp_1[1] < 0xf0) {
3516184610Salfred				p0 |= sub->temp_1[1] >> 4;
3517184610Salfred			} else {
3518184610Salfred				p0 |= 0x02;
3519184610Salfred				sub->state = UMIDI_ST_UNKNOWN;
3520184610Salfred			}
3521184610Salfred			sub->temp_1[0] = p0;
3522184610Salfred			sub->temp_1[2] = b;
3523184610Salfred			sub->temp_1[3] = 0;
3524184610Salfred			sub->temp_cmd = sub->temp_1;
3525184610Salfred			return (1);
3526184610Salfred		case UMIDI_ST_2PARAM_1:
3527184610Salfred			sub->temp_1[2] = b;
3528184610Salfred			sub->state = UMIDI_ST_2PARAM_2;
3529184610Salfred			break;
3530184610Salfred		case UMIDI_ST_2PARAM_2:
3531184610Salfred			if (sub->temp_1[1] < 0xf0) {
3532184610Salfred				p0 |= sub->temp_1[1] >> 4;
3533184610Salfred				sub->state = UMIDI_ST_2PARAM_1;
3534184610Salfred			} else {
3535184610Salfred				p0 |= 0x03;
3536184610Salfred				sub->state = UMIDI_ST_UNKNOWN;
3537184610Salfred			}
3538184610Salfred			sub->temp_1[0] = p0;
3539184610Salfred			sub->temp_1[3] = b;
3540184610Salfred			sub->temp_cmd = sub->temp_1;
3541184610Salfred			return (1);
3542184610Salfred		case UMIDI_ST_SYSEX_0:
3543184610Salfred			sub->temp_1[1] = b;
3544184610Salfred			sub->state = UMIDI_ST_SYSEX_1;
3545184610Salfred			break;
3546184610Salfred		case UMIDI_ST_SYSEX_1:
3547184610Salfred			sub->temp_1[2] = b;
3548184610Salfred			sub->state = UMIDI_ST_SYSEX_2;
3549184610Salfred			break;
3550184610Salfred		case UMIDI_ST_SYSEX_2:
3551184610Salfred			sub->temp_1[0] = p0 | 0x04;
3552184610Salfred			sub->temp_1[3] = b;
3553184610Salfred			sub->temp_cmd = sub->temp_1;
3554184610Salfred			sub->state = UMIDI_ST_SYSEX_0;
3555184610Salfred			return (1);
3556184610Salfred		}
3557184610Salfred	}
3558184610Salfred	return (0);
3559184610Salfred}
3560184610Salfred
3561184610Salfredstatic void
3562194677Sthompsaumidi_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
3563184610Salfred{
3564194677Sthompsa	struct umidi_chan *chan = usbd_xfer_softc(xfer);
3565184610Salfred	struct umidi_sub_chan *sub;
3566194677Sthompsa	struct usb_page_cache *pc;
3567184610Salfred	uint32_t actlen;
3568184610Salfred	uint16_t total_length;
3569184610Salfred	uint8_t buf;
3570184610Salfred	uint8_t start_cable;
3571184610Salfred	uint8_t tr_any;
3572194677Sthompsa	int len;
3573184610Salfred
3574194677Sthompsa	usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
3575194677Sthompsa
3576184610Salfred	switch (USB_GET_STATE(xfer)) {
3577184610Salfred	case USB_ST_TRANSFERRED:
3578194677Sthompsa		DPRINTF("actlen=%d bytes\n", len);
3579184610Salfred
3580184610Salfred	case USB_ST_SETUP:
3581184610Salfred
3582184610Salfred		DPRINTF("start\n");
3583184610Salfred
3584184610Salfred		if (chan->flags & UMIDI_FLAG_WRITE_STALL) {
3585194228Sthompsa			usbd_transfer_start(chan->xfer[2]);
3586184610Salfred			return;
3587184610Salfred		}
3588184610Salfred		total_length = 0;	/* reset */
3589184610Salfred		start_cable = chan->curr_cable;
3590184610Salfred		tr_any = 0;
3591194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
3592184610Salfred
3593184610Salfred		while (1) {
3594184610Salfred
3595184610Salfred			/* round robin de-queueing */
3596184610Salfred
3597184610Salfred			sub = &chan->sub[chan->curr_cable];
3598184610Salfred
3599184610Salfred			if (sub->write_open) {
3600194228Sthompsa				usb_fifo_get_data(sub->fifo.fp[USB_FIFO_TX],
3601194677Sthompsa				    pc, total_length, 1, &actlen, 0);
3602184610Salfred			} else {
3603184610Salfred				actlen = 0;
3604184610Salfred			}
3605184610Salfred
3606184610Salfred			if (actlen) {
3607194677Sthompsa				usbd_copy_out(pc, total_length, &buf, 1);
3608184610Salfred
3609184610Salfred				tr_any = 1;
3610184610Salfred
3611184610Salfred				DPRINTF("byte=0x%02x\n", buf);
3612184610Salfred
3613184610Salfred				if (umidi_convert_to_usb(sub, chan->curr_cable, buf)) {
3614184610Salfred
3615184610Salfred					DPRINTF("sub= %02x %02x %02x %02x\n",
3616184610Salfred					    sub->temp_cmd[0], sub->temp_cmd[1],
3617184610Salfred					    sub->temp_cmd[2], sub->temp_cmd[3]);
3618184610Salfred
3619194677Sthompsa					usbd_copy_in(pc, total_length,
3620184610Salfred					    sub->temp_cmd, 4);
3621184610Salfred
3622184610Salfred					total_length += 4;
3623184610Salfred
3624184610Salfred					if (total_length >= UMIDI_BULK_SIZE) {
3625184610Salfred						break;
3626184610Salfred					}
3627184610Salfred				} else {
3628184610Salfred					continue;
3629184610Salfred				}
3630184610Salfred			}
3631184610Salfred			chan->curr_cable++;
3632184610Salfred			if (chan->curr_cable >= chan->max_cable) {
3633184610Salfred				chan->curr_cable = 0;
3634184610Salfred			}
3635184610Salfred			if (chan->curr_cable == start_cable) {
3636184610Salfred				if (tr_any == 0) {
3637184610Salfred					break;
3638184610Salfred				}
3639184610Salfred				tr_any = 0;
3640184610Salfred			}
3641184610Salfred		}
3642184610Salfred
3643184610Salfred		if (total_length) {
3644194677Sthompsa			usbd_xfer_set_frame_len(xfer, 0, total_length);
3645194228Sthompsa			usbd_transfer_submit(xfer);
3646184610Salfred		}
3647184610Salfred		return;
3648184610Salfred
3649184610Salfred	default:			/* Error */
3650184610Salfred
3651194677Sthompsa		DPRINTF("error=%s\n", usbd_errstr(error));
3652184610Salfred
3653194677Sthompsa		if (error != USB_ERR_CANCELLED) {
3654184610Salfred			/* try to clear stall first */
3655184610Salfred			chan->flags |= UMIDI_FLAG_WRITE_STALL;
3656194228Sthompsa			usbd_transfer_start(chan->xfer[2]);
3657184610Salfred		}
3658184610Salfred		return;
3659184610Salfred
3660184610Salfred	}
3661184610Salfred}
3662184610Salfred
3663184610Salfredstatic struct umidi_sub_chan *
3664192984Sthompsaumidi_sub_by_fifo(struct usb_fifo *fifo)
3665184610Salfred{
3666194677Sthompsa	struct umidi_chan *chan = usb_fifo_softc(fifo);
3667184610Salfred	struct umidi_sub_chan *sub;
3668184610Salfred	uint32_t n;
3669184610Salfred
3670184610Salfred	for (n = 0; n < UMIDI_CABLES_MAX; n++) {
3671184610Salfred		sub = &chan->sub[n];
3672184610Salfred		if ((sub->fifo.fp[USB_FIFO_RX] == fifo) ||
3673184610Salfred		    (sub->fifo.fp[USB_FIFO_TX] == fifo)) {
3674184610Salfred			return (sub);
3675184610Salfred		}
3676184610Salfred	}
3677184610Salfred
3678192984Sthompsa	panic("%s:%d cannot find usb_fifo!\n",
3679184610Salfred	    __FILE__, __LINE__);
3680184610Salfred
3681184610Salfred	return (NULL);
3682184610Salfred}
3683184610Salfred
3684184610Salfredstatic void
3685192984Sthompsaumidi_start_read(struct usb_fifo *fifo)
3686184610Salfred{
3687194677Sthompsa	struct umidi_chan *chan = usb_fifo_softc(fifo);
3688184610Salfred
3689194228Sthompsa	usbd_transfer_start(chan->xfer[1]);
3690184610Salfred}
3691184610Salfred
3692184610Salfredstatic void
3693192984Sthompsaumidi_stop_read(struct usb_fifo *fifo)
3694184610Salfred{
3695194677Sthompsa	struct umidi_chan *chan = usb_fifo_softc(fifo);
3696184610Salfred	struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo);
3697184610Salfred
3698184610Salfred	DPRINTF("\n");
3699184610Salfred
3700184610Salfred	sub->read_open = 0;
3701184610Salfred
3702184610Salfred	if (--(chan->read_open_refcount) == 0) {
3703184610Salfred		/*
3704184610Salfred		 * XXX don't stop the read transfer here, hence that causes
3705184610Salfred		 * problems with some MIDI adapters
3706184610Salfred		 */
3707184610Salfred		DPRINTF("(stopping read transfer)\n");
3708184610Salfred	}
3709184610Salfred}
3710184610Salfred
3711184610Salfredstatic void
3712192984Sthompsaumidi_start_write(struct usb_fifo *fifo)
3713184610Salfred{
3714194677Sthompsa	struct umidi_chan *chan = usb_fifo_softc(fifo);
3715184610Salfred
3716194228Sthompsa	usbd_transfer_start(chan->xfer[0]);
3717184610Salfred}
3718184610Salfred
3719184610Salfredstatic void
3720192984Sthompsaumidi_stop_write(struct usb_fifo *fifo)
3721184610Salfred{
3722194677Sthompsa	struct umidi_chan *chan = usb_fifo_softc(fifo);
3723184610Salfred	struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo);
3724184610Salfred
3725184610Salfred	DPRINTF("\n");
3726184610Salfred
3727184610Salfred	sub->write_open = 0;
3728184610Salfred
3729184610Salfred	if (--(chan->write_open_refcount) == 0) {
3730184610Salfred		DPRINTF("(stopping write transfer)\n");
3731194228Sthompsa		usbd_transfer_stop(chan->xfer[2]);
3732194228Sthompsa		usbd_transfer_stop(chan->xfer[0]);
3733184610Salfred	}
3734184610Salfred}
3735184610Salfred
3736184610Salfredstatic int
3737192984Sthompsaumidi_open(struct usb_fifo *fifo, int fflags)
3738184610Salfred{
3739194677Sthompsa	struct umidi_chan *chan = usb_fifo_softc(fifo);
3740184610Salfred	struct umidi_sub_chan *sub = umidi_sub_by_fifo(fifo);
3741184610Salfred
3742184610Salfred	if (fflags & FREAD) {
3743194228Sthompsa		if (usb_fifo_alloc_buffer(fifo, 4, (1024 / 4))) {
3744184610Salfred			return (ENOMEM);
3745184610Salfred		}
3746195120Sthompsa		mtx_lock(&chan->mtx);
3747184610Salfred		chan->read_open_refcount++;
3748184610Salfred		sub->read_open = 1;
3749195120Sthompsa		mtx_unlock(&chan->mtx);
3750184610Salfred	}
3751184610Salfred	if (fflags & FWRITE) {
3752194228Sthompsa		if (usb_fifo_alloc_buffer(fifo, 32, (1024 / 32))) {
3753184610Salfred			return (ENOMEM);
3754184610Salfred		}
3755184610Salfred		/* clear stall first */
3756195120Sthompsa		mtx_lock(&chan->mtx);
3757184610Salfred		chan->flags |= UMIDI_FLAG_WRITE_STALL;
3758184610Salfred		chan->write_open_refcount++;
3759184610Salfred		sub->write_open = 1;
3760184610Salfred
3761184610Salfred		/* reset */
3762184610Salfred		sub->state = UMIDI_ST_UNKNOWN;
3763195120Sthompsa		mtx_unlock(&chan->mtx);
3764184610Salfred	}
3765184610Salfred	return (0);			/* success */
3766184610Salfred}
3767184610Salfred
3768184610Salfredstatic void
3769192984Sthompsaumidi_close(struct usb_fifo *fifo, int fflags)
3770184610Salfred{
3771184610Salfred	if (fflags & FREAD) {
3772194228Sthompsa		usb_fifo_free_buffer(fifo);
3773184610Salfred	}
3774184610Salfred	if (fflags & FWRITE) {
3775194228Sthompsa		usb_fifo_free_buffer(fifo);
3776184610Salfred	}
3777184610Salfred}
3778184610Salfred
3779184610Salfred
3780184610Salfredstatic int
3781192984Sthompsaumidi_ioctl(struct usb_fifo *fifo, u_long cmd, void *data,
3782189110Sthompsa    int fflags)
3783184610Salfred{
3784184610Salfred	return (ENODEV);
3785184610Salfred}
3786184610Salfred
3787184610Salfredstatic void
3788184610Salfredumidi_init(device_t dev)
3789184610Salfred{
3790184610Salfred	struct uaudio_softc *sc = device_get_softc(dev);
3791184610Salfred	struct umidi_chan *chan = &sc->sc_midi_chan;
3792184610Salfred
3793184610Salfred	mtx_init(&chan->mtx, "umidi lock", NULL, MTX_DEF | MTX_RECURSE);
3794184610Salfred}
3795184610Salfred
3796192984Sthompsastatic struct usb_fifo_methods umidi_fifo_methods = {
3797184610Salfred	.f_start_read = &umidi_start_read,
3798184610Salfred	.f_start_write = &umidi_start_write,
3799184610Salfred	.f_stop_read = &umidi_stop_read,
3800184610Salfred	.f_stop_write = &umidi_stop_write,
3801184610Salfred	.f_open = &umidi_open,
3802184610Salfred	.f_close = &umidi_close,
3803184610Salfred	.f_ioctl = &umidi_ioctl,
3804184610Salfred	.basename[0] = "umidi",
3805184610Salfred};
3806184610Salfred
3807184610Salfredstatic int32_t
3808184610Salfredumidi_probe(device_t dev)
3809184610Salfred{
3810184610Salfred	struct uaudio_softc *sc = device_get_softc(dev);
3811192984Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(dev);
3812184610Salfred	struct umidi_chan *chan = &sc->sc_midi_chan;
3813184610Salfred	struct umidi_sub_chan *sub;
3814184610Salfred	int unit = device_get_unit(dev);
3815184610Salfred	int error;
3816184610Salfred	uint32_t n;
3817184610Salfred
3818194228Sthompsa	if (usbd_set_alt_interface_index(sc->sc_udev, chan->iface_index,
3819184610Salfred	    chan->iface_alt_index)) {
3820184610Salfred		DPRINTF("setting of alternate index failed!\n");
3821184610Salfred		goto detach;
3822184610Salfred	}
3823194228Sthompsa	usbd_set_parent_iface(sc->sc_udev, chan->iface_index, sc->sc_mixer_iface_index);
3824184610Salfred
3825194228Sthompsa	error = usbd_transfer_setup(uaa->device, &chan->iface_index,
3826184610Salfred	    chan->xfer, umidi_config, UMIDI_N_TRANSFER,
3827184610Salfred	    chan, &chan->mtx);
3828184610Salfred	if (error) {
3829194228Sthompsa		DPRINTF("error=%s\n", usbd_errstr(error));
3830184610Salfred		goto detach;
3831184610Salfred	}
3832184610Salfred	if ((chan->max_cable > UMIDI_CABLES_MAX) ||
3833184610Salfred	    (chan->max_cable == 0)) {
3834184610Salfred		chan->max_cable = UMIDI_CABLES_MAX;
3835184610Salfred	}
3836184610Salfred
3837184610Salfred	for (n = 0; n < chan->max_cable; n++) {
3838184610Salfred
3839184610Salfred		sub = &chan->sub[n];
3840184610Salfred
3841194228Sthompsa		error = usb_fifo_attach(sc->sc_udev, chan, &chan->mtx,
3842184610Salfred		    &umidi_fifo_methods, &sub->fifo, unit, n,
3843189110Sthompsa		    chan->iface_index,
3844189110Sthompsa		    UID_ROOT, GID_OPERATOR, 0644);
3845184610Salfred		if (error) {
3846184610Salfred			goto detach;
3847184610Salfred		}
3848184610Salfred	}
3849184610Salfred
3850184610Salfred	mtx_lock(&chan->mtx);
3851184610Salfred
3852184610Salfred	/* clear stall first */
3853184610Salfred	chan->flags |= UMIDI_FLAG_READ_STALL;
3854184610Salfred
3855184610Salfred	/*
3856184610Salfred	 * NOTE: at least one device will not work properly unless
3857184610Salfred	 * the BULK pipe is open all the time.
3858184610Salfred	 */
3859194228Sthompsa	usbd_transfer_start(chan->xfer[1]);
3860184610Salfred
3861184610Salfred	mtx_unlock(&chan->mtx);
3862184610Salfred
3863184610Salfred	return (0);			/* success */
3864184610Salfred
3865184610Salfreddetach:
3866184610Salfred	return (ENXIO);			/* failure */
3867184610Salfred}
3868184610Salfred
3869184610Salfredstatic int32_t
3870184610Salfredumidi_detach(device_t dev)
3871184610Salfred{
3872184610Salfred	struct uaudio_softc *sc = device_get_softc(dev);
3873184610Salfred	struct umidi_chan *chan = &sc->sc_midi_chan;
3874184610Salfred	uint32_t n;
3875184610Salfred
3876184610Salfred	for (n = 0; n < UMIDI_CABLES_MAX; n++) {
3877194228Sthompsa		usb_fifo_detach(&chan->sub[n].fifo);
3878184610Salfred	}
3879184610Salfred
3880184610Salfred	mtx_lock(&chan->mtx);
3881184610Salfred
3882194228Sthompsa	usbd_transfer_stop(chan->xfer[3]);
3883194228Sthompsa	usbd_transfer_stop(chan->xfer[1]);
3884184610Salfred
3885184610Salfred	mtx_unlock(&chan->mtx);
3886184610Salfred
3887194228Sthompsa	usbd_transfer_unsetup(chan->xfer, UMIDI_N_TRANSFER);
3888184610Salfred
3889184610Salfred	mtx_destroy(&chan->mtx);
3890184610Salfred
3891184610Salfred	return (0);
3892184610Salfred}
3893184610Salfred
3894189275SthompsaDRIVER_MODULE(uaudio, uhub, uaudio_driver, uaudio_devclass, NULL, 0);
3895188942SthompsaMODULE_DEPEND(uaudio, usb, 1, 1, 1);
3896184610SalfredMODULE_DEPEND(uaudio, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
3897184610SalfredMODULE_VERSION(uaudio, 1);
3898