17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53c91d182Slg  * Common Development and Distribution License (the "License").
63c91d182Slg  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22ea1b934fSLin Guo - Sun Microsystems  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
263fe80ca4SDan Cross /*
273fe80ca4SDan Cross  * Copyright 2023 Oxide Computer Company
283fe80ca4SDan Cross  */
293fe80ca4SDan Cross 
307c478bd9Sstevel@tonic-gate /*
3188447a05SGarrett D'Amore  * AUDIO CONTROL Driver:
3288447a05SGarrett D'Amore  *
3388447a05SGarrett D'Amore  * usb_ac is a multiplexor that sits on top of usb_as and hid and is
3488447a05SGarrett D'Amore  * responsible for (1) providing the entry points to audio mixer framework,
3588447a05SGarrett D'Amore  * (2) passing control commands to and from usb_as and hid and (3) processing
3688447a05SGarrett D'Amore  * control messages from hid/usb_ah that it can handle.
377c478bd9Sstevel@tonic-gate  *
387c478bd9Sstevel@tonic-gate  * 1. Mixer entry points are: usb_ac_setup(), usb_ac_teardown(),
397c478bd9Sstevel@tonic-gate  *	usb_ac_set_config(), usb_ac_set_format(), usb_ac_start_play(),
407c478bd9Sstevel@tonic-gate  *	usb_ac_pause_play(), usb_ac_stop_play, usb_ac_start_record(),
417c478bd9Sstevel@tonic-gate  *	usb_ac_stop_record().
427c478bd9Sstevel@tonic-gate  * 2. usb_ac is a streams driver that passes streams messages down to
437c478bd9Sstevel@tonic-gate  *	usb_as that selects the correct alternate with passed format
447c478bd9Sstevel@tonic-gate  *	parameters, sets sample frequency, starts play/record, stops
457c478bd9Sstevel@tonic-gate  *	play/record, pause play/record, open/close isoc pipe.
467c478bd9Sstevel@tonic-gate  * 3. usb_ac handles the set_config command through the default pipe
477c478bd9Sstevel@tonic-gate  *	of sound control interface of the audio device in a synchronous
487c478bd9Sstevel@tonic-gate  *	manner.
497c478bd9Sstevel@tonic-gate  *
5088447a05SGarrett D'Amore  * Serialization: A competing thread can't be allowed to interfere with
5188447a05SGarrett D'Amore  * (1) pipe, (2) streams state.
527c478bd9Sstevel@tonic-gate  * So we need some kind of serialization among the asynchronous
537c478bd9Sstevel@tonic-gate  * threads that can run in the driver. The serialization is mostly
547c478bd9Sstevel@tonic-gate  * needed to avoid races among open/close/events/power entry points
557c478bd9Sstevel@tonic-gate  * etc. Once a routine takes control, it checks if the resource (pipe or
567c478bd9Sstevel@tonic-gate  * stream or dev state) is still accessible. If so, it proceeds with
577c478bd9Sstevel@tonic-gate  * its job and until it completes, no other thread requiring the same
587c478bd9Sstevel@tonic-gate  * resource can run.
597c478bd9Sstevel@tonic-gate  *
607c478bd9Sstevel@tonic-gate  * PM model in usb_ac: Raise power during attach. If a device is not at full
617c478bd9Sstevel@tonic-gate  * power, raise power in the entry points. After the command is over,
627c478bd9Sstevel@tonic-gate  * pm_idle_component() is called. The power is lowered in detach().
637c478bd9Sstevel@tonic-gate  */
647c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usbai_version.h>
657c478bd9Sstevel@tonic-gate #include <sys/usb/usba.h>
667c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
677c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
68d29f5a71Szhigang lu - Sun Microsystems - Beijing China #include <sys/strsun.h>
6988447a05SGarrett D'Amore #include <sys/ddi.h>
7088447a05SGarrett D'Amore #include <sys/sunddi.h>
7188447a05SGarrett D'Amore #include <sys/sunldi.h>
727c478bd9Sstevel@tonic-gate 
73e272e4c8SBinzi Cao - Sun Microsystems - Beijing China #include <sys/audio/audio_driver.h>
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate #include <sys/usb/clients/audio/usb_audio.h>
767c478bd9Sstevel@tonic-gate #include <sys/usb/clients/audio/usb_mixer.h>
777c478bd9Sstevel@tonic-gate #include <sys/usb/clients/audio/usb_ac/usb_ac.h>
787c478bd9Sstevel@tonic-gate 
7988447a05SGarrett D'Amore /* for getting the minor node info from hid */
8088447a05SGarrett D'Amore #include <sys/usb/clients/hid/hidminor.h>
8188447a05SGarrett D'Amore #include <sys/usb/clients/audio/usb_as/usb_as.h>
8288447a05SGarrett D'Amore 
8388447a05SGarrett D'Amore 
847c478bd9Sstevel@tonic-gate /* debug support */
85*d5ebc493SDan Cross uint_t	usb_ac_errlevel		= USB_LOG_L4;
864610e4a0Sfrits uint_t	usb_ac_errmask		= (uint_t)-1;
874610e4a0Sfrits uint_t	usb_ac_instance_debug	= (uint_t)-1;
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate /*
9088447a05SGarrett D'Amore  * wait period in seconds for the HID message processing thread
9188447a05SGarrett D'Amore  * used primarily to check when the stream has closed
927c478bd9Sstevel@tonic-gate  */
9388447a05SGarrett D'Amore uint_t usb_ac_wait_hid = 1;
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate /*
967c478bd9Sstevel@tonic-gate  * table for converting term types of input and output terminals
97e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  * to OSS port types (pretty rough mapping)
987c478bd9Sstevel@tonic-gate  */
99e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static const char *usb_audio_dtypes[] = {
100e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	AUDIO_PORT_LINEIN,
101e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	AUDIO_PORT_LINEOUT,
102e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	AUDIO_PORT_SPEAKER,
103e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	AUDIO_PORT_HEADPHONES,
104e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	AUDIO_PORT_HANDSET,
105e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	AUDIO_PORT_CD,
106e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	AUDIO_PORT_MIC,
107e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	AUDIO_PORT_PHONE,
108e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	AUDIO_PORT_SPDIFIN,
109e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	AUDIO_PORT_OTHER,
110e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	NULL,
111e272e4c8SBinzi Cao - Sun Microsystems - Beijing China };
112e272e4c8SBinzi Cao - Sun Microsystems - Beijing China enum {
113e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	USB_PORT_LINEIN = 0,
114e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	USB_PORT_LINEOUT,
115e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	USB_PORT_SPEAKER,
116e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	USB_PORT_HEADPHONES,
117e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	USB_PORT_HANDSET,
118e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	USB_PORT_CD,
119e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	USB_PORT_MIC,
120e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	USB_PORT_PHONE,
121e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	USB_PORT_SPDIFIN,
122e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	USB_PORT_UNKNOWN
123e272e4c8SBinzi Cao - Sun Microsystems - Beijing China };
124e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
1257c478bd9Sstevel@tonic-gate static struct {
1267c478bd9Sstevel@tonic-gate 	ushort_t	term_type;
127e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	uint_t	port_type;
1287c478bd9Sstevel@tonic-gate } usb_ac_term_type_map[] = {
129e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
130e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	/* Input Terminal Types */
131e272e4c8SBinzi Cao - Sun Microsystems - Beijing China { USB_AUDIO_TERM_TYPE_MICROPHONE,		USB_PORT_MIC },
132e272e4c8SBinzi Cao - Sun Microsystems - Beijing China { USB_AUDIO_TERM_TYPE_DT_MICROPHONE,		USB_PORT_MIC },
133e272e4c8SBinzi Cao - Sun Microsystems - Beijing China { USB_AUDIO_TERM_TYPE_PERS_MICROPHONE,		USB_PORT_MIC },
134e272e4c8SBinzi Cao - Sun Microsystems - Beijing China { USB_AUDIO_TERM_TYPE_OMNI_DIR_MICROPHONE,	USB_PORT_MIC },
135e272e4c8SBinzi Cao - Sun Microsystems - Beijing China { USB_AUDIO_TERM_TYPE_MICROPHONE_ARRAY,		USB_PORT_MIC },
136e272e4c8SBinzi Cao - Sun Microsystems - Beijing China { USB_AUDIO_TERM_TYPE_PROCESSING_MIC_ARRAY,	USB_PORT_MIC },
137e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
138e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	/* Output Terminal Types */
139e272e4c8SBinzi Cao - Sun Microsystems - Beijing China { USB_AUDIO_TERM_TYPE_SPEAKER,			USB_PORT_SPEAKER },
140e272e4c8SBinzi Cao - Sun Microsystems - Beijing China { USB_AUDIO_TERM_TYPE_HEADPHONES,		USB_PORT_HEADPHONES },
141e272e4c8SBinzi Cao - Sun Microsystems - Beijing China { USB_AUDIO_TERM_TYPE_DISPLAY_AUDIO,		USB_PORT_LINEOUT },
142e272e4c8SBinzi Cao - Sun Microsystems - Beijing China { USB_AUDIO_TERM_TYPE_DT_SPEAKER,		USB_PORT_SPEAKER },
143e272e4c8SBinzi Cao - Sun Microsystems - Beijing China { USB_AUDIO_TERM_TYPE_ROOM_SPEAKER,		USB_PORT_SPEAKER },
144e272e4c8SBinzi Cao - Sun Microsystems - Beijing China { USB_AUDIO_TERM_TYPE_COMM_SPEAKER,		USB_PORT_SPEAKER },
145e272e4c8SBinzi Cao - Sun Microsystems - Beijing China { USB_AUDIO_TERM_TYPE_LF_EFFECTS_SPEAKER,	USB_PORT_SPEAKER },
146e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
147e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	/* Bi-directional Terminal Types */
148e272e4c8SBinzi Cao - Sun Microsystems - Beijing China { USB_AUDIO_TERM_TYPE_HANDSET,		USB_PORT_HANDSET },
149e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
150e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	/* Telephony Terminal Types */
151e272e4c8SBinzi Cao - Sun Microsystems - Beijing China { USB_AUDIO_TERM_TYPE_PHONE_LINE,	USB_PORT_PHONE},
152e272e4c8SBinzi Cao - Sun Microsystems - Beijing China { USB_AUDIO_TERM_TYPE_TELEPHONE,	USB_PORT_PHONE},
153e272e4c8SBinzi Cao - Sun Microsystems - Beijing China { USB_AUDIO_TERM_TYPE_DOWN_LINE_PHONE,	USB_PORT_PHONE },
154e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
155e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	/* External Terminal Types */
156e272e4c8SBinzi Cao - Sun Microsystems - Beijing China { USB_AUDIO_TERM_TYPE_SPDIF_IF,		USB_PORT_SPDIFIN },
157e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	/* Embedded Function Terminal Types */
158e272e4c8SBinzi Cao - Sun Microsystems - Beijing China { USB_AUDIO_TERM_TYPE_CD_PLAYER,	USB_PORT_CD },
1597c478bd9Sstevel@tonic-gate { 0, 0 }
1607c478bd9Sstevel@tonic-gate };
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate /*
1647c478bd9Sstevel@tonic-gate  * Module linkage routines for the kernel
1657c478bd9Sstevel@tonic-gate  */
1667c478bd9Sstevel@tonic-gate static int	usb_ac_attach(dev_info_t *, ddi_attach_cmd_t);
1677c478bd9Sstevel@tonic-gate static int	usb_ac_detach(dev_info_t *, ddi_detach_cmd_t);
1687c478bd9Sstevel@tonic-gate static int	usb_ac_power(dev_info_t *, int, int);
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate static uint_t	usb_ac_get_featureID(usb_ac_state_t *, uchar_t, uint_t,
1717c478bd9Sstevel@tonic-gate 				uint_t);
1727c478bd9Sstevel@tonic-gate 
17388447a05SGarrett D'Amore /* module entry points */
17488447a05SGarrett D'Amore int		usb_ac_open(dev_info_t *);
17588447a05SGarrett D'Amore void		usb_ac_close(dev_info_t *);
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate /* descriptor handling */
1787c478bd9Sstevel@tonic-gate static int	usb_ac_handle_descriptors(usb_ac_state_t *);
1797c478bd9Sstevel@tonic-gate static void	usb_ac_add_unit_descriptor(usb_ac_state_t *, uchar_t *, size_t);
1807c478bd9Sstevel@tonic-gate static void	usb_ac_alloc_unit(usb_ac_state_t *, uint_t);
1817c478bd9Sstevel@tonic-gate static void	usb_ac_free_all_units(usb_ac_state_t *);
1827c478bd9Sstevel@tonic-gate static void	usb_ac_setup_connections(usb_ac_state_t *);
1837c478bd9Sstevel@tonic-gate static void	usb_ac_map_termtype_to_port(usb_ac_state_t *, uint_t);
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate /* power management */
1867c478bd9Sstevel@tonic-gate static int	usb_ac_pwrlvl0(usb_ac_state_t *);
1877c478bd9Sstevel@tonic-gate static int	usb_ac_pwrlvl1(usb_ac_state_t *);
1887c478bd9Sstevel@tonic-gate static int	usb_ac_pwrlvl2(usb_ac_state_t *);
1897c478bd9Sstevel@tonic-gate static int	usb_ac_pwrlvl3(usb_ac_state_t *);
1907c478bd9Sstevel@tonic-gate static void	usb_ac_create_pm_components(dev_info_t *, usb_ac_state_t *);
1917c478bd9Sstevel@tonic-gate static void	usb_ac_pm_busy_component(usb_ac_state_t *);
1927c478bd9Sstevel@tonic-gate static void	usb_ac_pm_idle_component(usb_ac_state_t *);
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate /* event handling */
1957c478bd9Sstevel@tonic-gate static int	usb_ac_disconnect_event_cb(dev_info_t *);
1967c478bd9Sstevel@tonic-gate static int	usb_ac_reconnect_event_cb(dev_info_t *);
1977c478bd9Sstevel@tonic-gate static int	usb_ac_cpr_suspend(dev_info_t *);
1987c478bd9Sstevel@tonic-gate static void	usb_ac_cpr_resume(dev_info_t *);
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate static usb_event_t usb_ac_events = {
2017c478bd9Sstevel@tonic-gate 	usb_ac_disconnect_event_cb,
2027c478bd9Sstevel@tonic-gate 	usb_ac_reconnect_event_cb,
2037c478bd9Sstevel@tonic-gate 	NULL, NULL
2047c478bd9Sstevel@tonic-gate };
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate /* misc. support */
2077c478bd9Sstevel@tonic-gate static void	usb_ac_restore_device_state(dev_info_t *, usb_ac_state_t *);
2087c478bd9Sstevel@tonic-gate static int	usb_ac_cleanup(dev_info_t *, usb_ac_state_t *);
2097c478bd9Sstevel@tonic-gate static void	usb_ac_serialize_access(usb_ac_state_t *);
2107c478bd9Sstevel@tonic-gate static void	usb_ac_release_access(usb_ac_state_t *);
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate static void	usb_ac_push_unit_id(usb_ac_state_t *, uint_t);
2137c478bd9Sstevel@tonic-gate static void	usb_ac_pop_unit_id(usb_ac_state_t *, uint_t);
2147c478bd9Sstevel@tonic-gate static void	usb_ac_show_traverse_path(usb_ac_state_t *);
2157c478bd9Sstevel@tonic-gate static int	usb_ac_check_path(usb_ac_state_t *, uint_t);
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate static uint_t	usb_ac_traverse_connections(usb_ac_state_t *, uint_t, uint_t,
2187c478bd9Sstevel@tonic-gate 				uint_t, uint_t, uint_t, uint_t,
2197c478bd9Sstevel@tonic-gate 				uint_t *, uint_t, uint_t *,
2207c478bd9Sstevel@tonic-gate 				int (*func)(usb_ac_state_t *, uint_t, uint_t,
2217c478bd9Sstevel@tonic-gate 				uint_t, uint_t, uint_t, uint_t *));
2227c478bd9Sstevel@tonic-gate static uint_t	usb_ac_set_port(usb_ac_state_t *, uint_t, uint_t);
2237c478bd9Sstevel@tonic-gate static uint_t	usb_ac_set_control(usb_ac_state_t *, uint_t, uint_t,
2247c478bd9Sstevel@tonic-gate 				uint_t, uint_t, uint_t,
2257c478bd9Sstevel@tonic-gate 				uint_t *, uint_t,
2267c478bd9Sstevel@tonic-gate 				int (*func)(usb_ac_state_t *, uint_t, uint_t,
2277c478bd9Sstevel@tonic-gate 				uint_t, uint_t, uint_t, uint_t *));
2287c478bd9Sstevel@tonic-gate static uint_t	usb_ac_set_monitor_gain_control(usb_ac_state_t *, uint_t,
2297c478bd9Sstevel@tonic-gate 				uint_t, uint_t, uint_t, uint_t,
2307c478bd9Sstevel@tonic-gate 				uint_t *, uint_t,
2317c478bd9Sstevel@tonic-gate 				int (*func)(usb_ac_state_t *, uint_t, uint_t,
2327c478bd9Sstevel@tonic-gate 				uint_t, uint_t, uint_t, uint_t *));
2337c478bd9Sstevel@tonic-gate static uint_t	usb_ac_traverse_all_units(usb_ac_state_t *, uint_t, uint_t,
2347c478bd9Sstevel@tonic-gate 				uint_t, uint_t, uint_t, uint_t *,
2357c478bd9Sstevel@tonic-gate 				uint_t, uint_t *,
2367c478bd9Sstevel@tonic-gate 				int (*func)(usb_ac_state_t *, uint_t, uint_t,
2377c478bd9Sstevel@tonic-gate 				uint_t, uint_t, uint_t, uint_t *));
2387c478bd9Sstevel@tonic-gate static int	usb_ac_update_port(usb_ac_state_t *, uint_t,
2397c478bd9Sstevel@tonic-gate 				uint_t, uint_t, uint_t, uint_t, uint_t *);
2407c478bd9Sstevel@tonic-gate static int	usb_ac_set_selector(usb_ac_state_t *, uint_t,
2417c478bd9Sstevel@tonic-gate 				uint_t, uint_t, uint_t, uint_t, uint_t *);
2427c478bd9Sstevel@tonic-gate static int	usb_ac_feature_unit_check(usb_ac_state_t *, uint_t,
2437c478bd9Sstevel@tonic-gate 				uint_t, uint_t, uint_t, uint_t, uint_t *);
2447c478bd9Sstevel@tonic-gate static int	usb_ac_set_gain(usb_ac_state_t *, uint_t,
2457c478bd9Sstevel@tonic-gate 				uint_t, uint_t, uint_t, uint_t, uint_t *);
2467c478bd9Sstevel@tonic-gate static int	usb_ac_set_monitor_gain(usb_ac_state_t *, uint_t,
2477c478bd9Sstevel@tonic-gate 				uint_t, uint_t, uint_t, uint_t, uint_t *);
2487c478bd9Sstevel@tonic-gate static int	usb_ac_set_volume(usb_ac_state_t *, uint_t, short, int dir,
2497c478bd9Sstevel@tonic-gate 				int);
2507c478bd9Sstevel@tonic-gate static int	usb_ac_get_maxmin_volume(usb_ac_state_t *, uint_t, int, int,
25188447a05SGarrett D'Amore 				int, short *);
252e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int	usb_ac_send_as_cmd(usb_ac_state_t *, usb_audio_eng_t *,
2537c478bd9Sstevel@tonic-gate 				int, void *);
254e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int	usb_ac_set_format(usb_ac_state_t *, usb_audio_eng_t *);
255e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int	usb_ac_do_setup(usb_ac_state_t *, usb_audio_eng_t *);
256e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
257e272e4c8SBinzi Cao - Sun Microsystems - Beijing China /*  usb audio basic function entries */
258e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int	usb_ac_setup(usb_ac_state_t *, usb_audio_eng_t *);
259e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static void	usb_ac_teardown(usb_ac_state_t *, usb_audio_eng_t *);
260e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int	usb_ac_start_play(usb_ac_state_t *, usb_audio_eng_t *);
261e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int	usb_ac_start_record(usb_ac_state_t *, usb_audio_eng_t *);
262e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static void	usb_ac_stop_record(usb_ac_state_t *, usb_audio_eng_t *);
2637c478bd9Sstevel@tonic-gate static int	usb_ac_restore_audio_state(usb_ac_state_t *, int);
2647c478bd9Sstevel@tonic-gate 
265e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int	usb_ac_ctrl_restore(usb_ac_state_t *);
2667c478bd9Sstevel@tonic-gate /*
26788447a05SGarrett D'Amore  * Mux
2687c478bd9Sstevel@tonic-gate  */
26988447a05SGarrett D'Amore static int	usb_ac_mux_walk_siblings(usb_ac_state_t *);
27088447a05SGarrett D'Amore static void	usb_ac_print_reg_data(usb_ac_state_t *,
27188447a05SGarrett D'Amore 				usb_as_registration_t *);
27288447a05SGarrett D'Amore static int	usb_ac_get_reg_data(usb_ac_state_t *, ldi_handle_t, int);
273e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int	usb_ac_setup_plumbed(usb_ac_state_t *, int, int);
27488447a05SGarrett D'Amore static int	usb_ac_mixer_registration(usb_ac_state_t *);
27588447a05SGarrett D'Amore static void	usb_ac_hold_siblings(usb_ac_state_t *);
27688447a05SGarrett D'Amore static int	usb_ac_online_siblings(usb_ac_state_t *);
27788447a05SGarrett D'Amore static void	usb_ac_rele_siblings(usb_ac_state_t *);
27888447a05SGarrett D'Amore static int	usb_ac_mux_plumbing(usb_ac_state_t *);
27988447a05SGarrett D'Amore static void	usb_ac_mux_plumbing_tq(void *);
28088447a05SGarrett D'Amore static int	usb_ac_mux_unplumbing(usb_ac_state_t *);
28188447a05SGarrett D'Amore static void	usb_ac_mux_unplumbing_tq(void *);
28288447a05SGarrett D'Amore static int	usb_ac_plumb(usb_ac_plumbed_t *);
28388447a05SGarrett D'Amore static void	usb_ac_unplumb(usb_ac_plumbed_t *);
28488447a05SGarrett D'Amore static void	usb_ac_reader(void *);
28588447a05SGarrett D'Amore static int	usb_ac_read_msg(usb_ac_plumbed_t *, mblk_t *);
28688447a05SGarrett D'Amore static int	usb_ac_do_plumbing(usb_ac_state_t *);
28788447a05SGarrett D'Amore static int	usb_ac_do_unplumbing(usb_ac_state_t *);
28888447a05SGarrett D'Amore 
2897c478bd9Sstevel@tonic-gate 
290e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int usb_change_phy_vol(usb_ac_state_t *, int);
291e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static void usb_restore_engine(usb_ac_state_t *);
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate /* anchor for soft state structures */
29488447a05SGarrett D'Amore void	*usb_ac_statep;
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate /*
2977c478bd9Sstevel@tonic-gate  * DDI Structures
2987c478bd9Sstevel@tonic-gate  */
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate /* Device operations structure */
3017c478bd9Sstevel@tonic-gate static struct dev_ops usb_ac_dev_ops = {
3027c478bd9Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev */
3037c478bd9Sstevel@tonic-gate 	0,			/* devo_refcnt */
30488447a05SGarrett D'Amore 	NULL,			/* devo_getinfo */
3057c478bd9Sstevel@tonic-gate 	nulldev,		/* devo_identify - obsolete */
3067c478bd9Sstevel@tonic-gate 	nulldev,		/* devo_probe - not needed */
3077c478bd9Sstevel@tonic-gate 	usb_ac_attach,		/* devo_attach */
3087c478bd9Sstevel@tonic-gate 	usb_ac_detach,		/* devo_detach */
3097c478bd9Sstevel@tonic-gate 	nodev,			/* devo_reset */
31088447a05SGarrett D'Amore 	NULL,			/* devi_cb_ops */
3117c478bd9Sstevel@tonic-gate 	NULL,			/* devo_busb_ac_ops */
31219397407SSherry Moore 	usb_ac_power,		/* devo_power */
313be529ebcSRaymond Chen 	ddi_quiesce_not_needed,	/* devo_quiesce */
3147c478bd9Sstevel@tonic-gate };
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate /* Linkage structure for loadable drivers */
3177c478bd9Sstevel@tonic-gate static struct modldrv usb_ac_modldrv = {
3187c478bd9Sstevel@tonic-gate 	&mod_driverops,				/* drv_modops */
31977e51571Sgongtian zhao - Sun Microsystems - Beijing China 	"USB Audio Control Driver",		/* drv_linkinfo */
3207c478bd9Sstevel@tonic-gate 	&usb_ac_dev_ops				/* drv_dev_ops */
3217c478bd9Sstevel@tonic-gate };
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate /* Module linkage structure */
3247c478bd9Sstevel@tonic-gate static struct modlinkage usb_ac_modlinkage = {
3257c478bd9Sstevel@tonic-gate 	MODREV_1,			/* ml_rev */
3267c478bd9Sstevel@tonic-gate 	(void *)&usb_ac_modldrv,	/* ml_linkage */
3277c478bd9Sstevel@tonic-gate 	NULL				/* NULL terminates the list */
3287c478bd9Sstevel@tonic-gate };
3297c478bd9Sstevel@tonic-gate 
330e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int usb_audio_register(usb_ac_state_t *);
331e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int usb_audio_unregister(usb_ac_state_t *);
332e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
33368c47f65SGarrett D'Amore static int usb_engine_open(void *, int, unsigned *, caddr_t *);
334e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static void usb_engine_close(void *);
335e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static uint64_t usb_engine_count(void *);
336e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int usb_engine_start(void *);
337e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static void usb_engine_stop(void *);
338e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int usb_engine_format(void *);
339e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int usb_engine_channels(void *);
340e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int usb_engine_rate(void *);
341e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static void usb_engine_sync(void *, unsigned);
342f9ead4a5SGarrett D'Amore static unsigned usb_engine_qlen(void *);
343e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
344e272e4c8SBinzi Cao - Sun Microsystems - Beijing China /* engine buffer size in terms of fragments */
345e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
346e272e4c8SBinzi Cao - Sun Microsystems - Beijing China audio_engine_ops_t usb_engine_ops = {
347e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	AUDIO_ENGINE_VERSION,
348e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_engine_open,
349e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_engine_close,
350e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_engine_start,
351e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_engine_stop,
352e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_engine_count,
353e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_engine_format,
354e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_engine_channels,
355e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_engine_rate,
356e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_engine_sync,
357e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_engine_qlen,
358e272e4c8SBinzi Cao - Sun Microsystems - Beijing China };
359e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
360e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
361e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
362e272e4c8SBinzi Cao - Sun Microsystems - Beijing China _NOTE(SCHEME_PROTECTS_DATA("unique per call", mblk_t))
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate /* standard entry points */
3657c478bd9Sstevel@tonic-gate int
_init(void)3667c478bd9Sstevel@tonic-gate _init(void)
3677c478bd9Sstevel@tonic-gate {
3687c478bd9Sstevel@tonic-gate 	int rval;
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	/* initialize the soft state */
3717c478bd9Sstevel@tonic-gate 	if ((rval = ddi_soft_state_init(&usb_ac_statep,
3727c478bd9Sstevel@tonic-gate 	    sizeof (usb_ac_state_t), 1)) != DDI_SUCCESS) {
3737c478bd9Sstevel@tonic-gate 		return (rval);
3747c478bd9Sstevel@tonic-gate 	}
3757c478bd9Sstevel@tonic-gate 
37688447a05SGarrett D'Amore 	audio_init_ops(&usb_ac_dev_ops, "usb_ac");
37788447a05SGarrett D'Amore 
3787c478bd9Sstevel@tonic-gate 	if ((rval = mod_install(&usb_ac_modlinkage)) != 0) {
3797c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&usb_ac_statep);
38088447a05SGarrett D'Amore 		audio_fini_ops(&usb_ac_dev_ops);
3817c478bd9Sstevel@tonic-gate 	}
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	return (rval);
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate int
_fini(void)3877c478bd9Sstevel@tonic-gate _fini(void)
3887c478bd9Sstevel@tonic-gate {
3897c478bd9Sstevel@tonic-gate 	int rval;
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	if ((rval = mod_remove(&usb_ac_modlinkage)) == 0) {
3927c478bd9Sstevel@tonic-gate 		/* Free the soft state internal structures */
3937c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&usb_ac_statep);
39488447a05SGarrett D'Amore 		audio_fini_ops(&usb_ac_dev_ops);
3957c478bd9Sstevel@tonic-gate 	}
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	return (rval);
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)4017c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
4027c478bd9Sstevel@tonic-gate {
4037c478bd9Sstevel@tonic-gate 	return (mod_info(&usb_ac_modlinkage, modinfop));
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate extern	uint_t		nproc;
4077c478bd9Sstevel@tonic-gate #define	INIT_PROCESS_CNT 3
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate static int
usb_ac_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)4107c478bd9Sstevel@tonic-gate usb_ac_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
4117c478bd9Sstevel@tonic-gate {
4127c478bd9Sstevel@tonic-gate 	usb_ac_state_t		*uacp = NULL;
4137c478bd9Sstevel@tonic-gate 	int			instance = ddi_get_instance(dip);
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	switch (cmd) {
4167c478bd9Sstevel@tonic-gate 		case DDI_ATTACH:
4177c478bd9Sstevel@tonic-gate 			break;
4187c478bd9Sstevel@tonic-gate 		case DDI_RESUME:
4197c478bd9Sstevel@tonic-gate 			usb_ac_cpr_resume(dip);
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
4227c478bd9Sstevel@tonic-gate 		default:
4237c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
4247c478bd9Sstevel@tonic-gate 	}
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	/*
4277c478bd9Sstevel@tonic-gate 	 * wait  until all processes are started from main.
4287c478bd9Sstevel@tonic-gate 	 * USB enumerates early in boot (ie. consconfig time).
4297c478bd9Sstevel@tonic-gate 	 * If the plumbing takes place early, the file descriptors
4307c478bd9Sstevel@tonic-gate 	 * are owned by the init process and can never be closed anymore
4317c478bd9Sstevel@tonic-gate 	 * Consequently, hot removal is not possible and the dips
4327c478bd9Sstevel@tonic-gate 	 * never go away. By waiting some time, e.g. INIT_PROCESS_CNT,
4337c478bd9Sstevel@tonic-gate 	 * the problem is avoided.
4347c478bd9Sstevel@tonic-gate 	 */
4357c478bd9Sstevel@tonic-gate 	if (nproc < INIT_PROCESS_CNT) {
4367c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, NULL,
4377c478bd9Sstevel@tonic-gate 		    "usb_ac%d attach too early", instance);
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4407c478bd9Sstevel@tonic-gate 	}
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	/*
4437c478bd9Sstevel@tonic-gate 	 * Allocate soft state information.
4447c478bd9Sstevel@tonic-gate 	 */
4457c478bd9Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(usb_ac_statep, instance) != DDI_SUCCESS) {
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 		goto fail;
4487c478bd9Sstevel@tonic-gate 	}
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	/*
4517c478bd9Sstevel@tonic-gate 	 * get soft state space and initialize
4527c478bd9Sstevel@tonic-gate 	 */
4537c478bd9Sstevel@tonic-gate 	uacp = (usb_ac_state_t *)ddi_get_soft_state(usb_ac_statep, instance);
4547c478bd9Sstevel@tonic-gate 	if (uacp == NULL) {
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 		goto fail;
4577c478bd9Sstevel@tonic-gate 	}
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	/* get log handle */
4607c478bd9Sstevel@tonic-gate 	uacp->usb_ac_log_handle = usb_alloc_log_hdl(dip, "ac",
461112116d8Sfb 	    &usb_ac_errlevel,
462112116d8Sfb 	    &usb_ac_errmask, &usb_ac_instance_debug,
463112116d8Sfb 	    0);
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	uacp->usb_ac_instance = instance;
4667c478bd9Sstevel@tonic-gate 	uacp->usb_ac_dip = dip;
4677c478bd9Sstevel@tonic-gate 
46888447a05SGarrett D'Amore 	(void) snprintf(uacp->dstr, sizeof (uacp->dstr), "%s#%d",
46988447a05SGarrett D'Amore 	    ddi_driver_name(dip), instance);
47088447a05SGarrett D'Amore 
4717c478bd9Sstevel@tonic-gate 	if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
4727c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
4737c478bd9Sstevel@tonic-gate 		    "usb_client_attach failed");
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 		usb_free_log_hdl(uacp->usb_ac_log_handle);
4767c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(usb_ac_statep, uacp->usb_ac_instance);
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4797c478bd9Sstevel@tonic-gate 	}
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	if (usb_get_dev_data(dip, &uacp->usb_ac_dev_data,
4827c478bd9Sstevel@tonic-gate 	    USB_PARSE_LVL_IF, 0) != USB_SUCCESS) {
4837c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
4847c478bd9Sstevel@tonic-gate 		    "usb_get_dev_data failed");
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 		usb_client_detach(dip, NULL);
4877c478bd9Sstevel@tonic-gate 		usb_free_log_hdl(uacp->usb_ac_log_handle);
4887c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(usb_ac_statep, uacp->usb_ac_instance);
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4917c478bd9Sstevel@tonic-gate 	}
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	/* initialize mutex & cv */
4947c478bd9Sstevel@tonic-gate 	mutex_init(&uacp->usb_ac_mutex, NULL, MUTEX_DRIVER,
495112116d8Sfb 	    uacp->usb_ac_dev_data->dev_iblock_cookie);
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	uacp->usb_ac_default_ph = uacp->usb_ac_dev_data->dev_default_ph;
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	/* parse all class specific descriptors */
5007c478bd9Sstevel@tonic-gate 	if (usb_ac_handle_descriptors(uacp) != USB_SUCCESS) {
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 		goto fail;
5037c478bd9Sstevel@tonic-gate 	}
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	/* we no longer need the descr tree */
5067c478bd9Sstevel@tonic-gate 	usb_free_descr_tree(dip, uacp->usb_ac_dev_data);
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	uacp->usb_ac_ser_acc = usb_init_serialization(dip,
509112116d8Sfb 	    USB_INIT_SER_CHECK_SAME_THREAD);
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	/* we are online */
5147c478bd9Sstevel@tonic-gate 	uacp->usb_ac_dev_state = USB_DEV_ONLINE;
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	/*
5177c478bd9Sstevel@tonic-gate 	 * safe guard the postattach to be executed
5187c478bd9Sstevel@tonic-gate 	 * only two states arepossible: plumbed / unplumbed
5197c478bd9Sstevel@tonic-gate 	 */
5207c478bd9Sstevel@tonic-gate 	uacp->usb_ac_plumbing_state = USB_AC_STATE_UNPLUMBED;
5217c478bd9Sstevel@tonic-gate 	uacp->usb_ac_current_plumbed_index = -1;
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	/* create components to power manage this device */
5267c478bd9Sstevel@tonic-gate 	usb_ac_create_pm_components(dip, uacp);
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	/* Register for events */
5297c478bd9Sstevel@tonic-gate 	if (usb_register_event_cbs(dip, &usb_ac_events, 0) != USB_SUCCESS) {
530d291d9f2Sfrits 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
5317c478bd9Sstevel@tonic-gate 		    "usb_ac_attach: couldn't register for events");
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 		goto fail;
5347c478bd9Sstevel@tonic-gate 	}
5357c478bd9Sstevel@tonic-gate 
53688447a05SGarrett D'Amore 	USB_DPRINTF_L4(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
53788447a05SGarrett D'Amore 	    "usb_ac_attach: End");
53888447a05SGarrett D'Amore 
5397c478bd9Sstevel@tonic-gate 	/* report device */
5407c478bd9Sstevel@tonic-gate 	ddi_report_dev(dip);
5417c478bd9Sstevel@tonic-gate 
54288447a05SGarrett D'Amore 	if (usb_ac_do_plumbing(uacp) != USB_SUCCESS)
54388447a05SGarrett D'Amore 		goto fail;
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
54688447a05SGarrett D'Amore 
5477c478bd9Sstevel@tonic-gate fail:
5487c478bd9Sstevel@tonic-gate 	if (uacp) {
549d291d9f2Sfrits 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
5507c478bd9Sstevel@tonic-gate 		    "attach failed");
55188447a05SGarrett D'Amore 
55288447a05SGarrett D'Amore 		/* wait for plumbing thread to finish */
55388447a05SGarrett D'Amore 		if (uacp->tqp != NULL) {
55488447a05SGarrett D'Amore 			ddi_taskq_wait(uacp->tqp);
55588447a05SGarrett D'Amore 			ddi_taskq_destroy(uacp->tqp);
55688447a05SGarrett D'Amore 			uacp->tqp = NULL;
55788447a05SGarrett D'Amore 		}
5587c478bd9Sstevel@tonic-gate 		(void) usb_ac_cleanup(dip, uacp);
5597c478bd9Sstevel@tonic-gate 	}
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
5627c478bd9Sstevel@tonic-gate }
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate static int
usb_ac_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)5667c478bd9Sstevel@tonic-gate usb_ac_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
5677c478bd9Sstevel@tonic-gate {
5687c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
5697c478bd9Sstevel@tonic-gate 	usb_ac_state_t	*uacp;
57088447a05SGarrett D'Amore 	int rval = USB_FAILURE;
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	uacp = ddi_get_soft_state(usb_ac_statep, instance);
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	switch (cmd) {
5757c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
5761cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L4(PRINT_MASK_ATTA,
5771cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    uacp->usb_ac_log_handle, "usb_ac_detach: detach");
57888447a05SGarrett D'Amore 
57988447a05SGarrett D'Amore 		/* wait for plumbing thread to finish */
58088447a05SGarrett D'Amore 		if (uacp->tqp != NULL)
58188447a05SGarrett D'Amore 			ddi_taskq_wait(uacp->tqp);
58288447a05SGarrett D'Amore 
58388447a05SGarrett D'Amore 		mutex_enter(&uacp->usb_ac_mutex);
58488447a05SGarrett D'Amore 
58588447a05SGarrett D'Amore 		/* do not allow detach if still busy */
58688447a05SGarrett D'Amore 		if (uacp->usb_ac_busy_count) {
5871cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 			USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
5881cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 			    "usb_ac_detach:still busy, usb_ac_busy_count = %d",
58988447a05SGarrett D'Amore 			    uacp->usb_ac_busy_count);
59088447a05SGarrett D'Amore 
59188447a05SGarrett D'Amore 			mutex_exit(&uacp->usb_ac_mutex);
59288447a05SGarrett D'Amore 			return (USB_FAILURE);
59388447a05SGarrett D'Amore 		}
594e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		mutex_exit(&uacp->usb_ac_mutex);
59588447a05SGarrett D'Amore 
596e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		(void) usb_audio_unregister(uacp);
59788447a05SGarrett D'Amore 
59888447a05SGarrett D'Amore 
59988447a05SGarrett D'Amore 
60088447a05SGarrett D'Amore 		/*
60188447a05SGarrett D'Amore 		 * unplumb to stop activity from other modules, then
60288447a05SGarrett D'Amore 		 * cleanup, which will also teardown audio framework state
60388447a05SGarrett D'Amore 		 */
60488447a05SGarrett D'Amore 		if (usb_ac_do_unplumbing(uacp) == USB_SUCCESS)
60588447a05SGarrett D'Amore 			rval = usb_ac_cleanup(dip, uacp);
60688447a05SGarrett D'Amore 
60788447a05SGarrett D'Amore 		if (rval != USB_SUCCESS) {
60888447a05SGarrett D'Amore 			USB_DPRINTF_L2(PRINT_MASK_ATTA,
60988447a05SGarrett D'Amore 			    uacp->usb_ac_log_handle, "detach failed: %s%d",
61088447a05SGarrett D'Amore 			    ddi_driver_name(dip), instance);
61188447a05SGarrett D'Amore 		}
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 		return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
6147c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
6151cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L4(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
6161cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_detach: suspending");
61788447a05SGarrett D'Amore 
6187c478bd9Sstevel@tonic-gate 		rval = usb_ac_cpr_suspend(dip);
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 		return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
6217c478bd9Sstevel@tonic-gate 	default:
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6247c478bd9Sstevel@tonic-gate 	}
6257c478bd9Sstevel@tonic-gate }
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate /*
6297c478bd9Sstevel@tonic-gate  * usb_ac_cleanup:
6307c478bd9Sstevel@tonic-gate  *	cleanup on attach failure and detach
6317c478bd9Sstevel@tonic-gate  */
6327c478bd9Sstevel@tonic-gate static int
usb_ac_cleanup(dev_info_t * dip,usb_ac_state_t * uacp)6337c478bd9Sstevel@tonic-gate usb_ac_cleanup(dev_info_t *dip, usb_ac_state_t *uacp)
6347c478bd9Sstevel@tonic-gate {
6357c478bd9Sstevel@tonic-gate 	usb_ac_power_t	*uacpm;
6367c478bd9Sstevel@tonic-gate 	int	rval = USB_FAILURE;
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
6407c478bd9Sstevel@tonic-gate 	uacpm = uacp->usb_ac_pm;
6417c478bd9Sstevel@tonic-gate 
6421cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
6431cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_cleanup:begain");
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	ASSERT(uacp->usb_ac_busy_count == 0);
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	ASSERT(uacp->usb_ac_plumbing_state == USB_AC_STATE_UNPLUMBED);
6487c478bd9Sstevel@tonic-gate 
649e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&uacp->usb_ac_mutex);
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	/*
6527c478bd9Sstevel@tonic-gate 	 * Disable the event callbacks, after this point, event
6537c478bd9Sstevel@tonic-gate 	 * callbacks will never get called. Note we shouldn't hold
6547c478bd9Sstevel@tonic-gate 	 * the mutex while unregistering events because there may be a
6557c478bd9Sstevel@tonic-gate 	 * competing event callback thread. Event callbacks are done
6567c478bd9Sstevel@tonic-gate 	 * with ndi mutex held and this can cause a potential deadlock.
6577c478bd9Sstevel@tonic-gate 	 */
6587c478bd9Sstevel@tonic-gate 	usb_unregister_event_cbs(dip, &usb_ac_events);
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	if (uacpm && (uacp->usb_ac_dev_state != USB_DEV_DISCONNECTED)) {
6637c478bd9Sstevel@tonic-gate 		if (uacpm->acpm_wakeup_enabled) {
6647c478bd9Sstevel@tonic-gate 			mutex_exit(&uacp->usb_ac_mutex);
6657c478bd9Sstevel@tonic-gate 			usb_ac_pm_busy_component(uacp);
6667c478bd9Sstevel@tonic-gate 			(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 			rval = usb_handle_remote_wakeup(dip,
669112116d8Sfb 			    USB_REMOTE_WAKEUP_DISABLE);
6707c478bd9Sstevel@tonic-gate 			if (rval != USB_SUCCESS) {
6717c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L2(PRINT_MASK_PM,
6727c478bd9Sstevel@tonic-gate 				    uacp->usb_ac_log_handle,
6737c478bd9Sstevel@tonic-gate 				    "usb_ac_cleanup: disable remote "
6747c478bd9Sstevel@tonic-gate 				    "wakeup failed, rval=%d", rval);
6757c478bd9Sstevel@tonic-gate 			}
6767c478bd9Sstevel@tonic-gate 			usb_ac_pm_idle_component(uacp);
6777c478bd9Sstevel@tonic-gate 		} else {
6787c478bd9Sstevel@tonic-gate 			mutex_exit(&uacp->usb_ac_mutex);
6797c478bd9Sstevel@tonic-gate 		}
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 		(void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 		mutex_enter(&uacp->usb_ac_mutex);
6847c478bd9Sstevel@tonic-gate 	}
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 	if (uacpm) {
6877c478bd9Sstevel@tonic-gate 		kmem_free(uacpm,  sizeof (usb_ac_power_t));
6887c478bd9Sstevel@tonic-gate 		uacp->usb_ac_pm = NULL;
6897c478bd9Sstevel@tonic-gate 	}
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	usb_client_detach(dip, uacp->usb_ac_dev_data);
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	/* free descriptors */
6947c478bd9Sstevel@tonic-gate 	usb_ac_free_all_units(uacp);
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	mutex_destroy(&uacp->usb_ac_mutex);
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	usb_fini_serialization(uacp->usb_ac_ser_acc);
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
7037c478bd9Sstevel@tonic-gate 	    "usb_ac_cleanup: Ending");
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	usb_free_log_hdl(uacp->usb_ac_log_handle);
7067c478bd9Sstevel@tonic-gate 	kmem_free(uacp->usb_ac_connections, uacp->usb_ac_connections_len);
7077c478bd9Sstevel@tonic-gate 	kmem_free(uacp->usb_ac_connections_a, uacp->usb_ac_connections_a_len);
7087c478bd9Sstevel@tonic-gate 	kmem_free(uacp->usb_ac_unit_type, uacp->usb_ac_max_unit);
7097c478bd9Sstevel@tonic-gate 	kmem_free(uacp->usb_ac_traverse_path, uacp->usb_ac_max_unit);
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 	ddi_soft_state_free(usb_ac_statep, uacp->usb_ac_instance);
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	ddi_prop_remove_all(dip);
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
7167c478bd9Sstevel@tonic-gate }
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 
71988447a05SGarrett D'Amore int
usb_ac_open(dev_info_t * dip)72088447a05SGarrett D'Amore usb_ac_open(dev_info_t *dip)
7217c478bd9Sstevel@tonic-gate {
72288447a05SGarrett D'Amore 	int inst = ddi_get_instance(dip);
72388447a05SGarrett D'Amore 	usb_ac_state_t *uacp = ddi_get_soft_state(usb_ac_statep, inst);
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
7267c478bd9Sstevel@tonic-gate 
72788447a05SGarrett D'Amore 	uacp->usb_ac_busy_count++;
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
7307c478bd9Sstevel@tonic-gate 
73188447a05SGarrett D'Amore 	usb_ac_pm_busy_component(uacp);
73288447a05SGarrett D'Amore 	(void) pm_raise_power(uacp->usb_ac_dip, 0, USB_DEV_OS_FULL_PWR);
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 	return (0);
7357c478bd9Sstevel@tonic-gate }
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 
73888447a05SGarrett D'Amore void
usb_ac_close(dev_info_t * dip)73988447a05SGarrett D'Amore usb_ac_close(dev_info_t *dip)
7407c478bd9Sstevel@tonic-gate {
74188447a05SGarrett D'Amore 	int inst = ddi_get_instance(dip);
74288447a05SGarrett D'Amore 	usb_ac_state_t *uacp = ddi_get_soft_state(usb_ac_statep, inst);
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
7457c478bd9Sstevel@tonic-gate 
74688447a05SGarrett D'Amore 	if (uacp->usb_ac_busy_count > 0)
74788447a05SGarrett D'Amore 		uacp->usb_ac_busy_count--;
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
7507c478bd9Sstevel@tonic-gate 
75188447a05SGarrett D'Amore 	usb_ac_pm_idle_component(uacp);
7527c478bd9Sstevel@tonic-gate }
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate /*
75688447a05SGarrett D'Amore  * usb_ac_read_msg:
75788447a05SGarrett D'Amore  *	Handle asynchronous response from opened streams
7587c478bd9Sstevel@tonic-gate  */
7597c478bd9Sstevel@tonic-gate static int
usb_ac_read_msg(usb_ac_plumbed_t * plumb_infop,mblk_t * mp)76088447a05SGarrett D'Amore usb_ac_read_msg(usb_ac_plumbed_t *plumb_infop, mblk_t *mp)
7617c478bd9Sstevel@tonic-gate {
76288447a05SGarrett D'Amore 	usb_ac_state_t	*uacp = plumb_infop->acp_uacp;
7637c478bd9Sstevel@tonic-gate 	int error = DDI_SUCCESS;
7647c478bd9Sstevel@tonic-gate 	int	val;
7657c478bd9Sstevel@tonic-gate 	char	val1;
7667c478bd9Sstevel@tonic-gate 	struct iocblk *iocp;
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 
76988447a05SGarrett D'Amore 	ASSERT(mutex_owned(&uacp->usb_ac_mutex));
7707c478bd9Sstevel@tonic-gate 
77188447a05SGarrett D'Amore 	/*
77288447a05SGarrett D'Amore 	 * typically an M_CTL is used between modules but in order to pass
77388447a05SGarrett D'Amore 	 * through the streamhead, an M_PROTO type must be used instead
77488447a05SGarrett D'Amore 	 */
7757c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
77688447a05SGarrett D'Amore 	case M_PROTO:
7777c478bd9Sstevel@tonic-gate 	case M_ERROR:
7787c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
7797c478bd9Sstevel@tonic-gate 		    "M_CTL/M_ERROR");
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 		switch (plumb_infop->acp_driver) {
7827c478bd9Sstevel@tonic-gate 		case USB_AH_PLUMBED:
7837c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
78488447a05SGarrett D'Amore 			    "message from hid, instance=%d",
78588447a05SGarrett D'Amore 			    ddi_get_instance(plumb_infop->acp_dip));
7867c478bd9Sstevel@tonic-gate 
78788447a05SGarrett D'Amore 			iocp = (struct iocblk *)(void *)mp->b_rptr;
7887c478bd9Sstevel@tonic-gate 			ASSERT(mp->b_cont != NULL);
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 			if (uacp->usb_ac_registered_with_mixer) {
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 				val1 = *((char *)mp->b_cont->b_rptr);
7937c478bd9Sstevel@tonic-gate 				val = (int)val1;
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L4(PRINT_MASK_ALL,
7967c478bd9Sstevel@tonic-gate 				    uacp->usb_ac_log_handle, "val1=0x%x(%d),"
7977c478bd9Sstevel@tonic-gate 				    "val=0x%x(%d)", val1, val1, val, val);
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 				switch (iocp->ioc_cmd) {
8007c478bd9Sstevel@tonic-gate 				/* Handle relative volume change */
8017c478bd9Sstevel@tonic-gate 				case USB_AUDIO_VOL_CHANGE:
8027c478bd9Sstevel@tonic-gate 					/* prevent unplumbing */
8037c478bd9Sstevel@tonic-gate 					uacp->usb_ac_busy_count++;
8047c478bd9Sstevel@tonic-gate 					if (uacp->usb_ac_plumbing_state ==
8057c478bd9Sstevel@tonic-gate 					    USB_AC_STATE_PLUMBED) {
8067c478bd9Sstevel@tonic-gate 						mutex_exit(&uacp->usb_ac_mutex);
807e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 						(void) usb_change_phy_vol(
808e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 						    uacp, val);
8097c478bd9Sstevel@tonic-gate 						mutex_enter(&uacp->
810112116d8Sfb 						    usb_ac_mutex);
8117c478bd9Sstevel@tonic-gate 					}
8127c478bd9Sstevel@tonic-gate 					uacp->usb_ac_busy_count--;
8137c478bd9Sstevel@tonic-gate 					/* FALLTHRU */
8147c478bd9Sstevel@tonic-gate 				case USB_AUDIO_MUTE:
8157c478bd9Sstevel@tonic-gate 				default:
8167c478bd9Sstevel@tonic-gate 					freemsg(mp);
8177c478bd9Sstevel@tonic-gate 					break;
8187c478bd9Sstevel@tonic-gate 				}
8197c478bd9Sstevel@tonic-gate 			} else {
8207c478bd9Sstevel@tonic-gate 				freemsg(mp);
8217c478bd9Sstevel@tonic-gate 			}
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 			break;
8247c478bd9Sstevel@tonic-gate 		default:
8257c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
82688447a05SGarrett D'Amore 			    "message from unknown module(%s)",
8277c478bd9Sstevel@tonic-gate 			    ddi_driver_name(plumb_infop->acp_dip));
8287c478bd9Sstevel@tonic-gate 			freemsg(mp);
8297c478bd9Sstevel@tonic-gate 		}
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 		break;
8327c478bd9Sstevel@tonic-gate 	default:
8337c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
8347c478bd9Sstevel@tonic-gate 		    "Unknown type=%d", mp->b_datap->db_type);
83588447a05SGarrett D'Amore 		freemsg(mp);
8367c478bd9Sstevel@tonic-gate 	}
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 	return (error);
8407c478bd9Sstevel@tonic-gate }
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate /*
8447c478bd9Sstevel@tonic-gate  * Power Management
8457c478bd9Sstevel@tonic-gate  * usb_ac_power:
8467c478bd9Sstevel@tonic-gate  *	power entry point
8477c478bd9Sstevel@tonic-gate  */
8487c478bd9Sstevel@tonic-gate static int
usb_ac_power(dev_info_t * dip,int comp,int level)8497c478bd9Sstevel@tonic-gate usb_ac_power(dev_info_t *dip, int comp, int level)
8507c478bd9Sstevel@tonic-gate {
851e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	_NOTE(ARGUNUSED(comp));
8527c478bd9Sstevel@tonic-gate 	int		instance = ddi_get_instance(dip);
8537c478bd9Sstevel@tonic-gate 	usb_ac_state_t	*uacp;
8547c478bd9Sstevel@tonic-gate 	usb_ac_power_t	*uacpm;
8557c478bd9Sstevel@tonic-gate 	int		rval = DDI_FAILURE;
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 	uacp = ddi_get_soft_state(usb_ac_statep, instance);
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
8607c478bd9Sstevel@tonic-gate 	uacpm = uacp->usb_ac_pm;
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 	if (USB_DEV_PWRSTATE_OK(uacpm->acpm_pwr_states, level)) {
8637c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_PM, uacp->usb_ac_log_handle,
8647c478bd9Sstevel@tonic-gate 		    "usb_ac_power: illegal level=%d pwr_states=%d",
8657c478bd9Sstevel@tonic-gate 		    level, uacpm->acpm_pwr_states);
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 		goto done;
8687c478bd9Sstevel@tonic-gate 	}
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	switch (level) {
8717c478bd9Sstevel@tonic-gate 	case USB_DEV_OS_PWR_OFF:
8727c478bd9Sstevel@tonic-gate 		rval = usb_ac_pwrlvl0(uacp);
8737c478bd9Sstevel@tonic-gate 		break;
8747c478bd9Sstevel@tonic-gate 	case USB_DEV_OS_PWR_1:
8757c478bd9Sstevel@tonic-gate 		rval = usb_ac_pwrlvl1(uacp);
8767c478bd9Sstevel@tonic-gate 		break;
8777c478bd9Sstevel@tonic-gate 	case USB_DEV_OS_PWR_2:
8787c478bd9Sstevel@tonic-gate 		rval = usb_ac_pwrlvl2(uacp);
8797c478bd9Sstevel@tonic-gate 		break;
8807c478bd9Sstevel@tonic-gate 	case USB_DEV_OS_FULL_PWR:
8817c478bd9Sstevel@tonic-gate 		rval = usb_ac_pwrlvl3(uacp);
8827c478bd9Sstevel@tonic-gate 		break;
8837c478bd9Sstevel@tonic-gate 	}
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate done:
8867c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 	return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
8897c478bd9Sstevel@tonic-gate }
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate /*
8937c478bd9Sstevel@tonic-gate  * functions to handle power transition for various levels
8947c478bd9Sstevel@tonic-gate  * These functions act as place holders to issue USB commands
8957c478bd9Sstevel@tonic-gate  * to the devices to change their power levels
8967c478bd9Sstevel@tonic-gate  * Level 0 = Device is powered off
8977c478bd9Sstevel@tonic-gate  * Level 3 = Device if full powered
8987c478bd9Sstevel@tonic-gate  * Level 1,2 = Intermediate power level of the device as implemented
8997c478bd9Sstevel@tonic-gate  *	by the hardware.
9007c478bd9Sstevel@tonic-gate  * Note that Level 0 is OS power-off and Level 3 is OS full-power.
9017c478bd9Sstevel@tonic-gate  */
9027c478bd9Sstevel@tonic-gate static int
usb_ac_pwrlvl0(usb_ac_state_t * uacp)9037c478bd9Sstevel@tonic-gate usb_ac_pwrlvl0(usb_ac_state_t *uacp)
9047c478bd9Sstevel@tonic-gate {
9057c478bd9Sstevel@tonic-gate 	usb_ac_power_t	*uacpm;
9067c478bd9Sstevel@tonic-gate 	int		rval;
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 	uacpm = uacp->usb_ac_pm;
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	switch (uacp->usb_ac_dev_state) {
9117c478bd9Sstevel@tonic-gate 	case USB_DEV_ONLINE:
9127c478bd9Sstevel@tonic-gate 		/* Deny the powerdown request if the device is busy */
9137c478bd9Sstevel@tonic-gate 		if (uacpm->acpm_pm_busy != 0) {
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
9167c478bd9Sstevel@tonic-gate 		}
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 		/* Issue USB D3 command to the device here */
9197c478bd9Sstevel@tonic-gate 		rval = usb_set_device_pwrlvl3(uacp->usb_ac_dip);
9207c478bd9Sstevel@tonic-gate 		ASSERT(rval == USB_SUCCESS);
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate 		uacp->usb_ac_dev_state = USB_DEV_PWRED_DOWN;
9237c478bd9Sstevel@tonic-gate 		uacpm->acpm_current_power = USB_DEV_OS_PWR_OFF;
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
9267c478bd9Sstevel@tonic-gate 	case USB_DEV_DISCONNECTED:
9277c478bd9Sstevel@tonic-gate 	case USB_DEV_SUSPENDED:
9287c478bd9Sstevel@tonic-gate 	case USB_DEV_PWRED_DOWN:
9297c478bd9Sstevel@tonic-gate 	default:
9307c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
9317c478bd9Sstevel@tonic-gate 	}
9327c478bd9Sstevel@tonic-gate }
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate /* ARGSUSED */
9367c478bd9Sstevel@tonic-gate static int
usb_ac_pwrlvl1(usb_ac_state_t * uacp)9377c478bd9Sstevel@tonic-gate usb_ac_pwrlvl1(usb_ac_state_t *uacp)
9387c478bd9Sstevel@tonic-gate {
9397c478bd9Sstevel@tonic-gate 	int		rval;
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 	/* Issue USB D2 command to the device here */
9427c478bd9Sstevel@tonic-gate 	rval = usb_set_device_pwrlvl2(uacp->usb_ac_dip);
9437c478bd9Sstevel@tonic-gate 	ASSERT(rval == USB_SUCCESS);
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
9467c478bd9Sstevel@tonic-gate }
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate /* ARGSUSED */
9507c478bd9Sstevel@tonic-gate static int
usb_ac_pwrlvl2(usb_ac_state_t * uacp)9517c478bd9Sstevel@tonic-gate usb_ac_pwrlvl2(usb_ac_state_t *uacp)
9527c478bd9Sstevel@tonic-gate {
9537c478bd9Sstevel@tonic-gate 	int		rval;
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	rval = usb_set_device_pwrlvl1(uacp->usb_ac_dip);
9567c478bd9Sstevel@tonic-gate 	ASSERT(rval == USB_SUCCESS);
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
9597c478bd9Sstevel@tonic-gate }
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate static int
usb_ac_pwrlvl3(usb_ac_state_t * uacp)9637c478bd9Sstevel@tonic-gate usb_ac_pwrlvl3(usb_ac_state_t *uacp)
9647c478bd9Sstevel@tonic-gate {
9657c478bd9Sstevel@tonic-gate 	usb_ac_power_t	*uacpm;
9667c478bd9Sstevel@tonic-gate 	int		rval;
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 	uacpm = uacp->usb_ac_pm;
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 	switch (uacp->usb_ac_dev_state) {
9717c478bd9Sstevel@tonic-gate 	case USB_DEV_PWRED_DOWN:
9727c478bd9Sstevel@tonic-gate 		/* Issue USB D0 command to the device here */
9737c478bd9Sstevel@tonic-gate 		rval = usb_set_device_pwrlvl0(uacp->usb_ac_dip);
9747c478bd9Sstevel@tonic-gate 		ASSERT(rval == USB_SUCCESS);
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 		uacp->usb_ac_dev_state = USB_DEV_ONLINE;
9777c478bd9Sstevel@tonic-gate 		uacpm->acpm_current_power = USB_DEV_OS_FULL_PWR;
9787c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
9797c478bd9Sstevel@tonic-gate 	case USB_DEV_ONLINE:
9807c478bd9Sstevel@tonic-gate 		/* we are already in full power */
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
9837c478bd9Sstevel@tonic-gate 	case USB_DEV_DISCONNECTED:
9847c478bd9Sstevel@tonic-gate 	case USB_DEV_SUSPENDED:
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
9877c478bd9Sstevel@tonic-gate 	default:
9887c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_PM, uacp->usb_ac_log_handle,
9897c478bd9Sstevel@tonic-gate 		    "usb_ac_pwerlvl3: Illegal dev_state");
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
9927c478bd9Sstevel@tonic-gate 	}
9937c478bd9Sstevel@tonic-gate }
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate static void
usb_ac_create_pm_components(dev_info_t * dip,usb_ac_state_t * uacp)9977c478bd9Sstevel@tonic-gate usb_ac_create_pm_components(dev_info_t *dip, usb_ac_state_t *uacp)
9987c478bd9Sstevel@tonic-gate {
9997c478bd9Sstevel@tonic-gate 	usb_ac_power_t	*uacpm;
10007c478bd9Sstevel@tonic-gate 	uint_t		pwr_states;
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_PM, uacp->usb_ac_log_handle,
10037c478bd9Sstevel@tonic-gate 	    "usb_ac_create_pm_components: begin");
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate 	/* Allocate the state structure */
10067c478bd9Sstevel@tonic-gate 	uacpm = kmem_zalloc(sizeof (usb_ac_power_t), KM_SLEEP);
10077c478bd9Sstevel@tonic-gate 	uacp->usb_ac_pm = uacpm;
10087c478bd9Sstevel@tonic-gate 	uacpm->acpm_state = uacp;
10097c478bd9Sstevel@tonic-gate 	uacpm->acpm_capabilities = 0;
10107c478bd9Sstevel@tonic-gate 	uacpm->acpm_current_power = USB_DEV_OS_FULL_PWR;
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate 	if (usb_create_pm_components(dip, &pwr_states) ==
10137c478bd9Sstevel@tonic-gate 	    USB_SUCCESS) {
10147c478bd9Sstevel@tonic-gate 		if (usb_handle_remote_wakeup(dip,
10157c478bd9Sstevel@tonic-gate 		    USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) {
10167c478bd9Sstevel@tonic-gate 			uacpm->acpm_wakeup_enabled = 1;
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L4(PRINT_MASK_PM,
10197c478bd9Sstevel@tonic-gate 			    uacp->usb_ac_log_handle,
10207c478bd9Sstevel@tonic-gate 			    "remote Wakeup enabled");
10217c478bd9Sstevel@tonic-gate 		}
10227c478bd9Sstevel@tonic-gate 		uacpm->acpm_pwr_states = (uint8_t)pwr_states;
10237c478bd9Sstevel@tonic-gate 		(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
10247c478bd9Sstevel@tonic-gate 	} else {
10257c478bd9Sstevel@tonic-gate 		if (uacpm) {
10267c478bd9Sstevel@tonic-gate 			kmem_free(uacpm,  sizeof (usb_ac_power_t));
10277c478bd9Sstevel@tonic-gate 			uacp->usb_ac_pm = NULL;
10287c478bd9Sstevel@tonic-gate 		}
10297c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_PM, uacp->usb_ac_log_handle,
10307c478bd9Sstevel@tonic-gate 		    "pm not enabled");
10317c478bd9Sstevel@tonic-gate 	}
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate }
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate /*
10367c478bd9Sstevel@tonic-gate  * usb_ac_get_featureID:
10377c478bd9Sstevel@tonic-gate  *	find out if there is at least one feature unit that supports
10387c478bd9Sstevel@tonic-gate  *	the request controls.
10397c478bd9Sstevel@tonic-gate  *	Return featureID or USB_AC_ID_NONE.
10407c478bd9Sstevel@tonic-gate  */
10417c478bd9Sstevel@tonic-gate static uint_t
usb_ac_get_featureID(usb_ac_state_t * uacp,uchar_t dir,uint_t channel,uint_t control)10427c478bd9Sstevel@tonic-gate usb_ac_get_featureID(usb_ac_state_t *uacp, uchar_t dir,
10437c478bd9Sstevel@tonic-gate     uint_t channel, uint_t control)
10447c478bd9Sstevel@tonic-gate {
10457c478bd9Sstevel@tonic-gate 	uint_t count = 0;
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 	return (usb_ac_set_control(uacp, dir, USB_AUDIO_FEATURE_UNIT,
1048112116d8Sfb 	    channel, control, USB_AC_FIND_ONE, &count, 0,
1049112116d8Sfb 	    usb_ac_feature_unit_check));
10507c478bd9Sstevel@tonic-gate }
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate /*
10547c478bd9Sstevel@tonic-gate  * usb_ac_feature_unit_check:
10557c478bd9Sstevel@tonic-gate  *	check if a feature unit can support the required channel
10567c478bd9Sstevel@tonic-gate  *	and control combination. Return USB_SUCCESS or USB_FAILURE.
10577c478bd9Sstevel@tonic-gate  *	Called for each matching unit from usb_ac_traverse_connections.
10587c478bd9Sstevel@tonic-gate  */
10597c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10607c478bd9Sstevel@tonic-gate static int
usb_ac_feature_unit_check(usb_ac_state_t * uacp,uint_t featureID,uint_t dir,uint_t channel,uint_t control,uint_t arg1,uint_t * depth)10617c478bd9Sstevel@tonic-gate usb_ac_feature_unit_check(usb_ac_state_t *uacp, uint_t featureID,
10627c478bd9Sstevel@tonic-gate     uint_t dir, uint_t channel, uint_t control, uint_t arg1, uint_t *depth)
10637c478bd9Sstevel@tonic-gate {
10647c478bd9Sstevel@tonic-gate 	usb_audio_feature_unit_descr1_t *feature_descrp;
10657c478bd9Sstevel@tonic-gate 	int				n_channel_controls;
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate 
1068d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	ASSERT(featureID < uacp->usb_ac_max_unit);
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate 	/*
10717c478bd9Sstevel@tonic-gate 	 * check if this control is supported on this channel
10727c478bd9Sstevel@tonic-gate 	 */
10737c478bd9Sstevel@tonic-gate 	feature_descrp = (usb_audio_feature_unit_descr1_t *)
1074112116d8Sfb 	    uacp->usb_ac_units[featureID].acu_descriptor;
10757c478bd9Sstevel@tonic-gate 	ASSERT(feature_descrp->bUnitID == featureID);
10767c478bd9Sstevel@tonic-gate 
10777c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
10787c478bd9Sstevel@tonic-gate 	    "bControlSize=%d", feature_descrp->bControlSize);
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate 	if (feature_descrp->bControlSize == 0) {
10817c478bd9Sstevel@tonic-gate 		featureID = USB_AC_ID_NONE;
10827c478bd9Sstevel@tonic-gate 	} else {
10837c478bd9Sstevel@tonic-gate 		uint_t index;
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 		n_channel_controls = (feature_descrp->bLength -
10867c478bd9Sstevel@tonic-gate 		    offsetof(usb_audio_feature_unit_descr1_t,
10877c478bd9Sstevel@tonic-gate 		    bmaControls))/feature_descrp->bControlSize;
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL,
10907c478bd9Sstevel@tonic-gate 		    uacp->usb_ac_log_handle,
10917c478bd9Sstevel@tonic-gate 		    "#controls: %d index=%d", n_channel_controls,
10927c478bd9Sstevel@tonic-gate 		    feature_descrp->bControlSize * channel);
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 		if (channel > n_channel_controls) {
10957c478bd9Sstevel@tonic-gate 			featureID = USB_AC_ID_NONE;
10967c478bd9Sstevel@tonic-gate 		} else {
10977c478bd9Sstevel@tonic-gate 			/*
10987c478bd9Sstevel@tonic-gate 			 * we only support MUTE and VOLUME
10997c478bd9Sstevel@tonic-gate 			 * which are in the first byte
11007c478bd9Sstevel@tonic-gate 			 */
11017c478bd9Sstevel@tonic-gate 			index = feature_descrp->bControlSize *
1102112116d8Sfb 			    channel;
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ALL,
11057c478bd9Sstevel@tonic-gate 			    uacp->usb_ac_log_handle,
11067c478bd9Sstevel@tonic-gate 			    "control: 0x%x",
11077c478bd9Sstevel@tonic-gate 			    feature_descrp->bmaControls[index]);
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 			if ((feature_descrp->bmaControls[index] &
11107c478bd9Sstevel@tonic-gate 			    control) == 0) {
11117c478bd9Sstevel@tonic-gate 				featureID = USB_AC_ID_NONE;
11127c478bd9Sstevel@tonic-gate 			}
11137c478bd9Sstevel@tonic-gate 		}
11147c478bd9Sstevel@tonic-gate 	}
11157c478bd9Sstevel@tonic-gate 
11167c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
11177c478bd9Sstevel@tonic-gate 	    "usb_ac_feature_unit_check: dir=%d featureID=0x%x",
11187c478bd9Sstevel@tonic-gate 	    dir, featureID);
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate 	return ((featureID != USB_AC_ID_NONE) ?
1121112116d8Sfb 	    USB_SUCCESS : USB_FAILURE);
11227c478bd9Sstevel@tonic-gate }
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate /*
11267c478bd9Sstevel@tonic-gate  * Descriptor Management
11277c478bd9Sstevel@tonic-gate  *
11287c478bd9Sstevel@tonic-gate  * usb_ac_handle_descriptors:
11297c478bd9Sstevel@tonic-gate  *	extract interesting descriptors from the config cloud
11307c478bd9Sstevel@tonic-gate  */
11317c478bd9Sstevel@tonic-gate static int
usb_ac_handle_descriptors(usb_ac_state_t * uacp)11327c478bd9Sstevel@tonic-gate usb_ac_handle_descriptors(usb_ac_state_t *uacp)
11337c478bd9Sstevel@tonic-gate {
1134ebb3b3c9SJimmy Vetayases 	int			len, index;
11357c478bd9Sstevel@tonic-gate 	int			rval = USB_FAILURE;
11367c478bd9Sstevel@tonic-gate 	usb_audio_cs_if_descr_t descr;
11377c478bd9Sstevel@tonic-gate 	usb_client_dev_data_t	*dev_data = uacp->usb_ac_dev_data;
11387c478bd9Sstevel@tonic-gate 	usb_alt_if_data_t	*altif_data;
11397c478bd9Sstevel@tonic-gate 	usb_cvs_data_t		*cvs;
11407c478bd9Sstevel@tonic-gate 
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate 	altif_data = &dev_data->dev_curr_cfg->
1143112116d8Sfb 	    cfg_if[dev_data->dev_curr_if].if_alt[0];
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate 	uacp->usb_ac_ifno	= dev_data->dev_curr_if;
11467c478bd9Sstevel@tonic-gate 	uacp->usb_ac_if_descr	= altif_data->altif_descr;
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 	/* find USB_AUDIO_CS_INTERFACE type descriptor */
11497c478bd9Sstevel@tonic-gate 	for (index = 0; index < altif_data->altif_n_cvs; index++) {
11507c478bd9Sstevel@tonic-gate 		cvs = &altif_data->altif_cvs[index];
11517c478bd9Sstevel@tonic-gate 		if (cvs->cvs_buf == NULL) {
11527c478bd9Sstevel@tonic-gate 			continue;
11537c478bd9Sstevel@tonic-gate 		}
11547c478bd9Sstevel@tonic-gate 		if (cvs->cvs_buf[1] == USB_AUDIO_CS_INTERFACE) {
11557c478bd9Sstevel@tonic-gate 			break;
11567c478bd9Sstevel@tonic-gate 		}
11577c478bd9Sstevel@tonic-gate 	}
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 	if (index == altif_data->altif_n_cvs) {
11607c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1161e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_handle_descriptors:cannot find descriptor type %d",
1162e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    USB_AUDIO_CS_INTERFACE);
11637c478bd9Sstevel@tonic-gate 
11643c91d182Slg 		return (rval);
11657c478bd9Sstevel@tonic-gate 	}
11667c478bd9Sstevel@tonic-gate 
11677c478bd9Sstevel@tonic-gate 	len = usb_parse_data(
1168112116d8Sfb 	    CS_AC_IF_HEADER_FORMAT,
1169112116d8Sfb 	    cvs->cvs_buf, cvs->cvs_buf_len,
1170112116d8Sfb 	    (void *)&descr, sizeof (usb_audio_cs_if_descr_t));
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate 	/* is this a sane header descriptor */
11737c478bd9Sstevel@tonic-gate 	if (!((len >= CS_AC_IF_HEADER_SIZE) &&
11747c478bd9Sstevel@tonic-gate 	    (descr.bDescriptorType == USB_AUDIO_CS_INTERFACE) &&
11757c478bd9Sstevel@tonic-gate 	    (descr.bDescriptorSubType == USB_AUDIO_HEADER))) {
11767c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
11777c478bd9Sstevel@tonic-gate 		    "invalid header");
11787c478bd9Sstevel@tonic-gate 
11793c91d182Slg 		return (rval);
11807c478bd9Sstevel@tonic-gate 	}
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1183e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    "index %d, header: type=0x%x subtype=0x%x bcdADC=0x%x\n\t"
1184b0fe7b8fSlg 	    "total=0x%x InCol=0x%x",
1185e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    index,
11867c478bd9Sstevel@tonic-gate 	    descr.bDescriptorType,
11877c478bd9Sstevel@tonic-gate 	    descr.bDescriptorSubType,
11887c478bd9Sstevel@tonic-gate 	    descr.bcdADC,
11897c478bd9Sstevel@tonic-gate 	    descr.wTotalLength,
1190b0fe7b8fSlg 	    descr.blnCollection);
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 	/*
11937c478bd9Sstevel@tonic-gate 	 * we read descriptors by index and store them in ID array.
11947c478bd9Sstevel@tonic-gate 	 * the actual parsing is done in usb_ac_add_unit_descriptor()
11957c478bd9Sstevel@tonic-gate 	 */
1196ebb3b3c9SJimmy Vetayases 	for (index++; index < altif_data->altif_n_cvs; index++) {
11977c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1198ebb3b3c9SJimmy Vetayases 		    "index=%d", index);
11997c478bd9Sstevel@tonic-gate 
12007c478bd9Sstevel@tonic-gate 		cvs = &altif_data->altif_cvs[index];
12017c478bd9Sstevel@tonic-gate 		if (cvs->cvs_buf == NULL) {
12027c478bd9Sstevel@tonic-gate 			continue;
12037c478bd9Sstevel@tonic-gate 		}
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate 		/* add to ID array */
12067c478bd9Sstevel@tonic-gate 		usb_ac_add_unit_descriptor(uacp, cvs->cvs_buf,
1207112116d8Sfb 		    cvs->cvs_buf_len);
12087c478bd9Sstevel@tonic-gate 	}
12097c478bd9Sstevel@tonic-gate 	rval = USB_SUCCESS;
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate 	usb_ac_setup_connections(uacp);
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 	/* determine port types */
1214e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_ac_map_termtype_to_port(uacp, USB_AUDIO_PLAY);
1215e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_ac_map_termtype_to_port(uacp, USB_AUDIO_RECORD);
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 	return (rval);
12197c478bd9Sstevel@tonic-gate }
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate /*
12237c478bd9Sstevel@tonic-gate  * usb_ac_setup_connections:
12247c478bd9Sstevel@tonic-gate  *	build a matrix reflecting all connections
12257c478bd9Sstevel@tonic-gate  */
12267c478bd9Sstevel@tonic-gate static void
usb_ac_setup_connections(usb_ac_state_t * uacp)12277c478bd9Sstevel@tonic-gate usb_ac_setup_connections(usb_ac_state_t *uacp)
12287c478bd9Sstevel@tonic-gate {
12297c478bd9Sstevel@tonic-gate 	usb_ac_unit_list_t	*units = uacp->usb_ac_units;
12307c478bd9Sstevel@tonic-gate 	uchar_t			*a, **p, i, unit;
12317c478bd9Sstevel@tonic-gate 	size_t			a_len, p_len;
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 	/* allocate array for unit types for quick reference */
12347c478bd9Sstevel@tonic-gate 	uacp->usb_ac_unit_type = kmem_zalloc(uacp->usb_ac_max_unit,
1235112116d8Sfb 	    KM_SLEEP);
12367c478bd9Sstevel@tonic-gate 	/* allocate array for traversal path */
12377c478bd9Sstevel@tonic-gate 	uacp->usb_ac_traverse_path = kmem_zalloc(uacp->usb_ac_max_unit,
1238112116d8Sfb 	    KM_SLEEP);
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 	/* allocate the connection matrix and set it up */
12427c478bd9Sstevel@tonic-gate 	a_len = uacp->usb_ac_max_unit * uacp->usb_ac_max_unit;
12437c478bd9Sstevel@tonic-gate 	p_len = uacp->usb_ac_max_unit * sizeof (uchar_t *);
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate 	/* trick to create a 2 dimensional array */
12467c478bd9Sstevel@tonic-gate 	a = kmem_zalloc(a_len, KM_SLEEP);
12477c478bd9Sstevel@tonic-gate 	p = kmem_zalloc(p_len, KM_SLEEP);
12487c478bd9Sstevel@tonic-gate 	for (i = 0; i < uacp->usb_ac_max_unit; i++) {
12497c478bd9Sstevel@tonic-gate 		p[i] = a + i * uacp->usb_ac_max_unit;
12507c478bd9Sstevel@tonic-gate 	}
12517c478bd9Sstevel@tonic-gate 	uacp->usb_ac_connections = p;
12527c478bd9Sstevel@tonic-gate 	uacp->usb_ac_connections_len = p_len;
12537c478bd9Sstevel@tonic-gate 	uacp->usb_ac_connections_a = a;
12547c478bd9Sstevel@tonic-gate 	uacp->usb_ac_connections_a_len = a_len;
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 	/* traverse all units and set connections */
12577c478bd9Sstevel@tonic-gate 	for (unit = 0; unit < uacp->usb_ac_max_unit; unit++) {
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1260e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "--------traversing unit=0x%x type=0x%x--------",
12617c478bd9Sstevel@tonic-gate 		    unit, units[unit].acu_type);
12627c478bd9Sstevel@tonic-gate 
12637c478bd9Sstevel@tonic-gate 		/* store type in the first unused column */
12647c478bd9Sstevel@tonic-gate 		uacp->usb_ac_unit_type[unit] = units[unit].acu_type;
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate 		/* save the Unit ID in the unit it points to */
12677c478bd9Sstevel@tonic-gate 		switch (units[unit].acu_type) {
12687c478bd9Sstevel@tonic-gate 		case USB_AUDIO_FEATURE_UNIT:
12697c478bd9Sstevel@tonic-gate 		{
12707c478bd9Sstevel@tonic-gate 			usb_audio_feature_unit_descr1_t *d =
1271112116d8Sfb 			    units[unit].acu_descriptor;
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1274e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			    "USB_AUDIO_FEATURE_UNIT:sourceID=0x%x type=0x%x",
1275e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			    d->bSourceID, units[d->bSourceID].acu_type);
12767c478bd9Sstevel@tonic-gate 
12777c478bd9Sstevel@tonic-gate 			if (d->bSourceID != 0) {
12787c478bd9Sstevel@tonic-gate 				ASSERT(p[unit][d->bSourceID] == B_FALSE);
12797c478bd9Sstevel@tonic-gate 				p[unit][d->bSourceID] = B_TRUE;
12807c478bd9Sstevel@tonic-gate 			}
12817c478bd9Sstevel@tonic-gate 
12827c478bd9Sstevel@tonic-gate 			break;
12837c478bd9Sstevel@tonic-gate 		}
12847c478bd9Sstevel@tonic-gate 		case USB_AUDIO_OUTPUT_TERMINAL:
12857c478bd9Sstevel@tonic-gate 		{
12867c478bd9Sstevel@tonic-gate 			usb_audio_output_term_descr_t *d =
1287112116d8Sfb 			    units[unit].acu_descriptor;
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1290e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			    "USB_AUDIO_OUTPUT_TERMINAL:sourceID=0x%x type=0x%x",
1291e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			    d->bSourceID, units[d->bSourceID].acu_type);
12927c478bd9Sstevel@tonic-gate 
12937c478bd9Sstevel@tonic-gate 			if (d->bSourceID != 0) {
12947c478bd9Sstevel@tonic-gate 				ASSERT(p[unit][d->bSourceID] == B_FALSE);
12957c478bd9Sstevel@tonic-gate 				p[unit][d->bSourceID] = B_TRUE;
12967c478bd9Sstevel@tonic-gate 			}
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate 			break;
12997c478bd9Sstevel@tonic-gate 		}
13007c478bd9Sstevel@tonic-gate 		case USB_AUDIO_MIXER_UNIT:
13017c478bd9Sstevel@tonic-gate 		{
13027c478bd9Sstevel@tonic-gate 			usb_audio_mixer_unit_descr1_t *d =
1303112116d8Sfb 			    units[unit].acu_descriptor;
13047c478bd9Sstevel@tonic-gate 			int n_sourceID = d->bNrInPins;
13057c478bd9Sstevel@tonic-gate 			int id;
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate 			for (id = 0; id < n_sourceID; id++) {
13087c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L3(PRINT_MASK_ATTA,
13097c478bd9Sstevel@tonic-gate 				    uacp->usb_ac_log_handle,
1310e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 				    "USB_AUDIO_MIXER_UNIT:sourceID=0x%x"
1311e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 				    "type=0x%x c=%d",
13127c478bd9Sstevel@tonic-gate 				    d->baSourceID[id],
13137c478bd9Sstevel@tonic-gate 				    units[d->baSourceID[id]].acu_type,
13147c478bd9Sstevel@tonic-gate 				    p[unit][d->baSourceID[id]]);
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 				if (d->baSourceID[id] != 0) {
13177c478bd9Sstevel@tonic-gate 					ASSERT(p[unit][d->baSourceID[id]] ==
13187c478bd9Sstevel@tonic-gate 					    B_FALSE);
13197c478bd9Sstevel@tonic-gate 					p[unit][d->baSourceID[id]] = B_TRUE;
13207c478bd9Sstevel@tonic-gate 				}
13217c478bd9Sstevel@tonic-gate 			}
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate 			break;
13247c478bd9Sstevel@tonic-gate 		}
13257c478bd9Sstevel@tonic-gate 		case USB_AUDIO_SELECTOR_UNIT:
13267c478bd9Sstevel@tonic-gate 		{
13277c478bd9Sstevel@tonic-gate 			usb_audio_selector_unit_descr1_t *d =
1328112116d8Sfb 			    units[unit].acu_descriptor;
13297c478bd9Sstevel@tonic-gate 			int n_sourceID = d->bNrInPins;
13307c478bd9Sstevel@tonic-gate 			int id;
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 			for (id = 0; id < n_sourceID; id++) {
13337c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L3(PRINT_MASK_ATTA,
13347c478bd9Sstevel@tonic-gate 				    uacp->usb_ac_log_handle,
1335e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 				    "USB_AUDIO_SELECTOR_UNIT:sourceID=0x%x"
1336e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 				    " type=0x%x", d->baSourceID[id],
13377c478bd9Sstevel@tonic-gate 				    units[d->baSourceID[id]].acu_type);
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate 				if (d->baSourceID[id] != 0) {
13407c478bd9Sstevel@tonic-gate 					ASSERT(p[unit][d->baSourceID[id]] ==
13417c478bd9Sstevel@tonic-gate 					    B_FALSE);
13427c478bd9Sstevel@tonic-gate 					p[unit][d->baSourceID[id]] = B_TRUE;
13437c478bd9Sstevel@tonic-gate 				}
13447c478bd9Sstevel@tonic-gate 			}
13457c478bd9Sstevel@tonic-gate 
13467c478bd9Sstevel@tonic-gate 			break;
13477c478bd9Sstevel@tonic-gate 		}
13487c478bd9Sstevel@tonic-gate 		case USB_AUDIO_PROCESSING_UNIT:
13497c478bd9Sstevel@tonic-gate 		{
13507c478bd9Sstevel@tonic-gate 			usb_audio_mixer_unit_descr1_t *d =
1351112116d8Sfb 			    units[unit].acu_descriptor;
13527c478bd9Sstevel@tonic-gate 			int n_sourceID = d->bNrInPins;
13537c478bd9Sstevel@tonic-gate 			int id;
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 			for (id = 0; id < n_sourceID; id++) {
13567c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L3(PRINT_MASK_ATTA,
13577c478bd9Sstevel@tonic-gate 				    uacp->usb_ac_log_handle,
1358e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 				    "USB_AUDIO_PROCESSING_UNIT:sourceID=0x%x"
1359e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 				    " type=0x%x", d->baSourceID[id],
13607c478bd9Sstevel@tonic-gate 				    units[d->baSourceID[id]].acu_type);
13617c478bd9Sstevel@tonic-gate 
13627c478bd9Sstevel@tonic-gate 				if (d->baSourceID[id] != 0) {
13637c478bd9Sstevel@tonic-gate 					ASSERT(p[unit][d->baSourceID[id]] ==
13647c478bd9Sstevel@tonic-gate 					    B_FALSE);
13657c478bd9Sstevel@tonic-gate 					p[unit][d->baSourceID[id]] = B_TRUE;
13667c478bd9Sstevel@tonic-gate 				}
13677c478bd9Sstevel@tonic-gate 			}
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate 			break;
13707c478bd9Sstevel@tonic-gate 		}
13717c478bd9Sstevel@tonic-gate 		case USB_AUDIO_EXTENSION_UNIT:
13727c478bd9Sstevel@tonic-gate 		{
13737c478bd9Sstevel@tonic-gate 			usb_audio_extension_unit_descr1_t *d =
1374112116d8Sfb 			    units[unit].acu_descriptor;
13757c478bd9Sstevel@tonic-gate 			int n_sourceID = d->bNrInPins;
13767c478bd9Sstevel@tonic-gate 			int id;
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate 			for (id = 0; id < n_sourceID; id++) {
13797c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L3(PRINT_MASK_ATTA,
13807c478bd9Sstevel@tonic-gate 				    uacp->usb_ac_log_handle,
1381e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 				    "USB_AUDIO_EXTENSION_UNIT:sourceID=0x%x"
1382e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 				    "type=0x%x", d->baSourceID[id],
13837c478bd9Sstevel@tonic-gate 				    units[d->baSourceID[id]].acu_type);
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 				if (d->baSourceID[id] != 0) {
13867c478bd9Sstevel@tonic-gate 					ASSERT(p[unit][d->baSourceID[id]] ==
13877c478bd9Sstevel@tonic-gate 					    B_TRUE);
13887c478bd9Sstevel@tonic-gate 					p[unit][d->baSourceID[id]] = B_FALSE;
13897c478bd9Sstevel@tonic-gate 				}
13907c478bd9Sstevel@tonic-gate 			}
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 			break;
13937c478bd9Sstevel@tonic-gate 		}
13947c478bd9Sstevel@tonic-gate 		case USB_AUDIO_INPUT_TERMINAL:
13957c478bd9Sstevel@tonic-gate 
13967c478bd9Sstevel@tonic-gate 			break;
13977c478bd9Sstevel@tonic-gate 		default:
13987c478bd9Sstevel@tonic-gate 			/*
13997c478bd9Sstevel@tonic-gate 			 * Ignore the rest because they are not support yet
14007c478bd9Sstevel@tonic-gate 			 */
14017c478bd9Sstevel@tonic-gate 			break;
14027c478bd9Sstevel@tonic-gate 		}
14037c478bd9Sstevel@tonic-gate 	}
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate #ifdef DEBUG
14067c478bd9Sstevel@tonic-gate 	/* display topology in log buffer */
14077c478bd9Sstevel@tonic-gate {
14087c478bd9Sstevel@tonic-gate 	uint_t i, j, l;
14097c478bd9Sstevel@tonic-gate 	char *buf;
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate 	l = uacp->usb_ac_max_unit * 5;
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate 	buf = kmem_alloc(l, KM_SLEEP);
14147c478bd9Sstevel@tonic-gate 
14157c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
14167c478bd9Sstevel@tonic-gate 	    "unit types:");
14177c478bd9Sstevel@tonic-gate 
14187c478bd9Sstevel@tonic-gate 	/* two	strings so they won't be replaced accidentily by tab */
14197c478bd9Sstevel@tonic-gate 	(void) sprintf(&buf[0], "    ""    ");
14207c478bd9Sstevel@tonic-gate 	for (i = 1; i < uacp->usb_ac_max_unit; i++) {
14217c478bd9Sstevel@tonic-gate 		(void) sprintf(&buf[2 + (i*3)], "%02d ", i);
14227c478bd9Sstevel@tonic-gate 	}
14237c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, buf);
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate 	(void) sprintf(&buf[0], "  +-------");
14267c478bd9Sstevel@tonic-gate 	for (i = 1; i < uacp->usb_ac_max_unit; i++) {
14277c478bd9Sstevel@tonic-gate 		(void) sprintf(&buf[5+((i-1)*3)], "---");
14287c478bd9Sstevel@tonic-gate 	}
14297c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, buf);
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 	(void) sprintf(&buf[0], "    ""    ");
14327c478bd9Sstevel@tonic-gate 	for (i = 1; i < uacp->usb_ac_max_unit; i++) {
14337c478bd9Sstevel@tonic-gate 		(void) sprintf(&buf[2 + (i*3)], "%02d ",
1434112116d8Sfb 		    uacp->usb_ac_unit_type[i]);
14357c478bd9Sstevel@tonic-gate 	}
14367c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, buf);
14377c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, " ");
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
14407c478bd9Sstevel@tonic-gate 	    "adjacency matrix:");
14417c478bd9Sstevel@tonic-gate 	(void) sprintf(&buf[0], "    ""    ");
14427c478bd9Sstevel@tonic-gate 	for (i = 1; i < uacp->usb_ac_max_unit; i++) {
14437c478bd9Sstevel@tonic-gate 		(void) sprintf(&buf[2 + (i*3)], "%02d ", i);
14447c478bd9Sstevel@tonic-gate 	}
14457c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, buf);
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 	(void) sprintf(&buf[0], "  +-------");
14487c478bd9Sstevel@tonic-gate 	for (i = 1; i < uacp->usb_ac_max_unit; i++) {
14497c478bd9Sstevel@tonic-gate 		(void) sprintf(&buf[5+((i-1)*3)], "---");
14507c478bd9Sstevel@tonic-gate 	}
14517c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, buf);
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate 	for (i = 1; i < uacp->usb_ac_max_unit; i++) {
14547c478bd9Sstevel@tonic-gate 		(void) sprintf(&buf[0], "%02d| "" ", i);
14557c478bd9Sstevel@tonic-gate 		for (j = 1; j < uacp->usb_ac_max_unit; j++) {
14567c478bd9Sstevel@tonic-gate 			(void) sprintf(&buf[1+(j * 3)], "%2d ", p[i][j]);
14577c478bd9Sstevel@tonic-gate 		}
14587c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, buf);
14597c478bd9Sstevel@tonic-gate 	}
14607c478bd9Sstevel@tonic-gate 	kmem_free(buf, l);
14617c478bd9Sstevel@tonic-gate }
14627c478bd9Sstevel@tonic-gate #endif
14637c478bd9Sstevel@tonic-gate }
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate 
14667c478bd9Sstevel@tonic-gate /*
14677c478bd9Sstevel@tonic-gate  * usb_ac_add_unit_descriptor:
14687c478bd9Sstevel@tonic-gate  *	take the parsed descriptor in the buffer and store it in the ID unit
14697c478bd9Sstevel@tonic-gate  *	array. we grow the unit array if the ID exceeds the current max
14707c478bd9Sstevel@tonic-gate  */
14717c478bd9Sstevel@tonic-gate static void
usb_ac_add_unit_descriptor(usb_ac_state_t * uacp,uchar_t * buffer,size_t buflen)14727c478bd9Sstevel@tonic-gate usb_ac_add_unit_descriptor(usb_ac_state_t *uacp, uchar_t *buffer,
1473*d5ebc493SDan Cross     size_t buflen)
14747c478bd9Sstevel@tonic-gate {
14757c478bd9Sstevel@tonic-gate 	void	*descr;
14767c478bd9Sstevel@tonic-gate 	int	len;
14777c478bd9Sstevel@tonic-gate 	char	*format;
14787c478bd9Sstevel@tonic-gate 	size_t	size;
14797c478bd9Sstevel@tonic-gate 
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate 	/* doubling the length should allow for padding */
14827c478bd9Sstevel@tonic-gate 	len = 2 * buffer[0];
14837c478bd9Sstevel@tonic-gate 	descr = kmem_zalloc(len, KM_SLEEP);
14847c478bd9Sstevel@tonic-gate 
14857c478bd9Sstevel@tonic-gate 	switch (buffer[2]) {
14867c478bd9Sstevel@tonic-gate 	case USB_AUDIO_INPUT_TERMINAL:
14877c478bd9Sstevel@tonic-gate 		format = CS_AC_INPUT_TERM_FORMAT;
14887c478bd9Sstevel@tonic-gate 		size = CS_AC_INPUT_TERM_SIZE;
14897c478bd9Sstevel@tonic-gate 
14907c478bd9Sstevel@tonic-gate 		break;
14917c478bd9Sstevel@tonic-gate 	case USB_AUDIO_OUTPUT_TERMINAL:
14927c478bd9Sstevel@tonic-gate 		format = CS_AC_OUTPUT_TERM_FORMAT;
14937c478bd9Sstevel@tonic-gate 		size = CS_AC_OUTPUT_TERM_SIZE;
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate 		break;
14967c478bd9Sstevel@tonic-gate 	case USB_AUDIO_MIXER_UNIT:
14977c478bd9Sstevel@tonic-gate 		format = CS_AC_MIXER_UNIT_DESCR1_FORMAT "255c";
14987c478bd9Sstevel@tonic-gate 		size = CS_AC_MIXER_UNIT_DESCR1_SIZE + buffer[4] - 1;
14997c478bd9Sstevel@tonic-gate 
15007c478bd9Sstevel@tonic-gate 		break;
15017c478bd9Sstevel@tonic-gate 	case USB_AUDIO_SELECTOR_UNIT:
15027c478bd9Sstevel@tonic-gate 		format = CS_AC_SELECTOR_UNIT_DESCR1_FORMAT "255c";
15037c478bd9Sstevel@tonic-gate 		size = CS_AC_SELECTOR_UNIT_DESCR1_SIZE + buffer[4] - 1;
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate 		break;
15067c478bd9Sstevel@tonic-gate 	case USB_AUDIO_FEATURE_UNIT:
15077c478bd9Sstevel@tonic-gate 		format = CS_AC_FEATURE_UNIT_FORMAT "255c";
15087c478bd9Sstevel@tonic-gate 		size = CS_AC_FEATURE_UNIT_SIZE;
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 		break;
15117c478bd9Sstevel@tonic-gate 	case USB_AUDIO_PROCESSING_UNIT:
15127c478bd9Sstevel@tonic-gate 		format = CS_AC_PROCESSING_UNIT_DESCR1_FORMAT "255c";
15137c478bd9Sstevel@tonic-gate 		size = CS_AC_PROCESSING_UNIT_DESCR1_SIZE + buffer[6] - 1;
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate 		break;
15167c478bd9Sstevel@tonic-gate 	case USB_AUDIO_EXTENSION_UNIT:
15177c478bd9Sstevel@tonic-gate 		format = CS_AC_EXTENSION_UNIT_DESCR1_FORMAT "255c";
15187c478bd9Sstevel@tonic-gate 		size = CS_AC_EXTENSION_UNIT_DESCR1_SIZE + buffer[6] - 1;
15197c478bd9Sstevel@tonic-gate 
15207c478bd9Sstevel@tonic-gate 		break;
15217c478bd9Sstevel@tonic-gate 	default:
15227c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ATTA,
15237c478bd9Sstevel@tonic-gate 		    uacp->usb_ac_log_handle,
15247c478bd9Sstevel@tonic-gate 		    "unsupported descriptor %d", buffer[2]);
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate 		/* ignore this descriptor */
15277c478bd9Sstevel@tonic-gate 		kmem_free(descr, len);
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate 		return;
15307c478bd9Sstevel@tonic-gate 	}
15317c478bd9Sstevel@tonic-gate 
15327c478bd9Sstevel@tonic-gate 	if (usb_parse_data(format, buffer, buflen, descr, len) < size) {
15337c478bd9Sstevel@tonic-gate 		/* ignore this descriptor */
15347c478bd9Sstevel@tonic-gate 		kmem_free(descr, len);
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate 		return;
15377c478bd9Sstevel@tonic-gate 	}
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate 	switch (buffer[2]) {
15407c478bd9Sstevel@tonic-gate 	case USB_AUDIO_INPUT_TERMINAL:
15417c478bd9Sstevel@tonic-gate 	{
15427c478bd9Sstevel@tonic-gate 		usb_audio_input_term_descr_t *d =
15437c478bd9Sstevel@tonic-gate 		    (usb_audio_input_term_descr_t *)descr;
15447c478bd9Sstevel@tonic-gate 
15457c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA,
15467c478bd9Sstevel@tonic-gate 		    uacp->usb_ac_log_handle,
1547e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_units[%d] ---input term: type=0x%x sub=0x%x"
1548e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "termid=0x%x\n\t"
15497c478bd9Sstevel@tonic-gate 		    "termtype=0x%x assoc=0x%x #ch=%d "
15507c478bd9Sstevel@tonic-gate 		    "chconf=0x%x ich=0x%x iterm=0x%x",
1551e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    d->bTerminalID,
15527c478bd9Sstevel@tonic-gate 		    d->bDescriptorType, d->bDescriptorSubType,
15537c478bd9Sstevel@tonic-gate 		    d->bTerminalID, d->wTerminalType,
15547c478bd9Sstevel@tonic-gate 		    d->bAssocTerminal, d->bNrChannels,
15557c478bd9Sstevel@tonic-gate 		    d->wChannelConfig, d->iChannelNames,
15567c478bd9Sstevel@tonic-gate 		    d->iTerminal);
15577c478bd9Sstevel@tonic-gate 
15587c478bd9Sstevel@tonic-gate 		usb_ac_alloc_unit(uacp, d->bTerminalID);
15597c478bd9Sstevel@tonic-gate 		uacp->usb_ac_units[d->bTerminalID].acu_descriptor = descr;
15607c478bd9Sstevel@tonic-gate 		uacp->usb_ac_units[d->bTerminalID].acu_type = buffer[2];
15617c478bd9Sstevel@tonic-gate 		uacp->usb_ac_units[d->bTerminalID].acu_descr_length = len;
15627c478bd9Sstevel@tonic-gate 
15637c478bd9Sstevel@tonic-gate 		break;
15647c478bd9Sstevel@tonic-gate 	}
15657c478bd9Sstevel@tonic-gate 	case USB_AUDIO_OUTPUT_TERMINAL:
15667c478bd9Sstevel@tonic-gate 	{
15677c478bd9Sstevel@tonic-gate 		usb_audio_output_term_descr_t *d =
15687c478bd9Sstevel@tonic-gate 		    (usb_audio_output_term_descr_t *)descr;
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA,
15717c478bd9Sstevel@tonic-gate 		    uacp->usb_ac_log_handle,
1572e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_units[%d] ---output term: type=0x%x sub=0x%x"
1573e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    " termid=0x%x\n\t"
15747c478bd9Sstevel@tonic-gate 		    "termtype=0x%x assoc=0x%x sourceID=0x%x iterm=0x%x",
1575e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    d->bTerminalID,
15767c478bd9Sstevel@tonic-gate 		    d->bDescriptorType, d->bDescriptorSubType,
15777c478bd9Sstevel@tonic-gate 		    d->bTerminalID, d->wTerminalType,
15787c478bd9Sstevel@tonic-gate 		    d->bAssocTerminal, d->bSourceID,
15797c478bd9Sstevel@tonic-gate 		    d->iTerminal);
15807c478bd9Sstevel@tonic-gate 
15817c478bd9Sstevel@tonic-gate 		usb_ac_alloc_unit(uacp, d->bTerminalID);
15827c478bd9Sstevel@tonic-gate 		uacp->usb_ac_units[d->bTerminalID].acu_descriptor = descr;
15837c478bd9Sstevel@tonic-gate 		uacp->usb_ac_units[d->bTerminalID].acu_type = buffer[2];
15847c478bd9Sstevel@tonic-gate 		uacp->usb_ac_units[d->bTerminalID].acu_descr_length = len;
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate 		break;
15877c478bd9Sstevel@tonic-gate 	}
15887c478bd9Sstevel@tonic-gate 	case USB_AUDIO_MIXER_UNIT:
15897c478bd9Sstevel@tonic-gate 	{
15907c478bd9Sstevel@tonic-gate 		usb_audio_mixer_unit_descr1_t *d =
15917c478bd9Sstevel@tonic-gate 		    (usb_audio_mixer_unit_descr1_t *)descr;
15927c478bd9Sstevel@tonic-gate 
15937c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA,
15947c478bd9Sstevel@tonic-gate 		    uacp->usb_ac_log_handle,
1595e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_units[%d] ---mixer unit: type=0x%x sub=0x%x"
1596e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    " unitid=0x%x\n\t"
15977c478bd9Sstevel@tonic-gate 		    "#pins=0x%x sourceid[0]=0x%x",
1598e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    d->bUnitID,
15997c478bd9Sstevel@tonic-gate 		    d->bDescriptorType, d->bDescriptorSubType,
16007c478bd9Sstevel@tonic-gate 		    d->bUnitID, d->bNrInPins, d->baSourceID[0]);
16017c478bd9Sstevel@tonic-gate 		usb_ac_alloc_unit(uacp, d->bUnitID);
16027c478bd9Sstevel@tonic-gate 		uacp->usb_ac_units[d->bUnitID].acu_descriptor = descr;
16037c478bd9Sstevel@tonic-gate 		uacp->usb_ac_units[d->bUnitID].acu_type = buffer[2];
16047c478bd9Sstevel@tonic-gate 		uacp->usb_ac_units[d->bUnitID].acu_descr_length = len;
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate 		break;
16077c478bd9Sstevel@tonic-gate 	}
16087c478bd9Sstevel@tonic-gate 	case USB_AUDIO_SELECTOR_UNIT:
16097c478bd9Sstevel@tonic-gate 	{
16107c478bd9Sstevel@tonic-gate 		usb_audio_selector_unit_descr1_t *d =
16117c478bd9Sstevel@tonic-gate 		    (usb_audio_selector_unit_descr1_t *)descr;
16127c478bd9Sstevel@tonic-gate 
16137c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA,
16147c478bd9Sstevel@tonic-gate 		    uacp->usb_ac_log_handle,
1615e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_units[%d] ---selector unit: type=0x%x sub=0x%x"
1616e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    " unitid=0x%x\n\t"
16177c478bd9Sstevel@tonic-gate 		    "#pins=0x%x sourceid[0]=0x%x",
1618e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    d->bUnitID,
16197c478bd9Sstevel@tonic-gate 		    d->bDescriptorType, d->bDescriptorSubType,
16207c478bd9Sstevel@tonic-gate 		    d->bUnitID, d->bNrInPins, d->baSourceID[0]);
16217c478bd9Sstevel@tonic-gate 		usb_ac_alloc_unit(uacp, d->bUnitID);
16227c478bd9Sstevel@tonic-gate 		uacp->usb_ac_units[d->bUnitID].acu_descriptor = descr;
16237c478bd9Sstevel@tonic-gate 		uacp->usb_ac_units[d->bUnitID].acu_type = buffer[2];
16247c478bd9Sstevel@tonic-gate 		uacp->usb_ac_units[d->bUnitID].acu_descr_length = len;
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate 		break;
16277c478bd9Sstevel@tonic-gate 	}
16287c478bd9Sstevel@tonic-gate 	case USB_AUDIO_FEATURE_UNIT:
16297c478bd9Sstevel@tonic-gate 	{
16307c478bd9Sstevel@tonic-gate 		usb_audio_feature_unit_descr1_t *d =
16317c478bd9Sstevel@tonic-gate 		    (usb_audio_feature_unit_descr1_t *)descr;
16327c478bd9Sstevel@tonic-gate 
16337c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA,
16347c478bd9Sstevel@tonic-gate 		    uacp->usb_ac_log_handle,
1635e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_units[%d] ---feature unit: type=0x%x sub=0x%x"
1636e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    " unitid=0x%x\n\t"
1637b0fe7b8fSlg 		    "sourceid=0x%x size=0x%x",
1638e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    d->bUnitID,
16397c478bd9Sstevel@tonic-gate 		    d->bDescriptorType, d->bDescriptorSubType,
1640b0fe7b8fSlg 		    d->bUnitID, d->bSourceID, d->bControlSize);
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate 		usb_ac_alloc_unit(uacp, d->bUnitID);
16437c478bd9Sstevel@tonic-gate 		uacp->usb_ac_units[d->bUnitID].acu_descriptor = descr;
16447c478bd9Sstevel@tonic-gate 		uacp->usb_ac_units[d->bUnitID].acu_type = buffer[2];
16457c478bd9Sstevel@tonic-gate 		uacp->usb_ac_units[d->bUnitID].acu_descr_length = len;
16467c478bd9Sstevel@tonic-gate 
16477c478bd9Sstevel@tonic-gate 		break;
16487c478bd9Sstevel@tonic-gate 	}
16497c478bd9Sstevel@tonic-gate 	case USB_AUDIO_PROCESSING_UNIT:
16507c478bd9Sstevel@tonic-gate 	{
16517c478bd9Sstevel@tonic-gate 		usb_audio_processing_unit_descr1_t *d =
16527c478bd9Sstevel@tonic-gate 		    (usb_audio_processing_unit_descr1_t *)descr;
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA,
16557c478bd9Sstevel@tonic-gate 		    uacp->usb_ac_log_handle,
1656e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_units[%d] ---processing unit: type=0x%x sub=0x%x"
1657e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    " unitid=0x%x\n\t"
16587c478bd9Sstevel@tonic-gate 		    "#pins=0x%x sourceid[0]=0x%x",
1659e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    d->bUnitID,
16607c478bd9Sstevel@tonic-gate 		    d->bDescriptorType, d->bDescriptorSubType,
16617c478bd9Sstevel@tonic-gate 		    d->bUnitID, d->bNrInPins, d->baSourceID[0]);
16627c478bd9Sstevel@tonic-gate 		usb_ac_alloc_unit(uacp, d->bUnitID);
16637c478bd9Sstevel@tonic-gate 		uacp->usb_ac_units[d->bUnitID].acu_descriptor = descr;
16647c478bd9Sstevel@tonic-gate 		uacp->usb_ac_units[d->bUnitID].acu_type = buffer[2];
16657c478bd9Sstevel@tonic-gate 		uacp->usb_ac_units[d->bUnitID].acu_descr_length = len;
16667c478bd9Sstevel@tonic-gate 
16677c478bd9Sstevel@tonic-gate 		break;
16687c478bd9Sstevel@tonic-gate 	}
16697c478bd9Sstevel@tonic-gate 	case USB_AUDIO_EXTENSION_UNIT:
16707c478bd9Sstevel@tonic-gate 	{
16717c478bd9Sstevel@tonic-gate 		usb_audio_extension_unit_descr1_t *d =
16727c478bd9Sstevel@tonic-gate 		    (usb_audio_extension_unit_descr1_t *)descr;
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ATTA,
16757c478bd9Sstevel@tonic-gate 		    uacp->usb_ac_log_handle,
1676e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_units[%d] ---mixer unit: type=0x%x sub=0x%x"
1677e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    " unitid=0x%x\n\t"
16787c478bd9Sstevel@tonic-gate 		    "#pins=0x%x sourceid[0]=0x%x",
1679e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    d->bUnitID,
16807c478bd9Sstevel@tonic-gate 		    d->bDescriptorType, d->bDescriptorSubType,
16817c478bd9Sstevel@tonic-gate 		    d->bUnitID, d->bNrInPins, d->baSourceID[0]);
16827c478bd9Sstevel@tonic-gate 		usb_ac_alloc_unit(uacp, d->bUnitID);
16837c478bd9Sstevel@tonic-gate 		uacp->usb_ac_units[d->bUnitID].acu_descriptor = descr;
16847c478bd9Sstevel@tonic-gate 		uacp->usb_ac_units[d->bUnitID].acu_type = buffer[2];
16857c478bd9Sstevel@tonic-gate 		uacp->usb_ac_units[d->bUnitID].acu_descr_length = len;
16867c478bd9Sstevel@tonic-gate 
16877c478bd9Sstevel@tonic-gate 		break;
16887c478bd9Sstevel@tonic-gate 	}
16897c478bd9Sstevel@tonic-gate 	default:
16907c478bd9Sstevel@tonic-gate 		break;
16917c478bd9Sstevel@tonic-gate 	}
16927c478bd9Sstevel@tonic-gate }
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 
16957c478bd9Sstevel@tonic-gate /*
16967c478bd9Sstevel@tonic-gate  * usb_ac_alloc_unit:
16977c478bd9Sstevel@tonic-gate  *	check if the unit ID is less than max_unit in which case no
16987c478bd9Sstevel@tonic-gate  *	extra entries are needed. If more entries are needed, copy over
16997c478bd9Sstevel@tonic-gate  *	the existing array into a new larger array
17007c478bd9Sstevel@tonic-gate  */
17017c478bd9Sstevel@tonic-gate static void
usb_ac_alloc_unit(usb_ac_state_t * uacp,uint_t unit)17027c478bd9Sstevel@tonic-gate usb_ac_alloc_unit(usb_ac_state_t *uacp, uint_t unit)
17037c478bd9Sstevel@tonic-gate {
17047c478bd9Sstevel@tonic-gate 	usb_ac_unit_list_t *old = NULL;
17057c478bd9Sstevel@tonic-gate 	uint_t	max_unit;
17067c478bd9Sstevel@tonic-gate 
17077c478bd9Sstevel@tonic-gate 
17087c478bd9Sstevel@tonic-gate 	if (uacp->usb_ac_units) {
17097c478bd9Sstevel@tonic-gate 		if (unit < uacp->usb_ac_max_unit) {
17107c478bd9Sstevel@tonic-gate 			/* existing array is big enough */
17117c478bd9Sstevel@tonic-gate 
17127c478bd9Sstevel@tonic-gate 			return;
17137c478bd9Sstevel@tonic-gate 		}
17147c478bd9Sstevel@tonic-gate 		old = uacp->usb_ac_units;
17157c478bd9Sstevel@tonic-gate 		max_unit = uacp->usb_ac_max_unit;
17167c478bd9Sstevel@tonic-gate 	}
17177c478bd9Sstevel@tonic-gate 
17187c478bd9Sstevel@tonic-gate 	/* allocate two extra ones */
17197c478bd9Sstevel@tonic-gate 	unit += 2;
17207c478bd9Sstevel@tonic-gate 	uacp->usb_ac_max_unit = unit;
17217c478bd9Sstevel@tonic-gate 	uacp->usb_ac_units = kmem_zalloc(unit *
1722112116d8Sfb 	    sizeof (usb_ac_unit_list_t), KM_SLEEP);
17237c478bd9Sstevel@tonic-gate 
17247c478bd9Sstevel@tonic-gate 	if (old) {
17257c478bd9Sstevel@tonic-gate 		size_t len = max_unit * sizeof (usb_ac_unit_list_t);
17267c478bd9Sstevel@tonic-gate 		bcopy(old, uacp->usb_ac_units, len);
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate 		kmem_free(old, len);
17297c478bd9Sstevel@tonic-gate 	}
17307c478bd9Sstevel@tonic-gate }
17317c478bd9Sstevel@tonic-gate 
17327c478bd9Sstevel@tonic-gate 
17337c478bd9Sstevel@tonic-gate /*
17347c478bd9Sstevel@tonic-gate  * usb_ac_free_all_units:
17357c478bd9Sstevel@tonic-gate  *	free the entire unit list
17367c478bd9Sstevel@tonic-gate  */
17377c478bd9Sstevel@tonic-gate static void
usb_ac_free_all_units(usb_ac_state_t * uacp)17387c478bd9Sstevel@tonic-gate usb_ac_free_all_units(usb_ac_state_t *uacp)
17397c478bd9Sstevel@tonic-gate {
17407c478bd9Sstevel@tonic-gate 	uint_t	unit;
17417c478bd9Sstevel@tonic-gate 	usb_ac_unit_list_t *unitp;
17427c478bd9Sstevel@tonic-gate 
17437c478bd9Sstevel@tonic-gate 	if (uacp->usb_ac_units == NULL) {
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate 		return;
17467c478bd9Sstevel@tonic-gate 	}
17477c478bd9Sstevel@tonic-gate 
17487c478bd9Sstevel@tonic-gate 
17497c478bd9Sstevel@tonic-gate 	for (unit = 0; unit < uacp->usb_ac_max_unit; unit++) {
17507c478bd9Sstevel@tonic-gate 		unitp = &uacp->usb_ac_units[unit];
17517c478bd9Sstevel@tonic-gate 		if (unitp) {
17527c478bd9Sstevel@tonic-gate 			if (unitp->acu_descriptor) {
17537c478bd9Sstevel@tonic-gate 				kmem_free(unitp->acu_descriptor,
1754112116d8Sfb 				    unitp->acu_descr_length);
17557c478bd9Sstevel@tonic-gate 			}
17567c478bd9Sstevel@tonic-gate 		}
17577c478bd9Sstevel@tonic-gate 	}
17587c478bd9Sstevel@tonic-gate 
17597c478bd9Sstevel@tonic-gate 	kmem_free(uacp->usb_ac_units, uacp->usb_ac_max_unit *
1760112116d8Sfb 	    sizeof (usb_ac_unit_list_t));
17617c478bd9Sstevel@tonic-gate }
17627c478bd9Sstevel@tonic-gate 
17637c478bd9Sstevel@tonic-gate 
17647c478bd9Sstevel@tonic-gate /*
17657c478bd9Sstevel@tonic-gate  * usb_ac_lookup_port_type:
17667c478bd9Sstevel@tonic-gate  *	map term type to port type
17677c478bd9Sstevel@tonic-gate  *	default just return LINE_IN + LINE_OUT
17687c478bd9Sstevel@tonic-gate  */
17697c478bd9Sstevel@tonic-gate static int
usb_ac_lookup_port_type(ushort_t termtype)17707c478bd9Sstevel@tonic-gate usb_ac_lookup_port_type(ushort_t termtype)
17717c478bd9Sstevel@tonic-gate {
17727c478bd9Sstevel@tonic-gate 	uint_t i;
17737c478bd9Sstevel@tonic-gate 
1774e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	/*
1775e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	 * Looking for a input/ouput terminal type to match the port
1776e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	 * type, it should not be common streaming type
1777e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	 */
1778e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	ASSERT(termtype != USB_AUDIO_TERM_TYPE_STREAMING);
1779e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
17807c478bd9Sstevel@tonic-gate 	for (i = 0; ; i++) {
17817c478bd9Sstevel@tonic-gate 		if (usb_ac_term_type_map[i].term_type == 0) {
17827c478bd9Sstevel@tonic-gate 
17837c478bd9Sstevel@tonic-gate 			break;
17847c478bd9Sstevel@tonic-gate 		}
17857c478bd9Sstevel@tonic-gate 
17867c478bd9Sstevel@tonic-gate 		if (usb_ac_term_type_map[i].term_type == termtype) {
17877c478bd9Sstevel@tonic-gate 
17887c478bd9Sstevel@tonic-gate 			return (usb_ac_term_type_map[i].port_type);
17897c478bd9Sstevel@tonic-gate 		}
17907c478bd9Sstevel@tonic-gate 	}
17917c478bd9Sstevel@tonic-gate 
1792e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (USB_PORT_UNKNOWN);
17937c478bd9Sstevel@tonic-gate }
17947c478bd9Sstevel@tonic-gate 
17957c478bd9Sstevel@tonic-gate 
17967c478bd9Sstevel@tonic-gate /*
17977c478bd9Sstevel@tonic-gate  * usb_ac_update_port:
17987c478bd9Sstevel@tonic-gate  *	called for each terminal
17997c478bd9Sstevel@tonic-gate  */
18007c478bd9Sstevel@tonic-gate /*ARGSUSED*/
18017c478bd9Sstevel@tonic-gate static int
usb_ac_update_port(usb_ac_state_t * uacp,uint_t id,uint_t dir,uint_t channel,uint_t control,uint_t arg1,uint_t * depth)18027c478bd9Sstevel@tonic-gate usb_ac_update_port(usb_ac_state_t *uacp, uint_t id,
18037c478bd9Sstevel@tonic-gate     uint_t dir, uint_t channel, uint_t control, uint_t arg1, uint_t *depth)
18047c478bd9Sstevel@tonic-gate {
1805e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (dir & USB_AUDIO_PLAY) {
18067c478bd9Sstevel@tonic-gate 		usb_audio_output_term_descr_t *d =
18077c478bd9Sstevel@tonic-gate 		    (usb_audio_output_term_descr_t *)
18087c478bd9Sstevel@tonic-gate 		    uacp->usb_ac_units[id].acu_descriptor;
18097c478bd9Sstevel@tonic-gate 		uint_t port_type =
1810112116d8Sfb 		    usb_ac_lookup_port_type(d->wTerminalType);
18117c478bd9Sstevel@tonic-gate 
18127c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
1813e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_update_port: dir=%d wTerminalType=0x%x, name=%s",
1814e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    dir, d->wTerminalType, usb_audio_dtypes[port_type]);
18157c478bd9Sstevel@tonic-gate 
1816e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		uacp->usb_ac_output_ports |= (1U << port_type);
18177c478bd9Sstevel@tonic-gate 	} else {
1818e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		usb_audio_input_term_descr_t *d =
1819e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    (usb_audio_input_term_descr_t *)
1820112116d8Sfb 		    uacp->usb_ac_units[id].acu_descriptor;
18217c478bd9Sstevel@tonic-gate 		uint_t port_type =
1822112116d8Sfb 		    usb_ac_lookup_port_type(d->wTerminalType);
18237c478bd9Sstevel@tonic-gate 
18247c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
1825e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_update_port: dir=%d wTerminalType=0x%x,  name=%s",
1826e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    dir, d->wTerminalType, usb_audio_dtypes[port_type]);
1827e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
1828e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		uacp->usb_ac_input_ports |= (1U << port_type);
18297c478bd9Sstevel@tonic-gate 
18307c478bd9Sstevel@tonic-gate 	}
18317c478bd9Sstevel@tonic-gate 
18327c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
18337c478bd9Sstevel@tonic-gate }
18347c478bd9Sstevel@tonic-gate 
18357c478bd9Sstevel@tonic-gate 
18367c478bd9Sstevel@tonic-gate /*
18377c478bd9Sstevel@tonic-gate  * usb_ac_map_termtype_to_port:
18387c478bd9Sstevel@tonic-gate  *	starting from a streaming termtype find all
18397c478bd9Sstevel@tonic-gate  *	input or output terminals and OR into uacp->usb_ac_input_ports
18407c478bd9Sstevel@tonic-gate  *	or uacp->usb_ac_output_ports;
18417c478bd9Sstevel@tonic-gate  */
18427c478bd9Sstevel@tonic-gate static void
usb_ac_map_termtype_to_port(usb_ac_state_t * uacp,uint_t dir)18437c478bd9Sstevel@tonic-gate usb_ac_map_termtype_to_port(usb_ac_state_t *uacp, uint_t dir)
18447c478bd9Sstevel@tonic-gate {
18457c478bd9Sstevel@tonic-gate 	uint_t count = 0;
18467c478bd9Sstevel@tonic-gate 	uint_t depth = 0;
1847e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	uint_t search_type = (dir & USB_AUDIO_PLAY) ?
18487c478bd9Sstevel@tonic-gate 	    USB_AUDIO_OUTPUT_TERMINAL : USB_AUDIO_INPUT_TERMINAL;
18497c478bd9Sstevel@tonic-gate 
18507c478bd9Sstevel@tonic-gate 
18517c478bd9Sstevel@tonic-gate 	(void) usb_ac_traverse_all_units(uacp, dir, search_type, 0,
18527c478bd9Sstevel@tonic-gate 	    0, USB_AC_FIND_ALL, &count, 0, &depth, usb_ac_update_port);
18537c478bd9Sstevel@tonic-gate 
18547c478bd9Sstevel@tonic-gate 	ASSERT(depth == 0);
18557c478bd9Sstevel@tonic-gate }
18567c478bd9Sstevel@tonic-gate 
18577c478bd9Sstevel@tonic-gate 
18587c478bd9Sstevel@tonic-gate /*
18597c478bd9Sstevel@tonic-gate  * usb_ac_set_port:
18607c478bd9Sstevel@tonic-gate  *	find a selector port (record side only) and set the
18617c478bd9Sstevel@tonic-gate  *	input to the matching pin
18627c478bd9Sstevel@tonic-gate  */
18637c478bd9Sstevel@tonic-gate static uint_t
usb_ac_set_port(usb_ac_state_t * uacp,uint_t dir,uint_t port)18647c478bd9Sstevel@tonic-gate usb_ac_set_port(usb_ac_state_t *uacp, uint_t dir, uint_t port)
18657c478bd9Sstevel@tonic-gate {
18667c478bd9Sstevel@tonic-gate 	uint_t count = 0;
18677c478bd9Sstevel@tonic-gate 	uint_t id;
18687c478bd9Sstevel@tonic-gate 	uint_t depth = 0;
18697c478bd9Sstevel@tonic-gate 
18707c478bd9Sstevel@tonic-gate 
18717c478bd9Sstevel@tonic-gate 	/* we only support the selector for the record side */
1872e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (dir & USB_AUDIO_RECORD) {
18737c478bd9Sstevel@tonic-gate 		id = usb_ac_traverse_all_units(uacp, dir,
18747c478bd9Sstevel@tonic-gate 		    USB_AUDIO_SELECTOR_UNIT, 0,
18757c478bd9Sstevel@tonic-gate 		    0, USB_AC_FIND_ONE, &count, port, &depth,
18767c478bd9Sstevel@tonic-gate 		    usb_ac_set_selector);
18777c478bd9Sstevel@tonic-gate 
18787c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
18797c478bd9Sstevel@tonic-gate 		    "usb_ac_set_port: id=%d count=%d port=%d",
18807c478bd9Sstevel@tonic-gate 		    id, count, port);
18817c478bd9Sstevel@tonic-gate 
18827c478bd9Sstevel@tonic-gate 		ASSERT(depth == 0);
18837c478bd9Sstevel@tonic-gate 	}
18847c478bd9Sstevel@tonic-gate 
18857c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
18867c478bd9Sstevel@tonic-gate }
18877c478bd9Sstevel@tonic-gate 
18887c478bd9Sstevel@tonic-gate 
18897c478bd9Sstevel@tonic-gate /*
18907c478bd9Sstevel@tonic-gate  * usb_ac_match_port:
18917c478bd9Sstevel@tonic-gate  *	given the requested port type, find a correspondig term type
18927c478bd9Sstevel@tonic-gate  *	Called from usb_ac_traverse_all_units()
18937c478bd9Sstevel@tonic-gate  */
18947c478bd9Sstevel@tonic-gate /*ARGSUSED*/
18957c478bd9Sstevel@tonic-gate static int
usb_ac_match_port(usb_ac_state_t * uacp,uint_t id,uint_t dir,uint_t channel,uint_t control,uint_t arg1,uint_t * depth)18967c478bd9Sstevel@tonic-gate usb_ac_match_port(usb_ac_state_t *uacp, uint_t id,
18977c478bd9Sstevel@tonic-gate     uint_t dir, uint_t channel, uint_t control, uint_t arg1, uint_t *depth)
18987c478bd9Sstevel@tonic-gate {
18997c478bd9Sstevel@tonic-gate 	uint_t port_type;
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate 
1902e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (dir & USB_AUDIO_PLAY) {
19037c478bd9Sstevel@tonic-gate 		usb_audio_output_term_descr_t *d =
19047c478bd9Sstevel@tonic-gate 		    (usb_audio_output_term_descr_t *)
19057c478bd9Sstevel@tonic-gate 		    uacp->usb_ac_units[id].acu_descriptor;
19067c478bd9Sstevel@tonic-gate 		port_type = usb_ac_lookup_port_type(d->wTerminalType);
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
19097c478bd9Sstevel@tonic-gate 		    "usb_ac_match_port: "
19107c478bd9Sstevel@tonic-gate 		    "dir=%d type=0x%x port_type=%d port=%d",
19117c478bd9Sstevel@tonic-gate 		    dir, d->wTerminalType, port_type, arg1);
19127c478bd9Sstevel@tonic-gate 	} else {
19137c478bd9Sstevel@tonic-gate 		usb_audio_output_term_descr_t *d =
1914112116d8Sfb 		    (usb_audio_output_term_descr_t *)
1915112116d8Sfb 		    uacp->usb_ac_units[id].acu_descriptor;
19167c478bd9Sstevel@tonic-gate 		port_type = usb_ac_lookup_port_type(d->wTerminalType);
19177c478bd9Sstevel@tonic-gate 
19187c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
19197c478bd9Sstevel@tonic-gate 		    "usb_ac_match_port: "
19207c478bd9Sstevel@tonic-gate 		    "dir=%d type=0x%x port_type=%d port=%d",
19217c478bd9Sstevel@tonic-gate 		    dir, d->wTerminalType, port_type, arg1);
19227c478bd9Sstevel@tonic-gate 	}
19237c478bd9Sstevel@tonic-gate 
1924e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (((1U << port_type) & arg1) ? USB_SUCCESS : USB_FAILURE);
19257c478bd9Sstevel@tonic-gate }
19267c478bd9Sstevel@tonic-gate 
19277c478bd9Sstevel@tonic-gate 
19287c478bd9Sstevel@tonic-gate /*
19297c478bd9Sstevel@tonic-gate  * usb_ac_set_selector:
19307c478bd9Sstevel@tonic-gate  *	Called from usb_ac_traverse_all_units()
19317c478bd9Sstevel@tonic-gate  *	Find the correct pin and set selector to this pin
19327c478bd9Sstevel@tonic-gate  */
19337c478bd9Sstevel@tonic-gate /*ARGSUSED*/
19347c478bd9Sstevel@tonic-gate static int
usb_ac_set_selector(usb_ac_state_t * uacp,uint_t id,uint_t dir,uint_t channel,uint_t control,uint_t arg1,uint_t * depth)19357c478bd9Sstevel@tonic-gate usb_ac_set_selector(usb_ac_state_t *uacp, uint_t id,
19367c478bd9Sstevel@tonic-gate     uint_t dir, uint_t channel, uint_t control, uint_t arg1, uint_t *depth)
19377c478bd9Sstevel@tonic-gate {
19387c478bd9Sstevel@tonic-gate 	uint_t count = 0;
19397c478bd9Sstevel@tonic-gate 	uint_t unit = USB_AC_ID_NONE;
19407c478bd9Sstevel@tonic-gate 	uint_t pin;
19417c478bd9Sstevel@tonic-gate 	uint_t search_target =
1942e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    (dir & USB_AUDIO_PLAY) ? USB_AUDIO_OUTPUT_TERMINAL :
1943112116d8Sfb 	    USB_AUDIO_INPUT_TERMINAL;
19447c478bd9Sstevel@tonic-gate 	usb_audio_selector_unit_descr1_t *d =
1945112116d8Sfb 	    (usb_audio_selector_unit_descr1_t *)
1946112116d8Sfb 	    uacp->usb_ac_units[id].acu_descriptor;
19477c478bd9Sstevel@tonic-gate 	int n_sourceID = d->bNrInPins;
19487c478bd9Sstevel@tonic-gate 	int rval = USB_FAILURE;
19497c478bd9Sstevel@tonic-gate 
19507c478bd9Sstevel@tonic-gate 
19517c478bd9Sstevel@tonic-gate 	/*
19527c478bd9Sstevel@tonic-gate 	 * for each pin, find a term type that matches the
19537c478bd9Sstevel@tonic-gate 	 * requested port type
19547c478bd9Sstevel@tonic-gate 	 */
19557c478bd9Sstevel@tonic-gate 	for (pin = 0; pin < n_sourceID; pin++) {
19567c478bd9Sstevel@tonic-gate 		if (d->baSourceID[pin] == 0) {
19577c478bd9Sstevel@tonic-gate 
19587c478bd9Sstevel@tonic-gate 			break;
19597c478bd9Sstevel@tonic-gate 		}
19607c478bd9Sstevel@tonic-gate 		unit = d->baSourceID[pin];
19617c478bd9Sstevel@tonic-gate 
19627c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
19637c478bd9Sstevel@tonic-gate 		    "usb_ac_set_selector: pin=%d unit=%d", pin, unit);
19647c478bd9Sstevel@tonic-gate 
19657c478bd9Sstevel@tonic-gate 		if (uacp->usb_ac_unit_type[unit] == search_target) {
19667c478bd9Sstevel@tonic-gate 			if (usb_ac_match_port(uacp, unit, dir, channel,
19677c478bd9Sstevel@tonic-gate 			    control, arg1, depth) == USB_SUCCESS) {
19687c478bd9Sstevel@tonic-gate 
19697c478bd9Sstevel@tonic-gate 				break;
19707c478bd9Sstevel@tonic-gate 			} else {
19717c478bd9Sstevel@tonic-gate 				unit = USB_AC_ID_NONE;
19727c478bd9Sstevel@tonic-gate 
19737c478bd9Sstevel@tonic-gate 				continue;
19747c478bd9Sstevel@tonic-gate 			}
19757c478bd9Sstevel@tonic-gate 		}
19767c478bd9Sstevel@tonic-gate 
19777c478bd9Sstevel@tonic-gate 		/* find units connected to this unit */
19787c478bd9Sstevel@tonic-gate 		unit = usb_ac_traverse_connections(uacp, unit,
1979112116d8Sfb 		    dir, search_target, channel, control,
1980112116d8Sfb 		    USB_AC_FIND_ONE, &count, arg1, depth,
1981112116d8Sfb 		    usb_ac_match_port);
19827c478bd9Sstevel@tonic-gate 
19837c478bd9Sstevel@tonic-gate 		if (unit != USB_AC_ID_NONE) {
19847c478bd9Sstevel@tonic-gate 
19857c478bd9Sstevel@tonic-gate 			break;
19867c478bd9Sstevel@tonic-gate 		}
19877c478bd9Sstevel@tonic-gate 	}
19887c478bd9Sstevel@tonic-gate 
19897c478bd9Sstevel@tonic-gate 
19907c478bd9Sstevel@tonic-gate 	if (unit != USB_AC_ID_NONE) {
19917c478bd9Sstevel@tonic-gate 		mblk_t		*data;
19927c478bd9Sstevel@tonic-gate 		usb_cr_t	cr;
19937c478bd9Sstevel@tonic-gate 		usb_cb_flags_t	cb_flags;
19947c478bd9Sstevel@tonic-gate 
19957c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
19967c478bd9Sstevel@tonic-gate 		    "usb_ac_set_selector: found id=%d at pin %d", unit, pin);
19977c478bd9Sstevel@tonic-gate 
19987c478bd9Sstevel@tonic-gate 		mutex_exit(&uacp->usb_ac_mutex);
19997c478bd9Sstevel@tonic-gate 
2000e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		data = allocb(1, BPRI_HI);
2001e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		if (!data) {
2002e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2003e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			    "usb_ac_set_selector: allocate data failed");
2004e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			mutex_enter(&uacp->usb_ac_mutex);
2005e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
2006e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			return (USB_FAILURE);
2007e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		}
20087c478bd9Sstevel@tonic-gate 
20097c478bd9Sstevel@tonic-gate 		/* pins are 1-based */
20107c478bd9Sstevel@tonic-gate 		*(data->b_rptr) = (char)++pin;
20117c478bd9Sstevel@tonic-gate 
20127c478bd9Sstevel@tonic-gate 		if (usb_pipe_sync_ctrl_xfer(
20137c478bd9Sstevel@tonic-gate 		    uacp->usb_ac_dip,
20147c478bd9Sstevel@tonic-gate 		    uacp->usb_ac_default_ph,
20157c478bd9Sstevel@tonic-gate 		    USB_DEV_REQ_HOST_TO_DEV |
20167c478bd9Sstevel@tonic-gate 		    USB_DEV_REQ_TYPE_CLASS |
20177c478bd9Sstevel@tonic-gate 		    USB_DEV_REQ_RCPT_IF,	/* bmRequestType */
20187c478bd9Sstevel@tonic-gate 		    USB_AUDIO_SET_CUR,		/* bRequest */
20197c478bd9Sstevel@tonic-gate 		    0,				/* wValue */
20207c478bd9Sstevel@tonic-gate 						/* feature unit and id */
20217c478bd9Sstevel@tonic-gate 		    (id << 8)| uacp->usb_ac_ifno, /* wIndex */
20227c478bd9Sstevel@tonic-gate 		    1,				/* wLength */
20237c478bd9Sstevel@tonic-gate 		    &data,
20247c478bd9Sstevel@tonic-gate 		    USB_ATTRS_NONE,
20257c478bd9Sstevel@tonic-gate 		    &cr, &cb_flags,
20267c478bd9Sstevel@tonic-gate 		    USB_FLAGS_SLEEP) == USB_SUCCESS) {
20277c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ALL,
20287c478bd9Sstevel@tonic-gate 			    uacp->usb_ac_log_handle,
20297c478bd9Sstevel@tonic-gate 			    "set current selection: %d", *data->b_rptr);
20307c478bd9Sstevel@tonic-gate 
20317c478bd9Sstevel@tonic-gate 			rval = USB_SUCCESS;
20327c478bd9Sstevel@tonic-gate 		} else {
20337c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_ALL,
20347c478bd9Sstevel@tonic-gate 			    uacp->usb_ac_log_handle,
20357c478bd9Sstevel@tonic-gate 			    "set current pin selection failed");
20367c478bd9Sstevel@tonic-gate 		}
20377c478bd9Sstevel@tonic-gate 		freemsg(data);
20387c478bd9Sstevel@tonic-gate 
20397c478bd9Sstevel@tonic-gate 		mutex_enter(&uacp->usb_ac_mutex);
20407c478bd9Sstevel@tonic-gate 	} else {
20417c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
20427c478bd9Sstevel@tonic-gate 		    "usb_ac_set_selector: nothing found");
20437c478bd9Sstevel@tonic-gate 	}
20447c478bd9Sstevel@tonic-gate 
20457c478bd9Sstevel@tonic-gate 	return (rval);
20467c478bd9Sstevel@tonic-gate }
20477c478bd9Sstevel@tonic-gate 
20487c478bd9Sstevel@tonic-gate 
20497c478bd9Sstevel@tonic-gate /*
20507c478bd9Sstevel@tonic-gate  * usb_ac_set_control:
20517c478bd9Sstevel@tonic-gate  *	apply func to all units of search_target type for both the
20527c478bd9Sstevel@tonic-gate  *	requested channel and master channel
20537c478bd9Sstevel@tonic-gate  */
20547c478bd9Sstevel@tonic-gate static uint_t
usb_ac_set_control(usb_ac_state_t * uacp,uint_t dir,uint_t search_target,uint_t channel,uint_t control,uint_t all_or_one,uint_t * count,uint_t arg1,int (* func)(usb_ac_state_t * uacp,uint_t unit,uint_t dir,uint_t channel,uint_t control,uint_t arg1,uint_t * depth))20557c478bd9Sstevel@tonic-gate usb_ac_set_control(usb_ac_state_t *uacp, uint_t dir, uint_t search_target,
2056*d5ebc493SDan Cross     uint_t channel, uint_t control, uint_t all_or_one,
2057*d5ebc493SDan Cross     uint_t *count, uint_t arg1,
2058*d5ebc493SDan Cross     int (*func)(usb_ac_state_t *uacp, uint_t unit, uint_t dir,
2059*d5ebc493SDan Cross     uint_t channel, uint_t control, uint_t arg1, uint_t *depth))
20607c478bd9Sstevel@tonic-gate {
20617c478bd9Sstevel@tonic-gate 	uint_t id;
20627c478bd9Sstevel@tonic-gate 	uint_t depth = 0;
20637c478bd9Sstevel@tonic-gate 
20647c478bd9Sstevel@tonic-gate 	id = usb_ac_traverse_all_units(uacp, dir, search_target, channel,
20657c478bd9Sstevel@tonic-gate 	    control, all_or_one, count, arg1, &depth, func);
20667c478bd9Sstevel@tonic-gate 
20677c478bd9Sstevel@tonic-gate 	if ((channel != 0) &&
20687c478bd9Sstevel@tonic-gate 	    (((id == USB_AC_ID_NONE) && (all_or_one == USB_AC_FIND_ONE)) ||
20697c478bd9Sstevel@tonic-gate 	    (all_or_one == USB_AC_FIND_ALL)))  {
20707c478bd9Sstevel@tonic-gate 		/* try master channel */
20717c478bd9Sstevel@tonic-gate 		channel = 0;
20727c478bd9Sstevel@tonic-gate 		id = usb_ac_traverse_all_units(uacp, dir, search_target,
2073112116d8Sfb 		    channel, control, all_or_one, count, arg1,
2074112116d8Sfb 		    &depth, func);
20757c478bd9Sstevel@tonic-gate 	}
20767c478bd9Sstevel@tonic-gate 
20777c478bd9Sstevel@tonic-gate 	ASSERT(depth == 0);
20787c478bd9Sstevel@tonic-gate 
20797c478bd9Sstevel@tonic-gate 	return (id);
20807c478bd9Sstevel@tonic-gate }
20817c478bd9Sstevel@tonic-gate 
20827c478bd9Sstevel@tonic-gate 
20837c478bd9Sstevel@tonic-gate /*
20847c478bd9Sstevel@tonic-gate  * usb_ac_traverse_all_units:
20857c478bd9Sstevel@tonic-gate  *	traverse all units starting with all IT or OT depending on direction.
20867c478bd9Sstevel@tonic-gate  *	If no unit is found for the particular channel, try master channel
20877c478bd9Sstevel@tonic-gate  *	If a matching unit is found, apply the function passed by
20887c478bd9Sstevel@tonic-gate  *	the caller
20897c478bd9Sstevel@tonic-gate  */
20907c478bd9Sstevel@tonic-gate static uint_t
usb_ac_traverse_all_units(usb_ac_state_t * uacp,uint_t dir,uint_t search_target,uint_t channel,uint_t control,uint_t all_or_one,uint_t * count,uint_t arg1,uint_t * depth,int (* func)(usb_ac_state_t * uacp,uint_t unit,uint_t dir,uint_t channel,uint_t control,uint_t arg1,uint_t * depth))20917c478bd9Sstevel@tonic-gate usb_ac_traverse_all_units(usb_ac_state_t *uacp, uint_t dir,
2092*d5ebc493SDan Cross     uint_t search_target, uint_t channel, uint_t control,
2093*d5ebc493SDan Cross     uint_t all_or_one, uint_t *count, uint_t arg1, uint_t *depth,
2094*d5ebc493SDan Cross     int (*func)(usb_ac_state_t *uacp, uint_t unit, uint_t dir,
2095*d5ebc493SDan Cross     uint_t channel, uint_t control, uint_t arg1, uint_t *depth))
20967c478bd9Sstevel@tonic-gate {
20977c478bd9Sstevel@tonic-gate 	uint_t unit, start_type, id;
20987c478bd9Sstevel@tonic-gate 
2099e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	start_type = (dir & USB_AUDIO_PLAY) ? USB_AUDIO_INPUT_TERMINAL :
2100112116d8Sfb 	    USB_AUDIO_OUTPUT_TERMINAL;
21017c478bd9Sstevel@tonic-gate 
21027c478bd9Sstevel@tonic-gate 	/* keep track of recursion */
21037c478bd9Sstevel@tonic-gate 	if ((*depth)++ > USB_AC_MAX_DEPTH) {
21047c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
21057c478bd9Sstevel@tonic-gate 		    "Unit topology too complex, giving up");
21067c478bd9Sstevel@tonic-gate 
21077c478bd9Sstevel@tonic-gate 		return (USB_AC_ID_NONE);
21087c478bd9Sstevel@tonic-gate 	}
21097c478bd9Sstevel@tonic-gate 
21107c478bd9Sstevel@tonic-gate 	for (unit = 1; unit < uacp->usb_ac_max_unit; unit++) {
21117c478bd9Sstevel@tonic-gate 		/* is this an IT or OT? */
21127c478bd9Sstevel@tonic-gate 		if (uacp->usb_ac_unit_type[unit] != start_type) {
21137c478bd9Sstevel@tonic-gate 
21147c478bd9Sstevel@tonic-gate 			continue;
21157c478bd9Sstevel@tonic-gate 		}
21167c478bd9Sstevel@tonic-gate 
21177c478bd9Sstevel@tonic-gate 		/* start at streaming term types */
2118e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		if (dir & USB_AUDIO_PLAY) {
21197c478bd9Sstevel@tonic-gate 			usb_audio_input_term_descr_t *d =
21207c478bd9Sstevel@tonic-gate 			    uacp->usb_ac_units[unit].acu_descriptor;
21217c478bd9Sstevel@tonic-gate 			if (d->wTerminalType !=
21227c478bd9Sstevel@tonic-gate 			    USB_AUDIO_TERM_TYPE_STREAMING) {
21237c478bd9Sstevel@tonic-gate 
21247c478bd9Sstevel@tonic-gate 				continue;
21257c478bd9Sstevel@tonic-gate 			}
21267c478bd9Sstevel@tonic-gate 		} else {
21277c478bd9Sstevel@tonic-gate 			usb_audio_output_term_descr_t *d =
21287c478bd9Sstevel@tonic-gate 			    uacp->usb_ac_units[unit].acu_descriptor;
21297c478bd9Sstevel@tonic-gate 			if (d->wTerminalType !=
21307c478bd9Sstevel@tonic-gate 			    USB_AUDIO_TERM_TYPE_STREAMING) {
21317c478bd9Sstevel@tonic-gate 
21327c478bd9Sstevel@tonic-gate 				continue;
21337c478bd9Sstevel@tonic-gate 			}
21347c478bd9Sstevel@tonic-gate 		}
21357c478bd9Sstevel@tonic-gate 
21367c478bd9Sstevel@tonic-gate 		/* find units connected to this unit */
21377c478bd9Sstevel@tonic-gate 		id = usb_ac_traverse_connections(uacp, unit, dir,
21387c478bd9Sstevel@tonic-gate 		    search_target, channel, control, all_or_one, count,
21397c478bd9Sstevel@tonic-gate 		    arg1, depth, func);
21407c478bd9Sstevel@tonic-gate 
21417c478bd9Sstevel@tonic-gate 		if ((all_or_one == USB_AC_FIND_ONE) &&
21427c478bd9Sstevel@tonic-gate 		    (id != USB_AC_ID_NONE)) {
21437c478bd9Sstevel@tonic-gate 			unit = id;
21447c478bd9Sstevel@tonic-gate 
21457c478bd9Sstevel@tonic-gate 			break;
21467c478bd9Sstevel@tonic-gate 		}
21477c478bd9Sstevel@tonic-gate 	}
21487c478bd9Sstevel@tonic-gate 
21497c478bd9Sstevel@tonic-gate 	(*depth)--;
21507c478bd9Sstevel@tonic-gate 
21517c478bd9Sstevel@tonic-gate 	return	((unit < uacp->usb_ac_max_unit) ? unit : USB_AC_ID_NONE);
21527c478bd9Sstevel@tonic-gate }
21537c478bd9Sstevel@tonic-gate 
21547c478bd9Sstevel@tonic-gate 
21557c478bd9Sstevel@tonic-gate /*
21567c478bd9Sstevel@tonic-gate  * usb_ac_set_monitor_gain_control:
21577c478bd9Sstevel@tonic-gate  *	search for a feature unit between output terminal (OT) and
21587c478bd9Sstevel@tonic-gate  *	input terminal. We are looking for a path between
21597c478bd9Sstevel@tonic-gate  *	for example a microphone and a speaker through a feature unit
21607c478bd9Sstevel@tonic-gate  *	and mixer
21617c478bd9Sstevel@tonic-gate  */
21627c478bd9Sstevel@tonic-gate static uint_t
usb_ac_set_monitor_gain_control(usb_ac_state_t * uacp,uint_t dir,uint_t search_target,uint_t channel,uint_t control,uint_t all_or_one,uint_t * count,uint_t arg1,int (* func)(usb_ac_state_t * uacp,uint_t unit,uint_t dir,uint_t channel,uint_t control,uint_t arg1,uint_t * depth))21637c478bd9Sstevel@tonic-gate usb_ac_set_monitor_gain_control(usb_ac_state_t *uacp, uint_t dir,
2164*d5ebc493SDan Cross     uint_t search_target, uint_t channel, uint_t control,
2165*d5ebc493SDan Cross     uint_t all_or_one, uint_t *count, uint_t arg1,
2166*d5ebc493SDan Cross     int (*func)(usb_ac_state_t *uacp, uint_t unit, uint_t dir,
2167*d5ebc493SDan Cross     uint_t channel, uint_t control, uint_t arg1, uint_t *depth))
21687c478bd9Sstevel@tonic-gate {
21697c478bd9Sstevel@tonic-gate 	uint_t unit, id;
21707c478bd9Sstevel@tonic-gate 	uint_t depth = 0;
21717c478bd9Sstevel@tonic-gate 
21727c478bd9Sstevel@tonic-gate 
21737c478bd9Sstevel@tonic-gate 	for (unit = 1; unit < uacp->usb_ac_max_unit; unit++) {
21747c478bd9Sstevel@tonic-gate 		usb_audio_output_term_descr_t *d =
2175112116d8Sfb 		    uacp->usb_ac_units[unit].acu_descriptor;
21767c478bd9Sstevel@tonic-gate 
21777c478bd9Sstevel@tonic-gate 		/* is this an OT and not stream type? */
21787c478bd9Sstevel@tonic-gate 		if ((uacp->usb_ac_unit_type[unit] ==
21797c478bd9Sstevel@tonic-gate 		    USB_AUDIO_OUTPUT_TERMINAL) &&
21807c478bd9Sstevel@tonic-gate 		    (d->wTerminalType != USB_AUDIO_TERM_TYPE_STREAMING)) {
21817c478bd9Sstevel@tonic-gate 
21827c478bd9Sstevel@tonic-gate 			/* find units connected to this unit */
21837c478bd9Sstevel@tonic-gate 			id = usb_ac_traverse_connections(uacp, unit, dir,
21847c478bd9Sstevel@tonic-gate 			    search_target, channel, control, all_or_one, count,
21857c478bd9Sstevel@tonic-gate 			    arg1, &depth, func);
21867c478bd9Sstevel@tonic-gate 
21877c478bd9Sstevel@tonic-gate 			if ((all_or_one == USB_AC_FIND_ONE) &&
21887c478bd9Sstevel@tonic-gate 			    (id != USB_AC_ID_NONE)) {
21897c478bd9Sstevel@tonic-gate 
21907c478bd9Sstevel@tonic-gate 				break;
21917c478bd9Sstevel@tonic-gate 			}
21927c478bd9Sstevel@tonic-gate 		}
21937c478bd9Sstevel@tonic-gate 	}
21947c478bd9Sstevel@tonic-gate 
21957c478bd9Sstevel@tonic-gate 	ASSERT(depth == 0);
21967c478bd9Sstevel@tonic-gate 
21977c478bd9Sstevel@tonic-gate 	return (id);
21987c478bd9Sstevel@tonic-gate }
21997c478bd9Sstevel@tonic-gate 
22007c478bd9Sstevel@tonic-gate 
22017c478bd9Sstevel@tonic-gate /*
22027c478bd9Sstevel@tonic-gate  * usb_ac_push/pop_unit
22037c478bd9Sstevel@tonic-gate  *	add/remove unit ID to the traverse path
22047c478bd9Sstevel@tonic-gate  */
22057c478bd9Sstevel@tonic-gate static void
usb_ac_push_unit_id(usb_ac_state_t * uacp,uint_t unit)22067c478bd9Sstevel@tonic-gate usb_ac_push_unit_id(usb_ac_state_t *uacp, uint_t unit)
22077c478bd9Sstevel@tonic-gate {
2208d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	uacp->usb_ac_traverse_path[uacp->usb_ac_traverse_path_index++] =
2209d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	    (uchar_t)unit;
22107c478bd9Sstevel@tonic-gate 	ASSERT(uacp->usb_ac_traverse_path_index < uacp->usb_ac_max_unit);
22117c478bd9Sstevel@tonic-gate }
22127c478bd9Sstevel@tonic-gate 
22137c478bd9Sstevel@tonic-gate 
2214e272e4c8SBinzi Cao - Sun Microsystems - Beijing China /* ARGSUSED */
22157c478bd9Sstevel@tonic-gate static void
usb_ac_pop_unit_id(usb_ac_state_t * uacp,uint_t unit)22167c478bd9Sstevel@tonic-gate usb_ac_pop_unit_id(usb_ac_state_t *uacp, uint_t unit)
22177c478bd9Sstevel@tonic-gate {
22187c478bd9Sstevel@tonic-gate 	uacp->usb_ac_traverse_path[uacp->usb_ac_traverse_path_index--] = 0;
22197c478bd9Sstevel@tonic-gate }
22207c478bd9Sstevel@tonic-gate 
22217c478bd9Sstevel@tonic-gate 
22227c478bd9Sstevel@tonic-gate /*
22237c478bd9Sstevel@tonic-gate  * usb_ac_show_traverse_path:
22247c478bd9Sstevel@tonic-gate  *	display entire path, just for debugging
22257c478bd9Sstevel@tonic-gate  */
22267c478bd9Sstevel@tonic-gate static void
usb_ac_show_traverse_path(usb_ac_state_t * uacp)22277c478bd9Sstevel@tonic-gate usb_ac_show_traverse_path(usb_ac_state_t *uacp)
22287c478bd9Sstevel@tonic-gate {
22297c478bd9Sstevel@tonic-gate 	int i;
22307c478bd9Sstevel@tonic-gate 
22317c478bd9Sstevel@tonic-gate 	for (i = 0; i < uacp->usb_ac_traverse_path_index; i++) {
22327c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
22337c478bd9Sstevel@tonic-gate 		    "traverse path %d: unit=%d type=%d",
2234112116d8Sfb 		    i, uacp->usb_ac_traverse_path[i],
2235112116d8Sfb 		    uacp->usb_ac_unit_type[uacp->usb_ac_traverse_path[i]]);
22367c478bd9Sstevel@tonic-gate 	}
22377c478bd9Sstevel@tonic-gate }
22387c478bd9Sstevel@tonic-gate 
22397c478bd9Sstevel@tonic-gate 
22407c478bd9Sstevel@tonic-gate /*
22417c478bd9Sstevel@tonic-gate  * usb_ac_check_path:
22427c478bd9Sstevel@tonic-gate  *	check for a specified type in the traverse path
22437c478bd9Sstevel@tonic-gate  */
22447c478bd9Sstevel@tonic-gate static int
usb_ac_check_path(usb_ac_state_t * uacp,uint_t type)22457c478bd9Sstevel@tonic-gate usb_ac_check_path(usb_ac_state_t *uacp, uint_t type)
22467c478bd9Sstevel@tonic-gate {
22477c478bd9Sstevel@tonic-gate 	int i;
22487c478bd9Sstevel@tonic-gate 
22497c478bd9Sstevel@tonic-gate 	for (i = 0; i < uacp->usb_ac_traverse_path_index; i++) {
22507c478bd9Sstevel@tonic-gate 		uint_t unit = uacp->usb_ac_traverse_path[i];
22517c478bd9Sstevel@tonic-gate 
22527c478bd9Sstevel@tonic-gate 		if (uacp->usb_ac_unit_type[unit] == type) {
22537c478bd9Sstevel@tonic-gate 
22547c478bd9Sstevel@tonic-gate 			return (USB_SUCCESS);
22557c478bd9Sstevel@tonic-gate 		}
22567c478bd9Sstevel@tonic-gate 	}
22577c478bd9Sstevel@tonic-gate 
22587c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
22597c478bd9Sstevel@tonic-gate }
22607c478bd9Sstevel@tonic-gate 
22617c478bd9Sstevel@tonic-gate 
22627c478bd9Sstevel@tonic-gate /*
22637c478bd9Sstevel@tonic-gate  * usb_ac_traverse_connections:
22647c478bd9Sstevel@tonic-gate  *	traverse all units and for each unit with the right type, call
22657c478bd9Sstevel@tonic-gate  *	func. If the func returns a success and search == USB_AC_FIND_ONE,
22667c478bd9Sstevel@tonic-gate  *	we are done. If all is set then we continue until we terminate
22677c478bd9Sstevel@tonic-gate  *	and input or output terminal.
22687c478bd9Sstevel@tonic-gate  *	For audio play, we traverse columns starting from an input terminal
22697c478bd9Sstevel@tonic-gate  *	to an output terminal while for record we traverse rows from output
22707c478bd9Sstevel@tonic-gate  *	terminal to input terminal.
22717c478bd9Sstevel@tonic-gate  */
22727c478bd9Sstevel@tonic-gate static uint_t
usb_ac_traverse_connections(usb_ac_state_t * uacp,uint_t start_unit,uint_t dir,uint_t search_target,uint_t channel,uint_t control,uint_t all_or_one,uint_t * count,uint_t arg1,uint_t * depth,int (* func)(usb_ac_state_t * uacp,uint_t unit,uint_t dir,uint_t channel,uint_t control,uint_t arg1,uint_t * depth))22737c478bd9Sstevel@tonic-gate usb_ac_traverse_connections(usb_ac_state_t *uacp, uint_t start_unit, uint_t dir,
2274*d5ebc493SDan Cross     uint_t search_target, uint_t channel, uint_t control,
2275*d5ebc493SDan Cross     uint_t all_or_one, uint_t *count, uint_t arg1, uint_t *depth,
2276*d5ebc493SDan Cross     int (*func)(usb_ac_state_t *uacp, uint_t unit, uint_t dir,
2277*d5ebc493SDan Cross     uint_t channel, uint_t control, uint_t arg1, uint_t *depth))
22787c478bd9Sstevel@tonic-gate {
22797c478bd9Sstevel@tonic-gate 	uint_t unit, id;
2280e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	uint_t done = (dir & USB_AUDIO_PLAY) ? USB_AUDIO_OUTPUT_TERMINAL :
2281112116d8Sfb 	    USB_AUDIO_INPUT_TERMINAL;
22827c478bd9Sstevel@tonic-gate 
22837c478bd9Sstevel@tonic-gate 
22847c478bd9Sstevel@tonic-gate 	/* keep track of recursion depth */
22857c478bd9Sstevel@tonic-gate 	if ((*depth)++ > USB_AC_MAX_DEPTH) {
22867c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
22877c478bd9Sstevel@tonic-gate 		    "Unit topology too complex, giving up");
22887c478bd9Sstevel@tonic-gate 
22897c478bd9Sstevel@tonic-gate 		return (USB_AC_ID_NONE);
22907c478bd9Sstevel@tonic-gate 	}
22917c478bd9Sstevel@tonic-gate 
22927c478bd9Sstevel@tonic-gate 	usb_ac_push_unit_id(uacp, start_unit);
22937c478bd9Sstevel@tonic-gate 
22947c478bd9Sstevel@tonic-gate 	for (unit = 1; unit < uacp->usb_ac_max_unit; unit++) {
2295e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		uint_t entry = (dir & USB_AUDIO_PLAY) ?
2296112116d8Sfb 		    uacp->usb_ac_connections[unit][start_unit] :
2297112116d8Sfb 		    uacp->usb_ac_connections[start_unit][unit];
22987c478bd9Sstevel@tonic-gate 
22997c478bd9Sstevel@tonic-gate 		if (entry) {
23007c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_ALL,
23017c478bd9Sstevel@tonic-gate 			    uacp->usb_ac_log_handle,
23027c478bd9Sstevel@tonic-gate 			    "start=%d unit=%d entry=%d type=%d "
23037c478bd9Sstevel@tonic-gate 			    "done=%d found=%d",
23047c478bd9Sstevel@tonic-gate 			    start_unit, unit, entry, search_target, done,
23057c478bd9Sstevel@tonic-gate 			    uacp->usb_ac_unit_type[unit]);
23067c478bd9Sstevel@tonic-gate 
23077c478bd9Sstevel@tonic-gate 			/* did we find a matching type? */
23087c478bd9Sstevel@tonic-gate 			if (uacp->usb_ac_unit_type[unit] == search_target) {
23097c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L3(PRINT_MASK_ALL,
23107c478bd9Sstevel@tonic-gate 				    uacp->usb_ac_log_handle,
23117c478bd9Sstevel@tonic-gate 				    "match: dir=%d unit=%d type=%d",
23127c478bd9Sstevel@tonic-gate 				    dir, unit, search_target);
23137c478bd9Sstevel@tonic-gate 
23147c478bd9Sstevel@tonic-gate 				/* yes, no apply function to this unit */
23157c478bd9Sstevel@tonic-gate 				if (func(uacp, unit, dir, channel,
23167c478bd9Sstevel@tonic-gate 				    control, arg1, depth) == USB_SUCCESS) {
23177c478bd9Sstevel@tonic-gate 					(*count)++;
23187c478bd9Sstevel@tonic-gate 
23197c478bd9Sstevel@tonic-gate 					USB_DPRINTF_L3(PRINT_MASK_ALL,
23207c478bd9Sstevel@tonic-gate 					    uacp->usb_ac_log_handle,
23217c478bd9Sstevel@tonic-gate 					    "func returned success, "
23227c478bd9Sstevel@tonic-gate 					    "unit=%d all=%d", unit,
23237c478bd9Sstevel@tonic-gate 					    all_or_one);
23247c478bd9Sstevel@tonic-gate 
23257c478bd9Sstevel@tonic-gate 					/* are we done? */
23267c478bd9Sstevel@tonic-gate 					if (all_or_one == USB_AC_FIND_ONE) {
23277c478bd9Sstevel@tonic-gate 
23287c478bd9Sstevel@tonic-gate 						break;
23297c478bd9Sstevel@tonic-gate 					}
23307c478bd9Sstevel@tonic-gate 				}
23317c478bd9Sstevel@tonic-gate 			}
23327c478bd9Sstevel@tonic-gate 
23337c478bd9Sstevel@tonic-gate 			/* did we find the terminating unit */
23347c478bd9Sstevel@tonic-gate 			if (uacp->usb_ac_unit_type[unit] == done) {
23357c478bd9Sstevel@tonic-gate 
23367c478bd9Sstevel@tonic-gate 				continue;
23377c478bd9Sstevel@tonic-gate 			}
23387c478bd9Sstevel@tonic-gate 			id = usb_ac_traverse_connections(uacp, unit, dir,
2339112116d8Sfb 			    search_target, channel, control,
2340112116d8Sfb 			    all_or_one, count, arg1, depth, func);
23417c478bd9Sstevel@tonic-gate 			if ((id != USB_AC_ID_NONE) &&
23427c478bd9Sstevel@tonic-gate 			    (all_or_one == USB_AC_FIND_ONE)) {
23437c478bd9Sstevel@tonic-gate 				unit = id;
23447c478bd9Sstevel@tonic-gate 
23457c478bd9Sstevel@tonic-gate 				break;
23467c478bd9Sstevel@tonic-gate 			}
23477c478bd9Sstevel@tonic-gate 		}
23487c478bd9Sstevel@tonic-gate 	}
23497c478bd9Sstevel@tonic-gate 
23507c478bd9Sstevel@tonic-gate 	(*depth)--;
23517c478bd9Sstevel@tonic-gate 	usb_ac_pop_unit_id(uacp, start_unit);
23527c478bd9Sstevel@tonic-gate 
23537c478bd9Sstevel@tonic-gate 	return	((unit < uacp->usb_ac_max_unit) ? unit : USB_AC_ID_NONE);
23547c478bd9Sstevel@tonic-gate }
23557c478bd9Sstevel@tonic-gate 
23567c478bd9Sstevel@tonic-gate 
23577c478bd9Sstevel@tonic-gate /*
23587c478bd9Sstevel@tonic-gate  * Event Management
23597c478bd9Sstevel@tonic-gate  *
23607c478bd9Sstevel@tonic-gate  * usb_ac_disconnect_event_cb:
23617c478bd9Sstevel@tonic-gate  *	The device has been disconnected. we either wait for
23627c478bd9Sstevel@tonic-gate  *	detach or a reconnect event.
23637c478bd9Sstevel@tonic-gate  */
23647c478bd9Sstevel@tonic-gate static int
usb_ac_disconnect_event_cb(dev_info_t * dip)23657c478bd9Sstevel@tonic-gate usb_ac_disconnect_event_cb(dev_info_t *dip)
23667c478bd9Sstevel@tonic-gate {
23677c478bd9Sstevel@tonic-gate 	usb_ac_state_t *uacp = (usb_ac_state_t *)ddi_get_soft_state(
23687c478bd9Sstevel@tonic-gate 	    usb_ac_statep, ddi_get_instance(dip));
23697c478bd9Sstevel@tonic-gate 
23701cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_EVENTS, uacp->usb_ac_log_handle,
23711cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_disconnect_event_cb:start");
23727c478bd9Sstevel@tonic-gate 
23737c478bd9Sstevel@tonic-gate 	usb_ac_serialize_access(uacp);
2374e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&uacp->usb_ac_mutex);
23757c478bd9Sstevel@tonic-gate 
23767c478bd9Sstevel@tonic-gate 	/* setting to disconnect state will prevent replumbing */
23777c478bd9Sstevel@tonic-gate 	uacp->usb_ac_dev_state = USB_DEV_DISCONNECTED;
23787c478bd9Sstevel@tonic-gate 
23797c478bd9Sstevel@tonic-gate 	if (uacp->usb_ac_busy_count) {
23807c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L0(PRINT_MASK_EVENTS, uacp->usb_ac_log_handle,
23817c478bd9Sstevel@tonic-gate 		    "device was disconnected while busy. "
23827c478bd9Sstevel@tonic-gate 		    "Data may have been lost");
23837c478bd9Sstevel@tonic-gate 	}
23847c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
23857c478bd9Sstevel@tonic-gate 
23867c478bd9Sstevel@tonic-gate 	usb_ac_release_access(uacp);
23871cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_EVENTS, uacp->usb_ac_log_handle,
23881cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_disconnect_event_cb:done");
23891cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 
23907c478bd9Sstevel@tonic-gate 
23917c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
23927c478bd9Sstevel@tonic-gate }
23937c478bd9Sstevel@tonic-gate 
23947c478bd9Sstevel@tonic-gate 
23957c478bd9Sstevel@tonic-gate /*
23967c478bd9Sstevel@tonic-gate  * usb_ac_cpr_suspend:
23977c478bd9Sstevel@tonic-gate  */
23987c478bd9Sstevel@tonic-gate static int
usb_ac_cpr_suspend(dev_info_t * dip)23997c478bd9Sstevel@tonic-gate usb_ac_cpr_suspend(dev_info_t *dip)
24007c478bd9Sstevel@tonic-gate {
24017c478bd9Sstevel@tonic-gate 	usb_ac_state_t *uacp = (usb_ac_state_t *)ddi_get_soft_state(
24027c478bd9Sstevel@tonic-gate 	    usb_ac_statep, ddi_get_instance(dip));
24037c478bd9Sstevel@tonic-gate 
24047c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
24057c478bd9Sstevel@tonic-gate 	    "usb_ac_cpr_suspend: Begin");
24067c478bd9Sstevel@tonic-gate 
24077c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
24087c478bd9Sstevel@tonic-gate 	uacp->usb_ac_dev_state = USB_DEV_SUSPENDED;
24097c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
24107c478bd9Sstevel@tonic-gate 
24117c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
24127c478bd9Sstevel@tonic-gate 	    "usb_ac_cpr_suspend: End");
24137c478bd9Sstevel@tonic-gate 
24147c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
24157c478bd9Sstevel@tonic-gate }
24167c478bd9Sstevel@tonic-gate 
24177c478bd9Sstevel@tonic-gate 
24187c478bd9Sstevel@tonic-gate 
24197c478bd9Sstevel@tonic-gate /*
24207c478bd9Sstevel@tonic-gate  * usb_ac_reconnect_event_cb:
24217c478bd9Sstevel@tonic-gate  *	The device was disconnected but this instance not detached, probably
24227c478bd9Sstevel@tonic-gate  *	because the device was busy.
24237c478bd9Sstevel@tonic-gate  *	if the same device, continue with restoring state
24247c478bd9Sstevel@tonic-gate  *	We should either be in the unplumbed state or the plumbed open
24257c478bd9Sstevel@tonic-gate  *	state.
24267c478bd9Sstevel@tonic-gate  */
24277c478bd9Sstevel@tonic-gate static int
usb_ac_reconnect_event_cb(dev_info_t * dip)24287c478bd9Sstevel@tonic-gate usb_ac_reconnect_event_cb(dev_info_t *dip)
24297c478bd9Sstevel@tonic-gate {
24307c478bd9Sstevel@tonic-gate 	usb_ac_state_t *uacp = (usb_ac_state_t *)ddi_get_soft_state(
24317c478bd9Sstevel@tonic-gate 	    usb_ac_statep, ddi_get_instance(dip));
24327c478bd9Sstevel@tonic-gate 
24331cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_EVENTS, uacp->usb_ac_log_handle,
24341cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_reconnect_event_cb:begain");
24357c478bd9Sstevel@tonic-gate 
24367c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
24377c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
24387c478bd9Sstevel@tonic-gate 
24397c478bd9Sstevel@tonic-gate 	usb_ac_serialize_access(uacp);
24407c478bd9Sstevel@tonic-gate 
24417c478bd9Sstevel@tonic-gate 	/* check the plumbing state */
24427c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
24437c478bd9Sstevel@tonic-gate 	uacp->usb_ac_busy_count++;
24447c478bd9Sstevel@tonic-gate 	if (uacp->usb_ac_plumbing_state ==
24457c478bd9Sstevel@tonic-gate 	    USB_AC_STATE_PLUMBED) {
24467c478bd9Sstevel@tonic-gate 		mutex_exit(&uacp->usb_ac_mutex);
24477c478bd9Sstevel@tonic-gate 		usb_ac_restore_device_state(dip, uacp);
24487c478bd9Sstevel@tonic-gate 		mutex_enter(&uacp->usb_ac_mutex);
24497c478bd9Sstevel@tonic-gate 	}
24507c478bd9Sstevel@tonic-gate 	uacp->usb_ac_busy_count--;
24517c478bd9Sstevel@tonic-gate 
24527c478bd9Sstevel@tonic-gate 	if (uacp->usb_ac_busy_count) {
24537c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L0(PRINT_MASK_EVENTS, uacp->usb_ac_log_handle,
24547c478bd9Sstevel@tonic-gate 		    "busy device has been reconnected");
24557c478bd9Sstevel@tonic-gate 	}
245688447a05SGarrett D'Amore 
24577c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
24587c478bd9Sstevel@tonic-gate 
24597c478bd9Sstevel@tonic-gate 	usb_ac_release_access(uacp);
24601cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_EVENTS, uacp->usb_ac_log_handle,
24611cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_reconnect_event_cb:done");
24627c478bd9Sstevel@tonic-gate 
24637c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
24647c478bd9Sstevel@tonic-gate }
24657c478bd9Sstevel@tonic-gate 
24667c478bd9Sstevel@tonic-gate 
24677c478bd9Sstevel@tonic-gate /*
24687c478bd9Sstevel@tonic-gate  * usb_ac_cpr_resume:
24697c478bd9Sstevel@tonic-gate  *	Restore device state
24707c478bd9Sstevel@tonic-gate  */
24717c478bd9Sstevel@tonic-gate static void
usb_ac_cpr_resume(dev_info_t * dip)24727c478bd9Sstevel@tonic-gate usb_ac_cpr_resume(dev_info_t *dip)
24737c478bd9Sstevel@tonic-gate {
24747c478bd9Sstevel@tonic-gate 	usb_ac_state_t *uacp = (usb_ac_state_t *)ddi_get_soft_state(
24757c478bd9Sstevel@tonic-gate 	    usb_ac_statep, ddi_get_instance(dip));
24767c478bd9Sstevel@tonic-gate 
24777c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_EVENTS, uacp->usb_ac_log_handle,
24787c478bd9Sstevel@tonic-gate 	    "usb_ac_cpr_resume");
24797c478bd9Sstevel@tonic-gate 
24807c478bd9Sstevel@tonic-gate 	usb_ac_serialize_access(uacp);
24817c478bd9Sstevel@tonic-gate 
24827c478bd9Sstevel@tonic-gate 	usb_ac_restore_device_state(dip, uacp);
24837c478bd9Sstevel@tonic-gate 
24847c478bd9Sstevel@tonic-gate 	usb_ac_release_access(uacp);
24857c478bd9Sstevel@tonic-gate }
24867c478bd9Sstevel@tonic-gate 
24877c478bd9Sstevel@tonic-gate 
24887c478bd9Sstevel@tonic-gate /*
24897c478bd9Sstevel@tonic-gate  * usb_ac_restore_device_state:
24907c478bd9Sstevel@tonic-gate  *	Set original configuration of the device
24917c478bd9Sstevel@tonic-gate  *	enable wrq - this starts new transactions on the control pipe
24927c478bd9Sstevel@tonic-gate  */
24937c478bd9Sstevel@tonic-gate static void
usb_ac_restore_device_state(dev_info_t * dip,usb_ac_state_t * uacp)24947c478bd9Sstevel@tonic-gate usb_ac_restore_device_state(dev_info_t *dip, usb_ac_state_t *uacp)
24957c478bd9Sstevel@tonic-gate {
24967c478bd9Sstevel@tonic-gate 	usb_ac_power_t	*uacpm;
24977c478bd9Sstevel@tonic-gate 	int	rval;
24987c478bd9Sstevel@tonic-gate 
24997c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
25007c478bd9Sstevel@tonic-gate 	    "usb_ac_restore_device_state:");
25017c478bd9Sstevel@tonic-gate 
25027c478bd9Sstevel@tonic-gate 	usb_ac_pm_busy_component(uacp);
25037c478bd9Sstevel@tonic-gate 	(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
25047c478bd9Sstevel@tonic-gate 
25057c478bd9Sstevel@tonic-gate 	/* Check if we are talking to the same device */
25067c478bd9Sstevel@tonic-gate 	if (usb_check_same_device(dip, uacp->usb_ac_log_handle,
25077c478bd9Sstevel@tonic-gate 	    USB_LOG_L0, PRINT_MASK_ALL,
25087c478bd9Sstevel@tonic-gate 	    USB_CHK_BASIC|USB_CHK_CFG, NULL) != USB_SUCCESS) {
25097c478bd9Sstevel@tonic-gate 		usb_ac_pm_idle_component(uacp);
25107c478bd9Sstevel@tonic-gate 
25117c478bd9Sstevel@tonic-gate 		/* change the device state from suspended to disconnected */
25127c478bd9Sstevel@tonic-gate 		mutex_enter(&uacp->usb_ac_mutex);
25137c478bd9Sstevel@tonic-gate 		uacp->usb_ac_dev_state = USB_DEV_DISCONNECTED;
25147c478bd9Sstevel@tonic-gate 		mutex_exit(&uacp->usb_ac_mutex);
25157c478bd9Sstevel@tonic-gate 
25167c478bd9Sstevel@tonic-gate 		return;
25177c478bd9Sstevel@tonic-gate 	}
25187c478bd9Sstevel@tonic-gate 
25197c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
25207c478bd9Sstevel@tonic-gate 	uacpm = uacp->usb_ac_pm;
25217c478bd9Sstevel@tonic-gate 	if (uacpm) {
25227c478bd9Sstevel@tonic-gate 		if (uacpm->acpm_wakeup_enabled) {
25237c478bd9Sstevel@tonic-gate 			mutex_exit(&uacp->usb_ac_mutex);
25247c478bd9Sstevel@tonic-gate 
25257c478bd9Sstevel@tonic-gate 			if ((rval = usb_handle_remote_wakeup(uacp->usb_ac_dip,
25267c478bd9Sstevel@tonic-gate 			    USB_REMOTE_WAKEUP_ENABLE)) != USB_SUCCESS) {
25277c478bd9Sstevel@tonic-gate 
25287c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L4(PRINT_MASK_ATTA,
25297c478bd9Sstevel@tonic-gate 				    uacp->usb_ac_log_handle,
25307c478bd9Sstevel@tonic-gate 				    "usb_ac_restore_device_state: "
25317c478bd9Sstevel@tonic-gate 				    "remote wakeup "
25327c478bd9Sstevel@tonic-gate 				    "enable failed, rval=%d", rval);
25337c478bd9Sstevel@tonic-gate 			}
25347c478bd9Sstevel@tonic-gate 
25357c478bd9Sstevel@tonic-gate 			mutex_enter(&uacp->usb_ac_mutex);
25367c478bd9Sstevel@tonic-gate 		}
25377c478bd9Sstevel@tonic-gate 	}
25387c478bd9Sstevel@tonic-gate 
25397c478bd9Sstevel@tonic-gate 	/* prevent unplumbing */
25407c478bd9Sstevel@tonic-gate 	uacp->usb_ac_busy_count++;
25417c478bd9Sstevel@tonic-gate 	uacp->usb_ac_dev_state = USB_DEV_ONLINE;
25427c478bd9Sstevel@tonic-gate 	if (uacp->usb_ac_plumbing_state == USB_AC_STATE_PLUMBED) {
25437c478bd9Sstevel@tonic-gate 		(void) usb_ac_restore_audio_state(uacp, 0);
25447c478bd9Sstevel@tonic-gate 	}
25457c478bd9Sstevel@tonic-gate 	uacp->usb_ac_busy_count--;
25467c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
25477c478bd9Sstevel@tonic-gate 	usb_ac_pm_idle_component(uacp);
25487c478bd9Sstevel@tonic-gate }
25497c478bd9Sstevel@tonic-gate 
25507c478bd9Sstevel@tonic-gate 
25517c478bd9Sstevel@tonic-gate /*
25527c478bd9Sstevel@tonic-gate  * usb_ac_am_restore_state
25537c478bd9Sstevel@tonic-gate  */
25547c478bd9Sstevel@tonic-gate static void
usb_ac_am_restore_state(void * arg)25557c478bd9Sstevel@tonic-gate usb_ac_am_restore_state(void *arg)
25567c478bd9Sstevel@tonic-gate {
25577c478bd9Sstevel@tonic-gate 	usb_ac_state_t *uacp = (usb_ac_state_t *)arg;
25587c478bd9Sstevel@tonic-gate 
25597c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
25607c478bd9Sstevel@tonic-gate 	    "usb_ac_am_restore_state: Begin");
25617c478bd9Sstevel@tonic-gate 
25627c478bd9Sstevel@tonic-gate 	usb_ac_serialize_access(uacp);
25637c478bd9Sstevel@tonic-gate 
25647c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
25657c478bd9Sstevel@tonic-gate 
25667c478bd9Sstevel@tonic-gate 	if (uacp->usb_ac_plumbing_state ==
25677c478bd9Sstevel@tonic-gate 	    USB_AC_STATE_PLUMBED_RESTORING) {
25687c478bd9Sstevel@tonic-gate 		mutex_exit(&uacp->usb_ac_mutex);
25697c478bd9Sstevel@tonic-gate 
25707c478bd9Sstevel@tonic-gate 		/*
25717c478bd9Sstevel@tonic-gate 		 * allow hid and usb_as to restore themselves
25727c478bd9Sstevel@tonic-gate 		 * (some handshake would have been preferable though)
25737c478bd9Sstevel@tonic-gate 		 */
25747c478bd9Sstevel@tonic-gate 		delay(USB_AC_RESTORE_DELAY);
25757c478bd9Sstevel@tonic-gate 
2576e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		usb_restore_engine(uacp);
25777c478bd9Sstevel@tonic-gate 
25787c478bd9Sstevel@tonic-gate 		mutex_enter(&uacp->usb_ac_mutex);
25797c478bd9Sstevel@tonic-gate 		uacp->usb_ac_plumbing_state = USB_AC_STATE_PLUMBED;
25807c478bd9Sstevel@tonic-gate 	}
25817c478bd9Sstevel@tonic-gate 
25827c478bd9Sstevel@tonic-gate 	/* allow unplumbing */
25837c478bd9Sstevel@tonic-gate 	uacp->usb_ac_busy_count--;
25847c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
25857c478bd9Sstevel@tonic-gate 
25867c478bd9Sstevel@tonic-gate 	usb_ac_release_access(uacp);
25877c478bd9Sstevel@tonic-gate 
25887c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
25897c478bd9Sstevel@tonic-gate 	    "usb_ac_am_restore_state: End");
25907c478bd9Sstevel@tonic-gate }
25917c478bd9Sstevel@tonic-gate 
25927c478bd9Sstevel@tonic-gate 
25937c478bd9Sstevel@tonic-gate /*
25947c478bd9Sstevel@tonic-gate  * usb_ac_restore_audio_state:
25957c478bd9Sstevel@tonic-gate  */
25967c478bd9Sstevel@tonic-gate static int
usb_ac_restore_audio_state(usb_ac_state_t * uacp,int flag)25977c478bd9Sstevel@tonic-gate usb_ac_restore_audio_state(usb_ac_state_t *uacp, int flag)
25987c478bd9Sstevel@tonic-gate {
25997c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&uacp->usb_ac_mutex));
26007c478bd9Sstevel@tonic-gate 
26017c478bd9Sstevel@tonic-gate 
26027c478bd9Sstevel@tonic-gate 	switch (uacp->usb_ac_plumbing_state) {
26037c478bd9Sstevel@tonic-gate 	case USB_AC_STATE_PLUMBED:
26047c478bd9Sstevel@tonic-gate 		uacp->usb_ac_plumbing_state =
2605112116d8Sfb 		    USB_AC_STATE_PLUMBED_RESTORING;
26067c478bd9Sstevel@tonic-gate 
26077c478bd9Sstevel@tonic-gate 		break;
26087c478bd9Sstevel@tonic-gate 	case USB_AC_STATE_UNPLUMBED:
26097c478bd9Sstevel@tonic-gate 
26107c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
26117c478bd9Sstevel@tonic-gate 	case USB_AC_STATE_PLUMBED_RESTORING:
26127c478bd9Sstevel@tonic-gate 	default:
26137c478bd9Sstevel@tonic-gate 
26147c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
26157c478bd9Sstevel@tonic-gate 	}
26167c478bd9Sstevel@tonic-gate 
26177c478bd9Sstevel@tonic-gate 	/*
26187c478bd9Sstevel@tonic-gate 	 * increment busy_count again, it will be decremented
26197c478bd9Sstevel@tonic-gate 	 * in usb_ac_am_restore_state
26207c478bd9Sstevel@tonic-gate 	 */
26217c478bd9Sstevel@tonic-gate 	uacp->usb_ac_busy_count++;
26227c478bd9Sstevel@tonic-gate 
26237c478bd9Sstevel@tonic-gate 	if (flag & USB_FLAGS_SLEEP) {
26247c478bd9Sstevel@tonic-gate 		mutex_exit(&uacp->usb_ac_mutex);
26257c478bd9Sstevel@tonic-gate 		usb_ac_am_restore_state((void *)uacp);
26267c478bd9Sstevel@tonic-gate 		mutex_enter(&uacp->usb_ac_mutex);
26277c478bd9Sstevel@tonic-gate 	} else {
26287c478bd9Sstevel@tonic-gate 		mutex_exit(&uacp->usb_ac_mutex);
26297c478bd9Sstevel@tonic-gate 		if (usb_async_req(uacp->usb_ac_dip,
26307c478bd9Sstevel@tonic-gate 		    usb_ac_am_restore_state,
26317c478bd9Sstevel@tonic-gate 		    (void *)uacp, USB_FLAGS_SLEEP) != USB_SUCCESS) {
26327c478bd9Sstevel@tonic-gate 
26337c478bd9Sstevel@tonic-gate 			mutex_enter(&uacp->usb_ac_mutex);
26347c478bd9Sstevel@tonic-gate 			uacp->usb_ac_busy_count--;
26357c478bd9Sstevel@tonic-gate 
26367c478bd9Sstevel@tonic-gate 			return (USB_FAILURE);
26377c478bd9Sstevel@tonic-gate 		}
26387c478bd9Sstevel@tonic-gate 		mutex_enter(&uacp->usb_ac_mutex);
26397c478bd9Sstevel@tonic-gate 	}
26407c478bd9Sstevel@tonic-gate 
26417c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
26427c478bd9Sstevel@tonic-gate }
26437c478bd9Sstevel@tonic-gate 
26447c478bd9Sstevel@tonic-gate 
26457c478bd9Sstevel@tonic-gate /*
26467c478bd9Sstevel@tonic-gate  * Mixer Callback Management
26477c478bd9Sstevel@tonic-gate  * NOTE: all mixer callbacks are serialized. we cannot be closed while
26487c478bd9Sstevel@tonic-gate  *	we are in the middle of a callback. There needs to be a
26497c478bd9Sstevel@tonic-gate  *	teardown first. We cannot be unplumbed as long as we are
26507c478bd9Sstevel@tonic-gate  *	still open.
26517c478bd9Sstevel@tonic-gate  *
26527c478bd9Sstevel@tonic-gate  * usb_ac_setup:
26537c478bd9Sstevel@tonic-gate  *	Send setup to usb_as if the first setup
26547c478bd9Sstevel@tonic-gate  *	Check power is done in usb_ac_send_as_cmd()
26557c478bd9Sstevel@tonic-gate  */
26567c478bd9Sstevel@tonic-gate static int
usb_ac_setup(usb_ac_state_t * uacp,usb_audio_eng_t * engine)2657e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_ac_setup(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
26587c478bd9Sstevel@tonic-gate {
2659e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int	rval = USB_SUCCESS;
26607c478bd9Sstevel@tonic-gate 
26617c478bd9Sstevel@tonic-gate 
26627c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
266388447a05SGarrett D'Amore 
26647c478bd9Sstevel@tonic-gate 	if (uacp->usb_ac_dev_state != USB_DEV_ONLINE) {
26657c478bd9Sstevel@tonic-gate 		mutex_exit(&uacp->usb_ac_mutex);
26667c478bd9Sstevel@tonic-gate 
2667e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return (USB_FAILURE);
26687c478bd9Sstevel@tonic-gate 	}
26697c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
26707c478bd9Sstevel@tonic-gate 
26717c478bd9Sstevel@tonic-gate 	usb_ac_serialize_access(uacp);
26727c478bd9Sstevel@tonic-gate 
26737c478bd9Sstevel@tonic-gate 
2674e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	rval = usb_ac_do_setup(uacp, engine);
26757c478bd9Sstevel@tonic-gate 
26767c478bd9Sstevel@tonic-gate 	usb_ac_release_access(uacp);
26777c478bd9Sstevel@tonic-gate 
2678e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (rval);
26797c478bd9Sstevel@tonic-gate }
26807c478bd9Sstevel@tonic-gate 
26817c478bd9Sstevel@tonic-gate 
26827c478bd9Sstevel@tonic-gate /*
26837c478bd9Sstevel@tonic-gate  * usb_ac_do_setup:
26847c478bd9Sstevel@tonic-gate  *	Wrapper function for usb_ac_setup which can be called
26857c478bd9Sstevel@tonic-gate  *	either from audio framework for usb_ac_set_format
26867c478bd9Sstevel@tonic-gate  */
26877c478bd9Sstevel@tonic-gate static int
usb_ac_do_setup(usb_ac_state_t * uacp,usb_audio_eng_t * engine)2688e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_ac_do_setup(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
26897c478bd9Sstevel@tonic-gate {
26907c478bd9Sstevel@tonic-gate 	usb_ac_streams_info_t	*streams_infop = NULL;
26917c478bd9Sstevel@tonic-gate 
26927c478bd9Sstevel@tonic-gate 
26937c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
26947c478bd9Sstevel@tonic-gate 
26957c478bd9Sstevel@tonic-gate 
2696e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	streams_infop = (usb_ac_streams_info_t *)engine->streams;
26977c478bd9Sstevel@tonic-gate 
26987c478bd9Sstevel@tonic-gate 	/*
26997c478bd9Sstevel@tonic-gate 	 * Handle multiple setup calls. Pass the setup call to usb_as only
27007c478bd9Sstevel@tonic-gate 	 * the first time so isoc pipe will be opened only once
27017c478bd9Sstevel@tonic-gate 	 */
27027c478bd9Sstevel@tonic-gate 	if (streams_infop->acs_setup_teardown_count++) {
27037c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
27047c478bd9Sstevel@tonic-gate 		    "usb_ac_do_setup: more than one setup, cnt=%d",
27057c478bd9Sstevel@tonic-gate 		    streams_infop->acs_setup_teardown_count);
27067c478bd9Sstevel@tonic-gate 
27077c478bd9Sstevel@tonic-gate 		mutex_exit(&uacp->usb_ac_mutex);
27087c478bd9Sstevel@tonic-gate 
27097c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
27107c478bd9Sstevel@tonic-gate 	}
27117c478bd9Sstevel@tonic-gate 
27127c478bd9Sstevel@tonic-gate 	/* Send setup command to usb_as */
2713e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_SETUP, 0) !=
27147c478bd9Sstevel@tonic-gate 	    USB_SUCCESS) {
27157c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
27167c478bd9Sstevel@tonic-gate 		    "usb_ac_do_setup: failure");
27177c478bd9Sstevel@tonic-gate 
27187c478bd9Sstevel@tonic-gate 		streams_infop->acs_setup_teardown_count--;
27197c478bd9Sstevel@tonic-gate 
27207c478bd9Sstevel@tonic-gate 		mutex_exit(&uacp->usb_ac_mutex);
27217c478bd9Sstevel@tonic-gate 
27227c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
27237c478bd9Sstevel@tonic-gate 	}
27247c478bd9Sstevel@tonic-gate 
27257c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
27267c478bd9Sstevel@tonic-gate 
27277c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
27287c478bd9Sstevel@tonic-gate }
27297c478bd9Sstevel@tonic-gate 
27307c478bd9Sstevel@tonic-gate 
27317c478bd9Sstevel@tonic-gate /*
27327c478bd9Sstevel@tonic-gate  * usb_ac_teardown:
27337c478bd9Sstevel@tonic-gate  *	Send teardown to usb_as if the last teardown
27347c478bd9Sstevel@tonic-gate  *	Check power is done in usb_ac_send_as_cmd()
27357c478bd9Sstevel@tonic-gate  *	NOTE: allow teardown when disconnected
27367c478bd9Sstevel@tonic-gate  */
27377c478bd9Sstevel@tonic-gate static void
usb_ac_teardown(usb_ac_state_t * uacp,usb_audio_eng_t * engine)2738e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_ac_teardown(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
27397c478bd9Sstevel@tonic-gate {
27407c478bd9Sstevel@tonic-gate 
2741e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_ac_streams_info_t	*streams_infop = NULL;
27427c478bd9Sstevel@tonic-gate 
27437c478bd9Sstevel@tonic-gate 	usb_ac_serialize_access(uacp);
27447c478bd9Sstevel@tonic-gate 
27457c478bd9Sstevel@tonic-gate 
2746e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	streams_infop = engine->streams;
27477c478bd9Sstevel@tonic-gate 
27487c478bd9Sstevel@tonic-gate 
27497c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
27507c478bd9Sstevel@tonic-gate 
27517c478bd9Sstevel@tonic-gate 
27527c478bd9Sstevel@tonic-gate 
27537c478bd9Sstevel@tonic-gate 	/* There should be at least one matching setup call */
27547c478bd9Sstevel@tonic-gate 	ASSERT(streams_infop->acs_setup_teardown_count);
27557c478bd9Sstevel@tonic-gate 
27567c478bd9Sstevel@tonic-gate 	/*
27577c478bd9Sstevel@tonic-gate 	 * Handle multiple setup/teardown calls. Pass the call to usb_as
27587c478bd9Sstevel@tonic-gate 	 * only this is the last teardown so that isoc pipe is closed
27597c478bd9Sstevel@tonic-gate 	 * only once
27607c478bd9Sstevel@tonic-gate 	 */
27617c478bd9Sstevel@tonic-gate 	if (--(streams_infop->acs_setup_teardown_count)) {
27627c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2763e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_teardown: more than one setup/teardown, "
27647c478bd9Sstevel@tonic-gate 		    "cnt=%d",
27657c478bd9Sstevel@tonic-gate 		    streams_infop->acs_setup_teardown_count);
27667c478bd9Sstevel@tonic-gate 
2767e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		goto done;
27687c478bd9Sstevel@tonic-gate 	}
27697c478bd9Sstevel@tonic-gate 
27707c478bd9Sstevel@tonic-gate 	/* Send teardown command to usb_as */
2771e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_TEARDOWN,
27727c478bd9Sstevel@tonic-gate 	    (void *)NULL) != USB_SUCCESS) {
27737c478bd9Sstevel@tonic-gate 
27747c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2775e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_teardown: failure");
27767c478bd9Sstevel@tonic-gate 
27777c478bd9Sstevel@tonic-gate 		streams_infop->acs_setup_teardown_count++;
27787c478bd9Sstevel@tonic-gate 
27797c478bd9Sstevel@tonic-gate 
2780e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		goto done;
27817c478bd9Sstevel@tonic-gate 	}
2782e272e4c8SBinzi Cao - Sun Microsystems - Beijing China done:
27837c478bd9Sstevel@tonic-gate 
27847c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
27857c478bd9Sstevel@tonic-gate 
27867c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2787e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_teardown: End");
27887c478bd9Sstevel@tonic-gate 	usb_ac_release_access(uacp);
27897c478bd9Sstevel@tonic-gate }
27907c478bd9Sstevel@tonic-gate 
27917c478bd9Sstevel@tonic-gate 
27927c478bd9Sstevel@tonic-gate /*
27937c478bd9Sstevel@tonic-gate  * usb_ac_set_monitor_gain:
27947c478bd9Sstevel@tonic-gate  *	called for each output terminal which supports
27957c478bd9Sstevel@tonic-gate  *	from usb_ac_traverse_connections
27967c478bd9Sstevel@tonic-gate  */
27977c478bd9Sstevel@tonic-gate static int
usb_ac_set_monitor_gain(usb_ac_state_t * uacp,uint_t unit,uint_t dir,uint_t channel,uint_t control,uint_t gain,uint_t * depth)27987c478bd9Sstevel@tonic-gate usb_ac_set_monitor_gain(usb_ac_state_t *uacp, uint_t unit,
27997c478bd9Sstevel@tonic-gate     uint_t dir, uint_t channel, uint_t control, uint_t gain, uint_t *depth)
28007c478bd9Sstevel@tonic-gate {
28017c478bd9Sstevel@tonic-gate 	usb_audio_output_term_descr_t *d =
2802112116d8Sfb 	    uacp->usb_ac_units[unit].acu_descriptor;
28037c478bd9Sstevel@tonic-gate 
28047c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
28057c478bd9Sstevel@tonic-gate 	    "usb_ac_set_monitor_gain: ");
28067c478bd9Sstevel@tonic-gate 
28077c478bd9Sstevel@tonic-gate 	/* log how we got here */
28087c478bd9Sstevel@tonic-gate 	usb_ac_push_unit_id(uacp, unit);
28097c478bd9Sstevel@tonic-gate 	usb_ac_show_traverse_path(uacp);
28107c478bd9Sstevel@tonic-gate 	usb_ac_pop_unit_id(uacp, unit);
28117c478bd9Sstevel@tonic-gate 
28127c478bd9Sstevel@tonic-gate 	/* we only care about the ITs connected to real hw inputs */
28137c478bd9Sstevel@tonic-gate 	switch (d->wTerminalType) {
28147c478bd9Sstevel@tonic-gate 	case USB_AUDIO_TERM_TYPE_STREAMING:
28157c478bd9Sstevel@tonic-gate 
28167c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
28177c478bd9Sstevel@tonic-gate 
28187c478bd9Sstevel@tonic-gate 	case USB_AUDIO_TERM_TYPE_DT_MICROPHONE:
28197c478bd9Sstevel@tonic-gate 	case USB_AUDIO_TERM_TYPE_PERS_MICROPHONE:
28207c478bd9Sstevel@tonic-gate 	case USB_AUDIO_TERM_TYPE_OMNI_DIR_MICROPHONE:
28217c478bd9Sstevel@tonic-gate 	case USB_AUDIO_TERM_TYPE_MICROPHONE_ARRAY:
28227c478bd9Sstevel@tonic-gate 	case USB_AUDIO_TERM_TYPE_PROCESSING_MIC_ARRAY:
28237c478bd9Sstevel@tonic-gate 	default:
28247c478bd9Sstevel@tonic-gate 
28257c478bd9Sstevel@tonic-gate 		break;
28267c478bd9Sstevel@tonic-gate 	}
28277c478bd9Sstevel@tonic-gate 
28287c478bd9Sstevel@tonic-gate 	/*
28297c478bd9Sstevel@tonic-gate 	 * we can only do this if the microphone is mixed into the
28307c478bd9Sstevel@tonic-gate 	 * audio output so look for a mixer first
28317c478bd9Sstevel@tonic-gate 	 */
28327c478bd9Sstevel@tonic-gate 	if (usb_ac_check_path(uacp, USB_AUDIO_MIXER_UNIT) ==
28337c478bd9Sstevel@tonic-gate 	    USB_SUCCESS) {
28347c478bd9Sstevel@tonic-gate 		int i, id;
28357c478bd9Sstevel@tonic-gate 
28367c478bd9Sstevel@tonic-gate 		/* now look for a feature unit */
28377c478bd9Sstevel@tonic-gate 		for (i = uacp->usb_ac_traverse_path_index - 1; i >= 0;
28387c478bd9Sstevel@tonic-gate 		    i--) {
28397c478bd9Sstevel@tonic-gate 			id = uacp->usb_ac_traverse_path[i];
28407c478bd9Sstevel@tonic-gate 
28417c478bd9Sstevel@tonic-gate 			switch (uacp->usb_ac_unit_type[id]) {
28427c478bd9Sstevel@tonic-gate 			case USB_AUDIO_MIXER_UNIT:
28437c478bd9Sstevel@tonic-gate 
28447c478bd9Sstevel@tonic-gate 				/* the FU should be before the mixer */
28457c478bd9Sstevel@tonic-gate 				return (USB_FAILURE);
28467c478bd9Sstevel@tonic-gate 
28477c478bd9Sstevel@tonic-gate 			case USB_AUDIO_FEATURE_UNIT:
28487c478bd9Sstevel@tonic-gate 				/*
28497c478bd9Sstevel@tonic-gate 				 * now set the volume
28507c478bd9Sstevel@tonic-gate 				 */
28517c478bd9Sstevel@tonic-gate 				if (usb_ac_set_gain(uacp, id, dir, channel,
28527c478bd9Sstevel@tonic-gate 				    control, gain, depth) != USB_SUCCESS) {
28537c478bd9Sstevel@tonic-gate 
28547c478bd9Sstevel@tonic-gate 					/* try master channel */
28557c478bd9Sstevel@tonic-gate 					if (usb_ac_set_gain(uacp, id, dir,
28567c478bd9Sstevel@tonic-gate 					    0, control, gain, depth) !=
28577c478bd9Sstevel@tonic-gate 					    USB_SUCCESS) {
28587c478bd9Sstevel@tonic-gate 
28597c478bd9Sstevel@tonic-gate 						return (USB_FAILURE);
28607c478bd9Sstevel@tonic-gate 					}
28617c478bd9Sstevel@tonic-gate 				}
28627c478bd9Sstevel@tonic-gate 
28637c478bd9Sstevel@tonic-gate 				return (USB_SUCCESS);
28647c478bd9Sstevel@tonic-gate 
28657c478bd9Sstevel@tonic-gate 			default:
28667c478bd9Sstevel@tonic-gate 				continue;
28677c478bd9Sstevel@tonic-gate 			}
28687c478bd9Sstevel@tonic-gate 		}
28697c478bd9Sstevel@tonic-gate 	}
28707c478bd9Sstevel@tonic-gate 
28717c478bd9Sstevel@tonic-gate 	return (USB_FAILURE);
28727c478bd9Sstevel@tonic-gate }
28737c478bd9Sstevel@tonic-gate 
28747c478bd9Sstevel@tonic-gate 
28757c478bd9Sstevel@tonic-gate /*
28767c478bd9Sstevel@tonic-gate  * usb_ac_set_gain is called for each feature unit which supports
28777c478bd9Sstevel@tonic-gate  * the requested controls from usb_ac_traverse_connections
28787c478bd9Sstevel@tonic-gate  * we still need to check whether this unit supports the requested
28797c478bd9Sstevel@tonic-gate  * control.
28807c478bd9Sstevel@tonic-gate  */
28817c478bd9Sstevel@tonic-gate static int
usb_ac_set_gain(usb_ac_state_t * uacp,uint_t featureID,uint_t dir,uint_t channel,uint_t control,uint_t gain,uint_t * depth)28827c478bd9Sstevel@tonic-gate usb_ac_set_gain(usb_ac_state_t *uacp, uint_t featureID,
28837c478bd9Sstevel@tonic-gate     uint_t dir, uint_t channel, uint_t control, uint_t gain, uint_t *depth)
28847c478bd9Sstevel@tonic-gate {
28857c478bd9Sstevel@tonic-gate 	short max, min, current;
28867c478bd9Sstevel@tonic-gate 
28877c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
28887c478bd9Sstevel@tonic-gate 	    "usb_ac_set_gain: id=%d dir=%d ch=%d cntl=%d gain=%d",
28897c478bd9Sstevel@tonic-gate 	    featureID, dir, channel, control, gain);
28907c478bd9Sstevel@tonic-gate 
28917c478bd9Sstevel@tonic-gate 	if (usb_ac_feature_unit_check(uacp, featureID,
28927c478bd9Sstevel@tonic-gate 	    dir, channel, control, gain, depth) != USB_SUCCESS) {
28937c478bd9Sstevel@tonic-gate 
28947c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
28957c478bd9Sstevel@tonic-gate 	}
28967c478bd9Sstevel@tonic-gate 
289788447a05SGarrett D'Amore 	if (usb_ac_get_maxmin_volume(uacp, channel,
289888447a05SGarrett D'Amore 	    USB_AUDIO_GET_MAX, dir, featureID, &max) != USB_SUCCESS) {
28997c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
29007c478bd9Sstevel@tonic-gate 		    "usb_ac_set_gain: getting max gain failed");
29017c478bd9Sstevel@tonic-gate 
29027c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
29037c478bd9Sstevel@tonic-gate 	}
29047c478bd9Sstevel@tonic-gate 
29057c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
29067c478bd9Sstevel@tonic-gate 	    "usb_ac_set_gain: channel %d, max=%d", channel, max);
29077c478bd9Sstevel@tonic-gate 
290888447a05SGarrett D'Amore 	if (usb_ac_get_maxmin_volume(uacp, channel,
290988447a05SGarrett D'Amore 	    USB_AUDIO_GET_MIN, dir, featureID, &min) != USB_SUCCESS) {
29107c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
29117c478bd9Sstevel@tonic-gate 		    "usb_ac_set_gain: getting min gain failed");
29127c478bd9Sstevel@tonic-gate 
29137c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
29147c478bd9Sstevel@tonic-gate 	}
29157c478bd9Sstevel@tonic-gate 
29167c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
29177c478bd9Sstevel@tonic-gate 	    "usb_ac_set_gain: channel=%d, min=%d", channel, min);
29187c478bd9Sstevel@tonic-gate 
291988447a05SGarrett D'Amore 	if (usb_ac_get_maxmin_volume(uacp, channel,
292088447a05SGarrett D'Amore 	    USB_AUDIO_GET_CUR, dir, featureID, &current) != USB_SUCCESS) {
29217c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
29227c478bd9Sstevel@tonic-gate 		    "usb_ac_set_gain: getting cur gain failed");
29237c478bd9Sstevel@tonic-gate 
29247c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
29257c478bd9Sstevel@tonic-gate 	}
29267c478bd9Sstevel@tonic-gate 
29277c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
29287c478bd9Sstevel@tonic-gate 	    "usb_ac_set_gain: channel=%d, cur=%d", channel, current);
29297c478bd9Sstevel@tonic-gate 
29307c478bd9Sstevel@tonic-gate 	/*
29317c478bd9Sstevel@tonic-gate 	 * Set the gain for a channel. The audio mixer calculates the
29327c478bd9Sstevel@tonic-gate 	 * impact, if any, on the channel's gain.
29337c478bd9Sstevel@tonic-gate 	 *
29347c478bd9Sstevel@tonic-gate 	 *	0 <= gain <= AUDIO_MAX_GAIN
29357c478bd9Sstevel@tonic-gate 	 *
29367c478bd9Sstevel@tonic-gate 	 *	channel #, 0 == left, 1 == right
29377c478bd9Sstevel@tonic-gate 	 */
29387c478bd9Sstevel@tonic-gate 
29397c478bd9Sstevel@tonic-gate 	if (gain == 0) {
29407c478bd9Sstevel@tonic-gate 		gain = USB_AUDIO_VOLUME_SILENCE;
29417c478bd9Sstevel@tonic-gate 	} else {
2942e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		gain = max - ((max - min) * (AF_MAX_GAIN - gain))/AF_MAX_GAIN;
29437c478bd9Sstevel@tonic-gate 	}
29447c478bd9Sstevel@tonic-gate 
29457c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
29467c478bd9Sstevel@tonic-gate 	    "usb_ac_set_gain: ch=%d dir=%d max=%d min=%d gain=%d",
29477c478bd9Sstevel@tonic-gate 	    channel, dir, max, min, gain);
29487c478bd9Sstevel@tonic-gate 
29497c478bd9Sstevel@tonic-gate 	if (usb_ac_set_volume(uacp, channel, gain, dir,
29507c478bd9Sstevel@tonic-gate 	    featureID) != USB_SUCCESS) {
29517c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
29527c478bd9Sstevel@tonic-gate 		    "usb_ac_set_gain: setting volume failed");
29537c478bd9Sstevel@tonic-gate 
29547c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
29557c478bd9Sstevel@tonic-gate 	}
29567c478bd9Sstevel@tonic-gate 
29577c478bd9Sstevel@tonic-gate 	/* just curious, read it back, device may round up/down */
295888447a05SGarrett D'Amore 	if (usb_ac_get_maxmin_volume(uacp, channel,
295988447a05SGarrett D'Amore 	    USB_AUDIO_GET_CUR, dir, featureID, &current) != USB_SUCCESS) {
29607c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
29617c478bd9Sstevel@tonic-gate 		    "usb_ac_set_gain: getting cur gain failed");
29627c478bd9Sstevel@tonic-gate 	}
29637c478bd9Sstevel@tonic-gate 
29647c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
29657c478bd9Sstevel@tonic-gate 	    "usb_ac_set_gain done: "
29667c478bd9Sstevel@tonic-gate 	    "id=%d channel=%d, cur=%d gain=%d", featureID, channel,
29677c478bd9Sstevel@tonic-gate 	    (ushort_t)current, (ushort_t)gain);
29687c478bd9Sstevel@tonic-gate 
29697c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
29707c478bd9Sstevel@tonic-gate }
29717c478bd9Sstevel@tonic-gate 
29727c478bd9Sstevel@tonic-gate 
29737c478bd9Sstevel@tonic-gate /*
29747c478bd9Sstevel@tonic-gate  * usb_ac_set_format
29757c478bd9Sstevel@tonic-gate  *	This mixer callback initiates a command to be sent to
29767c478bd9Sstevel@tonic-gate  *	usb_as to select an alternate with the passed characteristics
29777c478bd9Sstevel@tonic-gate  *	and also to set the sample frequency.
29787c478bd9Sstevel@tonic-gate  *	Note that this may be called when a playing is going on in
29797c478bd9Sstevel@tonic-gate  *	the streaming interface. To handle that, first stop
29807c478bd9Sstevel@tonic-gate  *	playing/recording, close the pipe by sending a teardown
29817c478bd9Sstevel@tonic-gate  *	command, send the set_format command down and then reopen
29827c478bd9Sstevel@tonic-gate  *	the pipe. Note : (1) audio framework will restart play/record
29837c478bd9Sstevel@tonic-gate  *	after a set_format command. (2) Check power is done in
29847c478bd9Sstevel@tonic-gate  *	usb_ac_send_as_cmd().
29857c478bd9Sstevel@tonic-gate  */
2986e272e4c8SBinzi Cao - Sun Microsystems - Beijing China int
usb_ac_set_format(usb_ac_state_t * uacp,usb_audio_eng_t * engine)2987e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_ac_set_format(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
29887c478bd9Sstevel@tonic-gate {
29897c478bd9Sstevel@tonic-gate 	usb_ac_streams_info_t	*streams_infop = NULL;
2990e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_formats_t	format;
2991e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int old_setup_teardown_count = 0;
29927c478bd9Sstevel@tonic-gate 
29937c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
2994e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	streams_infop = (usb_ac_streams_info_t *)engine->streams;
2995e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
29967c478bd9Sstevel@tonic-gate 	if (uacp->usb_ac_dev_state != USB_DEV_ONLINE) {
29977c478bd9Sstevel@tonic-gate 		mutex_exit(&uacp->usb_ac_mutex);
29987c478bd9Sstevel@tonic-gate 
2999e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return (USB_FAILURE);
30007c478bd9Sstevel@tonic-gate 	}
30017c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
30027c478bd9Sstevel@tonic-gate 
30037c478bd9Sstevel@tonic-gate 	usb_ac_serialize_access(uacp);
30047c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
30057c478bd9Sstevel@tonic-gate 
3006e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	bzero(&format, sizeof (usb_audio_formats_t));
30077c478bd9Sstevel@tonic-gate 
3008e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	/* save format info */
300964391892SAlbert Lee 	format.fmt_n_srs	= 1;
301064391892SAlbert Lee 	format.fmt_srs		= (uint_t *)&(engine->fmt.sr);
301164391892SAlbert Lee 	format.fmt_chns		= (uchar_t)engine->fmt.ch;
3012e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	format.fmt_precision	= (uchar_t)engine->fmt.prec;
3013e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	format.fmt_encoding	= (uchar_t)engine->fmt.enc;
30147c478bd9Sstevel@tonic-gate 
3015e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	old_setup_teardown_count = streams_infop->acs_setup_teardown_count;
30167c478bd9Sstevel@tonic-gate 
30177c478bd9Sstevel@tonic-gate 	/* isoc pipe not open and playing is not in progress */
3018e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (old_setup_teardown_count) {
3019e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		streams_infop->acs_setup_teardown_count = 1;
30207c478bd9Sstevel@tonic-gate 
30217c478bd9Sstevel@tonic-gate 		mutex_exit(&uacp->usb_ac_mutex);
30227c478bd9Sstevel@tonic-gate 		usb_ac_release_access(uacp);
30237c478bd9Sstevel@tonic-gate 
3024e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		usb_ac_stop_play(uacp, engine);
3025e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		usb_ac_teardown(uacp, engine);
3026e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
3027e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		usb_ac_serialize_access(uacp);
3028e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		mutex_enter(&uacp->usb_ac_mutex);
30297c478bd9Sstevel@tonic-gate 	}
30307c478bd9Sstevel@tonic-gate 
3031e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	/*
3032e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	 * Set format for the streaming interface with lower write queue
3033e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	 * This boils down to set_alternate  interface command in
3034e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	 * usb_as and the reply mp contains the currently active
3035e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	 * alternate number that is stored in the as_req structure
3036e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	 */
3037e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (usb_ac_send_as_cmd(uacp, engine,
3038e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AUDIO_SET_FORMAT, &format) != USB_SUCCESS) {
3039e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ALL,
3040e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    uacp->usb_ac_log_handle,
3041e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_set_format: failed");
3042e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		goto fail;
30437c478bd9Sstevel@tonic-gate 
3044e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
3045e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int sample =  engine->fmt.sr;
30467c478bd9Sstevel@tonic-gate 
3047e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	/* Set the sample rate */
3048e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_SET_SAMPLE_FREQ,
3049e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    &sample) != USB_SUCCESS) {
3050e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3051e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_set_format: setting format failed");
3052e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		goto fail;
30537c478bd9Sstevel@tonic-gate 
3054e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
30557c478bd9Sstevel@tonic-gate 
30567c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
30577c478bd9Sstevel@tonic-gate 
3058e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_ac_release_access(uacp);
30597c478bd9Sstevel@tonic-gate 
3060e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	/* This should block until successful */
3061e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (old_setup_teardown_count) {
3062e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		(void) usb_ac_setup(uacp, engine);
3063e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
30647c478bd9Sstevel@tonic-gate 
30657c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
30667c478bd9Sstevel@tonic-gate 	streams_infop->acs_setup_teardown_count = old_setup_teardown_count;
30677c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
30687c478bd9Sstevel@tonic-gate 
3069e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (USB_SUCCESS);
3070e272e4c8SBinzi Cao - Sun Microsystems - Beijing China fail:
3071e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	streams_infop->acs_setup_teardown_count = old_setup_teardown_count;
3072e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&uacp->usb_ac_mutex);
30737c478bd9Sstevel@tonic-gate 	usb_ac_release_access(uacp);
30747c478bd9Sstevel@tonic-gate 
3075e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (USB_FAILURE);
30767c478bd9Sstevel@tonic-gate 
30777c478bd9Sstevel@tonic-gate }
30787c478bd9Sstevel@tonic-gate 
30797c478bd9Sstevel@tonic-gate /*
30807c478bd9Sstevel@tonic-gate  * usb_ac_start_play
30817c478bd9Sstevel@tonic-gate  *	Send a start_play command down to usb_as
30827c478bd9Sstevel@tonic-gate  *	Check power is done in usb_ac_send_as_cmd()
30837c478bd9Sstevel@tonic-gate  */
30847c478bd9Sstevel@tonic-gate static int
usb_ac_start_play(usb_ac_state_t * uacp,usb_audio_eng_t * engine)3085e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_ac_start_play(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
30867c478bd9Sstevel@tonic-gate {
3087e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int			samples;
30887c478bd9Sstevel@tonic-gate 	usb_audio_play_req_t	play_req;
30897c478bd9Sstevel@tonic-gate 
30907c478bd9Sstevel@tonic-gate 
30917c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
30927c478bd9Sstevel@tonic-gate 	if (uacp->usb_ac_dev_state != USB_DEV_ONLINE) {
30937c478bd9Sstevel@tonic-gate 		mutex_exit(&uacp->usb_ac_mutex);
30947c478bd9Sstevel@tonic-gate 
3095e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return (USB_FAILURE);
30967c478bd9Sstevel@tonic-gate 	}
30977c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
30987c478bd9Sstevel@tonic-gate 
30997c478bd9Sstevel@tonic-gate 	usb_ac_serialize_access(uacp);
31007c478bd9Sstevel@tonic-gate 
31017c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
31027c478bd9Sstevel@tonic-gate 
31037c478bd9Sstevel@tonic-gate 
31047c478bd9Sstevel@tonic-gate 
31057c478bd9Sstevel@tonic-gate 	/* Check for continuous sample rate done in usb_as */
3106e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	samples = engine->fmt.sr * engine->fmt.ch / engine->intrate;
3107e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (samples & engine->fmt.ch) {
31087c478bd9Sstevel@tonic-gate 		samples++;
31097c478bd9Sstevel@tonic-gate 	}
31107c478bd9Sstevel@tonic-gate 
31117c478bd9Sstevel@tonic-gate 	play_req.up_samples = samples;
3112e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	play_req.up_handle = uacp;
31137c478bd9Sstevel@tonic-gate 
31147c478bd9Sstevel@tonic-gate 	/* Send setup command to usb_as */
3115e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_START_PLAY,
31167c478bd9Sstevel@tonic-gate 	    (void *)&play_req) != USB_SUCCESS) {
31177c478bd9Sstevel@tonic-gate 
31187c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
31197c478bd9Sstevel@tonic-gate 		    "usb_ac_start_play: failure");
31207c478bd9Sstevel@tonic-gate 
31217c478bd9Sstevel@tonic-gate 		mutex_exit(&uacp->usb_ac_mutex);
31227c478bd9Sstevel@tonic-gate 
31237c478bd9Sstevel@tonic-gate 		usb_ac_release_access(uacp);
31247c478bd9Sstevel@tonic-gate 
3125e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return (USB_FAILURE);
31267c478bd9Sstevel@tonic-gate 	}
31277c478bd9Sstevel@tonic-gate 
31287c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
31297c478bd9Sstevel@tonic-gate 
31307c478bd9Sstevel@tonic-gate 	usb_ac_release_access(uacp);
31317c478bd9Sstevel@tonic-gate 
3132e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (USB_SUCCESS);
31337c478bd9Sstevel@tonic-gate }
31347c478bd9Sstevel@tonic-gate 
31357c478bd9Sstevel@tonic-gate 
31367c478bd9Sstevel@tonic-gate /*
313788447a05SGarrett D'Amore  * usb_ac_stop_play:
3138e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  *	Stop the play engine
31397c478bd9Sstevel@tonic-gate  *	called from mixer framework.
31407c478bd9Sstevel@tonic-gate  */
3141e272e4c8SBinzi Cao - Sun Microsystems - Beijing China void
usb_ac_stop_play(usb_ac_state_t * uacp,usb_audio_eng_t * engine)3142e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_ac_stop_play(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
31437c478bd9Sstevel@tonic-gate {
31447c478bd9Sstevel@tonic-gate 
3145e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (engine == NULL) {
3146e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		engine = &(uacp->engines[0]);
3147e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
31487c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
31497c478bd9Sstevel@tonic-gate 	if (uacp->usb_ac_dev_state != USB_DEV_ONLINE) {
31507c478bd9Sstevel@tonic-gate 		mutex_exit(&uacp->usb_ac_mutex);
31517c478bd9Sstevel@tonic-gate 
31527c478bd9Sstevel@tonic-gate 		return;
31537c478bd9Sstevel@tonic-gate 	}
31547c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
31557c478bd9Sstevel@tonic-gate 
31567c478bd9Sstevel@tonic-gate 	usb_ac_serialize_access(uacp);
31577c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
31587c478bd9Sstevel@tonic-gate 
31597c478bd9Sstevel@tonic-gate 	/* Send setup command to usb_as */
3160e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_PAUSE_PLAY,
31617c478bd9Sstevel@tonic-gate 	    (void *)NULL) != USB_SUCCESS) {
31627c478bd9Sstevel@tonic-gate 
31637c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
31647c478bd9Sstevel@tonic-gate 		    "usb_ac_do_pause_play: failure");
31657c478bd9Sstevel@tonic-gate 	}
31667c478bd9Sstevel@tonic-gate 
31677c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
3168e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_ac_release_access(uacp);
31697c478bd9Sstevel@tonic-gate }
31707c478bd9Sstevel@tonic-gate 
31717c478bd9Sstevel@tonic-gate 
31727c478bd9Sstevel@tonic-gate /*
31737c478bd9Sstevel@tonic-gate  * usb_ac_start_record:
31747c478bd9Sstevel@tonic-gate  *	Sends a start record command down to usb_as.
31757c478bd9Sstevel@tonic-gate  *	Check power is done in usb_ac_send_as_cmd()
31767c478bd9Sstevel@tonic-gate  */
31777c478bd9Sstevel@tonic-gate static int
usb_ac_start_record(usb_ac_state_t * uacp,usb_audio_eng_t * engine)3178e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_ac_start_record(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
31797c478bd9Sstevel@tonic-gate {
31807c478bd9Sstevel@tonic-gate 
31817c478bd9Sstevel@tonic-gate 
31827c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
31837c478bd9Sstevel@tonic-gate 	if (uacp->usb_ac_dev_state != USB_DEV_ONLINE) {
31847c478bd9Sstevel@tonic-gate 		mutex_exit(&uacp->usb_ac_mutex);
31857c478bd9Sstevel@tonic-gate 
3186e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return (USB_FAILURE);
31877c478bd9Sstevel@tonic-gate 	}
31887c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
31897c478bd9Sstevel@tonic-gate 
31907c478bd9Sstevel@tonic-gate 	usb_ac_serialize_access(uacp);
31917c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
31927c478bd9Sstevel@tonic-gate 
31937c478bd9Sstevel@tonic-gate 
31947c478bd9Sstevel@tonic-gate 	/* Send setup command to usb_as */
3195e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_START_RECORD,
3196e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    (void *)uacp) != USB_SUCCESS) {
31977c478bd9Sstevel@tonic-gate 
31987c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
31997c478bd9Sstevel@tonic-gate 		    "usb_ac_start_record: failure");
32007c478bd9Sstevel@tonic-gate 
32017c478bd9Sstevel@tonic-gate 		mutex_exit(&uacp->usb_ac_mutex);
32027c478bd9Sstevel@tonic-gate 
32037c478bd9Sstevel@tonic-gate 		usb_ac_release_access(uacp);
32047c478bd9Sstevel@tonic-gate 
3205e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return (USB_FAILURE);
32067c478bd9Sstevel@tonic-gate 	}
32077c478bd9Sstevel@tonic-gate 
32087c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
32097c478bd9Sstevel@tonic-gate 	usb_ac_release_access(uacp);
32107c478bd9Sstevel@tonic-gate 
3211e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (USB_SUCCESS);
32127c478bd9Sstevel@tonic-gate }
32137c478bd9Sstevel@tonic-gate 
32147c478bd9Sstevel@tonic-gate 
32157c478bd9Sstevel@tonic-gate /*
32167c478bd9Sstevel@tonic-gate  * usb_ac_stop_record:
32177c478bd9Sstevel@tonic-gate  *	Wrapper function for usb_ac_do_stop_record and is
32187c478bd9Sstevel@tonic-gate  *	called form mixer framework.
32197c478bd9Sstevel@tonic-gate  */
32207c478bd9Sstevel@tonic-gate static void
usb_ac_stop_record(usb_ac_state_t * uacp,usb_audio_eng_t * engine)3221e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_ac_stop_record(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
32227c478bd9Sstevel@tonic-gate {
32237c478bd9Sstevel@tonic-gate 
32247c478bd9Sstevel@tonic-gate 	usb_ac_serialize_access(uacp);
32257c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
32267c478bd9Sstevel@tonic-gate 
32277c478bd9Sstevel@tonic-gate 	/* Send setup command to usb_as */
3228e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_STOP_RECORD,
32297c478bd9Sstevel@tonic-gate 	    NULL) != USB_SUCCESS) {
32307c478bd9Sstevel@tonic-gate 
32317c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
32327c478bd9Sstevel@tonic-gate 		    "usb_ac_do_stop_record: failure");
32337c478bd9Sstevel@tonic-gate 	}
32347c478bd9Sstevel@tonic-gate 
32357c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
3236e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_ac_release_access(uacp);
32377c478bd9Sstevel@tonic-gate }
32387c478bd9Sstevel@tonic-gate 
32397c478bd9Sstevel@tonic-gate 
32407c478bd9Sstevel@tonic-gate /*
32417c478bd9Sstevel@tonic-gate  * Helper Functions for Mixer callbacks
32427c478bd9Sstevel@tonic-gate  *
32437c478bd9Sstevel@tonic-gate  * usb_ac_get_maxmin_volume:
32447c478bd9Sstevel@tonic-gate  *	Send USBA command down to get the maximum or minimum gain balance
32457c478bd9Sstevel@tonic-gate  *	Calculate min or max gain balance and return that. Return
32467c478bd9Sstevel@tonic-gate  *	USB_FAILURE for failure cases
32477c478bd9Sstevel@tonic-gate  */
3248e272e4c8SBinzi Cao - Sun Microsystems - Beijing China /* ARGSUSED */
32497c478bd9Sstevel@tonic-gate static int
usb_ac_get_maxmin_volume(usb_ac_state_t * uacp,uint_t channel,int cmd,int dir,int feature_unitID,short * max_or_minp)32507c478bd9Sstevel@tonic-gate usb_ac_get_maxmin_volume(usb_ac_state_t *uacp, uint_t channel, int cmd,
325188447a05SGarrett D'Amore     int dir, int feature_unitID, short *max_or_minp)
32527c478bd9Sstevel@tonic-gate {
32537c478bd9Sstevel@tonic-gate 	mblk_t		*data = NULL;
32547c478bd9Sstevel@tonic-gate 	usb_cr_t	cr;
32557c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
325688447a05SGarrett D'Amore 
32577c478bd9Sstevel@tonic-gate 
32587c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
32597c478bd9Sstevel@tonic-gate 
32607c478bd9Sstevel@tonic-gate 	if (usb_pipe_sync_ctrl_xfer(
32617c478bd9Sstevel@tonic-gate 	    uacp->usb_ac_dip,
32627c478bd9Sstevel@tonic-gate 	    uacp->usb_ac_default_ph,
32637c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_DEV_TO_HOST |
32647c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_TYPE_CLASS |
32657c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_RCPT_IF,	/* bmRequestType */
32667c478bd9Sstevel@tonic-gate 	    cmd,			/* bRequest */
32677c478bd9Sstevel@tonic-gate 	    (USB_AUDIO_VOLUME_CONTROL << 8) | channel, /* wValue */
32687c478bd9Sstevel@tonic-gate 					/* feature unit and id */
32697c478bd9Sstevel@tonic-gate 	    (feature_unitID << 8)| uacp->usb_ac_ifno, /* wIndex */
32707c478bd9Sstevel@tonic-gate 	    2,				/* wLength */
32717c478bd9Sstevel@tonic-gate 	    &data,
32727c478bd9Sstevel@tonic-gate 	    USB_ATTRS_NONE,
32737c478bd9Sstevel@tonic-gate 	    &cr, &cb_flags,
32747c478bd9Sstevel@tonic-gate 	    USB_FLAGS_SLEEP) != USB_SUCCESS) {
32757c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
32767c478bd9Sstevel@tonic-gate 		    "usb_ac_get_maxmin_volume: failed, "
32777c478bd9Sstevel@tonic-gate 		    "cr=%d, cb=0x%x cmd=%d, data=0x%p",
3278112116d8Sfb 		    cr, cb_flags, cmd, (void *)data);
32797c478bd9Sstevel@tonic-gate 
32807c478bd9Sstevel@tonic-gate 		freemsg(data);
32817c478bd9Sstevel@tonic-gate 		mutex_enter(&uacp->usb_ac_mutex);
32827c478bd9Sstevel@tonic-gate 
32837c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
32847c478bd9Sstevel@tonic-gate 	}
32857c478bd9Sstevel@tonic-gate 
32867c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
3287d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	ASSERT(MBLKL(data) == 2);
32887c478bd9Sstevel@tonic-gate 
328988447a05SGarrett D'Amore 	*max_or_minp = (*(data->b_rptr+1) << 8) | *data->b_rptr;
32907c478bd9Sstevel@tonic-gate 
32917c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
329288447a05SGarrett D'Amore 	    "usb_ac_get_maxmin_volume: max_or_min=0x%x", *max_or_minp);
32937c478bd9Sstevel@tonic-gate 
32947c478bd9Sstevel@tonic-gate 	freemsg(data);
32957c478bd9Sstevel@tonic-gate 
329688447a05SGarrett D'Amore 	return (USB_SUCCESS);
32977c478bd9Sstevel@tonic-gate }
32987c478bd9Sstevel@tonic-gate 
32997c478bd9Sstevel@tonic-gate 
33007c478bd9Sstevel@tonic-gate /*
33017c478bd9Sstevel@tonic-gate  * usb_ac_set_volume:
33027c478bd9Sstevel@tonic-gate  *	Send USBA command down to set the gain balance
33037c478bd9Sstevel@tonic-gate  */
3304e272e4c8SBinzi Cao - Sun Microsystems - Beijing China /* ARGSUSED */
33057c478bd9Sstevel@tonic-gate static int
usb_ac_set_volume(usb_ac_state_t * uacp,uint_t channel,short gain,int dir,int feature_unitID)33067c478bd9Sstevel@tonic-gate usb_ac_set_volume(usb_ac_state_t *uacp, uint_t channel, short gain, int dir,
33077c478bd9Sstevel@tonic-gate     int feature_unitID)
33087c478bd9Sstevel@tonic-gate {
33097c478bd9Sstevel@tonic-gate 	mblk_t		*data = NULL;
33107c478bd9Sstevel@tonic-gate 	usb_cr_t	cr;
33117c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
33127c478bd9Sstevel@tonic-gate 	int		rval = USB_FAILURE;
33137c478bd9Sstevel@tonic-gate 
33147c478bd9Sstevel@tonic-gate 
33157c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
33167c478bd9Sstevel@tonic-gate 
33177c478bd9Sstevel@tonic-gate 	/* Construct the mblk_t from gain for sending to USBA */
3318e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	data = allocb(4, BPRI_HI);
3319e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (!data) {
3320e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3321e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_set_volume: allocate data failed");
3322e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		mutex_enter(&uacp->usb_ac_mutex);
3323e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
3324e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return (USB_FAILURE);
3325e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
3326e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
3327e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
33287c478bd9Sstevel@tonic-gate 
33297c478bd9Sstevel@tonic-gate 	*(data->b_wptr++) = (char)gain;
33307c478bd9Sstevel@tonic-gate 	*(data->b_wptr++) = (char)(gain >> 8);
33317c478bd9Sstevel@tonic-gate 
33327c478bd9Sstevel@tonic-gate 	if ((rval = usb_pipe_sync_ctrl_xfer(
33337c478bd9Sstevel@tonic-gate 	    uacp->usb_ac_dip,
33347c478bd9Sstevel@tonic-gate 	    uacp->usb_ac_default_ph,
33357c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_HOST_TO_DEV |
33367c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_TYPE_CLASS |
33377c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_RCPT_IF,		/* bmRequestType */
33387c478bd9Sstevel@tonic-gate 	    USB_AUDIO_SET_CUR,			/* bRequest */
33397c478bd9Sstevel@tonic-gate 	    (USB_AUDIO_VOLUME_CONTROL << 8) | channel, /* wValue */
33407c478bd9Sstevel@tonic-gate 						/* feature unit and id */
33417c478bd9Sstevel@tonic-gate 	    (feature_unitID << 8) | uacp->usb_ac_ifno,	/* wIndex */
33427c478bd9Sstevel@tonic-gate 	    2,					/* wLength */
33437c478bd9Sstevel@tonic-gate 	    &data, 0,
33447c478bd9Sstevel@tonic-gate 	    &cr, &cb_flags, USB_FLAGS_SLEEP)) != USB_SUCCESS) {
33457c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
33467c478bd9Sstevel@tonic-gate 		    "usb_ac_set_volume: failed, cr=%d cb=0x%x",
33477c478bd9Sstevel@tonic-gate 		    cr, cb_flags);
33487c478bd9Sstevel@tonic-gate 	}
33497c478bd9Sstevel@tonic-gate 
33507c478bd9Sstevel@tonic-gate 	freemsg(data);
33517c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
33527c478bd9Sstevel@tonic-gate 
33537c478bd9Sstevel@tonic-gate 	return (rval);
33547c478bd9Sstevel@tonic-gate }
33557c478bd9Sstevel@tonic-gate 
33567c478bd9Sstevel@tonic-gate 
33577c478bd9Sstevel@tonic-gate /*
33587c478bd9Sstevel@tonic-gate  * usb_ac_set_mute is called for each unit that supports the
33597c478bd9Sstevel@tonic-gate  * requested control from usb_ac_traverse_connections
33607c478bd9Sstevel@tonic-gate  */
3361e272e4c8SBinzi Cao - Sun Microsystems - Beijing China int
usb_ac_set_mute(usb_ac_state_t * uacp,uint_t featureID,uint_t dir,uint_t channel,uint_t control,uint_t muteval,uint_t * depth)33627c478bd9Sstevel@tonic-gate usb_ac_set_mute(usb_ac_state_t *uacp, uint_t featureID, uint_t dir,
33637c478bd9Sstevel@tonic-gate     uint_t channel, uint_t control, uint_t muteval, uint_t *depth)
33647c478bd9Sstevel@tonic-gate {
33657c478bd9Sstevel@tonic-gate 	mblk_t		*data;
33667c478bd9Sstevel@tonic-gate 	usb_cr_t	cr;
33677c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	cb_flags;
33687c478bd9Sstevel@tonic-gate 	int		rval = USB_FAILURE;
33697c478bd9Sstevel@tonic-gate 
33707c478bd9Sstevel@tonic-gate 
33717c478bd9Sstevel@tonic-gate 	if (usb_ac_feature_unit_check(uacp, featureID,
33727c478bd9Sstevel@tonic-gate 	    dir, channel, control, 0, depth) != USB_SUCCESS) {
33737c478bd9Sstevel@tonic-gate 
33747c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
33757c478bd9Sstevel@tonic-gate 	}
33767c478bd9Sstevel@tonic-gate 	mutex_exit(&uacp->usb_ac_mutex);
33777c478bd9Sstevel@tonic-gate 
33787c478bd9Sstevel@tonic-gate 	/* Construct the mblk_t for sending to USBA */
3379e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	data = allocb(1, BPRI_HI);
3380e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
3381e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (!data) {
3382e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3383e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_set_mute: allocate data failed");
3384e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		mutex_enter(&uacp->usb_ac_mutex);
3385e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
3386e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return (USB_FAILURE);
3387e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
3388e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
3389e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
33907c478bd9Sstevel@tonic-gate 	*(data->b_wptr++) = (char)muteval;
33917c478bd9Sstevel@tonic-gate 
33927c478bd9Sstevel@tonic-gate 	if ((rval = usb_pipe_sync_ctrl_xfer(
33937c478bd9Sstevel@tonic-gate 	    uacp->usb_ac_dip,
33947c478bd9Sstevel@tonic-gate 	    uacp->usb_ac_default_ph,
33957c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_HOST_TO_DEV |
33967c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_TYPE_CLASS |
33977c478bd9Sstevel@tonic-gate 	    USB_DEV_REQ_RCPT_IF,		/* bmRequestType */
33987c478bd9Sstevel@tonic-gate 	    USB_AUDIO_SET_CUR,			/* bRequest */
33997c478bd9Sstevel@tonic-gate 	    (USB_AUDIO_MUTE_CONTROL << 8) | channel, /* wValue */
34007c478bd9Sstevel@tonic-gate 						/* feature unit and id */
34017c478bd9Sstevel@tonic-gate 	    (featureID << 8) | uacp->usb_ac_ifno, /* wIndex */
34027c478bd9Sstevel@tonic-gate 	    1,					/* wLength */
34037c478bd9Sstevel@tonic-gate 	    &data,
34047c478bd9Sstevel@tonic-gate 	    0,					/* attributes */
34057c478bd9Sstevel@tonic-gate 	    &cr, &cb_flags, 0)) != USB_SUCCESS) {
34067c478bd9Sstevel@tonic-gate 
34077c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
34087c478bd9Sstevel@tonic-gate 		    "usb_ac_set_mute: failed, cr=%d cb=0x%x", cr, cb_flags);
34097c478bd9Sstevel@tonic-gate 	}
34107c478bd9Sstevel@tonic-gate 	freemsg(data);
3411e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
34127c478bd9Sstevel@tonic-gate 	mutex_enter(&uacp->usb_ac_mutex);
34137c478bd9Sstevel@tonic-gate 
34147c478bd9Sstevel@tonic-gate 	return (rval);
34157c478bd9Sstevel@tonic-gate }
34167c478bd9Sstevel@tonic-gate 
34177c478bd9Sstevel@tonic-gate 
34187c478bd9Sstevel@tonic-gate /*
34197c478bd9Sstevel@tonic-gate  * usb_ac_send_as_cmd:
34207c478bd9Sstevel@tonic-gate  *	Allocate message blk, send a command down to usb_as,
34217c478bd9Sstevel@tonic-gate  *	wait for the reply and free the message
34227c478bd9Sstevel@tonic-gate  *
34237c478bd9Sstevel@tonic-gate  *	although not really needed to raise power if sending to as
34247c478bd9Sstevel@tonic-gate  *	it seems better to ensure that both interfaces are at full power
34257c478bd9Sstevel@tonic-gate  */
34267c478bd9Sstevel@tonic-gate static int
usb_ac_send_as_cmd(usb_ac_state_t * uacp,usb_audio_eng_t * engine,int cmd,void * arg)3427e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_ac_send_as_cmd(usb_ac_state_t *uacp, usb_audio_eng_t *engine,
34287c478bd9Sstevel@tonic-gate     int cmd, void *arg)
34297c478bd9Sstevel@tonic-gate {
34307c478bd9Sstevel@tonic-gate 	usb_ac_streams_info_t *streams_infop;
3431e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_ac_plumbed_t *plumb_infop;
343288447a05SGarrett D'Amore 	int		rv;
343388447a05SGarrett D'Amore 	int		rval;
343488447a05SGarrett D'Amore 	ldi_handle_t	lh;
34357c478bd9Sstevel@tonic-gate 
34367c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&uacp->usb_ac_mutex));
3437e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	streams_infop = engine->streams;
3438e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	plumb_infop = streams_infop->acs_plumbed;
34397c478bd9Sstevel@tonic-gate 
34407c478bd9Sstevel@tonic-gate 
344188447a05SGarrett D'Amore 	lh = plumb_infop->acp_lh;
34427c478bd9Sstevel@tonic-gate 
344388447a05SGarrett D'Amore 	rv = ldi_ioctl(lh, cmd, (intptr_t)arg, FKIOCTL, kcred, &rval);
344488447a05SGarrett D'Amore 	if (rv != 0) {
34451cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
34461cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_send_as_cmd: ldi_ioctl failed, error=%d", rv);
34477c478bd9Sstevel@tonic-gate 
344888447a05SGarrett D'Amore 		return (USB_FAILURE);
34497c478bd9Sstevel@tonic-gate 	}
34507c478bd9Sstevel@tonic-gate 
345188447a05SGarrett D'Amore 	return (USB_SUCCESS);
34527c478bd9Sstevel@tonic-gate }
34537c478bd9Sstevel@tonic-gate 
34547c478bd9Sstevel@tonic-gate 
34557c478bd9Sstevel@tonic-gate /*
34567c478bd9Sstevel@tonic-gate  * usb_ac_serialize/release_access:
34577c478bd9Sstevel@tonic-gate  */
34587c478bd9Sstevel@tonic-gate static void
usb_ac_serialize_access(usb_ac_state_t * uacp)34597c478bd9Sstevel@tonic-gate usb_ac_serialize_access(usb_ac_state_t	*uacp)
34607c478bd9Sstevel@tonic-gate {
34617c478bd9Sstevel@tonic-gate 	(void) usb_serialize_access(uacp->usb_ac_ser_acc, USB_WAIT, 0);
34627c478bd9Sstevel@tonic-gate }
34637c478bd9Sstevel@tonic-gate 
34647c478bd9Sstevel@tonic-gate static void
usb_ac_release_access(usb_ac_state_t * uacp)34657c478bd9Sstevel@tonic-gate usb_ac_release_access(usb_ac_state_t *uacp)
34667c478bd9Sstevel@tonic-gate {
34677c478bd9Sstevel@tonic-gate 	usb_release_access(uacp->usb_ac_ser_acc);
34687c478bd9Sstevel@tonic-gate }
34697c478bd9Sstevel@tonic-gate 
34707c478bd9Sstevel@tonic-gate 
34717c478bd9Sstevel@tonic-gate static void
usb_ac_pm_busy_component(usb_ac_state_t * usb_ac_statep)34727c478bd9Sstevel@tonic-gate usb_ac_pm_busy_component(usb_ac_state_t *usb_ac_statep)
34737c478bd9Sstevel@tonic-gate {
34747c478bd9Sstevel@tonic-gate 	ASSERT(!mutex_owned(&usb_ac_statep->usb_ac_mutex));
34757c478bd9Sstevel@tonic-gate 
34767c478bd9Sstevel@tonic-gate 	if (usb_ac_statep->usb_ac_pm != NULL) {
34777c478bd9Sstevel@tonic-gate 		mutex_enter(&usb_ac_statep->usb_ac_mutex);
34787c478bd9Sstevel@tonic-gate 		usb_ac_statep->usb_ac_pm->acpm_pm_busy++;
34797c478bd9Sstevel@tonic-gate 
34807c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_PM,
34817c478bd9Sstevel@tonic-gate 		    usb_ac_statep->usb_ac_log_handle,
34827c478bd9Sstevel@tonic-gate 		    "usb_ac_pm_busy_component: %d",
34837c478bd9Sstevel@tonic-gate 		    usb_ac_statep->usb_ac_pm->acpm_pm_busy);
34847c478bd9Sstevel@tonic-gate 
34857c478bd9Sstevel@tonic-gate 		mutex_exit(&usb_ac_statep->usb_ac_mutex);
34867c478bd9Sstevel@tonic-gate 
34877c478bd9Sstevel@tonic-gate 		if (pm_busy_component(usb_ac_statep->usb_ac_dip, 0) !=
34887c478bd9Sstevel@tonic-gate 		    DDI_SUCCESS) {
34897c478bd9Sstevel@tonic-gate 			mutex_enter(&usb_ac_statep->usb_ac_mutex);
34907c478bd9Sstevel@tonic-gate 			usb_ac_statep->usb_ac_pm->acpm_pm_busy--;
34917c478bd9Sstevel@tonic-gate 
34927c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_PM,
34937c478bd9Sstevel@tonic-gate 			    usb_ac_statep->usb_ac_log_handle,
34947c478bd9Sstevel@tonic-gate 			    "usb_ac_pm_busy_component failed: %d",
34957c478bd9Sstevel@tonic-gate 			    usb_ac_statep->usb_ac_pm->acpm_pm_busy);
34967c478bd9Sstevel@tonic-gate 
34977c478bd9Sstevel@tonic-gate 			mutex_exit(&usb_ac_statep->usb_ac_mutex);
34987c478bd9Sstevel@tonic-gate 		}
34997c478bd9Sstevel@tonic-gate 	}
35007c478bd9Sstevel@tonic-gate }
35017c478bd9Sstevel@tonic-gate 
35027c478bd9Sstevel@tonic-gate 
35037c478bd9Sstevel@tonic-gate static void
usb_ac_pm_idle_component(usb_ac_state_t * usb_ac_statep)35047c478bd9Sstevel@tonic-gate usb_ac_pm_idle_component(usb_ac_state_t *usb_ac_statep)
35057c478bd9Sstevel@tonic-gate {
35067c478bd9Sstevel@tonic-gate 	ASSERT(!mutex_owned(&usb_ac_statep->usb_ac_mutex));
35077c478bd9Sstevel@tonic-gate 
35087c478bd9Sstevel@tonic-gate 	if (usb_ac_statep->usb_ac_pm != NULL) {
35097c478bd9Sstevel@tonic-gate 		if (pm_idle_component(usb_ac_statep->usb_ac_dip, 0) ==
35107c478bd9Sstevel@tonic-gate 		    DDI_SUCCESS) {
35117c478bd9Sstevel@tonic-gate 			mutex_enter(&usb_ac_statep->usb_ac_mutex);
35127c478bd9Sstevel@tonic-gate 			ASSERT(usb_ac_statep->usb_ac_pm->acpm_pm_busy > 0);
35137c478bd9Sstevel@tonic-gate 			usb_ac_statep->usb_ac_pm->acpm_pm_busy--;
35147c478bd9Sstevel@tonic-gate 
35157c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L4(PRINT_MASK_PM,
35167c478bd9Sstevel@tonic-gate 			    usb_ac_statep->usb_ac_log_handle,
35177c478bd9Sstevel@tonic-gate 			    "usb_ac_pm_idle_component: %d",
35187c478bd9Sstevel@tonic-gate 			    usb_ac_statep->usb_ac_pm->acpm_pm_busy);
35197c478bd9Sstevel@tonic-gate 
35207c478bd9Sstevel@tonic-gate 			mutex_exit(&usb_ac_statep->usb_ac_mutex);
35217c478bd9Sstevel@tonic-gate 		}
35227c478bd9Sstevel@tonic-gate 	}
35237c478bd9Sstevel@tonic-gate }
352488447a05SGarrett D'Amore 
352588447a05SGarrett D'Amore 
352688447a05SGarrett D'Amore /*
352788447a05SGarrett D'Amore  * handle read from plumbed drivers
352888447a05SGarrett D'Amore  */
352988447a05SGarrett D'Amore static void
usb_ac_reader(void * argp)353088447a05SGarrett D'Amore usb_ac_reader(void *argp)
353188447a05SGarrett D'Amore {
353288447a05SGarrett D'Amore 	usb_ac_plumbed_t *acp = (usb_ac_plumbed_t *)argp;
353388447a05SGarrett D'Amore 	usb_ac_state_t *uacp = acp->acp_uacp;
353488447a05SGarrett D'Amore 	ldi_handle_t lh;
353588447a05SGarrett D'Amore 	mblk_t *mp;
353688447a05SGarrett D'Amore 	int rv;
353788447a05SGarrett D'Amore 	timestruc_t tv = {0};
353888447a05SGarrett D'Amore 
353988447a05SGarrett D'Amore 	mutex_enter(&uacp->usb_ac_mutex);
354088447a05SGarrett D'Amore 	lh = acp->acp_lh;
354188447a05SGarrett D'Amore 	tv.tv_sec = usb_ac_wait_hid;
354288447a05SGarrett D'Amore 
354388447a05SGarrett D'Amore 	while (acp->acp_flags & ACP_ENABLED) {
354488447a05SGarrett D'Amore 		mp = NULL;
354588447a05SGarrett D'Amore 
354688447a05SGarrett D'Amore 		mutex_exit(&uacp->usb_ac_mutex);
354788447a05SGarrett D'Amore 
354888447a05SGarrett D'Amore 		rv = ldi_getmsg(lh, &mp, &tv);
354988447a05SGarrett D'Amore 
355088447a05SGarrett D'Amore 		mutex_enter(&uacp->usb_ac_mutex);
355188447a05SGarrett D'Amore 
3552aa9e0d56SBinzi Cao - Sun Microsystems - Beijing China 		if (rv == ENODEV) {
3553aa9e0d56SBinzi Cao - Sun Microsystems - Beijing China 			USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3554aa9e0d56SBinzi Cao - Sun Microsystems - Beijing China 			    "Device is not availabe");
3555aa9e0d56SBinzi Cao - Sun Microsystems - Beijing China 			break;
3556aa9e0d56SBinzi Cao - Sun Microsystems - Beijing China 		}
3557aa9e0d56SBinzi Cao - Sun Microsystems - Beijing China 
3558e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
355988447a05SGarrett D'Amore 		if ((acp->acp_flags & ACP_ENABLED) && mp != NULL && rv == 0)
356088447a05SGarrett D'Amore 			rv = usb_ac_read_msg(acp, mp);
356188447a05SGarrett D'Amore 
356288447a05SGarrett D'Amore 	}
356388447a05SGarrett D'Amore 	mutex_exit(&uacp->usb_ac_mutex);
356488447a05SGarrett D'Amore }
356588447a05SGarrett D'Amore 
356688447a05SGarrett D'Amore 
356788447a05SGarrett D'Amore /*
356888447a05SGarrett D'Amore  * setup threads to read from the other usb modules that may send unsolicited
356988447a05SGarrett D'Amore  * or asynchronous messages, which is only hid currently
357088447a05SGarrett D'Amore  */
357188447a05SGarrett D'Amore static int
usb_ac_plumb(usb_ac_plumbed_t * acp)357288447a05SGarrett D'Amore usb_ac_plumb(usb_ac_plumbed_t *acp)
357388447a05SGarrett D'Amore {
357488447a05SGarrett D'Amore 	usb_ac_state_t	*uacp = acp->acp_uacp;
357588447a05SGarrett D'Amore 	dev_info_t	*dip;
357688447a05SGarrett D'Amore 	dev_info_t	*acp_dip;
357788447a05SGarrett D'Amore 	int		acp_inst;
357888447a05SGarrett D'Amore 	char		*acp_name;
357988447a05SGarrett D'Amore 	char		tq_nm[128];
358088447a05SGarrett D'Amore 	int		rv = USB_FAILURE;
358188447a05SGarrett D'Amore 
358288447a05SGarrett D'Amore 	mutex_enter(&uacp->usb_ac_mutex);
358388447a05SGarrett D'Amore 
358488447a05SGarrett D'Amore 	dip = uacp->usb_ac_dip;
358588447a05SGarrett D'Amore 
358688447a05SGarrett D'Amore 	acp_dip = acp->acp_dip;
358788447a05SGarrett D'Amore 	acp_inst = ddi_get_instance(acp_dip);
358888447a05SGarrett D'Amore 	acp_name = (char *)ddi_driver_name(acp_dip);
358988447a05SGarrett D'Amore 
35901cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
35911cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_plumb:begin");
359288447a05SGarrett D'Amore 
359388447a05SGarrett D'Amore 	if (strcmp(acp_name, "hid") != 0) {
359488447a05SGarrett D'Amore 		rv = USB_SUCCESS;
359588447a05SGarrett D'Amore 		goto OUT;
359688447a05SGarrett D'Amore 	}
359788447a05SGarrett D'Amore 
359888447a05SGarrett D'Amore 	(void) snprintf(tq_nm, sizeof (tq_nm), "%s_%d_tq",
359988447a05SGarrett D'Amore 	    ddi_driver_name(acp_dip), acp_inst);
360088447a05SGarrett D'Amore 
360188447a05SGarrett D'Amore 	acp->acp_tqp = ddi_taskq_create(dip, tq_nm, 1, TASKQ_DEFAULTPRI, 0);
360288447a05SGarrett D'Amore 	if (acp->acp_tqp == NULL)
360388447a05SGarrett D'Amore 		goto OUT;
360488447a05SGarrett D'Amore 
360588447a05SGarrett D'Amore 	if (ddi_taskq_dispatch(acp->acp_tqp, usb_ac_reader, (void *)acp,
360688447a05SGarrett D'Amore 	    DDI_SLEEP) != DDI_SUCCESS)
360788447a05SGarrett D'Amore 		goto OUT;
360888447a05SGarrett D'Amore 
36091cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
36101cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_plumb: dispatched reader");
361188447a05SGarrett D'Amore 
361288447a05SGarrett D'Amore 	rv = USB_SUCCESS;
361388447a05SGarrett D'Amore 
361488447a05SGarrett D'Amore OUT:
361588447a05SGarrett D'Amore 	mutex_exit(&uacp->usb_ac_mutex);
361688447a05SGarrett D'Amore 
36171cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
36181cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_plumb: done, rv=%d", rv);
361988447a05SGarrett D'Amore 
362088447a05SGarrett D'Amore 	return (rv);
362188447a05SGarrett D'Amore }
362288447a05SGarrett D'Amore 
362388447a05SGarrett D'Amore 
362488447a05SGarrett D'Amore static void
usb_ac_mux_plumbing_tq(void * arg)362588447a05SGarrett D'Amore usb_ac_mux_plumbing_tq(void *arg)
362688447a05SGarrett D'Amore {
362788447a05SGarrett D'Amore 	usb_ac_state_t *uacp = (usb_ac_state_t *)arg;
362888447a05SGarrett D'Amore 
362988447a05SGarrett D'Amore 	if (usb_ac_mux_plumbing(uacp) != USB_SUCCESS)
36301cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
36311cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_mux_plumbing_tq:failed");
363288447a05SGarrett D'Amore }
363388447a05SGarrett D'Amore 
363488447a05SGarrett D'Amore 
363588447a05SGarrett D'Amore static int
usb_ac_do_plumbing(usb_ac_state_t * uacp)363688447a05SGarrett D'Amore usb_ac_do_plumbing(usb_ac_state_t *uacp)
363788447a05SGarrett D'Amore {
363888447a05SGarrett D'Amore 	dev_info_t *dip = uacp->usb_ac_dip;
363988447a05SGarrett D'Amore 	int inst = ddi_get_instance(dip);
364088447a05SGarrett D'Amore 	char tq_nm[128];
364188447a05SGarrett D'Amore 	int rv = USB_FAILURE;
364288447a05SGarrett D'Amore 
364388447a05SGarrett D'Amore 	(void) snprintf(tq_nm, sizeof (tq_nm), "%s_%d_tq",
364488447a05SGarrett D'Amore 	    ddi_driver_name(dip), inst);
364588447a05SGarrett D'Amore 
364688447a05SGarrett D'Amore 	uacp->tqp = ddi_taskq_create(dip, tq_nm, 1, TASKQ_DEFAULTPRI, 0);
364788447a05SGarrett D'Amore 	if (uacp->tqp == NULL) {
364888447a05SGarrett D'Amore 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
364988447a05SGarrett D'Amore 		    "usb_ac_do_plumbing: ddi_taskq_create failed");
365088447a05SGarrett D'Amore 		goto OUT;
365188447a05SGarrett D'Amore 	}
365288447a05SGarrett D'Amore 
365388447a05SGarrett D'Amore 	if (ddi_taskq_dispatch(uacp->tqp, usb_ac_mux_plumbing_tq, (void *)uacp,
365488447a05SGarrett D'Amore 	    DDI_SLEEP) != DDI_SUCCESS) {
365588447a05SGarrett D'Amore 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
365688447a05SGarrett D'Amore 		    "usb_ac_do_plumbing: ddi_taskq_dispatch failed");
365788447a05SGarrett D'Amore 		goto OUT;
365888447a05SGarrett D'Amore 	}
365988447a05SGarrett D'Amore 
366088447a05SGarrett D'Amore 	rv = USB_SUCCESS;
366188447a05SGarrett D'Amore 
366288447a05SGarrett D'Amore OUT:
366388447a05SGarrett D'Amore 	return (rv);
366488447a05SGarrett D'Amore }
366588447a05SGarrett D'Amore 
366688447a05SGarrett D'Amore 
366788447a05SGarrett D'Amore 
366888447a05SGarrett D'Amore static void
usb_ac_mux_unplumbing_tq(void * arg)366988447a05SGarrett D'Amore usb_ac_mux_unplumbing_tq(void *arg)
367088447a05SGarrett D'Amore {
367188447a05SGarrett D'Amore 	usb_ac_state_t *uacp = (usb_ac_state_t *)arg;
367288447a05SGarrett D'Amore 
367388447a05SGarrett D'Amore 	if (usb_ac_mux_unplumbing(uacp) != USB_SUCCESS)
36741cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
36751cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_mux_unplumbing:failed");
367688447a05SGarrett D'Amore }
367788447a05SGarrett D'Amore 
367888447a05SGarrett D'Amore 
367988447a05SGarrett D'Amore static int
usb_ac_do_unplumbing(usb_ac_state_t * uacp)368088447a05SGarrett D'Amore usb_ac_do_unplumbing(usb_ac_state_t *uacp)
368188447a05SGarrett D'Amore {
368288447a05SGarrett D'Amore 	int rv = USB_FAILURE;
368388447a05SGarrett D'Amore 
368488447a05SGarrett D'Amore 	if (uacp->tqp == NULL)
368588447a05SGarrett D'Amore 		return (USB_SUCCESS);
368688447a05SGarrett D'Amore 
368788447a05SGarrett D'Amore 	if (ddi_taskq_dispatch(uacp->tqp, usb_ac_mux_unplumbing_tq,
368888447a05SGarrett D'Amore 	    (void *)uacp, DDI_SLEEP) != DDI_SUCCESS) {
368988447a05SGarrett D'Amore 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
369088447a05SGarrett D'Amore 		    "usb_ac_do_unplumbing: ddi_taskq_dispatch failed");
369188447a05SGarrett D'Amore 		goto OUT;
369288447a05SGarrett D'Amore 	}
369388447a05SGarrett D'Amore 
36941cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
36951cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_do_unplumbing: waiting for unplumb thread");
369688447a05SGarrett D'Amore 
369788447a05SGarrett D'Amore 	ddi_taskq_wait(uacp->tqp);
369888447a05SGarrett D'Amore 	rv = USB_SUCCESS;
369988447a05SGarrett D'Amore 
37001cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
37011cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_do_unplumbing: unplumb thread done");
370288447a05SGarrett D'Amore 
370388447a05SGarrett D'Amore OUT:
370488447a05SGarrett D'Amore 	if (uacp->tqp != NULL) {
370588447a05SGarrett D'Amore 		ddi_taskq_destroy(uacp->tqp);
370688447a05SGarrett D'Amore 		uacp->tqp = NULL;
370788447a05SGarrett D'Amore 	}
370888447a05SGarrett D'Amore 	return (rv);
370988447a05SGarrett D'Amore }
371088447a05SGarrett D'Amore 
371188447a05SGarrett D'Amore 
371288447a05SGarrett D'Amore /*
371388447a05SGarrett D'Amore  * teardown threads to the other usb modules
371488447a05SGarrett D'Amore  * and clear structures as part of unplumbing
371588447a05SGarrett D'Amore  */
371688447a05SGarrett D'Amore static void
usb_ac_unplumb(usb_ac_plumbed_t * acp)371788447a05SGarrett D'Amore usb_ac_unplumb(usb_ac_plumbed_t *acp)
371888447a05SGarrett D'Amore {
371988447a05SGarrett D'Amore 	usb_ac_streams_info_t *streams_infop;
372088447a05SGarrett D'Amore 	usb_ac_state_t	*uacp = acp->acp_uacp;
372188447a05SGarrett D'Amore 
372288447a05SGarrett D'Amore 
37231cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
37241cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_unplumb: begin");
372588447a05SGarrett D'Amore 
372688447a05SGarrett D'Amore 	if (acp->acp_tqp != NULL) {
37271cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
37281cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_unplumb: destroying taskq");
372988447a05SGarrett D'Amore 
373088447a05SGarrett D'Amore 		ddi_taskq_destroy(acp->acp_tqp);
373188447a05SGarrett D'Amore 	}
373288447a05SGarrett D'Amore 
373388447a05SGarrett D'Amore 	mutex_enter(&uacp->usb_ac_mutex);
373488447a05SGarrett D'Amore 
373588447a05SGarrett D'Amore 	if (acp->acp_driver == USB_AS_PLUMBED) {
373688447a05SGarrett D'Amore 		/*
373788447a05SGarrett D'Amore 		 * we bzero the streams info and plumbed structure
373888447a05SGarrett D'Amore 		 * since there is no guarantee that the next plumbing
373988447a05SGarrett D'Amore 		 * will be identical
374088447a05SGarrett D'Amore 		 */
374188447a05SGarrett D'Amore 		streams_infop = (usb_ac_streams_info_t *)acp->acp_data;
374288447a05SGarrett D'Amore 
374388447a05SGarrett D'Amore 		/* bzero the relevant plumbing structure */
374488447a05SGarrett D'Amore 		bzero(streams_infop, sizeof (usb_ac_streams_info_t));
374588447a05SGarrett D'Amore 	}
374688447a05SGarrett D'Amore 	bzero(acp, sizeof (usb_ac_plumbed_t));
374788447a05SGarrett D'Amore 
374888447a05SGarrett D'Amore 	mutex_exit(&uacp->usb_ac_mutex);
374988447a05SGarrett D'Amore 
37501cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
37511cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_unplumb: done");
375288447a05SGarrett D'Amore }
375388447a05SGarrett D'Amore 
375488447a05SGarrett D'Amore 
375588447a05SGarrett D'Amore /*ARGSUSED*/
375688447a05SGarrett D'Amore static int
usb_ac_mux_plumbing(usb_ac_state_t * uacp)375788447a05SGarrett D'Amore usb_ac_mux_plumbing(usb_ac_state_t *uacp)
375888447a05SGarrett D'Amore {
375988447a05SGarrett D'Amore 	dev_info_t		*dip;
376088447a05SGarrett D'Amore 
376188447a05SGarrett D'Amore 	/* get the usb_ac dip */
376288447a05SGarrett D'Amore 	dip = uacp->usb_ac_dip;
376388447a05SGarrett D'Amore 
376488447a05SGarrett D'Amore 	/* Access to the global variables is synchronized */
376588447a05SGarrett D'Amore 	mutex_enter(&uacp->usb_ac_mutex);
376688447a05SGarrett D'Amore 
37671cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
37681cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_mux_plumbing:state = %d",
376988447a05SGarrett D'Amore 	    uacp->usb_ac_plumbing_state);
377088447a05SGarrett D'Amore 
377188447a05SGarrett D'Amore 	if (uacp->usb_ac_plumbing_state >= USB_AC_STATE_PLUMBED) {
377288447a05SGarrett D'Amore 		mutex_exit(&uacp->usb_ac_mutex);
37731cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
37741cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_mux_plumbing: audio streams driver"
37751cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    " already plumbed");
377688447a05SGarrett D'Amore 
377788447a05SGarrett D'Amore 		return (USB_SUCCESS);
377888447a05SGarrett D'Amore 	}
377988447a05SGarrett D'Amore 
378088447a05SGarrett D'Amore 	/* usb_as and hid should be attached but double check */
378188447a05SGarrett D'Amore 	if (usb_ac_online_siblings(uacp) != USB_SUCCESS) {
378288447a05SGarrett D'Amore 		mutex_exit(&uacp->usb_ac_mutex);
37831cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
37841cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		"usb_ac_mux_plumbing:no audio streams driver plumbed");
378588447a05SGarrett D'Amore 
378688447a05SGarrett D'Amore 		return (USB_FAILURE);
378788447a05SGarrett D'Amore 	}
378888447a05SGarrett D'Amore 
37891cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
37901cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_mux_plumbing: raising power");
379188447a05SGarrett D'Amore 	mutex_exit(&uacp->usb_ac_mutex);
379288447a05SGarrett D'Amore 
379388447a05SGarrett D'Amore 	/* bring the device to full power */
379488447a05SGarrett D'Amore 	usb_ac_pm_busy_component(uacp);
379588447a05SGarrett D'Amore 	(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
379688447a05SGarrett D'Amore 
379788447a05SGarrett D'Amore 	/* avoid dips disappearing while we are plumbing */
379888447a05SGarrett D'Amore 	usb_ac_hold_siblings(uacp);
379988447a05SGarrett D'Amore 
380088447a05SGarrett D'Amore 	mutex_enter(&uacp->usb_ac_mutex);
380188447a05SGarrett D'Amore 
380288447a05SGarrett D'Amore 	/*
380388447a05SGarrett D'Amore 	 * walk all siblings and create the usb_ac<->usb_as and
380488447a05SGarrett D'Amore 	 * usb_ac<->hid streams. return of 0 indicates no or
380588447a05SGarrett D'Amore 	 * partial/failed plumbing
380688447a05SGarrett D'Amore 	 */
380788447a05SGarrett D'Amore 	if (usb_ac_mux_walk_siblings(uacp) == 0) {
380888447a05SGarrett D'Amore 		/* pretend that we are plumbed so we can unplumb */
380988447a05SGarrett D'Amore 		uacp->usb_ac_plumbing_state = USB_AC_STATE_PLUMBED;
381088447a05SGarrett D'Amore 
381188447a05SGarrett D'Amore 		mutex_exit(&uacp->usb_ac_mutex);
381288447a05SGarrett D'Amore 
381388447a05SGarrett D'Amore 		(void) usb_ac_mux_unplumbing(uacp);
381488447a05SGarrett D'Amore 
38151cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
38161cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_mux_plumbing: no audio streams driver plumbed");
381788447a05SGarrett D'Amore 
381888447a05SGarrett D'Amore 		usb_ac_rele_siblings(uacp);
381988447a05SGarrett D'Amore 
382088447a05SGarrett D'Amore 		usb_ac_pm_idle_component(uacp);
382188447a05SGarrett D'Amore 
382288447a05SGarrett D'Amore 		return (USB_FAILURE);
382388447a05SGarrett D'Amore 	}
382488447a05SGarrett D'Amore 	uacp->usb_ac_plumbing_state = USB_AC_STATE_PLUMBED;
382588447a05SGarrett D'Amore 
382688447a05SGarrett D'Amore 	/* restore state if we have already registered with the mixer */
382788447a05SGarrett D'Amore 	if (uacp->usb_ac_registered_with_mixer) {
38281cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
38291cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_mux_plumbing:already registered with mixer,"
38301cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "restoring state");
383188447a05SGarrett D'Amore 
383288447a05SGarrett D'Amore 		(void) usb_ac_restore_audio_state(uacp, USB_FLAGS_SLEEP);
383388447a05SGarrett D'Amore 
383488447a05SGarrett D'Amore 	} else if (usb_ac_mixer_registration(uacp) != USB_SUCCESS) {
383588447a05SGarrett D'Amore 		mutex_exit(&uacp->usb_ac_mutex);
383688447a05SGarrett D'Amore 
38371cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
38381cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_mux_plumbing: mixer registration failed");
383988447a05SGarrett D'Amore 
384088447a05SGarrett D'Amore 		(void) usb_ac_mux_unplumbing(uacp);
384188447a05SGarrett D'Amore 
384288447a05SGarrett D'Amore 		usb_ac_rele_siblings(uacp);
384388447a05SGarrett D'Amore 
384488447a05SGarrett D'Amore 		usb_ac_pm_idle_component(uacp);
384588447a05SGarrett D'Amore 
384688447a05SGarrett D'Amore 		return (USB_FAILURE);
384788447a05SGarrett D'Amore 	}
384888447a05SGarrett D'Amore 
384988447a05SGarrett D'Amore 	mutex_exit(&uacp->usb_ac_mutex);
385088447a05SGarrett D'Amore 	usb_ac_rele_siblings(uacp);
385188447a05SGarrett D'Amore 
385288447a05SGarrett D'Amore 	usb_ac_pm_idle_component(uacp);
385388447a05SGarrett D'Amore 
38541cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
38551cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_mux_plumbing:done");
385688447a05SGarrett D'Amore 
385788447a05SGarrett D'Amore 	return (USB_SUCCESS);
385888447a05SGarrett D'Amore }
385988447a05SGarrett D'Amore 
386088447a05SGarrett D'Amore 
386188447a05SGarrett D'Amore static int
usb_ac_mux_unplumbing(usb_ac_state_t * uacp)386288447a05SGarrett D'Amore usb_ac_mux_unplumbing(usb_ac_state_t *uacp)
386388447a05SGarrett D'Amore {
386488447a05SGarrett D'Amore 	usb_ac_plumbed_t	*acp;
386588447a05SGarrett D'Amore 	ldi_handle_t		lh;
386688447a05SGarrett D'Amore 	dev_info_t		*acp_dip;
386788447a05SGarrett D'Amore 	int			inst;
386888447a05SGarrett D'Amore 	int			i;
386988447a05SGarrett D'Amore 	dev_t			devt;
387088447a05SGarrett D'Amore 	minor_t			minor;
387188447a05SGarrett D'Amore 	int			maxlinked = 0;
387288447a05SGarrett D'Amore 
387388447a05SGarrett D'Amore 	mutex_enter(&uacp->usb_ac_mutex);
387488447a05SGarrett D'Amore 
387588447a05SGarrett D'Amore 
387688447a05SGarrett D'Amore 	if (uacp->usb_ac_plumbing_state == USB_AC_STATE_UNPLUMBED) {
38771cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
38781cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_mux_unplumbing: already unplumbed!");
387988447a05SGarrett D'Amore 		mutex_exit(&uacp->usb_ac_mutex);
388088447a05SGarrett D'Amore 
388188447a05SGarrett D'Amore 		return (USB_SUCCESS);
388288447a05SGarrett D'Amore 	}
388388447a05SGarrett D'Amore 
388488447a05SGarrett D'Amore 	/* usb_ac might not have anything plumbed yet */
388588447a05SGarrett D'Amore 	if (uacp->usb_ac_current_plumbed_index == -1) {
38861cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
38871cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_mux_unplumbing: nothing plumbed");
388888447a05SGarrett D'Amore 		uacp->usb_ac_plumbing_state = USB_AC_STATE_UNPLUMBED;
388988447a05SGarrett D'Amore 		mutex_exit(&uacp->usb_ac_mutex);
389088447a05SGarrett D'Amore 
389188447a05SGarrett D'Amore 		return (USB_SUCCESS);
389288447a05SGarrett D'Amore 	}
389388447a05SGarrett D'Amore 
389488447a05SGarrett D'Amore 	/* do not allow detach if still busy */
389588447a05SGarrett D'Amore 	if (uacp->usb_ac_busy_count) {
38961cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
38971cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_mux_unplumbing: mux still busy (%d)",
389888447a05SGarrett D'Amore 		    uacp->usb_ac_busy_count);
389988447a05SGarrett D'Amore 		mutex_exit(&uacp->usb_ac_mutex);
390088447a05SGarrett D'Amore 
390188447a05SGarrett D'Amore 		return (USB_FAILURE);
390288447a05SGarrett D'Amore 	}
390388447a05SGarrett D'Amore 
390488447a05SGarrett D'Amore 	uacp->usb_ac_plumbing_state = USB_AC_STATE_UNPLUMBED;
390588447a05SGarrett D'Amore 
390688447a05SGarrett D'Amore 	/* close ac-as and ac-hid streams */
390788447a05SGarrett D'Amore 	maxlinked = uacp->usb_ac_current_plumbed_index + 1;
39081cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
39091cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_mux_unplumbing: maxlinked = %d",  maxlinked);
391088447a05SGarrett D'Amore 
391188447a05SGarrett D'Amore 	for (i = 0; i < maxlinked; i++) {
391288447a05SGarrett D'Amore 		/*
391388447a05SGarrett D'Amore 		 * we must save members of usb_ac_plumbed[] before calling
391488447a05SGarrett D'Amore 		 * usb_ac_unplumb() because it clears the structure
391588447a05SGarrett D'Amore 		 */
391688447a05SGarrett D'Amore 		acp = &uacp->usb_ac_plumbed[i];
391788447a05SGarrett D'Amore 		lh = acp->acp_lh;
391888447a05SGarrett D'Amore 		acp_dip = acp->acp_dip;
391988447a05SGarrett D'Amore 		devt = acp->acp_devt;
392088447a05SGarrett D'Amore 
392188447a05SGarrett D'Amore 		if (acp_dip == NULL) {
39221cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 			USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
39231cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 			    "usb_ac_mux_unplumbing: [%d] - skipping",  i);
392488447a05SGarrett D'Amore 			continue;
392588447a05SGarrett D'Amore 		}
392688447a05SGarrett D'Amore 
392788447a05SGarrett D'Amore 		minor = getminor(devt);
392888447a05SGarrett D'Amore 		inst = ddi_get_instance(acp_dip);
392988447a05SGarrett D'Amore 
393088447a05SGarrett D'Amore 		uacp->usb_ac_current_plumbed_index = i;
393188447a05SGarrett D'Amore 
39321cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
39331cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_mux_unplumbing: [%d] - %s%d minor 0x%x",  i,
393488447a05SGarrett D'Amore 		    ddi_driver_name(acp_dip), inst, minor);
393588447a05SGarrett D'Amore 
393688447a05SGarrett D'Amore 		if (lh != NULL) {
393788447a05SGarrett D'Amore 
393888447a05SGarrett D'Amore 			acp->acp_flags &= ~ACP_ENABLED;
393988447a05SGarrett D'Amore 
3940e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			mutex_exit(&uacp->usb_ac_mutex);
3941e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
39421cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 			USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
39431cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 			    "usb_ac_mux_unplumbing:[%d] - closing", i);
394488447a05SGarrett D'Amore 
39452c8a3792SBinzi Cao - Sun Microsystems - Beijing China 			/*
39462c8a3792SBinzi Cao - Sun Microsystems - Beijing China 			 * ldi_close will cause panic if ldi_getmsg
39472c8a3792SBinzi Cao - Sun Microsystems - Beijing China 			 * is not finished. ddi_taskq_destroy will wait
39482c8a3792SBinzi Cao - Sun Microsystems - Beijing China 			 * for the thread to complete.
39492c8a3792SBinzi Cao - Sun Microsystems - Beijing China 			 */
39502c8a3792SBinzi Cao - Sun Microsystems - Beijing China 			usb_ac_unplumb(acp);
395188447a05SGarrett D'Amore 			(void) ldi_close(lh, FREAD|FWRITE, kcred);
395288447a05SGarrett D'Amore 
395388447a05SGarrett D'Amore 
39541cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 			USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
39551cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 			    "usb_ac_mux_unplumbing: [%d] - unplumbed", i);
395688447a05SGarrett D'Amore 
395788447a05SGarrett D'Amore 			mutex_enter(&uacp->usb_ac_mutex);
395888447a05SGarrett D'Amore 		}
395988447a05SGarrett D'Amore 	}
396088447a05SGarrett D'Amore 
396188447a05SGarrett D'Amore 	mutex_exit(&uacp->usb_ac_mutex);
396288447a05SGarrett D'Amore 
396388447a05SGarrett D'Amore 	/* Wait till all activity in the default pipe has drained */
396488447a05SGarrett D'Amore 	usb_ac_serialize_access(uacp);
396588447a05SGarrett D'Amore 	usb_ac_release_access(uacp);
396688447a05SGarrett D'Amore 
396788447a05SGarrett D'Amore 	mutex_enter(&uacp->usb_ac_mutex);
396888447a05SGarrett D'Amore 	uacp->usb_ac_current_plumbed_index = -1;
396988447a05SGarrett D'Amore 	mutex_exit(&uacp->usb_ac_mutex);
397088447a05SGarrett D'Amore 
39711cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
39721cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_mux_unplumbing: done");
397388447a05SGarrett D'Amore 
397488447a05SGarrett D'Amore 	return (USB_SUCCESS);
397588447a05SGarrett D'Amore }
397688447a05SGarrett D'Amore 
397788447a05SGarrett D'Amore 
397888447a05SGarrett D'Amore /*
397988447a05SGarrett D'Amore  * walk all siblings and create the ac<->as and ac<->hid streams
398088447a05SGarrett D'Amore  */
398188447a05SGarrett D'Amore static int
usb_ac_mux_walk_siblings(usb_ac_state_t * uacp)398288447a05SGarrett D'Amore usb_ac_mux_walk_siblings(usb_ac_state_t *uacp)
398388447a05SGarrett D'Amore {
398488447a05SGarrett D'Amore 	dev_info_t	*pdip;
398588447a05SGarrett D'Amore 	dev_info_t	*child_dip;
398688447a05SGarrett D'Amore 	major_t		drv_major;
398788447a05SGarrett D'Amore 	minor_t		drv_minor;
398888447a05SGarrett D'Amore 	int		drv_instance;
398988447a05SGarrett D'Amore 	char		*drv_name;
399088447a05SGarrett D'Amore 	dev_t		drv_devt;
399188447a05SGarrett D'Amore 	ldi_handle_t	drv_lh;
399288447a05SGarrett D'Amore 	ldi_ident_t	li;
399388447a05SGarrett D'Amore 	int		error;
399488447a05SGarrett D'Amore 	int		count = 0;
399588447a05SGarrett D'Amore 
399688447a05SGarrett D'Amore 	ASSERT(mutex_owned(&uacp->usb_ac_mutex));
399788447a05SGarrett D'Amore 
399888447a05SGarrett D'Amore 	pdip = ddi_get_parent(uacp->usb_ac_dip);
399988447a05SGarrett D'Amore 	child_dip = ddi_get_child(pdip);
400088447a05SGarrett D'Amore 
400188447a05SGarrett D'Amore 	while ((child_dip != NULL) && (count < USB_AC_MAX_PLUMBED)) {
400288447a05SGarrett D'Amore 		drv_instance = ddi_get_instance(child_dip);
400388447a05SGarrett D'Amore 		drv_name = (char *)ddi_driver_name(child_dip);
400488447a05SGarrett D'Amore 
40051cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
40061cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_mux_walk_siblings: plumbing %s%d count=%d",
400788447a05SGarrett D'Amore 		    drv_name, drv_instance, count);
400888447a05SGarrett D'Amore 
400988447a05SGarrett D'Amore 		/* ignore own dip */
401088447a05SGarrett D'Amore 		if (child_dip == uacp->usb_ac_dip) {
401188447a05SGarrett D'Amore 			child_dip = ddi_get_next_sibling(child_dip);
401288447a05SGarrett D'Amore 			continue;
401388447a05SGarrett D'Amore 		}
401488447a05SGarrett D'Amore 		drv_instance = ddi_get_instance(child_dip);
401588447a05SGarrett D'Amore 
401688447a05SGarrett D'Amore 		/* ignore other dip other than usb_as and hid */
401788447a05SGarrett D'Amore 		if (strcmp(ddi_driver_name(child_dip), "usb_as") == 0) {
401888447a05SGarrett D'Amore 			uacp->usb_ac_plumbed[count].acp_driver = USB_AS_PLUMBED;
401988447a05SGarrett D'Amore 			drv_minor = USB_AS_CONSTRUCT_MINOR(drv_instance);
402088447a05SGarrett D'Amore 		} else if (strcmp(ddi_driver_name(child_dip), "hid") == 0) {
402188447a05SGarrett D'Amore 			uacp->usb_ac_plumbed[count].acp_driver = USB_AH_PLUMBED;
402288447a05SGarrett D'Amore 			drv_minor = HID_CONSTRUCT_EXTERNAL_MINOR(drv_instance);
402388447a05SGarrett D'Amore 		} else {
402488447a05SGarrett D'Amore 			drv_minor = drv_instance;
402588447a05SGarrett D'Amore 			uacp->usb_ac_plumbed[count].acp_driver =
402688447a05SGarrett D'Amore 			    UNKNOWN_PLUMBED;
402788447a05SGarrett D'Amore 			child_dip = ddi_get_next_sibling(child_dip);
402888447a05SGarrett D'Amore 
402988447a05SGarrett D'Amore 			continue;
403088447a05SGarrett D'Amore 		}
403188447a05SGarrett D'Amore 
403288447a05SGarrett D'Amore 		if (!i_ddi_devi_attached(child_dip)) {
403388447a05SGarrett D'Amore 			child_dip = ddi_get_next_sibling(child_dip);
403488447a05SGarrett D'Amore 
403588447a05SGarrett D'Amore 			continue;
403688447a05SGarrett D'Amore 		}
403788447a05SGarrett D'Amore 
403888447a05SGarrett D'Amore 		if (DEVI_IS_DEVICE_REMOVED(child_dip)) {
403988447a05SGarrett D'Amore 			child_dip = ddi_get_next_sibling(child_dip);
404088447a05SGarrett D'Amore 
404188447a05SGarrett D'Amore 			continue;
404288447a05SGarrett D'Amore 		}
404388447a05SGarrett D'Amore 
404488447a05SGarrett D'Amore 		drv_major = ddi_driver_major(child_dip);
404588447a05SGarrett D'Amore 
404688447a05SGarrett D'Amore 		uacp->usb_ac_current_plumbed_index = count;
404788447a05SGarrett D'Amore 
404888447a05SGarrett D'Amore 		mutex_exit(&uacp->usb_ac_mutex);
404988447a05SGarrett D'Amore 
405088447a05SGarrett D'Amore 		drv_devt = makedevice(drv_major, drv_minor);
405188447a05SGarrett D'Amore 
40521cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
40531cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_mux_walk_siblings:: opening %s%d devt=(%d, 0x%x)",
405488447a05SGarrett D'Amore 		    drv_name, drv_instance, drv_major, drv_minor);
405588447a05SGarrett D'Amore 
405688447a05SGarrett D'Amore 		error = ldi_ident_from_dip(uacp->usb_ac_dip, &li);
405788447a05SGarrett D'Amore 		if (error == 0) {
4058e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			mutex_enter(&uacp->usb_ac_mutex);
405988447a05SGarrett D'Amore 			uacp->usb_ac_plumbed[count].acp_flags |= ACP_ENABLED;
4060e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			mutex_exit(&uacp->usb_ac_mutex);
406188447a05SGarrett D'Amore 
406288447a05SGarrett D'Amore 			error = ldi_open_by_dev(&drv_devt, OTYP_CHR,
406388447a05SGarrett D'Amore 			    FREAD|FWRITE, kcred, &drv_lh, li);
406488447a05SGarrett D'Amore 			ldi_ident_release(li);
406588447a05SGarrett D'Amore 		}
406688447a05SGarrett D'Amore 
406788447a05SGarrett D'Amore 		mutex_enter(&uacp->usb_ac_mutex);
406888447a05SGarrett D'Amore 		if (error) {
40691cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 			USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
40701cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 			    "usb_ac_mux_walk_siblings: open of devt=(%d, 0x%x)"
40711cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 			    " failed error=%d", drv_major, drv_minor, error);
407288447a05SGarrett D'Amore 
407388447a05SGarrett D'Amore 			return (0);
407488447a05SGarrett D'Amore 		}
407588447a05SGarrett D'Amore 
407688447a05SGarrett D'Amore 		uacp->usb_ac_plumbed[count].acp_uacp = uacp;
407788447a05SGarrett D'Amore 		uacp->usb_ac_plumbed[count].acp_devt = drv_devt;
407888447a05SGarrett D'Amore 		uacp->usb_ac_plumbed[count].acp_lh = drv_lh;
407988447a05SGarrett D'Amore 		uacp->usb_ac_plumbed[count].acp_dip = child_dip;
408088447a05SGarrett D'Amore 		uacp->usb_ac_plumbed[count].acp_ifno =
408188447a05SGarrett D'Amore 		    usb_get_if_number(child_dip);
408288447a05SGarrett D'Amore 
408388447a05SGarrett D'Amore 		if (uacp->usb_ac_plumbed[count].acp_driver == USB_AS_PLUMBED) {
408488447a05SGarrett D'Amore 			/* get registration data */
408588447a05SGarrett D'Amore 			if (usb_ac_get_reg_data(uacp, drv_lh, count) !=
408688447a05SGarrett D'Amore 			    USB_SUCCESS) {
408788447a05SGarrett D'Amore 
40881cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 				USB_DPRINTF_L3(PRINT_MASK_ALL,
40891cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 				    uacp->usb_ac_log_handle,
40901cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 				    "usb_ac_mux_walk_siblings:"
40911cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 				    "usb_ac_get_reg_data failed on %s%d",
409288447a05SGarrett D'Amore 				    drv_name, drv_instance);
409388447a05SGarrett D'Amore 
409488447a05SGarrett D'Amore 				uacp->usb_ac_plumbed[count].acp_dip = NULL;
409588447a05SGarrett D'Amore 
409688447a05SGarrett D'Amore 				return (0);
409788447a05SGarrett D'Amore 			}
409888447a05SGarrett D'Amore 		} else if (uacp->usb_ac_plumbed[count].acp_driver ==
409988447a05SGarrett D'Amore 		    USB_AH_PLUMBED) {
410088447a05SGarrett D'Amore 			int rval;
410188447a05SGarrett D'Amore 
41021cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 			USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
41031cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 			    "usb_ac_mux_walk_siblings: pushing usb_ah on %s%d",
410488447a05SGarrett D'Amore 			    drv_name, drv_instance);
410588447a05SGarrett D'Amore 
410688447a05SGarrett D'Amore 			mutex_exit(&uacp->usb_ac_mutex);
410788447a05SGarrett D'Amore 
410888447a05SGarrett D'Amore 			/* push usb_ah module on top of hid */
410988447a05SGarrett D'Amore 			error = ldi_ioctl(drv_lh, I_PUSH, (intptr_t)"usb_ah",
411088447a05SGarrett D'Amore 			    FKIOCTL, kcred, &rval);
411188447a05SGarrett D'Amore 			mutex_enter(&uacp->usb_ac_mutex);
411288447a05SGarrett D'Amore 
411388447a05SGarrett D'Amore 			if (error) {
41141cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 				USB_DPRINTF_L2(PRINT_MASK_ALL,
41151cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 				    uacp->usb_ac_log_handle,
41161cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 				    "usb_ac_mux_walk_siblings: ldi_ioctl"
41171cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 				    "I_PUSH failed on %s%d, error=%d",
411888447a05SGarrett D'Amore 				    drv_name, drv_instance, error);
411988447a05SGarrett D'Amore 
412088447a05SGarrett D'Amore 				uacp->usb_ac_plumbed[count].acp_dip = NULL;
412188447a05SGarrett D'Amore 
412288447a05SGarrett D'Amore 				/* skip plumbing the hid driver */
412388447a05SGarrett D'Amore 				child_dip = ddi_get_next_sibling(child_dip);
412488447a05SGarrett D'Amore 				continue;
412588447a05SGarrett D'Amore 			}
412688447a05SGarrett D'Amore 		} else {
412788447a05SGarrett D'Amore 			/* should not be here */
41281cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 			USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
41291cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 			    "usb_ac_mux_walk_siblings:- unknown module %s%d",
41301cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 			    drv_name, drv_instance);
413188447a05SGarrett D'Amore 			count--;
413288447a05SGarrett D'Amore 
413388447a05SGarrett D'Amore 			uacp->usb_ac_plumbed[count].acp_dip = NULL;
413488447a05SGarrett D'Amore 
413588447a05SGarrett D'Amore 			/* skip plumbing an unknown module */
413688447a05SGarrett D'Amore 			child_dip = ddi_get_next_sibling(child_dip);
413788447a05SGarrett D'Amore 			continue;
413888447a05SGarrett D'Amore 		}
413988447a05SGarrett D'Amore 
414088447a05SGarrett D'Amore 		mutex_exit(&uacp->usb_ac_mutex);
414188447a05SGarrett D'Amore 		error = usb_ac_plumb(&uacp->usb_ac_plumbed[count]);
414288447a05SGarrett D'Amore 		mutex_enter(&uacp->usb_ac_mutex);
414388447a05SGarrett D'Amore 
414488447a05SGarrett D'Amore 		if (error != USB_SUCCESS) {
41451cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 			USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
41461cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 			    "usb_ac_mux_walk_siblings: usb_ac_plumb "
41471cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 			    "failed for %s%d", drv_name, drv_instance);
414888447a05SGarrett D'Amore 
414988447a05SGarrett D'Amore 			return (0);
415088447a05SGarrett D'Amore 		}
415188447a05SGarrett D'Amore 
41521cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
41531cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_mux_walk_siblings:plumbed %d, minor 0x%x",
41541cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    drv_instance, drv_minor);
415588447a05SGarrett D'Amore 
415688447a05SGarrett D'Amore 		child_dip = ddi_get_next_sibling(child_dip);
415788447a05SGarrett D'Amore 		count++;
415888447a05SGarrett D'Amore 	}
415988447a05SGarrett D'Amore 
41601cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
41611cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_mux_walk_siblings: %d drivers plumbed under usb_ac mux",
416288447a05SGarrett D'Amore 	    count);
416388447a05SGarrett D'Amore 
416488447a05SGarrett D'Amore 	return (count);
416588447a05SGarrett D'Amore }
416688447a05SGarrett D'Amore 
416788447a05SGarrett D'Amore 
416888447a05SGarrett D'Amore /*
416988447a05SGarrett D'Amore  * Register with mixer only after first plumbing.
417088447a05SGarrett D'Amore  * Also do not register if earlier reg data
417188447a05SGarrett D'Amore  * couldn't be received from at least one
417288447a05SGarrett D'Amore  * streaming interface
417388447a05SGarrett D'Amore  */
417488447a05SGarrett D'Amore 
417588447a05SGarrett D'Amore static int
usb_ac_mixer_registration(usb_ac_state_t * uacp)417688447a05SGarrett D'Amore usb_ac_mixer_registration(usb_ac_state_t *uacp)
417788447a05SGarrett D'Amore {
417888447a05SGarrett D'Amore 	usb_as_registration_t *asreg;
4179e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int		n;
418088447a05SGarrett D'Amore 
418188447a05SGarrett D'Amore 	if (uacp->usb_ac_registered_with_mixer) {
418288447a05SGarrett D'Amore 		return (USB_SUCCESS);
418388447a05SGarrett D'Amore 	}
418488447a05SGarrett D'Amore 
418588447a05SGarrett D'Amore 	for (n = 0; n < USB_AC_MAX_AS_PLUMBED; n++) {
418688447a05SGarrett D'Amore 		if (uacp->usb_ac_streams[n].acs_rcvd_reg_data) {
418788447a05SGarrett D'Amore 			break;
418888447a05SGarrett D'Amore 		}
418988447a05SGarrett D'Amore 	}
419088447a05SGarrett D'Amore 
419188447a05SGarrett D'Amore 	/* Haven't found a streaming interface; fail mixer registration */
419288447a05SGarrett D'Amore 	if (n > USB_AC_MAX_AS_PLUMBED) {
41931cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
41941cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		"usb_ac_mixer_registration:- no streaming interface found");
419588447a05SGarrett D'Amore 
419688447a05SGarrett D'Amore 		return (USB_FAILURE);
419788447a05SGarrett D'Amore 	}
419888447a05SGarrett D'Amore 
419988447a05SGarrett D'Amore 	/*
420088447a05SGarrett D'Amore 	 * Fill out streaming interface specific stuff
420188447a05SGarrett D'Amore 	 * Note that we handle only one playing and one recording
420288447a05SGarrett D'Amore 	 * streaming interface at the most
420388447a05SGarrett D'Amore 	 */
420488447a05SGarrett D'Amore 	for (n = 0; n < USB_AC_MAX_AS_PLUMBED; n++) {
4205e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		int ch, chs, id;
420688447a05SGarrett D'Amore 
420788447a05SGarrett D'Amore 		if (uacp->usb_ac_streams[n].acs_rcvd_reg_data == 0) {
420888447a05SGarrett D'Amore 			continue;
420988447a05SGarrett D'Amore 		}
421088447a05SGarrett D'Amore 
4211e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		asreg = &(uacp->usb_ac_streams[n].acs_streams_reg);
421288447a05SGarrett D'Amore 		if (asreg->reg_valid == 0) {
421388447a05SGarrett D'Amore 			continue;
421488447a05SGarrett D'Amore 		}
421588447a05SGarrett D'Amore 
421688447a05SGarrett D'Amore 
421788447a05SGarrett D'Amore 		chs = asreg->reg_formats[0].fmt_chns;
421888447a05SGarrett D'Amore 
421988447a05SGarrett D'Amore 		/* check if any channel supports vol. control for this fmt */
422088447a05SGarrett D'Amore 		for (ch = 0; ch <= chs; ch++) {
422188447a05SGarrett D'Amore 			if ((id = usb_ac_get_featureID(uacp,
422288447a05SGarrett D'Amore 			    asreg->reg_mode, ch,
422388447a05SGarrett D'Amore 			    USB_AUDIO_VOLUME_CONTROL)) != -1) {
42241cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 				USB_DPRINTF_L3(PRINT_MASK_ALL,
42251cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 				    uacp->usb_ac_log_handle,
42261cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 				    "usb_ac_mixer_registration:n= [%d]"
42271cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 				    "- dir=%d featureID=%d",
42281cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 				    n, asreg->reg_mode, id);
422988447a05SGarrett D'Amore 
423088447a05SGarrett D'Amore 				break;
423188447a05SGarrett D'Amore 			}
423288447a05SGarrett D'Amore 		}
4233e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4234e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		uacp->usb_ac_streams[n].acs_default_gain =
4235e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    (id == USB_AC_ID_NONE) ?  (AF_MAX_GAIN): (AF_MAX_GAIN*3/4);
423688447a05SGarrett D'Amore 
42371cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
42381cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_mixer_registration:n= [%d] - mode=%d chs=%d"
42391cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "default_gain=%d id=%d",
4240e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    n, asreg->reg_mode, chs,
4241e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    uacp->usb_ac_streams[n].acs_default_gain, id);
424288447a05SGarrett D'Amore 
424388447a05SGarrett D'Amore 	}
424488447a05SGarrett D'Amore 
424588447a05SGarrett D'Amore 	/* the rest */
424688447a05SGarrett D'Amore 
42471cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4248e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_mixer_registration: calling usb_audio_register");
42491cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 
425088447a05SGarrett D'Amore 	mutex_exit(&uacp->usb_ac_mutex);
425188447a05SGarrett D'Amore 
4252e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (usb_audio_register(uacp) != USB_SUCCESS) {
42531cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4254e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_mixer_registration: usb_audio_register failed");
425588447a05SGarrett D'Amore 
425688447a05SGarrett D'Amore 		mutex_enter(&uacp->usb_ac_mutex);
425788447a05SGarrett D'Amore 
425888447a05SGarrett D'Amore 		return (USB_FAILURE);
425988447a05SGarrett D'Amore 	}
426088447a05SGarrett D'Amore 
426188447a05SGarrett D'Amore 	mutex_enter(&uacp->usb_ac_mutex);
426288447a05SGarrett D'Amore 
426388447a05SGarrett D'Amore 	uacp->usb_ac_registered_with_mixer = 1;
426488447a05SGarrett D'Amore 
426588447a05SGarrett D'Amore 	return (USB_SUCCESS);
426688447a05SGarrett D'Amore }
426788447a05SGarrett D'Amore 
426888447a05SGarrett D'Amore 
426988447a05SGarrett D'Amore /*
4270e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  * Get registriations data when driver attach
427188447a05SGarrett D'Amore  */
427288447a05SGarrett D'Amore static int
usb_ac_get_reg_data(usb_ac_state_t * uacp,ldi_handle_t drv_lh,int index)427388447a05SGarrett D'Amore usb_ac_get_reg_data(usb_ac_state_t *uacp, ldi_handle_t drv_lh, int index)
427488447a05SGarrett D'Amore {
427588447a05SGarrett D'Amore 	int n, error, rval;
427688447a05SGarrett D'Amore 	usb_as_registration_t *streams_reg;
427788447a05SGarrett D'Amore 
427888447a05SGarrett D'Amore 
4279e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	ASSERT(uacp->usb_ac_registered_with_mixer == 0);
428088447a05SGarrett D'Amore 
4281e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	for (n = 0; n < USB_AC_MAX_AS_PLUMBED; n++) {
428288447a05SGarrett D'Amore 		/*
428388447a05SGarrett D'Amore 		 * We haven't received registration data
428488447a05SGarrett D'Amore 		 * from n-th streaming interface in the array
428588447a05SGarrett D'Amore 		 */
428688447a05SGarrett D'Amore 		if (!uacp->usb_ac_streams[n].acs_rcvd_reg_data) {
428788447a05SGarrett D'Amore 			break;
428888447a05SGarrett D'Amore 		}
428988447a05SGarrett D'Amore 	}
429088447a05SGarrett D'Amore 
429188447a05SGarrett D'Amore 	if (n >= USB_AC_MAX_AS_PLUMBED) {
42921cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
42931cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		"More than 2 streaming interfaces (play "
42941cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		"and/or record) currently not supported");
429588447a05SGarrett D'Amore 
429688447a05SGarrett D'Amore 		return (USB_FAILURE);
429788447a05SGarrett D'Amore 	}
429888447a05SGarrett D'Amore 
429988447a05SGarrett D'Amore 	/* take the stream reg struct with the same index */
4300e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	streams_reg = &uacp->usb_ac_streams[n].acs_streams_reg;
430188447a05SGarrett D'Amore 
43021cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
43031cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	"usb_ac_get_reg_data:regdata from usb_as: streams_reg=0x%p, n=%d",
430488447a05SGarrett D'Amore 	    (void *)streams_reg, n);
430588447a05SGarrett D'Amore 
430688447a05SGarrett D'Amore 	mutex_exit(&uacp->usb_ac_mutex);
430788447a05SGarrett D'Amore 
430888447a05SGarrett D'Amore 	if ((error = ldi_ioctl(drv_lh, USB_AUDIO_MIXER_REGISTRATION,
430988447a05SGarrett D'Amore 	    (intptr_t)streams_reg, FKIOCTL, kcred, &rval)) != 0) {
43101cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
43111cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_get_reg_data: ldi_ioctl failed for"
43121cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "mixer registration error=%d", error);
431388447a05SGarrett D'Amore 
431488447a05SGarrett D'Amore 		mutex_enter(&uacp->usb_ac_mutex);
431588447a05SGarrett D'Amore 
431688447a05SGarrett D'Amore 		return (USB_FAILURE);
431788447a05SGarrett D'Amore 	} else {
431888447a05SGarrett D'Amore 		mutex_enter(&uacp->usb_ac_mutex);
431988447a05SGarrett D'Amore 
4320e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		rval = usb_ac_setup_plumbed(uacp, index, n);
432188447a05SGarrett D'Amore 
43221cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
43231cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		"usb_ac_get_reg_data:usb_ac_streams[%d]: "
43241cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "received_reg_data=%d type=%s",  index,
432588447a05SGarrett D'Amore 		    uacp->usb_ac_streams[n].acs_rcvd_reg_data,
4326e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    ((streams_reg->reg_mode == USB_AUDIO_PLAY) ?
432788447a05SGarrett D'Amore 		    "play" : "record"));
432888447a05SGarrett D'Amore 
432988447a05SGarrett D'Amore 		usb_ac_print_reg_data(uacp, streams_reg);
433088447a05SGarrett D'Amore 
433188447a05SGarrett D'Amore 		return (rval);
433288447a05SGarrett D'Amore 	}
433388447a05SGarrett D'Amore }
433488447a05SGarrett D'Amore 
433588447a05SGarrett D'Amore 
433688447a05SGarrett D'Amore /*
4337e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  * setup plumbed and stream info structure
433888447a05SGarrett D'Amore  */
433988447a05SGarrett D'Amore static int
usb_ac_setup_plumbed(usb_ac_state_t * uacp,int plb_idx,int str_idx)4340e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_ac_setup_plumbed(usb_ac_state_t *uacp, int plb_idx, int str_idx)
434188447a05SGarrett D'Amore {
434288447a05SGarrett D'Amore 	uacp->usb_ac_plumbed[plb_idx].acp_data =
434388447a05SGarrett D'Amore 	    &uacp->usb_ac_streams[str_idx];
434488447a05SGarrett D'Amore 	uacp->usb_ac_streams[str_idx].acs_plumbed =
434588447a05SGarrett D'Amore 	    &uacp->usb_ac_plumbed[plb_idx];
434688447a05SGarrett D'Amore 	uacp->usb_ac_streams[str_idx].acs_rcvd_reg_data = 1;
434788447a05SGarrett D'Amore 
434888447a05SGarrett D'Amore 
43491cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4350e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_setup_plumbed: done - plb_idx=%d str_idx=%d ",
4351e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    plb_idx, str_idx);
435288447a05SGarrett D'Amore 
435388447a05SGarrett D'Amore 	return (USB_SUCCESS);
435488447a05SGarrett D'Amore }
435588447a05SGarrett D'Amore 
435688447a05SGarrett D'Amore 
435788447a05SGarrett D'Amore /*
435888447a05SGarrett D'Amore  * function to dump registration data
435988447a05SGarrett D'Amore  */
436088447a05SGarrett D'Amore static void
usb_ac_print_reg_data(usb_ac_state_t * uacp,usb_as_registration_t * reg)436188447a05SGarrett D'Amore usb_ac_print_reg_data(usb_ac_state_t *uacp,
436288447a05SGarrett D'Amore     usb_as_registration_t *reg)
436388447a05SGarrett D'Amore {
436488447a05SGarrett D'Amore 	int n;
436588447a05SGarrett D'Amore 
436688447a05SGarrett D'Amore 	for (n = 0; n < reg->reg_n_formats; n++) {
436788447a05SGarrett D'Amore 		USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
436888447a05SGarrett D'Amore 		    "format%d: alt=%d chns=%d prec=%d enc=%d", n,
436988447a05SGarrett D'Amore 		    reg->reg_formats[n].fmt_alt,
437088447a05SGarrett D'Amore 		    reg->reg_formats[n].fmt_chns,
437188447a05SGarrett D'Amore 		    reg->reg_formats[n].fmt_precision,
437288447a05SGarrett D'Amore 		    reg->reg_formats[n].fmt_encoding);
437388447a05SGarrett D'Amore 	}
437488447a05SGarrett D'Amore 
437588447a05SGarrett D'Amore 	for (n = 0; n < USB_AS_N_FORMATS; n++) {
437688447a05SGarrett D'Amore 		USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
437788447a05SGarrett D'Amore 		    "reg_formats[%d] ptr=0x%p", n,
437888447a05SGarrett D'Amore 		    (void *)&reg->reg_formats[n]);
437988447a05SGarrett D'Amore 	}
438088447a05SGarrett D'Amore 
4381e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
438288447a05SGarrett D'Amore 	    "usb_ac_print_reg_data: End");
438388447a05SGarrett D'Amore }
438488447a05SGarrett D'Amore 
438588447a05SGarrett D'Amore 
438688447a05SGarrett D'Amore static int
usb_ac_online_siblings(usb_ac_state_t * uacp)438788447a05SGarrett D'Amore usb_ac_online_siblings(usb_ac_state_t *uacp)
438888447a05SGarrett D'Amore {
438988447a05SGarrett D'Amore 	dev_info_t	*pdip, *child_dip;
439088447a05SGarrett D'Amore 	int		rval = USB_SUCCESS;
439188447a05SGarrett D'Amore 
439288447a05SGarrett D'Amore 	ASSERT(mutex_owned(&uacp->usb_ac_mutex));
439388447a05SGarrett D'Amore 
43941cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
43951cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_online_siblings:start");
439688447a05SGarrett D'Amore 
439788447a05SGarrett D'Amore 	pdip = ddi_get_parent(uacp->usb_ac_dip);
439888447a05SGarrett D'Amore 
439988447a05SGarrett D'Amore 	child_dip = ddi_get_child(pdip);
440088447a05SGarrett D'Amore 	while (child_dip != NULL) {
440188447a05SGarrett D'Amore 
44021cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
44031cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_online_siblings: onlining %s%d ref=%d",
440488447a05SGarrett D'Amore 		    ddi_driver_name(child_dip),
440588447a05SGarrett D'Amore 		    ddi_get_instance(child_dip),
440688447a05SGarrett D'Amore 		    DEVI(child_dip)->devi_ref);
440788447a05SGarrett D'Amore 
440888447a05SGarrett D'Amore 		/* Online the child_dip of usb_as and hid,  if not already */
440988447a05SGarrett D'Amore 		if ((strcmp(ddi_driver_name(child_dip), "usb_as") == 0) ||
441088447a05SGarrett D'Amore 		    (strcmp(ddi_driver_name(child_dip), "hid") == 0)) {
441188447a05SGarrett D'Amore 
441288447a05SGarrett D'Amore 			mutex_exit(&uacp->usb_ac_mutex);
441388447a05SGarrett D'Amore 			if (ndi_devi_online(child_dip, NDI_ONLINE_ATTACH) !=
441488447a05SGarrett D'Amore 			    NDI_SUCCESS) {
44151cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 				USB_DPRINTF_L3(PRINT_MASK_ALL,
44161cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 				    uacp->usb_ac_log_handle,
44171cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 				    "usb_ac_online_siblings:failed to online"
44181cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 				    "device %s%d", ddi_driver_name(child_dip),
441988447a05SGarrett D'Amore 				    ddi_get_instance(child_dip));
442088447a05SGarrett D'Amore 
442188447a05SGarrett D'Amore 				/* only onlining usb_as is fatal */
442288447a05SGarrett D'Amore 				if (strcmp(ddi_driver_name(child_dip),
442388447a05SGarrett D'Amore 				    "usb_as") == 0) {
442488447a05SGarrett D'Amore 					mutex_enter(&uacp->usb_ac_mutex);
442588447a05SGarrett D'Amore 					rval = USB_FAILURE;
442688447a05SGarrett D'Amore 					break;
442788447a05SGarrett D'Amore 				}
442888447a05SGarrett D'Amore 			}
442988447a05SGarrett D'Amore 			mutex_enter(&uacp->usb_ac_mutex);
443088447a05SGarrett D'Amore 		}
443188447a05SGarrett D'Amore 		child_dip = ddi_get_next_sibling(child_dip);
443288447a05SGarrett D'Amore 	}
443388447a05SGarrett D'Amore 
443488447a05SGarrett D'Amore 	return (rval);
443588447a05SGarrett D'Amore }
443688447a05SGarrett D'Amore 
443788447a05SGarrett D'Amore 
443888447a05SGarrett D'Amore /*
443988447a05SGarrett D'Amore  * hold all audio children before or after plumbing
444088447a05SGarrett D'Amore  * online usb_as and hid, if not already
444188447a05SGarrett D'Amore  */
444288447a05SGarrett D'Amore static void
usb_ac_hold_siblings(usb_ac_state_t * uacp)444388447a05SGarrett D'Amore usb_ac_hold_siblings(usb_ac_state_t *uacp)
444488447a05SGarrett D'Amore {
444588447a05SGarrett D'Amore 	dev_info_t	*pdip, *child_dip;
444688447a05SGarrett D'Amore 
44471cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
44481cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_hold_siblings:start");
444988447a05SGarrett D'Amore 
445088447a05SGarrett D'Amore 	/* hold all siblings and ourselves */
445188447a05SGarrett D'Amore 	pdip = ddi_get_parent(uacp->usb_ac_dip);
445288447a05SGarrett D'Amore 
445388447a05SGarrett D'Amore 	/* hold the children */
44543fe80ca4SDan Cross 	ndi_devi_enter(pdip);
445588447a05SGarrett D'Amore 	child_dip = ddi_get_child(pdip);
445688447a05SGarrett D'Amore 	while (child_dip != NULL) {
445788447a05SGarrett D'Amore 		ndi_hold_devi(child_dip);
445888447a05SGarrett D'Amore 
44591cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
44601cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_hold_siblings: held %s%d ref=%d",
446188447a05SGarrett D'Amore 		    ddi_driver_name(child_dip), ddi_get_instance(child_dip),
446288447a05SGarrett D'Amore 		    DEVI(child_dip)->devi_ref);
446388447a05SGarrett D'Amore 
446488447a05SGarrett D'Amore 		child_dip = ddi_get_next_sibling(child_dip);
446588447a05SGarrett D'Amore 	}
44663fe80ca4SDan Cross 	ndi_devi_exit(pdip);
446788447a05SGarrett D'Amore }
446888447a05SGarrett D'Amore 
446988447a05SGarrett D'Amore 
447088447a05SGarrett D'Amore /*
447188447a05SGarrett D'Amore  * release all audio children before or after plumbing
447288447a05SGarrett D'Amore  */
447388447a05SGarrett D'Amore static void
usb_ac_rele_siblings(usb_ac_state_t * uacp)447488447a05SGarrett D'Amore usb_ac_rele_siblings(usb_ac_state_t *uacp)
447588447a05SGarrett D'Amore {
447688447a05SGarrett D'Amore 	dev_info_t	*pdip, *child_dip;
447788447a05SGarrett D'Amore 
44781cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
44791cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_rele_siblings: start");
448088447a05SGarrett D'Amore 
448188447a05SGarrett D'Amore 	/* release all siblings and ourselves */
448288447a05SGarrett D'Amore 	pdip = ddi_get_parent(uacp->usb_ac_dip);
44833fe80ca4SDan Cross 	ndi_devi_enter(pdip);
448488447a05SGarrett D'Amore 	child_dip = ddi_get_child(pdip);
448588447a05SGarrett D'Amore 	while (child_dip != NULL) {
448688447a05SGarrett D'Amore 		ndi_rele_devi(child_dip);
448788447a05SGarrett D'Amore 
44881cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
44891cdd1aafSBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_rele_siblings: released %s%d ref=%d",
449088447a05SGarrett D'Amore 		    ddi_driver_name(child_dip), ddi_get_instance(child_dip),
449188447a05SGarrett D'Amore 		    DEVI(child_dip)->devi_ref);
449288447a05SGarrett D'Amore 
449388447a05SGarrett D'Amore 		child_dip = ddi_get_next_sibling(child_dip);
449488447a05SGarrett D'Amore 	}
44953fe80ca4SDan Cross 	ndi_devi_exit(pdip);
449688447a05SGarrett D'Amore }
4497e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static void
usb_restore_engine(usb_ac_state_t * statep)4498e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_restore_engine(usb_ac_state_t *statep)
4499e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
4500e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_eng_t *engp;
4501e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int i;
4502e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4503e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	for (i = 0; i < USB_AC_ENG_MAX; i++) {
4504e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4505e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		mutex_enter(&statep->usb_ac_mutex);
4506e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		engp = &statep->engines[i];
4507e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		mutex_exit(&statep->usb_ac_mutex);
4508e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4509e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		if (engp->af_engp == NULL)
4510e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			continue;
4511e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		if (usb_ac_set_format(statep, engp) != USB_SUCCESS) {
4512e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			USB_DPRINTF_L2(PRINT_MASK_ATTA,
4513e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			    statep->usb_ac_log_handle,
4514e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			    "usb_restore_engine:set format fail, i=%d", i);
4515e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			return;
4516e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		}
4517e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		if (engp->started) {
4518e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			(void) usb_engine_start(engp);
4519e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		}
4520e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4521e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
4522e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4523e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	(void) usb_ac_ctrl_restore(statep);
4524e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
4525e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4526e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4527e272e4c8SBinzi Cao - Sun Microsystems - Beijing China /*
4528e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  * get the maximum format specification the device supports
4529e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  */
4530e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static void
usb_ac_max_fmt(usb_as_registration_t * reg_data,usb_audio_format_t * fmtp)4531e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_ac_max_fmt(usb_as_registration_t *reg_data,
4532e272e4c8SBinzi Cao - Sun Microsystems - Beijing China     usb_audio_format_t *fmtp)
4533e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
4534e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
453564391892SAlbert Lee 	uint_t ch = 0, sr = 0, prec = 0, enc = 0;
4536e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int i;
4537e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4538e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_formats_t *reg_formats = reg_data->reg_formats;
4539e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
454064391892SAlbert Lee 	/* format priority: channels, sample rate, precision, encoding */
454164391892SAlbert Lee 	for (i = 0; i < reg_data->reg_n_formats; i++) {
454264391892SAlbert Lee 		uint_t val, fmt_sr;
454364391892SAlbert Lee 		int n, keep;
4544e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
454564391892SAlbert Lee 		val = reg_formats[i].fmt_chns;
454664391892SAlbert Lee 		if (val < ch)
454764391892SAlbert Lee 			continue;
4548e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		if (val > ch)
454964391892SAlbert Lee 			keep = 1;
455064391892SAlbert Lee 
455164391892SAlbert Lee 		for (n = 0, fmt_sr = 0; n < reg_formats[i].fmt_n_srs; n++) {
455264391892SAlbert Lee 			if (fmt_sr < reg_formats[i].fmt_srs[n]) {
455364391892SAlbert Lee 				fmt_sr = reg_formats[i].fmt_srs[n];
455464391892SAlbert Lee 			}
455564391892SAlbert Lee 		}
455664391892SAlbert Lee 		if (!keep && fmt_sr < sr)
455764391892SAlbert Lee 			continue;
455864391892SAlbert Lee 		if (fmt_sr > sr)
455964391892SAlbert Lee 			keep = 1;
4560e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4561e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		val = reg_formats[i].fmt_precision;
456264391892SAlbert Lee 		if (!keep && (val < prec))
456364391892SAlbert Lee 			continue;
4564e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		if (val > prec)
456564391892SAlbert Lee 			keep = 1;
4566e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4567e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		val = reg_formats[i].fmt_encoding;
456864391892SAlbert Lee 		if (!keep && (val < enc))
456964391892SAlbert Lee 			continue;
457064391892SAlbert Lee 
457164391892SAlbert Lee 		ch   = reg_formats[i].fmt_chns;
457264391892SAlbert Lee 		sr   = fmt_sr;
457364391892SAlbert Lee 		prec = reg_formats[i].fmt_precision;
457464391892SAlbert Lee 		enc  = reg_formats[i].fmt_encoding;
4575e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
4576e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
457764391892SAlbert Lee 	fmtp->ch   = ch;
457864391892SAlbert Lee 	fmtp->sr   = sr;
4579e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	fmtp->prec = prec;
458064391892SAlbert Lee 	fmtp->enc  = enc;
4581e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
4582e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4583e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4584e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static void
usb_ac_rem_eng(usb_ac_state_t * statep,usb_audio_eng_t * engp)4585e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_ac_rem_eng(usb_ac_state_t *statep, usb_audio_eng_t *engp)
4586e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
4587e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (statep->usb_ac_audio_dev == NULL || engp->af_engp == NULL)
4588e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return;
4589e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4590e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	audio_dev_remove_engine(statep->usb_ac_audio_dev, engp->af_engp);
4591e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	audio_engine_free(engp->af_engp);
4592e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4593e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&engp->lock);
4594e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->af_engp = NULL;
4595e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->streams = NULL;
4596e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&engp->lock);
4597ea1b934fSLin Guo - Sun Microsystems 
4598ea1b934fSLin Guo - Sun Microsystems 	mutex_destroy(&engp->lock);
4599ea1b934fSLin Guo - Sun Microsystems 	cv_destroy(&engp->usb_audio_cv);
4600e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
4601e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4602e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4603e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int
usb_ac_add_eng(usb_ac_state_t * uacp,usb_ac_streams_info_t * asinfo)4604e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_ac_add_eng(usb_ac_state_t *uacp, usb_ac_streams_info_t  *asinfo)
4605e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
4606e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	audio_dev_t *af_devp = uacp->usb_ac_audio_dev;
4607e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_eng_t *engp;
4608e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	audio_engine_t *af_engp;
4609e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int rv = USB_FAILURE;
4610e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int dir = asinfo->acs_streams_reg.reg_mode;
4611e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	uint_t defgain;
4612e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4613e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (asinfo->acs_rcvd_reg_data == 0) {
4614e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4615e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return (USB_SUCCESS);
4616e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
4617e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (dir == USB_AUDIO_PLAY) {
4618e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		engp = &(uacp->engines[0]);
4619e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	} else {
4620e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		engp = &(uacp->engines[1]);
4621e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
4622e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4623ea1b934fSLin Guo - Sun Microsystems 	cv_init(&engp->usb_audio_cv, NULL, CV_DRIVER, NULL);
4624ea1b934fSLin Guo - Sun Microsystems 
4625e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_init(&engp->lock, NULL, MUTEX_DRIVER, NULL);
4626e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4627e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&engp->lock);
4628e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4629e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->af_eflags =
4630e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    (dir == USB_AUDIO_PLAY)?ENGINE_OUTPUT_CAP:ENGINE_INPUT_CAP;
4631e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->statep = uacp;
4632e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4633e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	/* Set the format for the engine */
4634e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_ac_max_fmt(&(asinfo->acs_streams_reg), &engp->fmt);
4635e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4636e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	/* init the default gain */
4637e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	defgain = asinfo->acs_default_gain;
4638e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (engp->fmt.ch == 2) {
4639e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		engp->af_defgain = AUDIO_CTRL_STEREO_VAL(defgain, defgain);
4640e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	} else {
4641e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		engp->af_defgain = defgain;
4642e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
4643e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->streams = asinfo;
4644e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4645e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&engp->lock);
4646e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4647e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	af_engp = audio_engine_alloc(&usb_engine_ops, engp->af_eflags);
4648e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (af_engp == NULL) {
4649e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4650e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
4651e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "audio_engine_alloc failed");
4652e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		goto OUT;
4653e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
4654e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	ASSERT(engp->af_engp == 0);
4655e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4656e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&engp->lock);
4657e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->af_engp = af_engp;
4658e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&engp->lock);
4659e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4660e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	audio_engine_set_private(af_engp, engp);
4661e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	audio_dev_add_engine(af_devp, af_engp);
4662e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4663e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	/*
4664e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	 * Set the format for this engine
4665e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	 */
4666e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (usb_ac_set_format(uacp, engp) != USB_SUCCESS) {
4667e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
4668e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "set format failed, dir = %d", dir);
4669e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		goto OUT;
4670e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
4671e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	rv = USB_SUCCESS;
4672e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4673e272e4c8SBinzi Cao - Sun Microsystems - Beijing China OUT:
4674e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (rv != USB_SUCCESS)
4675e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		usb_ac_rem_eng(uacp, engp);
4676e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4677e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (rv);
4678e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
4679e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4680e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4681e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int
usb_ac_ctrl_set_defaults(usb_ac_state_t * statep)4682e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_ac_ctrl_set_defaults(usb_ac_state_t *statep)
4683e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
4684e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_ctrl_t *ctrlp;
4685e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int rv = USB_SUCCESS;
4686e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
4687e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_ctrl_set_defaults:begin");
4688e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4689e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	for (int i = 0; i < CTL_NUM; i++) {
4690e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		ctrlp = statep->controls[i];
4691e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		if (!ctrlp) {
4692e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			continue;
4693e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		}
4694e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		if (audio_control_write(ctrlp->af_ctrlp, ctrlp->cval)) {
4695e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			USB_DPRINTF_L2(PRINT_MASK_ATTA,
4696e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			    statep->usb_ac_log_handle,
4697e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			    "usb_ac_ctrl_set_defaults:control write failed");
4698e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			rv = USB_FAILURE;
4699e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		}
4700e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4701e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
4702e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	USB_DPRINTF_L4(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
4703e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    "usb_ac_ctrl_set_defaults:end");
4704e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (rv);
4705e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
4706e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4707e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4708e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int
usb_ac_ctrl_restore(usb_ac_state_t * statep)4709e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_ac_ctrl_restore(usb_ac_state_t *statep)
4710e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
4711e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_ctrl_t *ctrlp;
4712e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int rv = USB_SUCCESS;
4713e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4714e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	for (int i = 0; i < CTL_NUM; i++) {
4715e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		ctrlp = statep->controls[i];
4716e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		if (ctrlp) {
4717e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			USB_DPRINTF_L3(PRINT_MASK_ATTA,
4718e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			    statep->usb_ac_log_handle,
4719e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			    "usb_ac_ctrl_restore:i = %d", i);
4720e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			if (audio_control_write(ctrlp->af_ctrlp, ctrlp->cval)) {
4721e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 				rv = USB_FAILURE;
4722e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			}
4723e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		}
4724e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
4725e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (rv);
4726e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
4727e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4728e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4729e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4730e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4731e272e4c8SBinzi Cao - Sun Microsystems - Beijing China /*
4732e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  * moves data between driver buffer and framework/shim buffer
4733e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  */
4734e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static void
usb_eng_bufio(usb_audio_eng_t * engp,void * buf,size_t sz)4735e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_eng_bufio(usb_audio_eng_t *engp, void *buf, size_t sz)
4736e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
4737e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	size_t cpsz = sz;
4738e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	caddr_t *src, *dst;
4739e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4740e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (engp->af_eflags & ENGINE_OUTPUT_CAP) {
4741e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		src = &engp->bufpos;
4742e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		dst = (caddr_t *)&buf;
4743e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	} else {
4744e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		src = (caddr_t *)&buf;
4745e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		dst = &engp->bufpos;
4746e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
4747e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4748e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	/*
4749e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	 * Wrap.  If sz is exactly the remainder of the buffer
4750e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	 * (bufpos + sz == bufendp) then the second cpsz should be 0 and so
4751e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	 * the second memcpy() should have no effect, with bufpos updated
4752e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	 * to the head of the buffer.
4753e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	 */
4754e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (engp->bufpos + sz >= engp->bufendp) {
4755e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		cpsz = (size_t)engp->bufendp - (size_t)engp->bufpos;
4756e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		(void) memcpy(*dst, *src, cpsz);
4757e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4758e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4759e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		buf = (caddr_t)buf + cpsz;
4760e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		engp->bufpos = engp->bufp;
4761e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		cpsz = sz - cpsz;
4762e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
4763e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4764e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (cpsz) {
4765e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		(void) memcpy(*dst, *src, cpsz);
4766e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4767e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4768e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		engp->bufpos += cpsz;
4769e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
4770e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->bufio_count++;
4771e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
4772e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4773e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4774e272e4c8SBinzi Cao - Sun Microsystems - Beijing China /*
4775e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  * control read callback
4776e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  */
4777e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int
usb_audio_ctrl_read(void * arg,uint64_t * cvalp)4778e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_audio_ctrl_read(void *arg, uint64_t *cvalp)
4779e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
4780e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_ctrl_t *ctrlp = arg;
4781e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4782e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&ctrlp->ctrl_mutex);
4783e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	*cvalp = ctrlp->cval;
4784e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&ctrlp->ctrl_mutex);
4785e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4786e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (0);
4787e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
4788e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4789e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4790e272e4c8SBinzi Cao - Sun Microsystems - Beijing China /*
4791e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  * stereo level control callback
4792e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  */
4793e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int
usb_audio_write_stero_rec(void * arg,uint64_t cval)4794e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_audio_write_stero_rec(void *arg, uint64_t cval)
4795e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
4796e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_ctrl_t *ctrlp = arg;
4797e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_ac_state_t *statep = ctrlp->statep;
4798e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int rv = EIO;
4799e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int left, right;
4800e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	uint_t count = 0;
4801e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4802e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4803e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	left = AUDIO_CTRL_STEREO_LEFT(cval);
4804e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	right = AUDIO_CTRL_STEREO_RIGHT(cval);
4805e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4806e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (left < AF_MIN_GAIN || left > AF_MAX_GAIN ||
4807e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    right < AF_MIN_GAIN || right > AF_MAX_GAIN) {
4808e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4809e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return (EINVAL);
4810e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
4811e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4812e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&ctrlp->ctrl_mutex);
4813e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	ctrlp->cval = cval;
4814e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&ctrlp->ctrl_mutex);
4815e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4816e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&statep->usb_ac_mutex);
4817e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	(void) usb_ac_set_control(statep, USB_AUDIO_RECORD,
4818e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AUDIO_FEATURE_UNIT, 1,
4819e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AUDIO_VOLUME_CONTROL,
4820e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AC_FIND_ALL, &count, left, usb_ac_set_gain);
4821e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4822e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	(void) usb_ac_set_control(statep, USB_AUDIO_RECORD,
4823e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AUDIO_FEATURE_UNIT, 2,
4824e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AUDIO_VOLUME_CONTROL,
4825e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AC_FIND_ALL, &count, right, usb_ac_set_gain);
4826e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	rv = 0;
4827e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4828e272e4c8SBinzi Cao - Sun Microsystems - Beijing China done:
4829e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&statep->usb_ac_mutex);
4830e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (rv);
4831e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
4832e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4833e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int
usb_audio_write_ster_vol(void * arg,uint64_t cval)4834e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_audio_write_ster_vol(void *arg, uint64_t cval)
4835e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
4836e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_ctrl_t *ctrlp = arg;
4837e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_ac_state_t *statep = ctrlp->statep;
4838e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int rv = EIO;
4839e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int left, right;
4840e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	uint_t count = 0;
4841e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4842e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	left = AUDIO_CTRL_STEREO_LEFT(cval);
4843e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	right = AUDIO_CTRL_STEREO_RIGHT(cval);
4844e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4845e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (left < AF_MIN_GAIN || left > AF_MAX_GAIN ||
4846e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    right < AF_MIN_GAIN || right > AF_MAX_GAIN) {
4847e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return (EINVAL);
4848e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
4849e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4850e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&ctrlp->ctrl_mutex);
4851e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	ctrlp->cval = cval;
4852e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&ctrlp->ctrl_mutex);
4853e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4854e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4855e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&statep->usb_ac_mutex);
4856e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	(void) usb_ac_set_control(statep, USB_AUDIO_PLAY,
4857e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AUDIO_FEATURE_UNIT, 1,
4858e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AUDIO_VOLUME_CONTROL,
4859e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AC_FIND_ALL, &count, left, usb_ac_set_gain);
4860e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4861e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	(void) usb_ac_set_control(statep, USB_AUDIO_PLAY,
4862e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AUDIO_FEATURE_UNIT, 2,
4863e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AUDIO_VOLUME_CONTROL,
4864e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AC_FIND_ALL, &count, right, usb_ac_set_gain);
4865e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	rv = 0;
4866e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4867e272e4c8SBinzi Cao - Sun Microsystems - Beijing China OUT:
4868e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&statep->usb_ac_mutex);
4869e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (rv);
4870e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
4871e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4872e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4873e272e4c8SBinzi Cao - Sun Microsystems - Beijing China /*
4874e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  * mono level control callback
4875e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  */
4876e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int
usb_audio_write_mono_vol(void * arg,uint64_t cval)4877e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_audio_write_mono_vol(void *arg, uint64_t cval)
4878e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
4879e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_ctrl_t *ctrlp = arg;
4880e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_ac_state_t *statep = ctrlp->statep;
4881e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int rv = EIO;
4882e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int gain;
4883e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4884e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	uint_t count = 0;
4885e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4886e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (cval < (uint64_t)AF_MIN_GAIN || cval > (uint64_t)AF_MAX_GAIN) {
4887e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return (EINVAL);
4888e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
4889e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4890e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&ctrlp->ctrl_mutex);
4891e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	ctrlp->cval = cval;
4892e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&ctrlp->ctrl_mutex);
4893e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4894e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	gain = (int)(cval);
4895e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4896e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&statep->usb_ac_mutex);
4897e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	(void) usb_ac_set_control(statep, USB_AUDIO_PLAY,
4898e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AUDIO_FEATURE_UNIT, 1,
4899e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AUDIO_VOLUME_CONTROL,
4900e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AC_FIND_ALL, &count, gain, usb_ac_set_gain);
4901e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4902e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	rv = 0;
4903e272e4c8SBinzi Cao - Sun Microsystems - Beijing China OUT:
4904e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&statep->usb_ac_mutex);
4905e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4906e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (rv);
4907e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
4908e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4909e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4910e272e4c8SBinzi Cao - Sun Microsystems - Beijing China /*
4911e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  * mono level control callback
4912e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  */
4913e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int
usb_audio_write_monitor_gain(void * arg,uint64_t cval)4914e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_audio_write_monitor_gain(void *arg, uint64_t cval)
4915e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
4916e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_ctrl_t *ctrlp = arg;
4917e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_ac_state_t *statep = ctrlp->statep;
4918e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int rv = EIO;
4919e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int gain;
4920e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	uint_t count = 0;
4921e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4922e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (cval < (uint64_t)AF_MIN_GAIN || cval > (uint64_t)AF_MAX_GAIN) {
4923e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4924e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return (EINVAL);
4925e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
4926e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4927e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&ctrlp->ctrl_mutex);
4928e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	ctrlp->cval = cval;
4929e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&ctrlp->ctrl_mutex);
4930e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4931e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	gain = (int)(cval);
4932e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4933e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&statep->usb_ac_mutex);
4934e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	(void) usb_ac_set_monitor_gain_control(statep, USB_AUDIO_RECORD,
4935e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AUDIO_INPUT_TERMINAL, 1,
4936e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AUDIO_VOLUME_CONTROL,
4937e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AC_FIND_ALL, &count, gain,
4938e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    usb_ac_set_monitor_gain);
4939e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4940e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	rv = 0;
4941e272e4c8SBinzi Cao - Sun Microsystems - Beijing China OUT:
4942e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&statep->usb_ac_mutex);
4943e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (rv);
4944e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
4945e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4946e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int
usb_audio_write_mono_rec(void * arg,uint64_t cval)4947e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_audio_write_mono_rec(void *arg, uint64_t cval)
4948e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
4949e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_ctrl_t *ctrlp = arg;
4950e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_ac_state_t *statep = ctrlp->statep;
4951e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int rv = EIO;
4952e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int gain;
4953e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4954e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	uint_t count = 0;
4955e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4956e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (cval < (uint64_t)AF_MIN_GAIN || cval > (uint64_t)AF_MAX_GAIN) {
4957e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4958e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return (EINVAL);
4959e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
4960e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4961e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&ctrlp->ctrl_mutex);
4962e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	ctrlp->cval = cval;
4963e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&ctrlp->ctrl_mutex);
4964e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4965e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	gain = (int)(cval);
4966e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4967e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&statep->usb_ac_mutex);
4968e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	(void) usb_ac_set_control(statep, USB_AUDIO_RECORD,
4969e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AUDIO_FEATURE_UNIT, 1,
4970e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AUDIO_VOLUME_CONTROL,
4971e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AC_FIND_ALL, &count, gain, usb_ac_set_gain);
4972e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4973e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	rv = 0;
4974e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4975e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&statep->usb_ac_mutex);
4976e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (rv);
4977e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
4978e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4979e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int
usb_audio_write_mic_boost(void * arg,uint64_t cval)4980e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_audio_write_mic_boost(void *arg, uint64_t cval)
4981e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
4982e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_ctrl_t *ctrlp = arg;
4983e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4984e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&ctrlp->ctrl_mutex);
4985e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	ctrlp->cval = cval;
4986e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&ctrlp->ctrl_mutex);
4987e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	/* do nothing here */
4988e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (0);
4989e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
4990e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4991e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int
usb_audio_write_rec_src(void * arg,uint64_t cval)4992e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_audio_write_rec_src(void *arg, uint64_t cval)
4993e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
4994e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_ctrl_t *ctrlp = arg;
4995e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_ac_state_t *statep = ctrlp->statep;
4996e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int rv = 0;
4997e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
4998e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (cval & ~(statep->usb_ac_input_ports))
4999e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return (EINVAL);
5000e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5001e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&ctrlp->ctrl_mutex);
5002e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	ctrlp->cval = cval;
5003e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&ctrlp->ctrl_mutex);
5004e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5005e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&statep->usb_ac_mutex);
5006e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (usb_ac_set_port(statep, USB_AUDIO_RECORD, cval) != USB_SUCCESS) {
5007e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5008e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ALL, statep->usb_ac_log_handle,
5009e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "usb_audio_write_rec_src: failed");
5010e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		rv = EINVAL;
5011e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5012e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&statep->usb_ac_mutex);
5013e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	rv = 0;
5014e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5015e272e4c8SBinzi Cao - Sun Microsystems - Beijing China OUT:
5016e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (rv);
5017e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5018e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
5019e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5020e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5021e272e4c8SBinzi Cao - Sun Microsystems - Beijing China int
usb_audio_set_mute(usb_ac_state_t * statep,uint64_t cval)5022e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_audio_set_mute(usb_ac_state_t *statep, uint64_t cval)
5023e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
5024e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	short	muteval;
5025e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int	rval;
5026e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5027e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	uint_t count;
5028e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	muteval = (cval == 0) ? USB_AUDIO_MUTE_ON : USB_AUDIO_MUTE_OFF;
5029e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	count = 0;
5030e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	/* only support AUDIO_PLAY */
5031e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5032e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&statep->usb_ac_mutex);
5033e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	(void) usb_ac_set_control(statep, USB_AUDIO_PLAY,
5034e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AUDIO_FEATURE_UNIT, 0,
5035e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AUDIO_MUTE_CONTROL,
5036e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    USB_AC_FIND_ALL, &count, muteval,
5037e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    usb_ac_set_mute);
5038e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&statep->usb_ac_mutex);
5039e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5040e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	rval = (count == 0) ? USB_SUCCESS : USB_FAILURE;
5041e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5042e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (rval);
5043e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
5044e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5045e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5046e272e4c8SBinzi Cao - Sun Microsystems - Beijing China /*
5047e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  * port selection control callback
5048e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  */
5049e272e4c8SBinzi Cao - Sun Microsystems - Beijing China /*
5050e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  * audio control registration related routines
5051e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  */
5052e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5053e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static usb_audio_ctrl_t *
usb_audio_ctrl_alloc(usb_ac_state_t * statep,uint32_t num,uint64_t val)5054e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_audio_ctrl_alloc(usb_ac_state_t *statep, uint32_t num, uint64_t val)
5055e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
5056e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	audio_ctrl_desc_t	desc;
5057e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	audio_ctrl_wr_t		fn;
5058e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_ctrl_t	*pc;
5059e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5060e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	pc = kmem_zalloc(sizeof (usb_audio_ctrl_t), KM_SLEEP);
5061e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5062e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_init(&pc->ctrl_mutex, NULL, MUTEX_DRIVER, NULL);
5063e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5064e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	bzero(&desc, sizeof (desc));
5065e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5066e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	switch (num) {
5067e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	case CTL_VOLUME_MONO:
5068e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_name = AUDIO_CTRL_ID_VOLUME;
5069e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_type = AUDIO_CTRL_TYPE_MONO;
5070e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_minvalue = 0;
5071e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_maxvalue = AF_MAX_GAIN;
5072e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_flags = AUDIO_CTRL_FLAG_MAINVOL | AUDIO_CTRL_FLAG_RW
5073e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    | AUDIO_CTRL_FLAG_PLAY | AUDIO_CTRL_FLAG_POLL;
5074e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		fn = usb_audio_write_mono_vol;
5075e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		break;
5076e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5077e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	case CTL_VOLUME_STERO:
5078e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_name = AUDIO_CTRL_ID_VOLUME;
5079e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
5080e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_minvalue = 0;
5081e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_maxvalue = AF_MAX_GAIN;
5082e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_flags = AUDIO_CTRL_FLAG_MAINVOL | AUDIO_CTRL_FLAG_RW
5083e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    | AUDIO_CTRL_FLAG_PLAY | AUDIO_CTRL_FLAG_POLL;
5084e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		fn = usb_audio_write_ster_vol;
5085e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5086e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		break;
5087e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5088e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	case CTL_REC_MONO:
5089e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_name = AUDIO_CTRL_ID_RECGAIN;
5090e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_type = AUDIO_CTRL_TYPE_MONO;
5091e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_minvalue = 0;
5092e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_maxvalue = AF_MAX_GAIN;
5093e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_flags = AUDIO_CTRL_FLAG_RECVOL|AUDIO_CTRL_FLAG_REC
5094e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    | AUDIO_CTRL_FLAG_RW;
5095e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		fn = usb_audio_write_mono_rec;
5096e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		break;
5097e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	case CTL_REC_STERO:
5098e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5099e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_name = AUDIO_CTRL_ID_RECGAIN;
5100e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
5101e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_minvalue = 0;
5102e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_maxvalue = AF_MAX_GAIN;
5103e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_flags = AUDIO_CTRL_FLAG_RECVOL|AUDIO_CTRL_FLAG_REC
5104e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    | AUDIO_CTRL_FLAG_RW;
5105e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		fn = usb_audio_write_stero_rec;
5106e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		break;
5107e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5108e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	case CTL_MONITOR_GAIN:
5109e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5110e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_name = AUDIO_CTRL_ID_MONGAIN;
5111e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_type = AUDIO_CTRL_TYPE_MONO;
5112e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_minvalue = 0;
5113e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_maxvalue = AF_MAX_GAIN;
5114e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_flags = AUDIO_CTRL_FLAG_MONVOL |AUDIO_CTRL_FLAG_MONITOR
5115e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    |AUDIO_CTRL_FLAG_RW;
5116e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		fn = usb_audio_write_monitor_gain;
5117e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		break;
5118e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5119e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	case CTL_MIC_BOOST:
5120e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5121e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_name = AUDIO_CTRL_ID_MICBOOST;
5122e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_type = AUDIO_CTRL_TYPE_BOOLEAN;
5123e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_minvalue = 0;
5124e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_maxvalue = 1;
5125e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_flags = AUDIO_CTRL_FLAG_RW;
5126e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		fn = usb_audio_write_mic_boost;
5127e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		break;
5128e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	case CTL_REC_SRC:
5129e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5130e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_name = AUDIO_CTRL_ID_RECSRC;
5131e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_type = AUDIO_CTRL_TYPE_ENUM;
5132e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_minvalue = statep->usb_ac_input_ports;
5133e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_maxvalue = statep->usb_ac_input_ports;
5134e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		desc.acd_flags = AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_REC;
5135e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		for (int i = 0; usb_audio_dtypes[i]; i++) {
5136e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			desc.acd_enum[i] = usb_audio_dtypes[i];
5137e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		}
5138e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5139e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		fn = usb_audio_write_rec_src;
5140e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		break;
5141e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5142e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5143e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5144e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	default:
5145e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5146e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		break;
5147e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5148e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5149e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&pc->ctrl_mutex);
5150e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5151e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	pc->statep = statep;
5152e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	pc->cval = val;
5153e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	pc->af_ctrlp = audio_dev_add_control(statep->usb_ac_audio_dev, &desc,
5154e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    usb_audio_ctrl_read, fn, pc);
5155e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5156e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&pc->ctrl_mutex);
5157e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5158e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&statep->usb_ac_mutex);
5159e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	statep->controls[num] = pc;
5160e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&statep->usb_ac_mutex);
5161e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5162e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5163e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (pc);
5164e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
5165e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5166e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5167e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static void
usb_audio_ctrl_free(usb_audio_ctrl_t * ctrlp)5168e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_audio_ctrl_free(usb_audio_ctrl_t *ctrlp)
5169e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
5170e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	kmem_free(ctrlp, sizeof (usb_audio_ctrl_t));
5171e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
5172e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5173e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static void
usb_ac_rem_controls(usb_ac_state_t * statep)5174e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_ac_rem_controls(usb_ac_state_t *statep)
5175e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
5176e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_ctrl_t *ctrlp;
5177e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5178e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	for (int i = 0; i < CTL_NUM; i++) {
5179e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		ctrlp = statep->controls[i];
5180e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		if (ctrlp) {
5181e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			if (ctrlp->af_ctrlp != NULL)
5182e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 				audio_dev_del_control(ctrlp->af_ctrlp);
5183e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5184e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			usb_audio_ctrl_free(ctrlp);
5185e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			mutex_enter(&statep->usb_ac_mutex);
5186e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			statep->controls[i] = NULL;
5187e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			mutex_exit(&statep->usb_ac_mutex);
5188e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		}
5189e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5190e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5191e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
5192e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5193e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5194e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int
usb_ac_add_controls(usb_ac_state_t * statep)5195e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_ac_add_controls(usb_ac_state_t *statep)
5196e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
5197e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int rv = USB_FAILURE;
5198e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_format_t *format;
5199e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5200e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5201e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (statep->engines[0].af_engp) {
5202e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		/* Init controls for play format */
5203e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		format = &(statep->engines[0].fmt);
5204e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		if (format->ch == 2) {
5205e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			(void) usb_audio_ctrl_alloc(statep, CTL_VOLUME_STERO,
5206e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			    statep->engines[0].af_defgain);
5207e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		} else {
5208e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			(void) usb_audio_ctrl_alloc(statep, CTL_VOLUME_MONO,
5209e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			    statep->engines[0].af_defgain);
5210e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		}
5211e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5212e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5213e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5214e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	/* Init controls for rec format */
5215e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (statep->engines[1].af_engp) {
5216e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		format = &(statep->engines[1].fmt);
5217e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		if (format->ch == 2) {
5218e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			(void) usb_audio_ctrl_alloc(statep, CTL_REC_STERO,
5219e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			    statep->engines[1].af_defgain);
5220e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		} else {
5221e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			(void) usb_audio_ctrl_alloc(statep, CTL_REC_MONO,
5222e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			    statep->engines[1].af_defgain);
5223e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		}
5224e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5225e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		/* Add monitor control */
5226e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		{
5227e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			(void) usb_audio_ctrl_alloc(statep,
5228e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			    CTL_MONITOR_GAIN, 0);
5229e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		}
5230e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5231e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		/* Add ports control */
5232e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		{
5233e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			(void) usb_audio_ctrl_alloc(statep, CTL_REC_SRC,
5234e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			    statep->usb_ac_input_ports);
5235e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		}
5236e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5237e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5238e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5239e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5240e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	rv = USB_SUCCESS;
5241e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5242e272e4c8SBinzi Cao - Sun Microsystems - Beijing China OUT:
5243e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (rv != USB_SUCCESS)
5244e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		usb_ac_rem_controls(statep);
5245e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (rv);
5246e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
5247e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5248e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5249e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5250e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5251e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5252e272e4c8SBinzi Cao - Sun Microsystems - Beijing China /*ARGSUSED*/
5253e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int
usb_audio_unregister(usb_ac_state_t * statep)5254e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_audio_unregister(usb_ac_state_t *statep)
5255e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
5256e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int i;
5257e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5258e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (statep == NULL)
5259e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return (USB_SUCCESS);
5260e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5261e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (statep->usb_ac_audio_dev == NULL)
5262e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return (USB_SUCCESS);
5263e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5264e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if ((statep->flags & AF_REGISTERED) &&
5265e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    audio_dev_unregister(statep->usb_ac_audio_dev) != DDI_SUCCESS) {
5266e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return (USB_FAILURE);
5267e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5268e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&statep->usb_ac_mutex);
5269e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	statep->flags &= ~AF_REGISTERED;
5270e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&statep->usb_ac_mutex);
5271e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5272e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	for (i = 0; i < USB_AC_ENG_MAX; i++)
5273e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		usb_ac_rem_eng(statep, &statep->engines[i]);
5274e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5275e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_ac_rem_controls(statep);
5276e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5277e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	audio_dev_free(statep->usb_ac_audio_dev);
5278e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5279e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&statep->usb_ac_mutex);
5280e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	statep->usb_ac_audio_dev = NULL;
5281e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&statep->usb_ac_mutex);
5282e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5283e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (USB_SUCCESS);
5284e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
5285e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5286e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5287e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int
usb_audio_register(usb_ac_state_t * statep)5288*d5ebc493SDan Cross usb_audio_register(usb_ac_state_t *statep)
5289*d5ebc493SDan Cross {
5290e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	audio_dev_t *af_devp;
5291e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int rv = USB_FAILURE;
5292e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int n;
5293e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5294e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	af_devp = audio_dev_alloc(statep->usb_ac_dip, 0);
5295e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	audio_dev_set_description(af_devp,  "USB Audio");
5296e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	audio_dev_set_version(af_devp, "1.0");
5297e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5298e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&statep->usb_ac_mutex);
5299e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	statep->usb_ac_audio_dev = af_devp;
5300e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&statep->usb_ac_mutex);
5301e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5302e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5303e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	for (n = 0; n < USB_AC_MAX_AS_PLUMBED; n++) {
5304e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		if (usb_ac_add_eng(statep, &(statep->usb_ac_streams[n]))
5305e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    != USB_SUCCESS) {
5306e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			USB_DPRINTF_L2(PRINT_MASK_ATTA,
5307e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			    statep->usb_ac_log_handle,
5308e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			    "usb_audio_register: add engine n =%d failed", n);
5309e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			goto OUT;
5310e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		}
5311e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5312e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5313e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5314e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (usb_ac_add_controls(statep) != USB_SUCCESS) {
5315e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
5316e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "usb_audio_register: add controls failed");
5317e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		goto OUT;
5318e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5319e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5320e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (usb_ac_ctrl_set_defaults(statep) != USB_SUCCESS) {
5321e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
5322e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "usb_audio_register: set defaults failed");
5323e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		goto OUT;
5324e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5325e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5326e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (audio_dev_register(af_devp) != DDI_SUCCESS) {
5327e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
5328e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "audio_dev_register() failed");
5329e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		goto OUT;
5330e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5331e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&statep->usb_ac_mutex);
5332e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	statep->flags |= AF_REGISTERED;
5333e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&statep->usb_ac_mutex);
5334e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5335e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	rv = USB_SUCCESS;
5336e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5337e272e4c8SBinzi Cao - Sun Microsystems - Beijing China OUT:
5338e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (rv != USB_SUCCESS) {
5339e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		(void) usb_audio_unregister(statep);
5340e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5341e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (rv);
5342e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
5343e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5344e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5345e272e4c8SBinzi Cao - Sun Microsystems - Beijing China int
usb_ac_get_audio(void * handle,void * buf,int samples)5346e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_ac_get_audio(void *handle, void *buf, int samples)
5347e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
5348e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_ac_state_t *statep = (usb_ac_state_t *)(handle);
5349e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_eng_t *engp = &(statep->engines[0]);
5350e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	unsigned reqframes = samples >> engp->frsmshift;
5351e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	unsigned frames;
5352e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	unsigned i;
5353e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	size_t sz;
5354e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	caddr_t bp = buf;
5355e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5356ea1b934fSLin Guo - Sun Microsystems 	mutex_enter(&engp->lock);
5357e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (!engp->started) {
5358ea1b934fSLin Guo - Sun Microsystems 		mutex_exit(&engp->lock);
5359ea1b934fSLin Guo - Sun Microsystems 
5360e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return (0);
5361e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5362ea1b934fSLin Guo - Sun Microsystems 	engp->busy = B_TRUE;
5363ea1b934fSLin Guo - Sun Microsystems 	mutex_exit(&engp->lock);
5364e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5365e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	/* break requests from the driver into fragment sized chunks */
5366e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	for (i = 0; i < reqframes; i += frames) {
5367e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5368e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		mutex_enter(&engp->lock);
5369e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		frames = reqframes - i;
5370e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		if (frames > engp->fragfr)
5371e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			frames = engp->fragfr;
5372e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5373e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		sz = (frames << engp->frsmshift) << engp->smszshift;
5374e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5375e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		/* must move data before updating framework */
5376e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		usb_eng_bufio(engp, bp, sz);
5377e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		engp->frames += frames;
5378e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		bp += sz;
5379e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5380e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		mutex_exit(&engp->lock);
5381e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5382e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5383e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&engp->lock);
5384e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->io_count++;
5385ea1b934fSLin Guo - Sun Microsystems 	engp->busy = B_FALSE;
5386ea1b934fSLin Guo - Sun Microsystems 	cv_signal(&engp->usb_audio_cv);
5387e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&engp->lock);
5388e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5389e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (samples);
5390e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
5391e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5392e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5393e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5394e272e4c8SBinzi Cao - Sun Microsystems - Beijing China void
usb_ac_send_audio(void * handle,void * buf,int samples)5395e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_ac_send_audio(void *handle, void *buf, int samples)
5396e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
5397e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_ac_state_t *statep = (usb_ac_state_t *)(handle);
5398e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_eng_t *engp = &(statep->engines[1]);
5399e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	unsigned reqframes = samples >> engp->frsmshift;
5400e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	unsigned frames;
5401e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	unsigned i;
5402e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	size_t sz;
5403e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	caddr_t bp = buf;
5404e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5405e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&engp->lock);
5406e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5407e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (!engp->started) {
5408e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5409e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		mutex_exit(&engp->lock);
5410e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return;
5411e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5412ea1b934fSLin Guo - Sun Microsystems 	engp->busy = B_TRUE;
5413e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&engp->lock);
5414e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5415e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	/* break requests from the driver into fragment sized chunks */
5416e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	for (i = 0; i < reqframes; i += frames) {
5417e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		mutex_enter(&engp->lock);
5418e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5419e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		frames = reqframes - i;
5420e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		if (frames > engp->fragfr)
5421e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			frames = engp->fragfr;
5422e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5423e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		sz = (frames << engp->frsmshift) << engp->smszshift;
5424e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5425e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		/* must move data before updating framework */
5426e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		usb_eng_bufio(engp, bp, sz);
5427e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		engp->frames += frames;
5428e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		bp += sz;
5429e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5430e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		mutex_exit(&engp->lock);
5431e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5432e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5433e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&engp->lock);
5434e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->io_count++;
5435ea1b934fSLin Guo - Sun Microsystems 	engp->busy = B_FALSE;
5436ea1b934fSLin Guo - Sun Microsystems 	cv_signal(&engp->usb_audio_cv);
5437e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&engp->lock);
5438e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
5439e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5440e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5441e272e4c8SBinzi Cao - Sun Microsystems - Beijing China /*
5442e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  * **************************************************************************
5443e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  * audio framework engine callbacks
5444e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  */
5445e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int
usb_engine_open(void * arg,int flag,unsigned * nframesp,caddr_t * bufp)544668c47f65SGarrett D'Amore usb_engine_open(void *arg, int flag, unsigned *nframesp, caddr_t *bufp)
5447e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
5448e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_eng_t *engp = (usb_audio_eng_t *)arg;
5449e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_ac_state_t *statep = engp->statep;
5450e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int rv = EIO;
5451e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
545268c47f65SGarrett D'Amore 	_NOTE(ARGUNUSED(flag));
5453e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5454e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (usb_ac_open(statep->usb_ac_dip) != USB_SUCCESS) {
5455e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5456e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
5457e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "usb_ac_open() failed");
5458e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return (EIO);
5459e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5460e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5461e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&engp->lock);
5462e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5463e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->intrate =  150;
5464e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->sampsz = engp->fmt.prec / 8;
5465e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->framesz = engp->sampsz * engp->fmt.ch;
5466e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5467e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->frsmshift = engp->fmt.ch / 2;
5468e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->smszshift = engp->sampsz / 2;
5469e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5470e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	/*
5471e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	 * In order to match the requested number of samples per interrupt
5472e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	 * from SADA drivers when computing the fragment size,
5473e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	 * we need to first truncate the floating point result from
5474e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	 *	sample rate * channels / intr rate
5475e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	 * then adjust up to an even number, before multiplying it
5476e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	 * with the sample size
5477e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	 */
5478e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->fragsz = engp->fmt.sr * engp->fmt.ch / engp->intrate;
5479e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (engp->fragsz & 1)
5480e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		engp->fragsz++;
5481e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->fragsz *= engp->sampsz;
5482e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->fragfr = engp->fragsz / engp->framesz;
5483e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5484e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->nfrags = 10;
5485e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->bufsz = engp->fragsz * engp->nfrags;
5486e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5487e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->bufp = kmem_zalloc(engp->bufsz, KM_SLEEP);
5488e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->bufpos = engp->bufp;
5489e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->bufendp = engp->bufp + engp->bufsz;
5490e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->frames = 0;
5491e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->io_count = 0;
5492e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->bufio_count = 0;
5493ea1b934fSLin Guo - Sun Microsystems 	engp->started = B_FALSE;
5494ea1b934fSLin Guo - Sun Microsystems 	engp->busy = B_FALSE;
5495e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
549668c47f65SGarrett D'Amore 	*nframesp = engp->nfrags * engp->fragfr;
5497e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	*bufp = engp->bufp;
5498e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5499e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&engp->lock);
5500e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5501e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (usb_ac_setup(statep, engp) != USB_SUCCESS) {
5502e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
5503e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "device setup failed");
5504e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		goto OUT;
5505e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5506e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5507e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5508e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5509e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&statep->usb_ac_mutex);
5510e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	statep->flags |= AD_SETUP;
5511e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&statep->usb_ac_mutex);
5512e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5513e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	rv = 0;
5514e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5515e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5516e272e4c8SBinzi Cao - Sun Microsystems - Beijing China OUT:
5517e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (rv != 0)
5518e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		usb_engine_close(arg);
5519e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5520e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (rv);
5521e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
5522e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5523e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5524e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static void
usb_engine_close(void * arg)5525e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_engine_close(void *arg)
5526e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
5527e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_eng_t *engp = (usb_audio_eng_t *)arg;
5528e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_ac_state_t *statep = engp->statep;
5529e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5530ea1b934fSLin Guo - Sun Microsystems 	mutex_enter(&engp->lock);
5531ea1b934fSLin Guo - Sun Microsystems 	while (engp->busy) {
5532ea1b934fSLin Guo - Sun Microsystems 		cv_wait(&engp->usb_audio_cv, &engp->lock);
5533ea1b934fSLin Guo - Sun Microsystems 	}
5534ea1b934fSLin Guo - Sun Microsystems 
5535ea1b934fSLin Guo - Sun Microsystems 	mutex_exit(&engp->lock);
5536ea1b934fSLin Guo - Sun Microsystems 
5537e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (statep->flags & AD_SETUP) {
5538e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		usb_ac_teardown(statep, engp);
5539e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		mutex_enter(&statep->usb_ac_mutex);
5540e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		statep->flags &= ~AD_SETUP;
5541e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		mutex_exit(&statep->usb_ac_mutex);
5542e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5543e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&engp->lock);
5544e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5545e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (engp->bufp != NULL) {
5546e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		kmem_free(engp->bufp, engp->bufsz);
5547e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		engp->bufp = NULL;
5548e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		engp->bufpos = NULL;
5549e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		engp->bufendp = NULL;
5550e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5551e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5552e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&engp->lock);
5553e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5554e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_ac_close(statep->usb_ac_dip);
5555e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
5556e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5557e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5558e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5559e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int
usb_engine_start(void * arg)5560e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_engine_start(void *arg)
5561e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
5562e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_eng_t *engp = (usb_audio_eng_t *)arg;
5563e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int rv = 0;
5564e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int (*start)(usb_ac_state_t *, usb_audio_eng_t *);
5565e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5566e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&engp->lock);
5567e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->started = B_TRUE;
5568e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&engp->lock);
5569e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5570e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_ac_state_t *statep = engp->statep;
5571e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5572e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	start = ((engp)->af_eflags & ENGINE_OUTPUT_CAP) ?
5573e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    usb_ac_start_play : usb_ac_start_record;
5574e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5575e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if ((*start)(statep, engp) != USB_SUCCESS) {
5576e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
5577e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "failed to start %d engine", engp->af_eflags);
5578e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		rv = EIO;
5579e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5580e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5581e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5582e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (rv);
5583e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
5584e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5585e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5586e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static void
usb_engine_stop(void * arg)5587e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_engine_stop(void *arg)
5588e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
5589e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_eng_t *engp = (usb_audio_eng_t *)arg;
5590e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5591e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&engp->lock);
5592e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	engp->started = B_FALSE;
5593e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&engp->lock);
5594e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5595e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_ac_state_t *statep = engp->statep;
5596e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	void (*stop)(usb_ac_state_t *, usb_audio_eng_t *);
5597e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5598e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	stop = ((engp)->af_eflags & ENGINE_OUTPUT_CAP) ?
5599e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	    usb_ac_stop_play : usb_ac_stop_record;
5600e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5601e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	(*stop)(statep, engp);
5602e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
5603e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5604e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5605e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static uint64_t
usb_engine_count(void * arg)5606e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_engine_count(void *arg)
5607e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
5608e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_eng_t	*engp = arg;
5609e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	uint64_t	val;
5610e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5611e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_enter(&engp->lock);
5612e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	val = engp->frames;
5613e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	mutex_exit(&engp->lock);
5614e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5615e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (val);
5616e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
5617e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5618e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5619e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int
usb_engine_format(void * arg)5620e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_engine_format(void *arg)
5621e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
5622e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_eng_t *engp = arg;
5623e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5624e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	switch (engp->fmt.enc) {
5625e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		case USB_AUDIO_FORMAT_TYPE1_MULAW:
5626e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			return (AUDIO_FORMAT_ULAW);
5627e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		case USB_AUDIO_FORMAT_TYPE1_ALAW:
5628e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			return (AUDIO_FORMAT_ALAW);
5629e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		case USB_AUDIO_FORMAT_TYPE1_PCM8:
5630e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			return (AUDIO_FORMAT_U8);
5631e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5632e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		case USB_AUDIO_FORMAT_TYPE1_PCM:
5633e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			break;
5634e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		default:
5635e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			return (AUDIO_FORMAT_NONE);
5636e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5637e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5638e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	switch (engp->fmt.prec) {
563964391892SAlbert Lee 		case USB_AUDIO_PRECISION_8:
5640e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			return (AUDIO_FORMAT_S8);
564164391892SAlbert Lee 		case USB_AUDIO_PRECISION_16:
5642e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			return (AUDIO_FORMAT_S16_LE);
564364391892SAlbert Lee 		case USB_AUDIO_PRECISION_24:
5644e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			return (AUDIO_FORMAT_S24_LE);
564564391892SAlbert Lee 		case USB_AUDIO_PRECISION_32:
5646e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			return (AUDIO_FORMAT_S32_LE);
5647e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		default:
5648e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 			break;
5649e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5650e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (AUDIO_FORMAT_NONE);
5651e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5652e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5653e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
5654e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5655e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int
usb_engine_channels(void * arg)5656e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_engine_channels(void *arg)
5657e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
5658e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_eng_t *engp = arg;
5659e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5660e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (engp->fmt.ch);
5661e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
5662e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5663e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5664e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int
usb_engine_rate(void * arg)5665e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_engine_rate(void *arg)
5666e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
5667e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_eng_t *engp = arg;
5668e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5669e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (engp->fmt.sr);
5670e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
5671e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5672e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5673e272e4c8SBinzi Cao - Sun Microsystems - Beijing China /*ARGSUSED*/
5674e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static void
usb_engine_sync(void * arg,unsigned nframes)5675e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_engine_sync(void *arg, unsigned nframes)
5676e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
5677e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	/* Do nothing */
5678e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
5679e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5680e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5681f9ead4a5SGarrett D'Amore static unsigned
usb_engine_qlen(void * arg)5682e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_engine_qlen(void *arg)
5683e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
5684e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_eng_t *engp = (usb_audio_eng_t *)arg;
5685e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5686e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (engp->fragfr);
5687e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
5688e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5689e272e4c8SBinzi Cao - Sun Microsystems - Beijing China /*
5690e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  * **************************************************************************
5691e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  * interfaces used by USB audio
5692e272e4c8SBinzi Cao - Sun Microsystems - Beijing China  */
5693e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5694e272e4c8SBinzi Cao - Sun Microsystems - Beijing China /*ARGSUSED*/
5695e272e4c8SBinzi Cao - Sun Microsystems - Beijing China static int
usb_change_phy_vol(usb_ac_state_t * statep,int value)5696e272e4c8SBinzi Cao - Sun Microsystems - Beijing China usb_change_phy_vol(usb_ac_state_t *statep, int value)
5697e272e4c8SBinzi Cao - Sun Microsystems - Beijing China {
5698e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	usb_audio_ctrl_t *ctrlp;
5699e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	uint64_t cval = 0;
5700e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	int64_t left, right, delta = 0;
5701e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5702e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	ctrlp = statep->controls[CTL_VOLUME_STERO];
5703e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5704e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	ASSERT(value != 0);
5705e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5706e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	delta = (value < 0)?-1:1;
5707e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5708e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	left = AUDIO_CTRL_STEREO_LEFT(ctrlp->cval) + delta;
5709e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	right = AUDIO_CTRL_STEREO_RIGHT(ctrlp->cval) + delta;
5710e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5711e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (left > AF_MAX_GAIN)
5712e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		left = AF_MAX_GAIN;
5713e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (right > AF_MAX_GAIN)
5714e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		right = AF_MAX_GAIN;
5715e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5716e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (left < AF_MIN_GAIN)
5717e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		left = AF_MIN_GAIN;
5718e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (right < AF_MIN_GAIN)
5719e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		right = AF_MIN_GAIN;
5720e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5721e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	cval = AUDIO_CTRL_STEREO_VAL(left, right);
5722e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 
5723e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	if (audio_control_write(ctrlp->af_ctrlp, cval)) {
5724e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
5725e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    "updateing control  to value 0x%llx by driver failed",
5726e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		    (long long unsigned)cval);
5727e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 		return (USB_FAILURE);
5728e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	}
5729e272e4c8SBinzi Cao - Sun Microsystems - Beijing China 	return (USB_SUCCESS);
5730e272e4c8SBinzi Cao - Sun Microsystems - Beijing China }
5731