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, ¤t) != 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, ¤t) != 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_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