1582eadeeSfl /*
2582eadeeSfl * CDDL HEADER START
3582eadeeSfl *
4582eadeeSfl * The contents of this file are subject to the terms of the
5582eadeeSfl * Common Development and Distribution License (the "License").
6582eadeeSfl * You may not use this file except in compliance with the License.
7582eadeeSfl *
8582eadeeSfl * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9582eadeeSfl * or http://www.opensolaris.org/os/licensing.
10582eadeeSfl * See the License for the specific language governing permissions
11582eadeeSfl * and limitations under the License.
12582eadeeSfl *
13582eadeeSfl * When distributing Covered Code, include this CDDL HEADER in each
14582eadeeSfl * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15582eadeeSfl * If applicable, add the following below this CDDL HEADER, with the
16582eadeeSfl * fields enclosed by brackets "[]" replaced with your own identifying
17582eadeeSfl * information: Portions Copyright [yyyy] [name of copyright owner]
18582eadeeSfl *
19582eadeeSfl * CDDL HEADER END
20582eadeeSfl */
21582eadeeSfl /*
222c30fa45SGarrett D'Amore * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
23582eadeeSfl */
24582eadeeSfl
2588447a05SGarrett D'Amore #include <sys/audio/audio_driver.h>
26582eadeeSfl #include <sys/note.h>
2742c41cf8Slipeng sang - Sun Microsystems - Beijing China #include <sys/beep.h>
28582eadeeSfl #include <sys/pci.h>
2988447a05SGarrett D'Amore #include "audiohd.h"
30582eadeeSfl
3188447a05SGarrett D'Amore #define DRVNAME "audiohd"
3268c47f65SGarrett D'Amore
33582eadeeSfl /*
34582eadeeSfl * Module linkage routines for the kernel
35582eadeeSfl */
36582eadeeSfl static int audiohd_attach(dev_info_t *, ddi_attach_cmd_t);
37582eadeeSfl static int audiohd_detach(dev_info_t *, ddi_detach_cmd_t);
3819397407SSherry Moore static int audiohd_quiesce(dev_info_t *);
39d5247f45Sgs static int audiohd_resume(audiohd_state_t *);
40d5247f45Sgs static int audiohd_suspend(audiohd_state_t *);
41582eadeeSfl
42582eadeeSfl /*
43582eadeeSfl * Local routines
44582eadeeSfl */
45582eadeeSfl static int audiohd_init_state(audiohd_state_t *, dev_info_t *);
46582eadeeSfl static int audiohd_init_pci(audiohd_state_t *, ddi_device_acc_attr_t *);
47582eadeeSfl static void audiohd_fini_pci(audiohd_state_t *);
48582eadeeSfl static int audiohd_reset_controller(audiohd_state_t *);
49582eadeeSfl static int audiohd_init_controller(audiohd_state_t *);
50582eadeeSfl static void audiohd_fini_controller(audiohd_state_t *);
51582eadeeSfl static void audiohd_stop_dma(audiohd_state_t *);
52582eadeeSfl static void audiohd_disable_intr(audiohd_state_t *);
53582eadeeSfl static int audiohd_create_codec(audiohd_state_t *);
543a49c214SYang-Rong Jerry Zhou static void audiohd_build_path(audiohd_state_t *);
55582eadeeSfl static void audiohd_destroy_codec(audiohd_state_t *);
56582eadeeSfl static int audiohd_alloc_dma_mem(audiohd_state_t *, audiohd_dma_t *,
57582eadeeSfl size_t, ddi_dma_attr_t *, uint_t);
585ec2209cSZhao Edgar Liu - Sun Microsystems static void audiohd_finish_output_path(hda_codec_t *);
59582eadeeSfl static uint32_t audioha_codec_verb_get(void *, uint8_t,
60582eadeeSfl uint8_t, uint16_t, uint8_t);
61582eadeeSfl static uint32_t audioha_codec_4bit_verb_get(void *, uint8_t,
62582eadeeSfl uint8_t, uint16_t, uint16_t);
633a49c214SYang-Rong Jerry Zhou static int audiohd_reinit_hda(audiohd_state_t *);
645ec2209cSZhao Edgar Liu - Sun Microsystems static int audiohd_response_from_codec(audiohd_state_t *,
655ec2209cSZhao Edgar Liu - Sun Microsystems uint32_t *, uint32_t *);
665ec2209cSZhao Edgar Liu - Sun Microsystems static void audiohd_restore_codec_gpio(audiohd_state_t *);
675ec2209cSZhao Edgar Liu - Sun Microsystems static void audiohd_change_speaker_state(audiohd_state_t *, int);
685ec2209cSZhao Edgar Liu - Sun Microsystems static int audiohd_allocate_port(audiohd_state_t *);
695ec2209cSZhao Edgar Liu - Sun Microsystems static void audiohd_free_port(audiohd_state_t *);
705ec2209cSZhao Edgar Liu - Sun Microsystems static void audiohd_restore_path(audiohd_state_t *);
71c1cfefcdSZhao Edgar Liu - Sun Microsystems static void audiohd_create_controls(audiohd_state_t *);
725ec2209cSZhao Edgar Liu - Sun Microsystems static void audiohd_get_channels(audiohd_state_t *);
735ec2209cSZhao Edgar Liu - Sun Microsystems static void audiohd_init_path(audiohd_state_t *);
745ec2209cSZhao Edgar Liu - Sun Microsystems static void audiohd_del_controls(audiohd_state_t *);
755ec2209cSZhao Edgar Liu - Sun Microsystems static void audiohd_destroy(audiohd_state_t *);
765ec2209cSZhao Edgar Liu - Sun Microsystems static void audiohd_beep_on(void *);
775ec2209cSZhao Edgar Liu - Sun Microsystems static void audiohd_beep_off(void *);
785ec2209cSZhao Edgar Liu - Sun Microsystems static void audiohd_beep_freq(void *, int);
795ec2209cSZhao Edgar Liu - Sun Microsystems static wid_t audiohd_find_beep(hda_codec_t *, wid_t, int);
805ec2209cSZhao Edgar Liu - Sun Microsystems static void audiohd_build_beep_path(hda_codec_t *);
815ec2209cSZhao Edgar Liu - Sun Microsystems static void audiohd_build_beep_amp(hda_codec_t *);
825ec2209cSZhao Edgar Liu - Sun Microsystems static void audiohd_finish_beep_path(hda_codec_t *);
835ec2209cSZhao Edgar Liu - Sun Microsystems static void audiohd_do_set_beep_volume(audiohd_state_t *,
845ec2209cSZhao Edgar Liu - Sun Microsystems audiohd_path_t *, uint64_t);
855ec2209cSZhao Edgar Liu - Sun Microsystems static void audiohd_set_beep_volume(audiohd_state_t *);
865ec2209cSZhao Edgar Liu - Sun Microsystems static int audiohd_set_beep(void *, uint64_t);
87989b958fSZhao Edgar Liu - Sun Microsystems static void audiohd_pin_sense(audiohd_state_t *, uint32_t, uint32_t);
8842c41cf8Slipeng sang - Sun Microsystems - Beijing China
8942c41cf8Slipeng sang - Sun Microsystems - Beijing China static int audiohd_beep;
9042c41cf8Slipeng sang - Sun Microsystems - Beijing China static int audiohd_beep_divider;
9142c41cf8Slipeng sang - Sun Microsystems - Beijing China static int audiohd_beep_vol = 1;
92582eadeeSfl
93ea463888SZhao Edgar Liu - Sun Microsystems /* Warlock annotation */
94ea463888SZhao Edgar Liu - Sun Microsystems _NOTE(SCHEME_PROTECTS_DATA("unshared data", audiohd_beep))
95ea463888SZhao Edgar Liu - Sun Microsystems _NOTE(SCHEME_PROTECTS_DATA("unshared data", audiohd_beep_divider))
96ea463888SZhao Edgar Liu - Sun Microsystems _NOTE(SCHEME_PROTECTS_DATA("unshared data", audiohd_beep_vol))
97ea463888SZhao Edgar Liu - Sun Microsystems
98582eadeeSfl static ddi_device_acc_attr_t hda_dev_accattr = {
99582eadeeSfl DDI_DEVICE_ATTR_V0,
100582eadeeSfl DDI_STRUCTURE_LE_ACC,
101582eadeeSfl DDI_STRICTORDER_ACC
102582eadeeSfl };
103582eadeeSfl
10488447a05SGarrett D'Amore static const char *audiohd_dtypes[] = {
10588447a05SGarrett D'Amore AUDIO_PORT_LINEOUT,
10688447a05SGarrett D'Amore AUDIO_PORT_SPEAKER,
10788447a05SGarrett D'Amore AUDIO_PORT_HEADPHONES,
10888447a05SGarrett D'Amore AUDIO_PORT_CD,
10988447a05SGarrett D'Amore AUDIO_PORT_SPDIFOUT,
11088447a05SGarrett D'Amore AUDIO_PORT_DIGOUT,
11188447a05SGarrett D'Amore AUDIO_PORT_MODEM,
11288447a05SGarrett D'Amore AUDIO_PORT_HANDSET,
11388447a05SGarrett D'Amore AUDIO_PORT_LINEIN,
11488447a05SGarrett D'Amore AUDIO_PORT_AUX1IN,
11588447a05SGarrett D'Amore AUDIO_PORT_MIC,
11688447a05SGarrett D'Amore AUDIO_PORT_PHONE,
11788447a05SGarrett D'Amore AUDIO_PORT_SPDIFIN,
11888447a05SGarrett D'Amore AUDIO_PORT_DIGIN,
119c1cfefcdSZhao Edgar Liu - Sun Microsystems AUDIO_PORT_STEREOMIX,
12088447a05SGarrett D'Amore AUDIO_PORT_NONE, /* reserved port, don't use */
12188447a05SGarrett D'Amore AUDIO_PORT_OTHER,
122582eadeeSfl NULL,
123582eadeeSfl };
124582eadeeSfl
125cbe6566fSZhao Edgar Liu - Sun Microsystems static audiohd_codec_info_t audiohd_codecs[] = {
126cbe6566fSZhao Edgar Liu - Sun Microsystems {0x1002aa01, "ATI R600 HDMI", 0x0},
127cbe6566fSZhao Edgar Liu - Sun Microsystems {0x10134206, "Cirrus CS4206", 0x0},
128cbe6566fSZhao Edgar Liu - Sun Microsystems {0x10de0002, "nVidia MCP78 HDMI", 0x0},
1295ec2209cSZhao Edgar Liu - Sun Microsystems {0x10de0003, "nVidia MCP78 HDMI", 0x0},
1305ec2209cSZhao Edgar Liu - Sun Microsystems {0x10de0006, "nVidia MCP78 HDMI", 0x0},
131cbe6566fSZhao Edgar Liu - Sun Microsystems {0x10de0007, "nVidia MCP7A HDMI", 0x0},
132cbe6566fSZhao Edgar Liu - Sun Microsystems {0x10ec0260, "Realtek ALC260", (NO_GPIO)},
133ee97b734SZhao Edgar Liu - Sun Microsystems {0x10ec0262, "Realtek ALC262", (NO_GPIO | EN_PIN_BEEP)},
134cbe6566fSZhao Edgar Liu - Sun Microsystems {0x10ec0268, "Realtek ALC268", 0x0},
135cbe6566fSZhao Edgar Liu - Sun Microsystems {0x10ec0272, "Realtek ALC272", 0x0},
136cbe6566fSZhao Edgar Liu - Sun Microsystems {0x10ec0662, "Realtek ALC662", 0x0},
137cbe6566fSZhao Edgar Liu - Sun Microsystems {0x10ec0663, "Realtek ALC663", 0x0},
138cbe6566fSZhao Edgar Liu - Sun Microsystems {0x10ec0861, "Realtek ALC861", 0x0},
139cbe6566fSZhao Edgar Liu - Sun Microsystems {0x10ec0862, "Realtek ALC862", 0x0},
140cbe6566fSZhao Edgar Liu - Sun Microsystems {0x10ec0880, "Realtek ALC880", 0x0},
141cbe6566fSZhao Edgar Liu - Sun Microsystems {0x10ec0882, "Realtek ALC882", 0x0},
142cbe6566fSZhao Edgar Liu - Sun Microsystems {0x10ec0883, "Realtek ALC883", 0x0},
143cbe6566fSZhao Edgar Liu - Sun Microsystems {0x10ec0885, "Realtek ALC885", 0x0},
144cbe6566fSZhao Edgar Liu - Sun Microsystems {0x10ec0888, "Realtek ALC888", (NO_SPDIF)},
145*453b56c7SYuri Pankov {0x111d7603, "Integrated Devices 92HD75B3X5", (NO_MIXER)},
146cbe6566fSZhao Edgar Liu - Sun Microsystems {0x111d7608, "Integrated Devices 92HD75B2X5", (NO_MIXER)},
147cbe6566fSZhao Edgar Liu - Sun Microsystems {0x111d76b2, "Integrated Devices 92HD71B7X", (NO_MIXER)},
148cbe6566fSZhao Edgar Liu - Sun Microsystems {0x11d4194a, "Analog Devices AD1984A", 0x0},
149cbe6566fSZhao Edgar Liu - Sun Microsystems {0x11d41981, "Analog Devices AD1981", (NO_MIXER)},
150cbe6566fSZhao Edgar Liu - Sun Microsystems {0x11d41983, "Analog Devices AD1983", 0x0},
151cbe6566fSZhao Edgar Liu - Sun Microsystems {0x11d41984, "Analog Devices AD1984", 0x0},
152cbe6566fSZhao Edgar Liu - Sun Microsystems {0x11d41986, "Analog Devices AD1986A", 0x0},
153cbe6566fSZhao Edgar Liu - Sun Microsystems {0x11d41988, "Analog Devices AD1988A", 0x0},
154cbe6566fSZhao Edgar Liu - Sun Microsystems {0x11d4198b, "Analog Devices AD1988B", 0x0},
155cbe6566fSZhao Edgar Liu - Sun Microsystems {0x13f69880, "CMedia CMI19880", 0x0},
156cbe6566fSZhao Edgar Liu - Sun Microsystems {0x14f15045, "Conexant CX20549", (NO_MIXER)},
157cbe6566fSZhao Edgar Liu - Sun Microsystems {0x14f15051, "Conexant CX20561", 0x0},
158cbe6566fSZhao Edgar Liu - Sun Microsystems {0x434d4980, "CMedia CMI19880", 0x0},
159cbe6566fSZhao Edgar Liu - Sun Microsystems {0x80862802, "Intel HDMI", 0x0},
160cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847610, "Sigmatel STAC9230XN", 0x0},
161cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847611, "Sigmatel STAC9230DN", 0x0},
162cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847612, "Sigmatel STAC9230XT", 0x0},
163cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847613, "Sigmatel STAC9230DT", 0x0},
164cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847614, "Sigmatel STAC9229X", 0x0},
165cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847615, "Sigmatel STAC9229D", 0x0},
166cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847616, "Sigmatel STAC9228X", 0x0},
167cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847617, "Sigmatel STAC9228D", 0x0},
168cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847618, "Sigmatel STAC9227X", 0x0},
169cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847619, "Sigmatel STAC9227D", 0x0},
170cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847620, "Sigmatel STAC9274", 0x0},
171cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847621, "Sigmatel STAC9274D", 0x0},
172cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847622, "Sigmatel STAC9273X", 0x0},
173cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847623, "Sigmatel STAC9273D", 0x0},
174cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847624, "Sigmatel STAC9272X", 0x0},
175cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847625, "Sigmatel STAC9272D", 0x0},
176cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847626, "Sigmatel STAC9271X", 0x0},
177cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847627, "Sigmatel STAC9271D", 0x0},
178cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847628, "Sigmatel STAC9274X5NH", 0x0},
179cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847629, "Sigmatel STAC9274D5NH", 0x0},
180cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847662, "Sigmatel STAC9872AK", 0x0},
181cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847664, "Sigmatel STAC9872K", 0x0},
182cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847680, "Sigmatel STAC9221A1", 0x0},
183cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847680, "Sigmatel STAC9221A1", 0x0},
184cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847681, "Sigmatel STAC9220D", 0x0},
185cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847682, "Sigmatel STAC9221", 0x0},
186cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847683, "Sigmatel STAC9221D", 0x0},
187cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847690, "Sigmatel STAC9200", 0x0},
188cbe6566fSZhao Edgar Liu - Sun Microsystems {0x838476a0, "Sigmatel STAC9205", 0x0},
189cbe6566fSZhao Edgar Liu - Sun Microsystems {0x838476a1, "Sigmatel STAC9205D", 0x0},
190cbe6566fSZhao Edgar Liu - Sun Microsystems {0x838476a2, "Sigmatel STAC9204", 0x0},
191cbe6566fSZhao Edgar Liu - Sun Microsystems {0x838476a3, "Sigmatel STAC9204D", 0x0},
192cbe6566fSZhao Edgar Liu - Sun Microsystems {0x838476a4, "Sigmatel STAC9255", 0x0},
193cbe6566fSZhao Edgar Liu - Sun Microsystems {0x838476a5, "Sigmatel STAC9255D", 0x0},
194cbe6566fSZhao Edgar Liu - Sun Microsystems {0x838476a6, "Sigmatel STAC9254", 0x0},
195cbe6566fSZhao Edgar Liu - Sun Microsystems {0x838476a7, "Sigmatel STAC9254D", 0x0},
196cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847880, "Sigmatel STAC9220A1", 0x0},
197cbe6566fSZhao Edgar Liu - Sun Microsystems {0x83847882, "Sigmatel STAC9220A2", 0x0},
198cbe6566fSZhao Edgar Liu - Sun Microsystems {0x0, "Unknown 0x00000000", 0x0},
199cbe6566fSZhao Edgar Liu - Sun Microsystems };
200cbe6566fSZhao Edgar Liu - Sun Microsystems
20188447a05SGarrett D'Amore static void
audiohd_set_chipset_info(audiohd_state_t * statep)20288447a05SGarrett D'Amore audiohd_set_chipset_info(audiohd_state_t *statep)
203582eadeeSfl {
20488447a05SGarrett D'Amore uint32_t devid;
20588447a05SGarrett D'Amore const char *name;
20688447a05SGarrett D'Amore const char *vers;
207582eadeeSfl
20888447a05SGarrett D'Amore devid = pci_config_get16(statep->hda_pci_handle, PCI_CONF_VENID);
20988447a05SGarrett D'Amore devid <<= 16;
21088447a05SGarrett D'Amore devid |= pci_config_get16(statep->hda_pci_handle, PCI_CONF_DEVID);
21189e1f902SZhao Edgar Liu - Sun Microsystems statep->devid = devid;
212582eadeeSfl
21388447a05SGarrett D'Amore name = AUDIOHD_DEV_CONFIG;
21488447a05SGarrett D'Amore vers = AUDIOHD_DEV_VERSION;
215582eadeeSfl
21688447a05SGarrett D'Amore switch (devid) {
21726ae4a35SZhao Edgar Liu - Sun Microsystems case 0x1002437b:
21826ae4a35SZhao Edgar Liu - Sun Microsystems name = "ATI HD Audio";
21926ae4a35SZhao Edgar Liu - Sun Microsystems vers = "SB450";
22088447a05SGarrett D'Amore break;
22126ae4a35SZhao Edgar Liu - Sun Microsystems case 0x10024383:
22226ae4a35SZhao Edgar Liu - Sun Microsystems name = "ATI HD Audio";
22326ae4a35SZhao Edgar Liu - Sun Microsystems vers = "SB600";
22488447a05SGarrett D'Amore break;
22570feb41cSZhao Edgar Liu - Sun Microsystems case 0x10029442:
22670feb41cSZhao Edgar Liu - Sun Microsystems name = "ATI HD Audio";
22770feb41cSZhao Edgar Liu - Sun Microsystems vers = "Radeon HD 4850";
22870feb41cSZhao Edgar Liu - Sun Microsystems break;
229ee97b734SZhao Edgar Liu - Sun Microsystems case 0x1002aa30:
230ee97b734SZhao Edgar Liu - Sun Microsystems name = "ATI HD Audio";
231ee97b734SZhao Edgar Liu - Sun Microsystems vers = "HD 48x0";
232ee97b734SZhao Edgar Liu - Sun Microsystems break;
23326ae4a35SZhao Edgar Liu - Sun Microsystems case 0x1002aa38:
23426ae4a35SZhao Edgar Liu - Sun Microsystems name = "ATI HD Audio";
23526ae4a35SZhao Edgar Liu - Sun Microsystems vers = "Radeon HD 4670";
23688447a05SGarrett D'Amore break;
23788447a05SGarrett D'Amore case 0x10de026c:
23888447a05SGarrett D'Amore name = "NVIDIA HD Audio";
23989e1f902SZhao Edgar Liu - Sun Microsystems vers = "MCP51";
24088447a05SGarrett D'Amore break;
2410c240c64SZhao Edgar Liu - Sun Microsystems case 0x10de0371:
2420c240c64SZhao Edgar Liu - Sun Microsystems name = "NVIDIA HD Audio";
2430c240c64SZhao Edgar Liu - Sun Microsystems vers = "MCP55";
2440c240c64SZhao Edgar Liu - Sun Microsystems break;
24588447a05SGarrett D'Amore case 0x10de03e4:
24688447a05SGarrett D'Amore name = "NVIDIA HD Audio";
24788447a05SGarrett D'Amore vers = "MCP61";
24888447a05SGarrett D'Amore break;
2490c240c64SZhao Edgar Liu - Sun Microsystems case 0x10de03f0:
2500c240c64SZhao Edgar Liu - Sun Microsystems name = "NVIDIA HD Audio";
2510c240c64SZhao Edgar Liu - Sun Microsystems vers = "MCP61A";
2520c240c64SZhao Edgar Liu - Sun Microsystems break;
25388447a05SGarrett D'Amore case 0x10de044a:
25488447a05SGarrett D'Amore name = "NVIDIA HD Audio";
25588447a05SGarrett D'Amore vers = "MCP65";
25688447a05SGarrett D'Amore break;
25788447a05SGarrett D'Amore case 0x10de055c:
25888447a05SGarrett D'Amore name = "NVIDIA HD Audio";
25988447a05SGarrett D'Amore vers = "MCP67";
26088447a05SGarrett D'Amore break;
2610c240c64SZhao Edgar Liu - Sun Microsystems case 0x10de0774:
2620c240c64SZhao Edgar Liu - Sun Microsystems name = "NVIDIA HD Audio";
2630c240c64SZhao Edgar Liu - Sun Microsystems vers = "MCP78S";
2640c240c64SZhao Edgar Liu - Sun Microsystems break;
26589e1f902SZhao Edgar Liu - Sun Microsystems case 0x10de0ac0:
26689e1f902SZhao Edgar Liu - Sun Microsystems name = "NVIDIA HD Audio";
26789e1f902SZhao Edgar Liu - Sun Microsystems vers = "MCP79";
26889e1f902SZhao Edgar Liu - Sun Microsystems break;
26988447a05SGarrett D'Amore case 0x11063288:
27088447a05SGarrett D'Amore name = "VIA HD Audio";
27188447a05SGarrett D'Amore vers = "HDA";
272582eadeeSfl break;
27326ae4a35SZhao Edgar Liu - Sun Microsystems case 0x80862668:
27426ae4a35SZhao Edgar Liu - Sun Microsystems name = "Intel HD Audio";
27526ae4a35SZhao Edgar Liu - Sun Microsystems vers = "ICH6";
27626ae4a35SZhao Edgar Liu - Sun Microsystems break;
27726ae4a35SZhao Edgar Liu - Sun Microsystems case 0x808627d8:
27826ae4a35SZhao Edgar Liu - Sun Microsystems name = "Intel HD Audio";
27926ae4a35SZhao Edgar Liu - Sun Microsystems vers = "ICH7";
28026ae4a35SZhao Edgar Liu - Sun Microsystems break;
28126ae4a35SZhao Edgar Liu - Sun Microsystems case 0x8086284b:
28226ae4a35SZhao Edgar Liu - Sun Microsystems name = "Intel HD Audio";
28326ae4a35SZhao Edgar Liu - Sun Microsystems vers = "ICH8";
28426ae4a35SZhao Edgar Liu - Sun Microsystems break;
28526ae4a35SZhao Edgar Liu - Sun Microsystems case 0x8086293e:
28626ae4a35SZhao Edgar Liu - Sun Microsystems name = "Intel HD Audio";
28726ae4a35SZhao Edgar Liu - Sun Microsystems vers = "ICH9";
28826ae4a35SZhao Edgar Liu - Sun Microsystems break;
28926ae4a35SZhao Edgar Liu - Sun Microsystems case 0x80863a3e:
29026ae4a35SZhao Edgar Liu - Sun Microsystems name = "Intel HD Audio";
29126ae4a35SZhao Edgar Liu - Sun Microsystems vers = "ICH10";
29226ae4a35SZhao Edgar Liu - Sun Microsystems break;
293*453b56c7SYuri Pankov case 0x80863b56:
294*453b56c7SYuri Pankov name = "Intel HD Audio";
295*453b56c7SYuri Pankov vers = "PCH";
296*453b56c7SYuri Pankov break;
297582eadeeSfl }
29888447a05SGarrett D'Amore /* set device information */
29988447a05SGarrett D'Amore audio_dev_set_description(statep->adev, name);
30088447a05SGarrett D'Amore audio_dev_set_version(statep->adev, vers);
30188447a05SGarrett D'Amore }
302582eadeeSfl
30388447a05SGarrett D'Amore static int
audiohd_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)304582eadeeSfl audiohd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
305582eadeeSfl {
306582eadeeSfl audiohd_state_t *statep;
307582eadeeSfl int instance;
308582eadeeSfl
309582eadeeSfl instance = ddi_get_instance(dip);
310582eadeeSfl switch (cmd) {
311582eadeeSfl case DDI_ATTACH:
312582eadeeSfl break;
313582eadeeSfl
314582eadeeSfl case DDI_RESUME:
31588447a05SGarrett D'Amore statep = ddi_get_driver_private(dip);
316d5247f45Sgs ASSERT(statep != NULL);
317d5247f45Sgs return (audiohd_resume(statep));
318582eadeeSfl
319582eadeeSfl default:
320582eadeeSfl return (DDI_FAILURE);
321582eadeeSfl }
322582eadeeSfl
32388447a05SGarrett D'Amore /* allocate the soft state structure */
32488447a05SGarrett D'Amore statep = kmem_zalloc(sizeof (*statep), KM_SLEEP);
32588447a05SGarrett D'Amore ddi_set_driver_private(dip, statep);
326582eadeeSfl
327ea463888SZhao Edgar Liu - Sun Microsystems mutex_init(&statep->hda_mutex, NULL, MUTEX_DRIVER, 0);
328ea463888SZhao Edgar Liu - Sun Microsystems mutex_enter(&statep->hda_mutex);
329ea463888SZhao Edgar Liu - Sun Microsystems
330644f3c1fScg /* interrupt cookie and initialize mutex */
331c6e681c0SYang-Rong Jerry Zhou if (audiohd_init_state(statep, dip) != DDI_SUCCESS) {
332e7236f70SZhao Edgar Liu - Sun Microsystems audio_dev_warn(NULL, "audiohd_init_state failed");
333c6e681c0SYang-Rong Jerry Zhou goto error;
334582eadeeSfl }
335582eadeeSfl
336582eadeeSfl /* Set PCI command register to enable bus master and memeory I/O */
337c6e681c0SYang-Rong Jerry Zhou if (audiohd_init_pci(statep, &hda_dev_accattr) != DDI_SUCCESS) {
33888447a05SGarrett D'Amore audio_dev_warn(statep->adev,
33988447a05SGarrett D'Amore "couldn't init pci regs");
340c6e681c0SYang-Rong Jerry Zhou goto error;
341582eadeeSfl }
342582eadeeSfl
34388447a05SGarrett D'Amore audiohd_set_chipset_info(statep);
34488447a05SGarrett D'Amore
345c6e681c0SYang-Rong Jerry Zhou if (audiohd_init_controller(statep) != DDI_SUCCESS) {
34688447a05SGarrett D'Amore audio_dev_warn(statep->adev,
34788447a05SGarrett D'Amore "couldn't init controller");
348c6e681c0SYang-Rong Jerry Zhou goto error;
349582eadeeSfl }
350582eadeeSfl
351c6e681c0SYang-Rong Jerry Zhou if (audiohd_create_codec(statep) != DDI_SUCCESS) {
35288447a05SGarrett D'Amore audio_dev_warn(statep->adev,
35388447a05SGarrett D'Amore "couldn't create codec");
354c6e681c0SYang-Rong Jerry Zhou goto error;
355582eadeeSfl }
356582eadeeSfl
3573a49c214SYang-Rong Jerry Zhou audiohd_build_path(statep);
358a234d95bScg
35988447a05SGarrett D'Amore audiohd_get_channels(statep);
36088447a05SGarrett D'Amore if (audiohd_allocate_port(statep) != DDI_SUCCESS) {
36188447a05SGarrett D'Amore audio_dev_warn(statep->adev, "allocate port failure");
362c6e681c0SYang-Rong Jerry Zhou goto error;
363582eadeeSfl }
36488447a05SGarrett D'Amore audiohd_init_path(statep);
365582eadeeSfl /* set up kernel statistics */
36688447a05SGarrett D'Amore if ((statep->hda_ksp = kstat_create(DRVNAME, instance,
36788447a05SGarrett D'Amore DRVNAME, "controller", KSTAT_TYPE_INTR, 1,
368582eadeeSfl KSTAT_FLAG_PERSISTENT)) != NULL) {
369582eadeeSfl kstat_install(statep->hda_ksp);
370582eadeeSfl }
371582eadeeSfl
372582eadeeSfl /* disable interrupts and clear interrupt status */
373582eadeeSfl audiohd_disable_intr(statep);
374582eadeeSfl
37588447a05SGarrett D'Amore /*
37688447a05SGarrett D'Amore * Register audio controls.
37788447a05SGarrett D'Amore */
378c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_create_controls(statep);
379c1cfefcdSZhao Edgar Liu - Sun Microsystems
38088447a05SGarrett D'Amore if (audio_dev_register(statep->adev) != DDI_SUCCESS) {
38188447a05SGarrett D'Amore audio_dev_warn(statep->adev,
38288447a05SGarrett D'Amore "unable to register with framework");
383c6e681c0SYang-Rong Jerry Zhou goto error;
38488447a05SGarrett D'Amore }
385582eadeeSfl ddi_report_dev(dip);
386582eadeeSfl
387ea463888SZhao Edgar Liu - Sun Microsystems mutex_exit(&statep->hda_mutex);
388582eadeeSfl return (DDI_SUCCESS);
389c6e681c0SYang-Rong Jerry Zhou error:
390ea463888SZhao Edgar Liu - Sun Microsystems mutex_exit(&statep->hda_mutex);
391c6e681c0SYang-Rong Jerry Zhou audiohd_destroy(statep);
392582eadeeSfl return (DDI_FAILURE);
39388447a05SGarrett D'Amore }
394582eadeeSfl
39588447a05SGarrett D'Amore static int
audiohd_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)396582eadeeSfl audiohd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
397582eadeeSfl {
398582eadeeSfl audiohd_state_t *statep;
399582eadeeSfl
40088447a05SGarrett D'Amore statep = ddi_get_driver_private(dip);
40188447a05SGarrett D'Amore ASSERT(statep != NULL);
402582eadeeSfl
403582eadeeSfl switch (cmd) {
404582eadeeSfl case DDI_DETACH:
405582eadeeSfl break;
406582eadeeSfl
407582eadeeSfl case DDI_SUSPEND:
408d5247f45Sgs return (audiohd_suspend(statep));
409582eadeeSfl
410582eadeeSfl default:
411582eadeeSfl return (DDI_FAILURE);
412582eadeeSfl }
41388447a05SGarrett D'Amore if (audio_dev_unregister(statep->adev) != DDI_SUCCESS)
41488447a05SGarrett D'Amore return (DDI_FAILURE);
415582eadeeSfl
41642c41cf8Slipeng sang - Sun Microsystems - Beijing China if (audiohd_beep)
41742c41cf8Slipeng sang - Sun Microsystems - Beijing China (void) beep_fini();
418c6e681c0SYang-Rong Jerry Zhou audiohd_destroy(statep);
419582eadeeSfl return (DDI_SUCCESS);
42088447a05SGarrett D'Amore }
42188447a05SGarrett D'Amore
42288447a05SGarrett D'Amore static struct dev_ops audiohd_dev_ops = {
42388447a05SGarrett D'Amore DEVO_REV, /* rev */
42488447a05SGarrett D'Amore 0, /* refcnt */
42588447a05SGarrett D'Amore NULL, /* getinfo */
42688447a05SGarrett D'Amore nulldev, /* identify */
42788447a05SGarrett D'Amore nulldev, /* probe */
42888447a05SGarrett D'Amore audiohd_attach, /* attach */
42988447a05SGarrett D'Amore audiohd_detach, /* detach */
43088447a05SGarrett D'Amore nodev, /* reset */
43188447a05SGarrett D'Amore NULL, /* cb_ops */
43288447a05SGarrett D'Amore NULL, /* bus_ops */
43388447a05SGarrett D'Amore NULL, /* power */
43488447a05SGarrett D'Amore audiohd_quiesce, /* quiesce */
43588447a05SGarrett D'Amore };
43688447a05SGarrett D'Amore
43788447a05SGarrett D'Amore static struct modldrv audiohd_modldrv = {
43888447a05SGarrett D'Amore &mod_driverops, /* drv_modops */
43988447a05SGarrett D'Amore "AudioHD", /* linkinfo */
44088447a05SGarrett D'Amore &audiohd_dev_ops, /* dev_ops */
44188447a05SGarrett D'Amore };
44288447a05SGarrett D'Amore
44388447a05SGarrett D'Amore static struct modlinkage modlinkage = {
44488447a05SGarrett D'Amore MODREV_1,
44588447a05SGarrett D'Amore { &audiohd_modldrv, NULL }
44688447a05SGarrett D'Amore };
44788447a05SGarrett D'Amore
44888447a05SGarrett D'Amore int
_init(void)44988447a05SGarrett D'Amore _init(void)
45088447a05SGarrett D'Amore {
45188447a05SGarrett D'Amore int rv;
45288447a05SGarrett D'Amore
45388447a05SGarrett D'Amore audio_init_ops(&audiohd_dev_ops, DRVNAME);
45488447a05SGarrett D'Amore if ((rv = mod_install(&modlinkage)) != 0) {
45588447a05SGarrett D'Amore audio_fini_ops(&audiohd_dev_ops);
45688447a05SGarrett D'Amore }
45788447a05SGarrett D'Amore return (rv);
45888447a05SGarrett D'Amore }
459582eadeeSfl
46088447a05SGarrett D'Amore int
_fini(void)46188447a05SGarrett D'Amore _fini(void)
46288447a05SGarrett D'Amore {
46388447a05SGarrett D'Amore int rv;
46488447a05SGarrett D'Amore
46588447a05SGarrett D'Amore if ((rv = mod_remove(&modlinkage)) == 0) {
46688447a05SGarrett D'Amore audio_fini_ops(&audiohd_dev_ops);
46788447a05SGarrett D'Amore }
46888447a05SGarrett D'Amore return (rv);
46988447a05SGarrett D'Amore }
47088447a05SGarrett D'Amore
47188447a05SGarrett D'Amore int
_info(struct modinfo * modinfop)47288447a05SGarrett D'Amore _info(struct modinfo *modinfop)
47388447a05SGarrett D'Amore {
47488447a05SGarrett D'Amore return (mod_info(&modlinkage, modinfop));
47588447a05SGarrett D'Amore }
476582eadeeSfl
47719397407SSherry Moore /*
47888447a05SGarrett D'Amore * Audio routines
47919397407SSherry Moore */
48088447a05SGarrett D'Amore
48119397407SSherry Moore static int
audiohd_engine_format(void * arg)48288447a05SGarrett D'Amore audiohd_engine_format(void *arg)
48319397407SSherry Moore {
484a33ad26eSZhao Edgar Liu - Sun Microsystems audiohd_port_t *port = arg;
485a33ad26eSZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = port->statep;
48619397407SSherry Moore
487a33ad26eSZhao Edgar Liu - Sun Microsystems switch (statep->sample_bit_depth) {
488a33ad26eSZhao Edgar Liu - Sun Microsystems case AUDIOHD_BIT_DEPTH24:
489a33ad26eSZhao Edgar Liu - Sun Microsystems return (AUDIO_FORMAT_S32_LE);
490a33ad26eSZhao Edgar Liu - Sun Microsystems case AUDIOHD_BIT_DEPTH16:
491a33ad26eSZhao Edgar Liu - Sun Microsystems default:
492a33ad26eSZhao Edgar Liu - Sun Microsystems return (AUDIO_FORMAT_S16_LE);
493a33ad26eSZhao Edgar Liu - Sun Microsystems }
49488447a05SGarrett D'Amore }
49519397407SSherry Moore
49688447a05SGarrett D'Amore static int
audiohd_engine_channels(void * arg)49788447a05SGarrett D'Amore audiohd_engine_channels(void *arg)
49888447a05SGarrett D'Amore {
49988447a05SGarrett D'Amore audiohd_port_t *port = arg;
50019397407SSherry Moore
50188447a05SGarrett D'Amore return (port->nchan);
50288447a05SGarrett D'Amore }
50319397407SSherry Moore
50488447a05SGarrett D'Amore static int
audiohd_engine_rate(void * arg)50588447a05SGarrett D'Amore audiohd_engine_rate(void *arg)
50688447a05SGarrett D'Amore {
507a33ad26eSZhao Edgar Liu - Sun Microsystems audiohd_port_t *port = arg;
508a33ad26eSZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = port->statep;
50988447a05SGarrett D'Amore
510a33ad26eSZhao Edgar Liu - Sun Microsystems return (statep->sample_rate);
51119397407SSherry Moore }
512c6e681c0SYang-Rong Jerry Zhou static void
audiohd_free_path(audiohd_state_t * statep)513c6e681c0SYang-Rong Jerry Zhou audiohd_free_path(audiohd_state_t *statep)
514c6e681c0SYang-Rong Jerry Zhou {
515c6e681c0SYang-Rong Jerry Zhou audiohd_path_t *path;
516c6e681c0SYang-Rong Jerry Zhou int i;
517c6e681c0SYang-Rong Jerry Zhou
518c6e681c0SYang-Rong Jerry Zhou for (i = 0; i < statep->pathnum; i++) {
519c6e681c0SYang-Rong Jerry Zhou if (statep->path[i]) {
520c6e681c0SYang-Rong Jerry Zhou path = statep->path[i];
521c6e681c0SYang-Rong Jerry Zhou kmem_free(path, sizeof (audiohd_path_t));
522c6e681c0SYang-Rong Jerry Zhou }
523c6e681c0SYang-Rong Jerry Zhou }
524c6e681c0SYang-Rong Jerry Zhou }
525c6e681c0SYang-Rong Jerry Zhou static void
audiohd_destroy(audiohd_state_t * statep)526c6e681c0SYang-Rong Jerry Zhou audiohd_destroy(audiohd_state_t *statep)
527c6e681c0SYang-Rong Jerry Zhou {
528ea463888SZhao Edgar Liu - Sun Microsystems mutex_enter(&statep->hda_mutex);
529c6e681c0SYang-Rong Jerry Zhou audiohd_stop_dma(statep);
530c6e681c0SYang-Rong Jerry Zhou if (statep->hda_ksp)
531c6e681c0SYang-Rong Jerry Zhou kstat_delete(statep->hda_ksp);
532c6e681c0SYang-Rong Jerry Zhou audiohd_free_port(statep);
533c6e681c0SYang-Rong Jerry Zhou audiohd_free_path(statep);
534c6e681c0SYang-Rong Jerry Zhou audiohd_destroy_codec(statep);
535c6e681c0SYang-Rong Jerry Zhou audiohd_del_controls(statep);
536c6e681c0SYang-Rong Jerry Zhou audiohd_fini_controller(statep);
537c6e681c0SYang-Rong Jerry Zhou audiohd_fini_pci(statep);
538ea463888SZhao Edgar Liu - Sun Microsystems mutex_exit(&statep->hda_mutex);
539c6e681c0SYang-Rong Jerry Zhou mutex_destroy(&statep->hda_mutex);
540c6e681c0SYang-Rong Jerry Zhou if (statep->adev)
541c6e681c0SYang-Rong Jerry Zhou audio_dev_free(statep->adev);
542c6e681c0SYang-Rong Jerry Zhou kmem_free(statep, sizeof (*statep));
543c6e681c0SYang-Rong Jerry Zhou }
5443a49c214SYang-Rong Jerry Zhou /*
54588447a05SGarrett D'Amore * get the max channels the hardware supported
5463a49c214SYang-Rong Jerry Zhou */
5473a49c214SYang-Rong Jerry Zhou static void
audiohd_get_channels(audiohd_state_t * statep)54888447a05SGarrett D'Amore audiohd_get_channels(audiohd_state_t *statep)
5493a49c214SYang-Rong Jerry Zhou {
55088447a05SGarrett D'Amore int i;
55188447a05SGarrett D'Amore uint8_t maxp, assoc;
5523a49c214SYang-Rong Jerry Zhou
55388447a05SGarrett D'Amore maxp = 2;
55488447a05SGarrett D'Amore for (i = 0; i < AUDIOHD_MAX_ASSOC; i++) {
55588447a05SGarrett D'Amore if (maxp < statep->chann[i]) {
55688447a05SGarrett D'Amore maxp = statep->chann[i];
55788447a05SGarrett D'Amore assoc = i;
5583a49c214SYang-Rong Jerry Zhou }
5593a49c214SYang-Rong Jerry Zhou }
56088447a05SGarrett D'Amore statep->pchan = maxp;
56188447a05SGarrett D'Amore statep->assoc = assoc;
56288447a05SGarrett D'Amore /* for record, support stereo so far */
56388447a05SGarrett D'Amore statep->rchan = 2;
5643a49c214SYang-Rong Jerry Zhou }
5653a49c214SYang-Rong Jerry Zhou static void
audiohd_init_play_path(audiohd_path_t * path)56688447a05SGarrett D'Amore audiohd_init_play_path(audiohd_path_t *path)
5673a49c214SYang-Rong Jerry Zhou {
56888447a05SGarrett D'Amore int i;
56988447a05SGarrett D'Amore uint32_t ctrl;
57088447a05SGarrett D'Amore uint8_t ctrl8;
57188447a05SGarrett D'Amore uint8_t nchann;
57288447a05SGarrett D'Amore audiohd_widget_t *widget;
57388447a05SGarrett D'Amore audiohd_pin_t *pin;
57488447a05SGarrett D'Amore wid_t wid;
57588447a05SGarrett D'Amore audiohd_pin_color_t color;
57688447a05SGarrett D'Amore
57788447a05SGarrett D'Amore audiohd_state_t *statep = path->statep;
57888447a05SGarrett D'Amore hda_codec_t *codec = path->codec;
57988447a05SGarrett D'Amore
58088447a05SGarrett D'Amore /* enable SPDIF output */
58188447a05SGarrett D'Amore for (i = 0; i < path->pin_nums; i++) {
58288447a05SGarrett D'Amore wid = path->pin_wid[i];
58388447a05SGarrett D'Amore widget = codec->widget[wid];
58488447a05SGarrett D'Amore pin = (audiohd_pin_t *)widget->priv;
58588447a05SGarrett D'Amore if (pin->device == DTYPE_SPDIF_OUT) {
58688447a05SGarrett D'Amore ctrl = audioha_codec_verb_get(
58788447a05SGarrett D'Amore statep,
58888447a05SGarrett D'Amore codec->index,
58988447a05SGarrett D'Amore path->adda_wid,
59088447a05SGarrett D'Amore AUDIOHDC_VERB_GET_SPDIF_CTL,
59188447a05SGarrett D'Amore 0);
59288447a05SGarrett D'Amore ctrl |= AUDIOHD_SPDIF_ON;
59388447a05SGarrett D'Amore ctrl8 = ctrl &
59488447a05SGarrett D'Amore AUDIOHD_SPDIF_MASK;
59588447a05SGarrett D'Amore (void) audioha_codec_verb_get(
59688447a05SGarrett D'Amore statep,
59788447a05SGarrett D'Amore codec->index,
59888447a05SGarrett D'Amore path->adda_wid,
59988447a05SGarrett D'Amore AUDIOHDC_VERB_SET_SPDIF_LCL,
60088447a05SGarrett D'Amore ctrl8);
60165a41de7SYang-Rong Jerry Zhou /*
60265a41de7SYang-Rong Jerry Zhou * We find that on intel ICH10 chipset with codec
60365a41de7SYang-Rong Jerry Zhou * ALC888, audio is scratchy if we set the tag on the
60465a41de7SYang-Rong Jerry Zhou * SPDIF path. So we just return here without setting
60565a41de7SYang-Rong Jerry Zhou * the tag for the path as a workaround.
60665a41de7SYang-Rong Jerry Zhou */
6075ec2209cSZhao Edgar Liu - Sun Microsystems if (codec->codec_info->flags & NO_SPDIF)
60865a41de7SYang-Rong Jerry Zhou return;
60988447a05SGarrett D'Amore }
61088447a05SGarrett D'Amore }
61188447a05SGarrett D'Amore wid = path->pin_wid[0];
61288447a05SGarrett D'Amore widget = codec->widget[wid];
61388447a05SGarrett D'Amore pin = (audiohd_pin_t *)widget->priv;
61488447a05SGarrett D'Amore
61588447a05SGarrett D'Amore /* two channels supported */
61688447a05SGarrett D'Amore if (pin->device == DTYPE_SPEAKER ||
617c1aa074aSYang-Rong Jerry Zhou pin->device == DTYPE_HP_OUT ||
61888447a05SGarrett D'Amore pin->assoc != statep->assoc) {
61988447a05SGarrett D'Amore (void) audioha_codec_verb_get(
62088447a05SGarrett D'Amore statep,
62188447a05SGarrett D'Amore codec->index,
62288447a05SGarrett D'Amore path->adda_wid,
62388447a05SGarrett D'Amore AUDIOHDC_VERB_SET_STREAM_CHANN,
62488447a05SGarrett D'Amore statep->port[PORT_DAC]->index <<
62588447a05SGarrett D'Amore AUDIOHD_PLAY_TAG_OFF);
62688447a05SGarrett D'Amore (void) audioha_codec_4bit_verb_get(
62788447a05SGarrett D'Amore statep,
62888447a05SGarrett D'Amore codec->index,
62988447a05SGarrett D'Amore path->adda_wid,
63088447a05SGarrett D'Amore AUDIOHDC_VERB_SET_CONV_FMT,
631a33ad26eSZhao Edgar Liu - Sun Microsystems statep->port[PORT_DAC]->format << 4 |
63288447a05SGarrett D'Amore statep->pchan - 1);
63388447a05SGarrett D'Amore /* multichannel supported */
63488447a05SGarrett D'Amore } else {
63588447a05SGarrett D'Amore color = (pin->config >> AUDIOHD_PIN_CLR_OFF) &
63688447a05SGarrett D'Amore AUDIOHD_PIN_CLR_MASK;
63788447a05SGarrett D'Amore switch (color) {
63888447a05SGarrett D'Amore case AUDIOHD_PIN_BLACK:
63988447a05SGarrett D'Amore nchann = statep->pchan - 2;
64088447a05SGarrett D'Amore break;
64188447a05SGarrett D'Amore case AUDIOHD_PIN_ORANGE:
64288447a05SGarrett D'Amore nchann = 2;
64388447a05SGarrett D'Amore break;
64488447a05SGarrett D'Amore case AUDIOHD_PIN_GREY:
64588447a05SGarrett D'Amore nchann = 4;
64688447a05SGarrett D'Amore break;
64788447a05SGarrett D'Amore case AUDIOHD_PIN_GREEN:
64888447a05SGarrett D'Amore nchann = 0;
64988447a05SGarrett D'Amore break;
65088447a05SGarrett D'Amore default:
65188447a05SGarrett D'Amore nchann = 0;
65288447a05SGarrett D'Amore break;
65388447a05SGarrett D'Amore }
65488447a05SGarrett D'Amore (void) audioha_codec_verb_get(statep,
65588447a05SGarrett D'Amore codec->index,
65688447a05SGarrett D'Amore path->adda_wid,
65788447a05SGarrett D'Amore AUDIOHDC_VERB_SET_STREAM_CHANN,
65888447a05SGarrett D'Amore statep->port[PORT_DAC]->index <<
65988447a05SGarrett D'Amore AUDIOHD_PLAY_TAG_OFF |
66088447a05SGarrett D'Amore nchann);
66188447a05SGarrett D'Amore (void) audioha_codec_4bit_verb_get(
66288447a05SGarrett D'Amore statep,
66388447a05SGarrett D'Amore codec->index,
66488447a05SGarrett D'Amore path->adda_wid,
66588447a05SGarrett D'Amore AUDIOHDC_VERB_SET_CONV_FMT,
666a33ad26eSZhao Edgar Liu - Sun Microsystems statep->port[PORT_DAC]->format << 4 |
66788447a05SGarrett D'Amore statep->pchan - 1);
6683a49c214SYang-Rong Jerry Zhou }
6693a49c214SYang-Rong Jerry Zhou }
67088447a05SGarrett D'Amore static void
audiohd_init_record_path(audiohd_path_t * path)67188447a05SGarrett D'Amore audiohd_init_record_path(audiohd_path_t *path)
67288447a05SGarrett D'Amore {
67388447a05SGarrett D'Amore audiohd_state_t *statep = path->statep;
67488447a05SGarrett D'Amore hda_codec_t *codec = path->codec;
67588447a05SGarrett D'Amore int i;
67688447a05SGarrett D'Amore wid_t wid;
67788447a05SGarrett D'Amore audiohd_pin_t *pin;
67888447a05SGarrett D'Amore audiohd_widget_t *widget;
6793a49c214SYang-Rong Jerry Zhou
68088447a05SGarrett D'Amore for (i = 0; i < path->pin_nums; i++) {
68188447a05SGarrett D'Amore wid = path->pin_wid[i];
68288447a05SGarrett D'Amore widget = codec->widget[wid];
68388447a05SGarrett D'Amore pin = (audiohd_pin_t *)widget->priv;
68488447a05SGarrett D'Amore /*
68588447a05SGarrett D'Amore * Since there is no SPDIF input device available for test,
68688447a05SGarrett D'Amore * we will use this code in the future to support SPDIF input
68788447a05SGarrett D'Amore */
68888447a05SGarrett D'Amore #if 0
68988447a05SGarrett D'Amore if (pin->device == DTYPE_SPDIF_IN) {
69088447a05SGarrett D'Amore ctrl = audioha_codec_verb_get(
69188447a05SGarrett D'Amore statep,
69288447a05SGarrett D'Amore codec->index,
69388447a05SGarrett D'Amore path->adda_wid,
69488447a05SGarrett D'Amore AUDIOHDC_VERB_GET_SPDIF_CTL,
69588447a05SGarrett D'Amore 0);
69688447a05SGarrett D'Amore ctrl |= AUDIOHD_SPDIF_ON;
69788447a05SGarrett D'Amore ctrl8 = ctrl &
69888447a05SGarrett D'Amore AUDIOHD_SPDIF_MASK;
69988447a05SGarrett D'Amore (void) audioha_codec_verb_get(
70088447a05SGarrett D'Amore statep,
70188447a05SGarrett D'Amore codec->index,
70288447a05SGarrett D'Amore path->adda_wid,
70388447a05SGarrett D'Amore AUDIOHDC_VERB_SET_SPDIF_LCL,
70488447a05SGarrett D'Amore ctrl8);
70588447a05SGarrett D'Amore statep->inmask |= (1U << DTYPE_SPDIF_IN);
70688447a05SGarrett D'Amore }
70788447a05SGarrett D'Amore #endif
70888447a05SGarrett D'Amore if (pin->device == DTYPE_MIC_IN) {
70988447a05SGarrett D'Amore if (((pin->config >>
71088447a05SGarrett D'Amore AUDIOHD_PIN_CONTP_OFF) &
71188447a05SGarrett D'Amore AUDIOHD_PIN_CONTP_MASK) ==
71288447a05SGarrett D'Amore AUDIOHD_PIN_CON_FIXED)
71388447a05SGarrett D'Amore statep->port[PORT_ADC]->index = path->tag;
71488447a05SGarrett D'Amore }
71588447a05SGarrett D'Amore if ((pin->device == DTYPE_LINE_IN) ||
71688447a05SGarrett D'Amore (pin->device == DTYPE_CD) ||
71788447a05SGarrett D'Amore (pin->device == DTYPE_MIC_IN)) {
71888447a05SGarrett D'Amore statep->inmask |= (1U << pin->device);
71988447a05SGarrett D'Amore }
72088447a05SGarrett D'Amore }
72188447a05SGarrett D'Amore (void) audioha_codec_verb_get(statep,
72288447a05SGarrett D'Amore codec->index,
72388447a05SGarrett D'Amore path->adda_wid,
72488447a05SGarrett D'Amore AUDIOHDC_VERB_SET_STREAM_CHANN,
72588447a05SGarrett D'Amore path->tag <<
72688447a05SGarrett D'Amore AUDIOHD_REC_TAG_OFF);
72788447a05SGarrett D'Amore (void) audioha_codec_4bit_verb_get(statep,
72888447a05SGarrett D'Amore codec->index,
72988447a05SGarrett D'Amore path->adda_wid,
73088447a05SGarrett D'Amore AUDIOHDC_VERB_SET_CONV_FMT,
731a33ad26eSZhao Edgar Liu - Sun Microsystems statep->port[PORT_ADC]->format << 4 | statep->rchan - 1);
73288447a05SGarrett D'Amore }
733c1cfefcdSZhao Edgar Liu - Sun Microsystems
7343a49c214SYang-Rong Jerry Zhou static void
audiohd_init_path(audiohd_state_t * statep)73588447a05SGarrett D'Amore audiohd_init_path(audiohd_state_t *statep)
73688447a05SGarrett D'Amore {
73788447a05SGarrett D'Amore int i;
73888447a05SGarrett D'Amore audiohd_path_t *path;
73988447a05SGarrett D'Amore
74088447a05SGarrett D'Amore for (i = 0; i < statep->pathnum; i++) {
74188447a05SGarrett D'Amore path = statep->path[i];
74288447a05SGarrett D'Amore if (!path)
74388447a05SGarrett D'Amore continue;
74488447a05SGarrett D'Amore switch (path->path_type) {
74568c47f65SGarrett D'Amore case PLAY:
74668c47f65SGarrett D'Amore audiohd_init_play_path(path);
74768c47f65SGarrett D'Amore break;
74868c47f65SGarrett D'Amore case RECORD:
74968c47f65SGarrett D'Amore audiohd_init_record_path(path);
75068c47f65SGarrett D'Amore break;
75168c47f65SGarrett D'Amore default:
75268c47f65SGarrett D'Amore break;
75388447a05SGarrett D'Amore }
75488447a05SGarrett D'Amore }
75588447a05SGarrett D'Amore statep->in_port = 0;
75688447a05SGarrett D'Amore }
75788447a05SGarrett D'Amore
75888447a05SGarrett D'Amore static int
audiohd_reset_port(audiohd_port_t * port)75988447a05SGarrett D'Amore audiohd_reset_port(audiohd_port_t *port)
7603a49c214SYang-Rong Jerry Zhou {
76188447a05SGarrett D'Amore uint16_t regbase;
76288447a05SGarrett D'Amore audiohd_state_t *statep;
76388447a05SGarrett D'Amore uint8_t bTmp;
76488447a05SGarrett D'Amore int i;
76588447a05SGarrett D'Amore
76688447a05SGarrett D'Amore regbase = port->regoff;
76788447a05SGarrett D'Amore statep = port->statep;
76888447a05SGarrett D'Amore
76988447a05SGarrett D'Amore bTmp = AUDIOHD_REG_GET8(regbase + AUDIOHD_SDREG_OFFSET_CTL);
77088447a05SGarrett D'Amore /* stop stream */
77188447a05SGarrett D'Amore bTmp &= ~AUDIOHD_REG_RIRBSIZE;
77288447a05SGarrett D'Amore AUDIOHD_REG_SET8(regbase + AUDIOHD_SDREG_OFFSET_CTL, bTmp);
77388447a05SGarrett D'Amore
77488447a05SGarrett D'Amore /* wait 40us for stream to stop as HD spec */
77588447a05SGarrett D'Amore drv_usecwait(40);
77688447a05SGarrett D'Amore
77788447a05SGarrett D'Amore /* reset stream */
77888447a05SGarrett D'Amore bTmp |= AUDIOHDR_SD_CTL_SRST;
77988447a05SGarrett D'Amore AUDIOHD_REG_SET8(regbase + AUDIOHD_SDREG_OFFSET_CTL, bTmp);
78088447a05SGarrett D'Amore
78188447a05SGarrett D'Amore for (i = 0; i < AUDIOHD_RETRY_TIMES; i++) {
78288447a05SGarrett D'Amore /* Empirical testing time, which works well */
78388447a05SGarrett D'Amore drv_usecwait(50);
78488447a05SGarrett D'Amore bTmp = AUDIOHD_REG_GET8(regbase + AUDIOHD_SDREG_OFFSET_CTL);
78588447a05SGarrett D'Amore bTmp &= AUDIOHDR_SD_CTL_SRST;
78688447a05SGarrett D'Amore if (bTmp)
78788447a05SGarrett D'Amore break;
78888447a05SGarrett D'Amore }
78988447a05SGarrett D'Amore
79088447a05SGarrett D'Amore if (!bTmp) {
79188447a05SGarrett D'Amore audio_dev_warn(statep->adev, "Failed to reset stream %d",
79288447a05SGarrett D'Amore port->index);
79368c47f65SGarrett D'Amore return (EIO);
79488447a05SGarrett D'Amore }
79588447a05SGarrett D'Amore
79688447a05SGarrett D'Amore /* Empirical testing time, which works well */
79788447a05SGarrett D'Amore drv_usecwait(300);
79888447a05SGarrett D'Amore
79988447a05SGarrett D'Amore /* exit reset stream */
80088447a05SGarrett D'Amore bTmp &= ~AUDIOHDR_SD_CTL_SRST;
80188447a05SGarrett D'Amore AUDIOHD_REG_SET8(regbase + AUDIOHD_SDREG_OFFSET_CTL, bTmp);
80288447a05SGarrett D'Amore
80388447a05SGarrett D'Amore for (i = 0; i < AUDIOHD_RETRY_TIMES; i++) {
80488447a05SGarrett D'Amore /* Empircal testing time */
80588447a05SGarrett D'Amore drv_usecwait(50);
80688447a05SGarrett D'Amore bTmp = AUDIOHD_REG_GET8(regbase + AUDIOHD_SDREG_OFFSET_CTL);
80788447a05SGarrett D'Amore bTmp &= AUDIOHDR_SD_CTL_SRST;
80888447a05SGarrett D'Amore if (!bTmp)
80988447a05SGarrett D'Amore break;
81088447a05SGarrett D'Amore }
81188447a05SGarrett D'Amore
81288447a05SGarrett D'Amore if (bTmp) {
81388447a05SGarrett D'Amore audio_dev_warn(statep->adev,
81488447a05SGarrett D'Amore "Failed to exit reset state for"
81588447a05SGarrett D'Amore " stream %d, bTmp=0x%02x", port->index, bTmp);
81668c47f65SGarrett D'Amore return (EIO);
81788447a05SGarrett D'Amore }
8183a49c214SYang-Rong Jerry Zhou
8193a49c214SYang-Rong Jerry Zhou AUDIOHD_REG_SET32(regbase + AUDIOHD_SDREG_OFFSET_BDLPL,
82088447a05SGarrett D'Amore (uint32_t)port->bdl_paddr);
8213a49c214SYang-Rong Jerry Zhou AUDIOHD_REG_SET32(regbase + AUDIOHD_SDREG_OFFSET_BDLPU,
82288447a05SGarrett D'Amore (uint32_t)(port->bdl_paddr >> 32));
8233a49c214SYang-Rong Jerry Zhou AUDIOHD_REG_SET16(regbase + AUDIOHD_SDREG_OFFSET_LVI,
8243a49c214SYang-Rong Jerry Zhou AUDIOHD_BDLE_NUMS - 1);
82568c47f65SGarrett D'Amore AUDIOHD_REG_SET32(regbase + AUDIOHD_SDREG_OFFSET_CBL, port->bufsize);
8263a49c214SYang-Rong Jerry Zhou
8273a49c214SYang-Rong Jerry Zhou AUDIOHD_REG_SET16(regbase + AUDIOHD_SDREG_OFFSET_FORMAT,
82888447a05SGarrett D'Amore port->format << 4 | port->nchan - 1);
8293a49c214SYang-Rong Jerry Zhou
8303a49c214SYang-Rong Jerry Zhou /* clear status */
8313a49c214SYang-Rong Jerry Zhou AUDIOHD_REG_SET8(regbase + AUDIOHD_SDREG_OFFSET_STS,
8323a49c214SYang-Rong Jerry Zhou AUDIOHDR_SD_STS_BCIS | AUDIOHDR_SD_STS_FIFOE |
8333a49c214SYang-Rong Jerry Zhou AUDIOHDR_SD_STS_DESE);
8343a49c214SYang-Rong Jerry Zhou
83588447a05SGarrett D'Amore /* set stream tag */
8363a49c214SYang-Rong Jerry Zhou AUDIOHD_REG_SET8(regbase + AUDIOHD_SDREG_OFFSET_CTL +
8373a49c214SYang-Rong Jerry Zhou AUDIOHD_PLAY_CTL_OFF,
83888447a05SGarrett D'Amore (port->index) << AUDIOHD_PLAY_TAG_OFF);
8393a49c214SYang-Rong Jerry Zhou
84068c47f65SGarrett D'Amore return (0);
84188447a05SGarrett D'Amore }
84289e1f902SZhao Edgar Liu - Sun Microsystems
84388447a05SGarrett D'Amore static int
audiohd_engine_open(void * arg,int flag,unsigned * nframes,caddr_t * bufp)84468c47f65SGarrett D'Amore audiohd_engine_open(void *arg, int flag, unsigned *nframes, caddr_t *bufp)
84588447a05SGarrett D'Amore {
84688447a05SGarrett D'Amore audiohd_port_t *port = arg;
847ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = port->statep;
8483a49c214SYang-Rong Jerry Zhou
84988447a05SGarrett D'Amore _NOTE(ARGUNUSED(flag));
8503a49c214SYang-Rong Jerry Zhou
851ea463888SZhao Edgar Liu - Sun Microsystems mutex_enter(&statep->hda_mutex);
85288447a05SGarrett D'Amore port->count = 0;
85388447a05SGarrett D'Amore port->curpos = 0;
85468c47f65SGarrett D'Amore *nframes = port->nframes;
85588447a05SGarrett D'Amore *bufp = port->samp_kaddr;
856ea463888SZhao Edgar Liu - Sun Microsystems mutex_exit(&statep->hda_mutex);
8573a49c214SYang-Rong Jerry Zhou
85888447a05SGarrett D'Amore return (0);
8593a49c214SYang-Rong Jerry Zhou }
86088447a05SGarrett D'Amore
861d5247f45Sgs static int
audiohd_engine_start(void * arg)86288447a05SGarrett D'Amore audiohd_engine_start(void *arg)
863d5247f45Sgs {
86488447a05SGarrett D'Amore audiohd_port_t *port = arg;
86588447a05SGarrett D'Amore audiohd_state_t *statep = port->statep;
86668c47f65SGarrett D'Amore int rv;
8673a49c214SYang-Rong Jerry Zhou
868d5247f45Sgs mutex_enter(&statep->hda_mutex);
86968c47f65SGarrett D'Amore
87068c47f65SGarrett D'Amore if ((rv = audiohd_reset_port(port)) != 0) {
871ea463888SZhao Edgar Liu - Sun Microsystems mutex_exit(&statep->hda_mutex);
87268c47f65SGarrett D'Amore return (rv);
873d5247f45Sgs }
87468c47f65SGarrett D'Amore /* Start DMA */
87568c47f65SGarrett D'Amore AUDIOHD_REG_SET8(port->regoff + AUDIOHD_SDREG_OFFSET_CTL,
87668c47f65SGarrett D'Amore AUDIOHDR_SD_CTL_SRUN);
87768c47f65SGarrett D'Amore
878d5247f45Sgs mutex_exit(&statep->hda_mutex);
87988447a05SGarrett D'Amore return (0);
88088447a05SGarrett D'Amore }
881d5247f45Sgs
88288447a05SGarrett D'Amore static void
audiohd_engine_stop(void * arg)88388447a05SGarrett D'Amore audiohd_engine_stop(void *arg)
88488447a05SGarrett D'Amore {
88588447a05SGarrett D'Amore audiohd_port_t *port = arg;
88688447a05SGarrett D'Amore audiohd_state_t *statep = port->statep;
8873a49c214SYang-Rong Jerry Zhou
888d5247f45Sgs mutex_enter(&statep->hda_mutex);
88968c47f65SGarrett D'Amore AUDIOHD_REG_SET8(port->regoff + AUDIOHD_SDREG_OFFSET_CTL, 0);
890d5247f45Sgs mutex_exit(&statep->hda_mutex);
89188447a05SGarrett D'Amore }
892d5247f45Sgs
89388447a05SGarrett D'Amore static void
audiohd_update_port(audiohd_port_t * port)89488447a05SGarrett D'Amore audiohd_update_port(audiohd_port_t *port)
895d5247f45Sgs {
896989b958fSZhao Edgar Liu - Sun Microsystems uint32_t pos, len;
89788447a05SGarrett D'Amore audiohd_state_t *statep = port->statep;
898989b958fSZhao Edgar Liu - Sun Microsystems int i, ret;
899989b958fSZhao Edgar Liu - Sun Microsystems uint32_t status, resp = 0, respex = 0;
900989b958fSZhao Edgar Liu - Sun Microsystems uint8_t rirbsts;
90188447a05SGarrett D'Amore
90288447a05SGarrett D'Amore pos = AUDIOHD_REG_GET32(port->regoff + AUDIOHD_SDREG_OFFSET_LPIB);
9030c240c64SZhao Edgar Liu - Sun Microsystems /* Convert the position into a frame count */
904a33ad26eSZhao Edgar Liu - Sun Microsystems pos /= (port->nchan * statep->sample_packed_bytes);
9050c240c64SZhao Edgar Liu - Sun Microsystems
90668c47f65SGarrett D'Amore ASSERT(pos <= port->nframes);
90768c47f65SGarrett D'Amore if (pos >= port->curpos) {
9080c240c64SZhao Edgar Liu - Sun Microsystems len = (pos - port->curpos);
90968c47f65SGarrett D'Amore } else {
9100c240c64SZhao Edgar Liu - Sun Microsystems len = pos + port->nframes - port->curpos;
911d5247f45Sgs }
9123a49c214SYang-Rong Jerry Zhou
9130c240c64SZhao Edgar Liu - Sun Microsystems ASSERT(len <= port->nframes);
9140c240c64SZhao Edgar Liu - Sun Microsystems port->curpos = pos;
9150c240c64SZhao Edgar Liu - Sun Microsystems port->count += len;
916989b958fSZhao Edgar Liu - Sun Microsystems
917989b958fSZhao Edgar Liu - Sun Microsystems /*
918989b958fSZhao Edgar Liu - Sun Microsystems * Check unsolicited response from pins, maybe something plugged in or
919989b958fSZhao Edgar Liu - Sun Microsystems * out of the jack.
920989b958fSZhao Edgar Liu - Sun Microsystems */
921989b958fSZhao Edgar Liu - Sun Microsystems status = AUDIOHD_REG_GET32(AUDIOHD_REG_INTSTS);
922989b958fSZhao Edgar Liu - Sun Microsystems if (status == 0) {
923989b958fSZhao Edgar Liu - Sun Microsystems /* No pending interrupt we should take care */
924989b958fSZhao Edgar Liu - Sun Microsystems return;
925989b958fSZhao Edgar Liu - Sun Microsystems }
926989b958fSZhao Edgar Liu - Sun Microsystems
927989b958fSZhao Edgar Liu - Sun Microsystems if (status & AUDIOHD_CIS_MASK) {
928989b958fSZhao Edgar Liu - Sun Microsystems /* Clear the unsolicited response interrupt */
929989b958fSZhao Edgar Liu - Sun Microsystems rirbsts = AUDIOHD_REG_GET8(AUDIOHD_REG_RIRBSTS);
930989b958fSZhao Edgar Liu - Sun Microsystems AUDIOHD_REG_SET8(AUDIOHD_REG_RIRBSTS, rirbsts);
931989b958fSZhao Edgar Liu - Sun Microsystems
932989b958fSZhao Edgar Liu - Sun Microsystems /*
933989b958fSZhao Edgar Liu - Sun Microsystems * We have to wait and try several times to make sure the
934989b958fSZhao Edgar Liu - Sun Microsystems * unsolicited response is generated by our pins.
935989b958fSZhao Edgar Liu - Sun Microsystems * we need to make it work for audiohd spec 0.9, which is
936989b958fSZhao Edgar Liu - Sun Microsystems * just a draft version and requires more time to wait.
937989b958fSZhao Edgar Liu - Sun Microsystems */
938989b958fSZhao Edgar Liu - Sun Microsystems for (i = 0; i < AUDIOHD_TEST_TIMES; i++) {
939989b958fSZhao Edgar Liu - Sun Microsystems ret = audiohd_response_from_codec(statep, &resp,
940989b958fSZhao Edgar Liu - Sun Microsystems &respex);
941989b958fSZhao Edgar Liu - Sun Microsystems if ((ret == DDI_SUCCESS) &&
942989b958fSZhao Edgar Liu - Sun Microsystems (respex & AUDIOHD_RIRB_UR_MASK)) {
943989b958fSZhao Edgar Liu - Sun Microsystems /*
944989b958fSZhao Edgar Liu - Sun Microsystems * A pin may generate more than one ur rirb,
945989b958fSZhao Edgar Liu - Sun Microsystems * we only need handle one of them, and clear
946989b958fSZhao Edgar Liu - Sun Microsystems * the other ones
947989b958fSZhao Edgar Liu - Sun Microsystems */
948989b958fSZhao Edgar Liu - Sun Microsystems statep->hda_rirb_rp =
949989b958fSZhao Edgar Liu - Sun Microsystems AUDIOHD_REG_GET16(AUDIOHD_REG_RIRBWP) &
950989b958fSZhao Edgar Liu - Sun Microsystems AUDIOHD_RIRB_WPMASK;
951989b958fSZhao Edgar Liu - Sun Microsystems audiohd_pin_sense(statep, resp, respex);
952989b958fSZhao Edgar Liu - Sun Microsystems break;
953989b958fSZhao Edgar Liu - Sun Microsystems }
954989b958fSZhao Edgar Liu - Sun Microsystems }
955989b958fSZhao Edgar Liu - Sun Microsystems }
95688447a05SGarrett D'Amore }
95788447a05SGarrett D'Amore
95888447a05SGarrett D'Amore static uint64_t
audiohd_engine_count(void * arg)95988447a05SGarrett D'Amore audiohd_engine_count(void *arg)
9603a49c214SYang-Rong Jerry Zhou {
96188447a05SGarrett D'Amore audiohd_port_t *port = arg;
96288447a05SGarrett D'Amore audiohd_state_t *statep = port->statep;
96388447a05SGarrett D'Amore uint64_t val;
96488447a05SGarrett D'Amore
96588447a05SGarrett D'Amore mutex_enter(&statep->hda_mutex);
96668c47f65SGarrett D'Amore audiohd_update_port(port);
96788447a05SGarrett D'Amore val = port->count;
96888447a05SGarrett D'Amore mutex_exit(&statep->hda_mutex);
96988447a05SGarrett D'Amore return (val);
9703a49c214SYang-Rong Jerry Zhou }
9713a49c214SYang-Rong Jerry Zhou
97288447a05SGarrett D'Amore static void
audiohd_engine_close(void * arg)97388447a05SGarrett D'Amore audiohd_engine_close(void *arg)
9743a49c214SYang-Rong Jerry Zhou {
97568c47f65SGarrett D'Amore _NOTE(ARGUNUSED(arg));
9763a49c214SYang-Rong Jerry Zhou }
97788447a05SGarrett D'Amore
9783a49c214SYang-Rong Jerry Zhou static void
audiohd_engine_sync(void * arg,unsigned nframes)97988447a05SGarrett D'Amore audiohd_engine_sync(void *arg, unsigned nframes)
9803a49c214SYang-Rong Jerry Zhou {
98188447a05SGarrett D'Amore audiohd_port_t *port = arg;
9823a49c214SYang-Rong Jerry Zhou
98388447a05SGarrett D'Amore _NOTE(ARGUNUSED(nframes));
98488447a05SGarrett D'Amore
98568c47f65SGarrett D'Amore (void) ddi_dma_sync(port->samp_dmah, 0, 0, port->sync_dir);
98688447a05SGarrett D'Amore
98788447a05SGarrett D'Amore }
98888447a05SGarrett D'Amore
98988447a05SGarrett D'Amore audio_engine_ops_t audiohd_engine_ops = {
99088447a05SGarrett D'Amore AUDIO_ENGINE_VERSION, /* version number */
99188447a05SGarrett D'Amore audiohd_engine_open,
99288447a05SGarrett D'Amore audiohd_engine_close,
99388447a05SGarrett D'Amore audiohd_engine_start,
99488447a05SGarrett D'Amore audiohd_engine_stop,
99588447a05SGarrett D'Amore audiohd_engine_count,
99688447a05SGarrett D'Amore audiohd_engine_format,
99788447a05SGarrett D'Amore audiohd_engine_channels,
99888447a05SGarrett D'Amore audiohd_engine_rate,
99988447a05SGarrett D'Amore audiohd_engine_sync,
1000f9ead4a5SGarrett D'Amore NULL,
1001f9ead4a5SGarrett D'Amore NULL,
1002f9ead4a5SGarrett D'Amore NULL
100388447a05SGarrett D'Amore };
100488447a05SGarrett D'Amore
100588447a05SGarrett D'Amore static int
audiohd_get_control(void * arg,uint64_t * val)1006c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_get_control(void *arg, uint64_t *val)
100788447a05SGarrett D'Amore {
1008c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_ctrl_t *ac = arg;
1009ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = ac->statep;
101088447a05SGarrett D'Amore
1011ea463888SZhao Edgar Liu - Sun Microsystems mutex_enter(&statep->hda_mutex);
1012c1cfefcdSZhao Edgar Liu - Sun Microsystems *val = ac->val;
1013ea463888SZhao Edgar Liu - Sun Microsystems mutex_exit(&statep->hda_mutex);
1014ea463888SZhao Edgar Liu - Sun Microsystems
101588447a05SGarrett D'Amore return (0);
101688447a05SGarrett D'Amore }
101788447a05SGarrett D'Amore
101813084339SYang-Rong Jerry Zhou static void
audiohd_do_set_pin_volume(audiohd_state_t * statep,audiohd_path_t * path,uint64_t val)101913084339SYang-Rong Jerry Zhou audiohd_do_set_pin_volume(audiohd_state_t *statep, audiohd_path_t *path,
1020c6e681c0SYang-Rong Jerry Zhou uint64_t val)
102113084339SYang-Rong Jerry Zhou {
102213084339SYang-Rong Jerry Zhou uint8_t l, r;
102313084339SYang-Rong Jerry Zhou uint_t tmp;
102413084339SYang-Rong Jerry Zhou int gain;
102513084339SYang-Rong Jerry Zhou
1026211ec5c5SYang-Rong Jerry Zhou if (path->mute_wid && val == 0) {
102713084339SYang-Rong Jerry Zhou (void) audioha_codec_4bit_verb_get(
102813084339SYang-Rong Jerry Zhou statep,
102913084339SYang-Rong Jerry Zhou path->codec->index,
1030c6e681c0SYang-Rong Jerry Zhou path->mute_wid,
103113084339SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_AMP_MUTE,
1032c6e681c0SYang-Rong Jerry Zhou path->mute_dir |
103313084339SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_LNR |
103413084339SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_MUTE);
103513084339SYang-Rong Jerry Zhou return;
103613084339SYang-Rong Jerry Zhou }
103713084339SYang-Rong Jerry Zhou
103813084339SYang-Rong Jerry Zhou l = (val & 0xff00) >> 8;
103913084339SYang-Rong Jerry Zhou r = (val & 0xff);
1040c6e681c0SYang-Rong Jerry Zhou tmp = l * path->gain_bits / 100;
104113084339SYang-Rong Jerry Zhou (void) audioha_codec_4bit_verb_get(statep,
104213084339SYang-Rong Jerry Zhou path->codec->index,
1043c6e681c0SYang-Rong Jerry Zhou path->gain_wid,
104413084339SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_AMP_MUTE,
1045c6e681c0SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_LEFT | path->gain_dir |
104613084339SYang-Rong Jerry Zhou tmp);
1047c6e681c0SYang-Rong Jerry Zhou tmp = r * path->gain_bits / 100;
104813084339SYang-Rong Jerry Zhou (void) audioha_codec_4bit_verb_get(statep,
104913084339SYang-Rong Jerry Zhou path->codec->index,
1050c6e681c0SYang-Rong Jerry Zhou path->gain_wid,
105113084339SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_AMP_MUTE,
1052c6e681c0SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_RIGHT | path->gain_dir |
105313084339SYang-Rong Jerry Zhou tmp);
10545ec2209cSZhao Edgar Liu - Sun Microsystems
1055211ec5c5SYang-Rong Jerry Zhou if (path->mute_wid && path->mute_wid != path->gain_wid) {
105613084339SYang-Rong Jerry Zhou gain = AUDIOHDC_GAIN_MAX;
105713084339SYang-Rong Jerry Zhou (void) audioha_codec_4bit_verb_get(
105813084339SYang-Rong Jerry Zhou statep,
105913084339SYang-Rong Jerry Zhou path->codec->index,
1060c6e681c0SYang-Rong Jerry Zhou path->mute_wid,
106113084339SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_AMP_MUTE,
1062c6e681c0SYang-Rong Jerry Zhou path->mute_dir |
106313084339SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_LEFT |
106413084339SYang-Rong Jerry Zhou gain);
106513084339SYang-Rong Jerry Zhou (void) audioha_codec_4bit_verb_get(
106613084339SYang-Rong Jerry Zhou statep,
106713084339SYang-Rong Jerry Zhou path->codec->index,
1068c6e681c0SYang-Rong Jerry Zhou path->mute_wid,
106913084339SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_AMP_MUTE,
1070c6e681c0SYang-Rong Jerry Zhou path->mute_dir |
107113084339SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_RIGHT |
107213084339SYang-Rong Jerry Zhou gain);
107388447a05SGarrett D'Amore }
107488447a05SGarrett D'Amore }
10753a49c214SYang-Rong Jerry Zhou
107688447a05SGarrett D'Amore static void
audiohd_set_pin_volume(audiohd_state_t * statep,audiohda_device_type_t type)107788447a05SGarrett D'Amore audiohd_set_pin_volume(audiohd_state_t *statep, audiohda_device_type_t type)
107888447a05SGarrett D'Amore {
107988447a05SGarrett D'Amore int i, j;
108088447a05SGarrett D'Amore audiohd_path_t *path;
108188447a05SGarrett D'Amore audiohd_widget_t *widget;
108288447a05SGarrett D'Amore wid_t wid;
108388447a05SGarrett D'Amore audiohd_pin_t *pin;
108488447a05SGarrett D'Amore hda_codec_t *codec;
108588447a05SGarrett D'Amore uint64_t val;
1086c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_ctrl_t control;
108788447a05SGarrett D'Amore
108888447a05SGarrett D'Amore switch (type) {
108988447a05SGarrett D'Amore case DTYPE_SPEAKER:
1090c1cfefcdSZhao Edgar Liu - Sun Microsystems control = statep->ctrls[CTL_SPEAKER];
1091901f2979SZhao Edgar Liu - Sun Microsystems if (control.ctrl == NULL)
1092901f2979SZhao Edgar Liu - Sun Microsystems return;
1093c1cfefcdSZhao Edgar Liu - Sun Microsystems val = control.val;
109488447a05SGarrett D'Amore break;
109588447a05SGarrett D'Amore case DTYPE_HP_OUT:
1096c1cfefcdSZhao Edgar Liu - Sun Microsystems control = statep->ctrls[CTL_HEADPHONE];
1097901f2979SZhao Edgar Liu - Sun Microsystems if (control.ctrl == NULL)
1098901f2979SZhao Edgar Liu - Sun Microsystems return;
1099c1cfefcdSZhao Edgar Liu - Sun Microsystems val = control.val;
110088447a05SGarrett D'Amore break;
1101211ec5c5SYang-Rong Jerry Zhou case DTYPE_LINEOUT:
1102c1cfefcdSZhao Edgar Liu - Sun Microsystems control = statep->ctrls[CTL_FRONT];
1103901f2979SZhao Edgar Liu - Sun Microsystems if (control.ctrl == NULL)
1104901f2979SZhao Edgar Liu - Sun Microsystems return;
1105c1cfefcdSZhao Edgar Liu - Sun Microsystems val = control.val;
1106211ec5c5SYang-Rong Jerry Zhou break;
110788447a05SGarrett D'Amore case DTYPE_CD:
1108c1cfefcdSZhao Edgar Liu - Sun Microsystems control = statep->ctrls[CTL_CD];
1109901f2979SZhao Edgar Liu - Sun Microsystems if (control.ctrl == NULL)
1110901f2979SZhao Edgar Liu - Sun Microsystems return;
1111c1cfefcdSZhao Edgar Liu - Sun Microsystems val = control.val;
111288447a05SGarrett D'Amore break;
111388447a05SGarrett D'Amore case DTYPE_LINE_IN:
1114c1cfefcdSZhao Edgar Liu - Sun Microsystems control = statep->ctrls[CTL_LINEIN];
1115901f2979SZhao Edgar Liu - Sun Microsystems if (control.ctrl == NULL)
1116901f2979SZhao Edgar Liu - Sun Microsystems return;
1117c1cfefcdSZhao Edgar Liu - Sun Microsystems val = control.val;
111888447a05SGarrett D'Amore break;
111988447a05SGarrett D'Amore case DTYPE_MIC_IN:
1120c1cfefcdSZhao Edgar Liu - Sun Microsystems control = statep->ctrls[CTL_MIC];
1121901f2979SZhao Edgar Liu - Sun Microsystems if (control.ctrl == NULL)
1122901f2979SZhao Edgar Liu - Sun Microsystems return;
1123c1cfefcdSZhao Edgar Liu - Sun Microsystems val = control.val;
112488447a05SGarrett D'Amore break;
112588447a05SGarrett D'Amore }
112688447a05SGarrett D'Amore
112788447a05SGarrett D'Amore for (i = 0; i < statep->pathnum; i++) {
1128e7236f70SZhao Edgar Liu - Sun Microsystems if ((path = statep->path[i]) == NULL)
112988447a05SGarrett D'Amore continue;
1130e7236f70SZhao Edgar Liu - Sun Microsystems
113188447a05SGarrett D'Amore codec = path->codec;
113288447a05SGarrett D'Amore for (j = 0; j < path->pin_nums; j++) {
113388447a05SGarrett D'Amore wid = path->pin_wid[j];
113488447a05SGarrett D'Amore widget = codec->widget[wid];
113588447a05SGarrett D'Amore pin = (audiohd_pin_t *)widget->priv;
1136c6e681c0SYang-Rong Jerry Zhou if ((pin->device == type) && path->gain_wid) {
1137c6e681c0SYang-Rong Jerry Zhou audiohd_do_set_pin_volume(statep, path, val);
11383a49c214SYang-Rong Jerry Zhou }
11393a49c214SYang-Rong Jerry Zhou }
11403a49c214SYang-Rong Jerry Zhou }
11413a49c214SYang-Rong Jerry Zhou }
114288447a05SGarrett D'Amore
114388447a05SGarrett D'Amore
11443a49c214SYang-Rong Jerry Zhou static void
audiohd_set_pin_volume_by_color(audiohd_state_t * statep,audiohd_pin_color_t color)114588447a05SGarrett D'Amore audiohd_set_pin_volume_by_color(audiohd_state_t *statep,
114688447a05SGarrett D'Amore audiohd_pin_color_t color)
11473a49c214SYang-Rong Jerry Zhou {
114888447a05SGarrett D'Amore int i, j;
114988447a05SGarrett D'Amore audiohd_path_t *path;
115088447a05SGarrett D'Amore audiohd_widget_t *widget;
115188447a05SGarrett D'Amore wid_t wid;
115288447a05SGarrett D'Amore audiohd_pin_t *pin;
11533a49c214SYang-Rong Jerry Zhou hda_codec_t *codec;
115488447a05SGarrett D'Amore uint8_t l, r;
115588447a05SGarrett D'Amore uint64_t val;
115688447a05SGarrett D'Amore audiohd_pin_color_t clr;
1157c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_ctrl_t control;
115888447a05SGarrett D'Amore
115988447a05SGarrett D'Amore switch (color) {
116065a41de7SYang-Rong Jerry Zhou case AUDIOHD_PIN_GREEN:
1161c1cfefcdSZhao Edgar Liu - Sun Microsystems control = statep->ctrls[CTL_FRONT];
1162901f2979SZhao Edgar Liu - Sun Microsystems if (control.ctrl == NULL)
1163901f2979SZhao Edgar Liu - Sun Microsystems return;
1164c1cfefcdSZhao Edgar Liu - Sun Microsystems val = control.val;
116565a41de7SYang-Rong Jerry Zhou break;
116688447a05SGarrett D'Amore case AUDIOHD_PIN_BLACK:
1167c1cfefcdSZhao Edgar Liu - Sun Microsystems control = statep->ctrls[CTL_REAR];
1168901f2979SZhao Edgar Liu - Sun Microsystems if (control.ctrl == NULL)
1169901f2979SZhao Edgar Liu - Sun Microsystems return;
1170c1cfefcdSZhao Edgar Liu - Sun Microsystems val = control.val;
117188447a05SGarrett D'Amore break;
117288447a05SGarrett D'Amore case AUDIOHD_PIN_ORANGE:
1173c1cfefcdSZhao Edgar Liu - Sun Microsystems control = statep->ctrls[CTL_CENTER];
1174901f2979SZhao Edgar Liu - Sun Microsystems if (control.ctrl == NULL)
1175901f2979SZhao Edgar Liu - Sun Microsystems return;
1176c1cfefcdSZhao Edgar Liu - Sun Microsystems l = control.val;
1177c1cfefcdSZhao Edgar Liu - Sun Microsystems control = statep->ctrls[CTL_LFE];
1178901f2979SZhao Edgar Liu - Sun Microsystems if (control.ctrl == NULL)
1179901f2979SZhao Edgar Liu - Sun Microsystems return;
1180c1cfefcdSZhao Edgar Liu - Sun Microsystems r = control.val;
118113084339SYang-Rong Jerry Zhou val = (l << 8) | r;
118288447a05SGarrett D'Amore break;
118388447a05SGarrett D'Amore case AUDIOHD_PIN_GREY:
1184c1cfefcdSZhao Edgar Liu - Sun Microsystems control = statep->ctrls[CTL_SURROUND];
1185901f2979SZhao Edgar Liu - Sun Microsystems if (control.ctrl == NULL)
1186901f2979SZhao Edgar Liu - Sun Microsystems return;
1187c1cfefcdSZhao Edgar Liu - Sun Microsystems val = control.val;
118888447a05SGarrett D'Amore break;
118988447a05SGarrett D'Amore }
119088447a05SGarrett D'Amore
119188447a05SGarrett D'Amore for (i = 0; i < statep->pathnum; i++) {
119288447a05SGarrett D'Amore path = statep->path[i];
119388447a05SGarrett D'Amore if (!path)
119488447a05SGarrett D'Amore continue;
119588447a05SGarrett D'Amore codec = path->codec;
119688447a05SGarrett D'Amore for (j = 0; j < path->pin_nums; j++) {
119788447a05SGarrett D'Amore wid = path->pin_wid[j];
119888447a05SGarrett D'Amore widget = codec->widget[wid];
119988447a05SGarrett D'Amore pin = (audiohd_pin_t *)widget->priv;
120088447a05SGarrett D'Amore clr = (pin->config >> AUDIOHD_PIN_CLR_OFF) &
120188447a05SGarrett D'Amore AUDIOHD_PIN_CLR_MASK;
1202c6e681c0SYang-Rong Jerry Zhou if ((clr == color) && path->gain_wid) {
1203c6e681c0SYang-Rong Jerry Zhou audiohd_do_set_pin_volume(statep, path, val);
120488447a05SGarrett D'Amore }
120588447a05SGarrett D'Amore }
120688447a05SGarrett D'Amore }
120788447a05SGarrett D'Amore }
120888447a05SGarrett D'Amore
120988447a05SGarrett D'Amore static int
audiohd_set_input_pin(audiohd_state_t * statep)121088447a05SGarrett D'Amore audiohd_set_input_pin(audiohd_state_t *statep)
121188447a05SGarrett D'Amore {
121288447a05SGarrett D'Amore uint64_t val;
1213a4c3d128SYang-Rong Jerry Zhou hda_codec_t *codec;
12143a49c214SYang-Rong Jerry Zhou audiohd_pin_t *pin;
121588447a05SGarrett D'Amore audiohd_path_t *path;
1216a4c3d128SYang-Rong Jerry Zhou audiohd_widget_t *widget, *w;
121788447a05SGarrett D'Amore int i, j;
1218a4c3d128SYang-Rong Jerry Zhou wid_t wid, pin_wid = 0;
1219c1cfefcdSZhao Edgar Liu - Sun Microsystems uint32_t set_val;
1220d5247f45Sgs
1221c1cfefcdSZhao Edgar Liu - Sun Microsystems val = statep->ctrls[CTL_RECSRC].val;
1222c1cfefcdSZhao Edgar Liu - Sun Microsystems set_val = ddi_ffs(val & 0xffff) - 1;
122388447a05SGarrett D'Amore for (i = 0; i < statep->pathnum; i++) {
1224e7236f70SZhao Edgar Liu - Sun Microsystems if ((path = statep->path[i]) == NULL ||
1225e7236f70SZhao Edgar Liu - Sun Microsystems path->path_type != RECORD)
122688447a05SGarrett D'Amore continue;
1227c1cfefcdSZhao Edgar Liu - Sun Microsystems
1228c1cfefcdSZhao Edgar Liu - Sun Microsystems switch (set_val) {
122988447a05SGarrett D'Amore case DTYPE_LINE_IN:
123088447a05SGarrett D'Amore case DTYPE_MIC_IN:
123188447a05SGarrett D'Amore case DTYPE_CD:
123288447a05SGarrett D'Amore for (j = 0; j < path->pin_nums; j++) {
123388447a05SGarrett D'Amore wid = path->pin_wid[j];
123488447a05SGarrett D'Amore widget = path->codec->widget[wid];
12353a49c214SYang-Rong Jerry Zhou pin = (audiohd_pin_t *)widget->priv;
1236e7236f70SZhao Edgar Liu - Sun Microsystems
123788447a05SGarrett D'Amore if ((1U << pin->device) == val) {
123888447a05SGarrett D'Amore AUDIOHD_ENABLE_PIN_IN(statep,
1239e7236f70SZhao Edgar Liu - Sun Microsystems path->codec->index, pin->wid);
1240a4c3d128SYang-Rong Jerry Zhou pin_wid = pin->wid;
1241a4c3d128SYang-Rong Jerry Zhou codec = path->codec;
124288447a05SGarrett D'Amore statep->in_port = pin->device;
124388447a05SGarrett D'Amore } else if (statep->in_port == pin->device) {
124488447a05SGarrett D'Amore AUDIOHD_DISABLE_PIN_IN(statep,
1245e7236f70SZhao Edgar Liu - Sun Microsystems path->codec->index, pin->wid);
124616600ba1SYang-Rong Jerry Zhou }
12473a49c214SYang-Rong Jerry Zhou }
12483a49c214SYang-Rong Jerry Zhou break;
124988447a05SGarrett D'Amore default:
125088447a05SGarrett D'Amore break;
125188447a05SGarrett D'Amore }
12523a49c214SYang-Rong Jerry Zhou }
1253e7236f70SZhao Edgar Liu - Sun Microsystems
1254a4c3d128SYang-Rong Jerry Zhou if (pin_wid == 0)
1255a4c3d128SYang-Rong Jerry Zhou return (DDI_SUCCESS);
1256e7236f70SZhao Edgar Liu - Sun Microsystems
1257a4c3d128SYang-Rong Jerry Zhou w = codec->widget[pin_wid];
1258a4c3d128SYang-Rong Jerry Zhou pin = (audiohd_pin_t *)w->priv;
1259e7236f70SZhao Edgar Liu - Sun Microsystems w = codec->widget[pin->adc_wid];
1260a4c3d128SYang-Rong Jerry Zhou path = (audiohd_path_t *)w->priv;
1261e7236f70SZhao Edgar Liu - Sun Microsystems
1262a4c3d128SYang-Rong Jerry Zhou /*
1263a4c3d128SYang-Rong Jerry Zhou * If there is a real selector in this input path,
1264a4c3d128SYang-Rong Jerry Zhou * we select the right one input for the selector.
1265a4c3d128SYang-Rong Jerry Zhou */
1266a4c3d128SYang-Rong Jerry Zhou if (path->sum_wid) {
1267a4c3d128SYang-Rong Jerry Zhou w = codec->widget[path->sum_wid];
1268a4c3d128SYang-Rong Jerry Zhou if (w->type == WTYPE_AUDIO_SEL) {
1269e7236f70SZhao Edgar Liu - Sun Microsystems for (i = 0; i < path->pin_nums; i++) {
1270e7236f70SZhao Edgar Liu - Sun Microsystems if (path->pin_wid[i] == pin->wid) {
1271e7236f70SZhao Edgar Liu - Sun Microsystems (void) audioha_codec_verb_get(
1272e7236f70SZhao Edgar Liu - Sun Microsystems statep, codec->index, path->sum_wid,
1273e7236f70SZhao Edgar Liu - Sun Microsystems AUDIOHDC_VERB_SET_CONN_SEL,
1274e7236f70SZhao Edgar Liu - Sun Microsystems path->sum_selconn[i]);
1275a4c3d128SYang-Rong Jerry Zhou break;
1276e7236f70SZhao Edgar Liu - Sun Microsystems }
1277e7236f70SZhao Edgar Liu - Sun Microsystems }
1278a4c3d128SYang-Rong Jerry Zhou }
1279a4c3d128SYang-Rong Jerry Zhou }
1280e7236f70SZhao Edgar Liu - Sun Microsystems
128188447a05SGarrett D'Amore return (DDI_SUCCESS);
128288447a05SGarrett D'Amore }
128388447a05SGarrett D'Amore
128488447a05SGarrett D'Amore static void
audiohd_set_pin_monitor_gain(hda_codec_t * codec,audiohd_state_t * statep,uint_t caddr,audiohd_pin_t * pin,uint64_t gain)128588447a05SGarrett D'Amore audiohd_set_pin_monitor_gain(hda_codec_t *codec, audiohd_state_t *statep,
128688447a05SGarrett D'Amore uint_t caddr, audiohd_pin_t *pin, uint64_t gain)
128788447a05SGarrett D'Amore {
128888447a05SGarrett D'Amore int i, k;
128988447a05SGarrett D'Amore uint_t ltmp, rtmp;
129088447a05SGarrett D'Amore audiohd_widget_t *widget;
129188447a05SGarrett D'Amore uint8_t l, r;
129288447a05SGarrett D'Amore
129388447a05SGarrett D'Amore l = (gain & 0xff00) >> 8;
129488447a05SGarrett D'Amore r = (gain & 0xff);
129588447a05SGarrett D'Amore
129688447a05SGarrett D'Amore for (k = 0; k < pin->num; k++) {
129788447a05SGarrett D'Amore ltmp = l * pin->mg_gain[k] / 100;
129888447a05SGarrett D'Amore rtmp = r * pin->mg_gain[k] / 100;
129988447a05SGarrett D'Amore widget = codec->widget[pin->mg_wid[k]];
130088447a05SGarrett D'Amore if (pin->mg_dir[k] == AUDIOHDC_AMP_SET_OUTPUT) {
130188447a05SGarrett D'Amore (void) audioha_codec_4bit_verb_get(
130288447a05SGarrett D'Amore statep,
130388447a05SGarrett D'Amore caddr,
130488447a05SGarrett D'Amore pin->mg_wid[k],
130588447a05SGarrett D'Amore AUDIOHDC_VERB_SET_AMP_MUTE,
130688447a05SGarrett D'Amore AUDIOHDC_AMP_SET_LEFT|
130788447a05SGarrett D'Amore pin->mg_dir[k] | ltmp);
130888447a05SGarrett D'Amore (void) audioha_codec_4bit_verb_get(
130988447a05SGarrett D'Amore statep,
131088447a05SGarrett D'Amore caddr,
131188447a05SGarrett D'Amore pin->mg_wid[k],
131288447a05SGarrett D'Amore AUDIOHDC_VERB_SET_AMP_MUTE,
131388447a05SGarrett D'Amore AUDIOHDC_AMP_SET_RIGHT|
131488447a05SGarrett D'Amore pin->mg_dir[k] | rtmp);
131588447a05SGarrett D'Amore } else if (pin->mg_dir[k] == AUDIOHDC_AMP_SET_INPUT) {
131688447a05SGarrett D'Amore for (i = 0; i < widget->used; i++) {
131788447a05SGarrett D'Amore (void) audioha_codec_4bit_verb_get(
131888447a05SGarrett D'Amore statep,
131988447a05SGarrett D'Amore caddr,
132088447a05SGarrett D'Amore pin->mg_wid[k],
132188447a05SGarrett D'Amore AUDIOHDC_VERB_SET_AMP_MUTE,
132288447a05SGarrett D'Amore AUDIOHDC_AMP_SET_RIGHT|
1323b96a6eceSZhao Edgar Liu - Sun Microsystems widget->monitor_path_next[i]<<
132488447a05SGarrett D'Amore AUDIOHDC_AMP_SET_INDEX_OFFSET |
132588447a05SGarrett D'Amore pin->mg_dir[k] | rtmp);
132688447a05SGarrett D'Amore (void) audioha_codec_4bit_verb_get(
132788447a05SGarrett D'Amore statep,
132888447a05SGarrett D'Amore caddr,
132988447a05SGarrett D'Amore pin->mg_wid[k],
133088447a05SGarrett D'Amore AUDIOHDC_VERB_SET_AMP_MUTE,
133188447a05SGarrett D'Amore AUDIOHDC_AMP_SET_LEFT|
1332b96a6eceSZhao Edgar Liu - Sun Microsystems widget->monitor_path_next[i]<<
133388447a05SGarrett D'Amore AUDIOHDC_AMP_SET_INDEX_OFFSET |
133488447a05SGarrett D'Amore pin->mg_dir[k] | ltmp);
133516600ba1SYang-Rong Jerry Zhou }
133616600ba1SYang-Rong Jerry Zhou }
133716600ba1SYang-Rong Jerry Zhou }
13383a49c214SYang-Rong Jerry Zhou }
133988447a05SGarrett D'Amore
13403a49c214SYang-Rong Jerry Zhou static void
audiohd_set_monitor_gain(audiohd_state_t * statep)134188447a05SGarrett D'Amore audiohd_set_monitor_gain(audiohd_state_t *statep)
13423a49c214SYang-Rong Jerry Zhou {
134388447a05SGarrett D'Amore int i, j;
134488447a05SGarrett D'Amore audiohd_path_t *path;
134588447a05SGarrett D'Amore uint_t caddr;
134688447a05SGarrett D'Amore audiohd_widget_t *w;
134788447a05SGarrett D'Amore wid_t wid;
13483a49c214SYang-Rong Jerry Zhou audiohd_pin_t *pin;
1349c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_ctrl_t ctrl;
135088447a05SGarrett D'Amore uint64_t val;
135116600ba1SYang-Rong Jerry Zhou
1352c1cfefcdSZhao Edgar Liu - Sun Microsystems ctrl = statep->ctrls[CTL_MONGAIN];
1353c1cfefcdSZhao Edgar Liu - Sun Microsystems val = ctrl.val;
13543a49c214SYang-Rong Jerry Zhou
135588447a05SGarrett D'Amore for (i = 0; i < statep->pathnum; i++) {
135688447a05SGarrett D'Amore path = statep->path[i];
135788447a05SGarrett D'Amore if (path == NULL || path->path_type != PLAY)
135888447a05SGarrett D'Amore continue;
135988447a05SGarrett D'Amore caddr = path->codec->index;
136088447a05SGarrett D'Amore for (j = 0; j < path->pin_nums; j++) {
136188447a05SGarrett D'Amore wid = path->pin_wid[j];
136288447a05SGarrett D'Amore w = path->codec->widget[wid];
136388447a05SGarrett D'Amore pin = (audiohd_pin_t *)w->priv;
136488447a05SGarrett D'Amore audiohd_set_pin_monitor_gain(path->codec, statep,
136588447a05SGarrett D'Amore caddr, pin, val);
13663a49c214SYang-Rong Jerry Zhou }
13673a49c214SYang-Rong Jerry Zhou }
1368d5247f45Sgs
13693a49c214SYang-Rong Jerry Zhou }
137088447a05SGarrett D'Amore
137142c41cf8Slipeng sang - Sun Microsystems - Beijing China static void
audiohd_set_beep_volume(audiohd_state_t * statep)137242c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_set_beep_volume(audiohd_state_t *statep)
137342c41cf8Slipeng sang - Sun Microsystems - Beijing China {
137442c41cf8Slipeng sang - Sun Microsystems - Beijing China int i;
137542c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_path_t *path;
137642c41cf8Slipeng sang - Sun Microsystems - Beijing China hda_codec_t *codec;
137742c41cf8Slipeng sang - Sun Microsystems - Beijing China uint64_t val;
137842c41cf8Slipeng sang - Sun Microsystems - Beijing China uint_t tmp;
1379c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_ctrl_t control;
138042c41cf8Slipeng sang - Sun Microsystems - Beijing China uint32_t vid;
138142c41cf8Slipeng sang - Sun Microsystems - Beijing China
1382c1cfefcdSZhao Edgar Liu - Sun Microsystems control = statep->ctrls[CTL_BEEP];
1383c1cfefcdSZhao Edgar Liu - Sun Microsystems val = control.val;
138442c41cf8Slipeng sang - Sun Microsystems - Beijing China for (i = 0; i < statep->pathnum; i++) {
138542c41cf8Slipeng sang - Sun Microsystems - Beijing China path = statep->path[i];
138642c41cf8Slipeng sang - Sun Microsystems - Beijing China if (!path || path->path_type != BEEP)
138742c41cf8Slipeng sang - Sun Microsystems - Beijing China continue;
138842c41cf8Slipeng sang - Sun Microsystems - Beijing China codec = path->codec;
138942c41cf8Slipeng sang - Sun Microsystems - Beijing China vid = codec->vid;
139042c41cf8Slipeng sang - Sun Microsystems - Beijing China vid = vid >> 16;
139142c41cf8Slipeng sang - Sun Microsystems - Beijing China
139242c41cf8Slipeng sang - Sun Microsystems - Beijing China switch (vid) {
139342c41cf8Slipeng sang - Sun Microsystems - Beijing China case AUDIOHD_VID_SIGMATEL:
139442c41cf8Slipeng sang - Sun Microsystems - Beijing China /*
139542c41cf8Slipeng sang - Sun Microsystems - Beijing China * Sigmatel HD codec specific operation.
139642c41cf8Slipeng sang - Sun Microsystems - Beijing China * There is a workaround,
139742c41cf8Slipeng sang - Sun Microsystems - Beijing China * Due to Sigmatel HD codec hardware problem,
139842c41cf8Slipeng sang - Sun Microsystems - Beijing China * which it can't mute beep when volume is 0.
139942c41cf8Slipeng sang - Sun Microsystems - Beijing China * So add global value audiohd_beep_vol,
140042c41cf8Slipeng sang - Sun Microsystems - Beijing China * Set freq to 0 when volume is 0.
140142c41cf8Slipeng sang - Sun Microsystems - Beijing China */
140242c41cf8Slipeng sang - Sun Microsystems - Beijing China tmp = val * path->gain_bits / 100;
140342c41cf8Slipeng sang - Sun Microsystems - Beijing China if (tmp == 0) {
140442c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_beep_vol = 0;
140542c41cf8Slipeng sang - Sun Microsystems - Beijing China } else {
140642c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_beep_vol = tmp;
140742c41cf8Slipeng sang - Sun Microsystems - Beijing China (void) audioha_codec_verb_get(
140842c41cf8Slipeng sang - Sun Microsystems - Beijing China statep,
140942c41cf8Slipeng sang - Sun Microsystems - Beijing China codec->index,
141042c41cf8Slipeng sang - Sun Microsystems - Beijing China path->beep_wid,
141142c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_VERB_SET_BEEP_VOL,
141242c41cf8Slipeng sang - Sun Microsystems - Beijing China tmp);
141342c41cf8Slipeng sang - Sun Microsystems - Beijing China }
141442c41cf8Slipeng sang - Sun Microsystems - Beijing China break;
141542c41cf8Slipeng sang - Sun Microsystems - Beijing China
141642c41cf8Slipeng sang - Sun Microsystems - Beijing China default:
141742c41cf8Slipeng sang - Sun Microsystems - Beijing China /* Common operation based on audiohd spec */
141842c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_do_set_beep_volume(statep, path, val);
141942c41cf8Slipeng sang - Sun Microsystems - Beijing China break;
142042c41cf8Slipeng sang - Sun Microsystems - Beijing China }
142142c41cf8Slipeng sang - Sun Microsystems - Beijing China }
142242c41cf8Slipeng sang - Sun Microsystems - Beijing China }
142342c41cf8Slipeng sang - Sun Microsystems - Beijing China
142442c41cf8Slipeng sang - Sun Microsystems - Beijing China static void
audiohd_do_set_beep_volume(audiohd_state_t * statep,audiohd_path_t * path,uint64_t val)142542c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_do_set_beep_volume(audiohd_state_t *statep, audiohd_path_t *path,
142642c41cf8Slipeng sang - Sun Microsystems - Beijing China uint64_t val)
142742c41cf8Slipeng sang - Sun Microsystems - Beijing China {
142842c41cf8Slipeng sang - Sun Microsystems - Beijing China uint8_t l, r;
142942c41cf8Slipeng sang - Sun Microsystems - Beijing China uint_t tmp;
143042c41cf8Slipeng sang - Sun Microsystems - Beijing China int gain;
143142c41cf8Slipeng sang - Sun Microsystems - Beijing China
143242c41cf8Slipeng sang - Sun Microsystems - Beijing China if (val == 0) {
143342c41cf8Slipeng sang - Sun Microsystems - Beijing China (void) audioha_codec_4bit_verb_get(
143442c41cf8Slipeng sang - Sun Microsystems - Beijing China statep,
143542c41cf8Slipeng sang - Sun Microsystems - Beijing China path->codec->index,
143642c41cf8Slipeng sang - Sun Microsystems - Beijing China path->mute_wid,
143742c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_VERB_SET_AMP_MUTE,
143842c41cf8Slipeng sang - Sun Microsystems - Beijing China path->mute_dir |
143942c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_AMP_SET_LNR |
144042c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_AMP_SET_MUTE);
144142c41cf8Slipeng sang - Sun Microsystems - Beijing China return;
144242c41cf8Slipeng sang - Sun Microsystems - Beijing China }
144342c41cf8Slipeng sang - Sun Microsystems - Beijing China
144442c41cf8Slipeng sang - Sun Microsystems - Beijing China r = (val & 0xff);
144542c41cf8Slipeng sang - Sun Microsystems - Beijing China l = r;
144642c41cf8Slipeng sang - Sun Microsystems - Beijing China
144742c41cf8Slipeng sang - Sun Microsystems - Beijing China tmp = l * path->gain_bits / 100;
144842c41cf8Slipeng sang - Sun Microsystems - Beijing China (void) audioha_codec_4bit_verb_get(statep,
144942c41cf8Slipeng sang - Sun Microsystems - Beijing China path->codec->index,
145042c41cf8Slipeng sang - Sun Microsystems - Beijing China path->gain_wid,
145142c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_VERB_SET_AMP_MUTE,
145242c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_AMP_SET_LEFT | path->gain_dir |
145342c41cf8Slipeng sang - Sun Microsystems - Beijing China tmp);
145442c41cf8Slipeng sang - Sun Microsystems - Beijing China tmp = r * path->gain_bits / 100;
145542c41cf8Slipeng sang - Sun Microsystems - Beijing China (void) audioha_codec_4bit_verb_get(statep,
145642c41cf8Slipeng sang - Sun Microsystems - Beijing China path->codec->index,
145742c41cf8Slipeng sang - Sun Microsystems - Beijing China path->gain_wid,
145842c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_VERB_SET_AMP_MUTE,
145942c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_AMP_SET_RIGHT | path->gain_dir |
146042c41cf8Slipeng sang - Sun Microsystems - Beijing China tmp);
146142c41cf8Slipeng sang - Sun Microsystems - Beijing China if (path->mute_wid != path->gain_wid) {
146242c41cf8Slipeng sang - Sun Microsystems - Beijing China gain = AUDIOHDC_GAIN_MAX;
146342c41cf8Slipeng sang - Sun Microsystems - Beijing China (void) audioha_codec_4bit_verb_get(
146442c41cf8Slipeng sang - Sun Microsystems - Beijing China statep,
146542c41cf8Slipeng sang - Sun Microsystems - Beijing China path->codec->index,
146642c41cf8Slipeng sang - Sun Microsystems - Beijing China path->mute_wid,
146742c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_VERB_SET_AMP_MUTE,
146842c41cf8Slipeng sang - Sun Microsystems - Beijing China path->mute_dir |
146942c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_AMP_SET_LEFT |
147042c41cf8Slipeng sang - Sun Microsystems - Beijing China gain);
147142c41cf8Slipeng sang - Sun Microsystems - Beijing China (void) audioha_codec_4bit_verb_get(
147242c41cf8Slipeng sang - Sun Microsystems - Beijing China statep,
147342c41cf8Slipeng sang - Sun Microsystems - Beijing China path->codec->index,
147442c41cf8Slipeng sang - Sun Microsystems - Beijing China path->mute_wid,
147542c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_VERB_SET_AMP_MUTE,
147642c41cf8Slipeng sang - Sun Microsystems - Beijing China path->mute_dir |
147742c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_AMP_SET_RIGHT |
147842c41cf8Slipeng sang - Sun Microsystems - Beijing China gain);
147942c41cf8Slipeng sang - Sun Microsystems - Beijing China }
148042c41cf8Slipeng sang - Sun Microsystems - Beijing China }
148142c41cf8Slipeng sang - Sun Microsystems - Beijing China
148288447a05SGarrett D'Amore static void
audiohd_configure_output(audiohd_state_t * statep)1483211ec5c5SYang-Rong Jerry Zhou audiohd_configure_output(audiohd_state_t *statep)
1484582eadeeSfl {
148588447a05SGarrett D'Amore audiohd_set_pin_volume(statep, DTYPE_LINEOUT);
148688447a05SGarrett D'Amore audiohd_set_pin_volume(statep, DTYPE_SPEAKER);
148788447a05SGarrett D'Amore audiohd_set_pin_volume(statep, DTYPE_HP_OUT);
148888447a05SGarrett D'Amore
1489211ec5c5SYang-Rong Jerry Zhou audiohd_set_pin_volume_by_color(statep, AUDIOHD_PIN_GREEN);
149088447a05SGarrett D'Amore audiohd_set_pin_volume_by_color(statep, AUDIOHD_PIN_BLACK);
149188447a05SGarrett D'Amore audiohd_set_pin_volume_by_color(statep, AUDIOHD_PIN_GREY);
149288447a05SGarrett D'Amore audiohd_set_pin_volume_by_color(statep, AUDIOHD_PIN_ORANGE);
149388447a05SGarrett D'Amore }
1494c7b817cfSZhao Edgar Liu - Sun Microsystems
149588447a05SGarrett D'Amore static void
audiohd_configure_input(audiohd_state_t * statep)149688447a05SGarrett D'Amore audiohd_configure_input(audiohd_state_t *statep)
149788447a05SGarrett D'Amore {
149888447a05SGarrett D'Amore (void) audiohd_set_input_pin(statep);
149988447a05SGarrett D'Amore audiohd_set_monitor_gain(statep);
150088447a05SGarrett D'Amore audiohd_set_pin_volume(statep, DTYPE_LINE_IN);
150188447a05SGarrett D'Amore audiohd_set_pin_volume(statep, DTYPE_CD);
150288447a05SGarrett D'Amore audiohd_set_pin_volume(statep, DTYPE_MIC_IN);
150388447a05SGarrett D'Amore }
1504c7b817cfSZhao Edgar Liu - Sun Microsystems
150588447a05SGarrett D'Amore static int
audiohd_set_recsrc(void * arg,uint64_t val)150688447a05SGarrett D'Amore audiohd_set_recsrc(void *arg, uint64_t val)
150788447a05SGarrett D'Amore {
150888447a05SGarrett D'Amore audiohd_ctrl_t *pc = arg;
150988447a05SGarrett D'Amore audiohd_state_t *statep = pc->statep;
15103a49c214SYang-Rong Jerry Zhou
151188447a05SGarrett D'Amore if (val & ~(statep->inmask))
151288447a05SGarrett D'Amore return (EINVAL);
1513582eadeeSfl
151488447a05SGarrett D'Amore mutex_enter(&statep->hda_mutex);
151588447a05SGarrett D'Amore pc->val = val;
151688447a05SGarrett D'Amore audiohd_configure_input(statep);
151788447a05SGarrett D'Amore mutex_exit(&statep->hda_mutex);
151888447a05SGarrett D'Amore return (0);
151988447a05SGarrett D'Amore }
1520582eadeeSfl
152188447a05SGarrett D'Amore static int
audiohd_set_rear(void * arg,uint64_t val)152288447a05SGarrett D'Amore audiohd_set_rear(void *arg, uint64_t val)
152388447a05SGarrett D'Amore {
152488447a05SGarrett D'Amore audiohd_ctrl_t *pc = arg;
152588447a05SGarrett D'Amore audiohd_state_t *statep = pc->statep;
1526c7b817cfSZhao Edgar Liu - Sun Microsystems AUDIOHD_CHECK_2CHANNELS_VOLUME(val);
1527582eadeeSfl
152888447a05SGarrett D'Amore mutex_enter(&statep->hda_mutex);
152988447a05SGarrett D'Amore pc->val = val;
153088447a05SGarrett D'Amore audiohd_set_pin_volume_by_color(statep, AUDIOHD_PIN_BLACK);
153188447a05SGarrett D'Amore mutex_exit(&statep->hda_mutex);
153288447a05SGarrett D'Amore
153388447a05SGarrett D'Amore return (0);
153488447a05SGarrett D'Amore }
153588447a05SGarrett D'Amore
153688447a05SGarrett D'Amore static int
audiohd_set_center(void * arg,uint64_t val)153788447a05SGarrett D'Amore audiohd_set_center(void *arg, uint64_t val)
153888447a05SGarrett D'Amore {
153988447a05SGarrett D'Amore audiohd_ctrl_t *pc = arg;
154088447a05SGarrett D'Amore audiohd_state_t *statep = pc->statep;
1541c7b817cfSZhao Edgar Liu - Sun Microsystems AUDIOHD_CHECK_CHANNEL_VOLUME(val);
154288447a05SGarrett D'Amore
154388447a05SGarrett D'Amore mutex_enter(&statep->hda_mutex);
154488447a05SGarrett D'Amore pc->val = val;
154588447a05SGarrett D'Amore audiohd_set_pin_volume_by_color(statep, AUDIOHD_PIN_ORANGE);
1546582eadeeSfl mutex_exit(&statep->hda_mutex);
1547582eadeeSfl
154888447a05SGarrett D'Amore return (0);
154988447a05SGarrett D'Amore }
1550582eadeeSfl
1551582eadeeSfl static int
audiohd_set_surround(void * arg,uint64_t val)155288447a05SGarrett D'Amore audiohd_set_surround(void *arg, uint64_t val)
1553582eadeeSfl {
155488447a05SGarrett D'Amore audiohd_ctrl_t *pc = arg;
155588447a05SGarrett D'Amore audiohd_state_t *statep = pc->statep;
1556c7b817cfSZhao Edgar Liu - Sun Microsystems AUDIOHD_CHECK_2CHANNELS_VOLUME(val);
1557582eadeeSfl
1558582eadeeSfl mutex_enter(&statep->hda_mutex);
155988447a05SGarrett D'Amore pc->val = val;
156088447a05SGarrett D'Amore audiohd_set_pin_volume_by_color(statep, AUDIOHD_PIN_GREY);
156188447a05SGarrett D'Amore mutex_exit(&statep->hda_mutex);
1562582eadeeSfl
156388447a05SGarrett D'Amore return (0);
156488447a05SGarrett D'Amore }
1565582eadeeSfl
156688447a05SGarrett D'Amore static int
audiohd_set_lfe(void * arg,uint64_t val)156788447a05SGarrett D'Amore audiohd_set_lfe(void *arg, uint64_t val)
156888447a05SGarrett D'Amore {
156988447a05SGarrett D'Amore audiohd_ctrl_t *pc = arg;
157088447a05SGarrett D'Amore audiohd_state_t *statep = pc->statep;
1571c7b817cfSZhao Edgar Liu - Sun Microsystems AUDIOHD_CHECK_CHANNEL_VOLUME(val);
1572582eadeeSfl
157388447a05SGarrett D'Amore mutex_enter(&statep->hda_mutex);
157488447a05SGarrett D'Amore pc->val = val;
157588447a05SGarrett D'Amore audiohd_set_pin_volume_by_color(statep, AUDIOHD_PIN_ORANGE);
157688447a05SGarrett D'Amore mutex_exit(&statep->hda_mutex);
1577582eadeeSfl
157888447a05SGarrett D'Amore return (0);
157988447a05SGarrett D'Amore }
158088447a05SGarrett D'Amore static int
audiohd_set_speaker(void * arg,uint64_t val)158188447a05SGarrett D'Amore audiohd_set_speaker(void *arg, uint64_t val)
158288447a05SGarrett D'Amore {
158388447a05SGarrett D'Amore audiohd_ctrl_t *pc = arg;
158488447a05SGarrett D'Amore audiohd_state_t *statep = pc->statep;
1585c7b817cfSZhao Edgar Liu - Sun Microsystems AUDIOHD_CHECK_2CHANNELS_VOLUME(val);
1586582eadeeSfl
158788447a05SGarrett D'Amore mutex_enter(&statep->hda_mutex);
158888447a05SGarrett D'Amore pc->val = val;
158988447a05SGarrett D'Amore audiohd_set_pin_volume(statep, DTYPE_SPEAKER);
159088447a05SGarrett D'Amore mutex_exit(&statep->hda_mutex);
159188447a05SGarrett D'Amore
159288447a05SGarrett D'Amore return (0);
159388447a05SGarrett D'Amore }
159488447a05SGarrett D'Amore static int
audiohd_set_front(void * arg,uint64_t val)159588447a05SGarrett D'Amore audiohd_set_front(void *arg, uint64_t val)
159688447a05SGarrett D'Amore {
159788447a05SGarrett D'Amore audiohd_ctrl_t *pc = arg;
159888447a05SGarrett D'Amore audiohd_state_t *statep = pc->statep;
1599c7b817cfSZhao Edgar Liu - Sun Microsystems AUDIOHD_CHECK_2CHANNELS_VOLUME(val);
160088447a05SGarrett D'Amore
160188447a05SGarrett D'Amore mutex_enter(&statep->hda_mutex);
160288447a05SGarrett D'Amore pc->val = val;
160365a41de7SYang-Rong Jerry Zhou audiohd_set_pin_volume_by_color(statep, AUDIOHD_PIN_GREEN);
160488447a05SGarrett D'Amore mutex_exit(&statep->hda_mutex);
160588447a05SGarrett D'Amore
160688447a05SGarrett D'Amore return (0);
160788447a05SGarrett D'Amore }
1608e7236f70SZhao Edgar Liu - Sun Microsystems
160988447a05SGarrett D'Amore static int
audiohd_set_headphone(void * arg,uint64_t val)161088447a05SGarrett D'Amore audiohd_set_headphone(void *arg, uint64_t val)
161188447a05SGarrett D'Amore {
161288447a05SGarrett D'Amore audiohd_ctrl_t *pc = arg;
161388447a05SGarrett D'Amore audiohd_state_t *statep = pc->statep;
1614c7b817cfSZhao Edgar Liu - Sun Microsystems AUDIOHD_CHECK_2CHANNELS_VOLUME(val);
161588447a05SGarrett D'Amore
161688447a05SGarrett D'Amore mutex_enter(&statep->hda_mutex);
161788447a05SGarrett D'Amore pc->val = val;
161888447a05SGarrett D'Amore audiohd_set_pin_volume(statep, DTYPE_HP_OUT);
161988447a05SGarrett D'Amore mutex_exit(&statep->hda_mutex);
162088447a05SGarrett D'Amore
162188447a05SGarrett D'Amore return (0);
162288447a05SGarrett D'Amore }
1623e7236f70SZhao Edgar Liu - Sun Microsystems
162488447a05SGarrett D'Amore static int
audiohd_set_linein(void * arg,uint64_t val)162588447a05SGarrett D'Amore audiohd_set_linein(void *arg, uint64_t val)
162688447a05SGarrett D'Amore {
162788447a05SGarrett D'Amore audiohd_ctrl_t *pc = arg;
162888447a05SGarrett D'Amore audiohd_state_t *statep = pc->statep;
1629c7b817cfSZhao Edgar Liu - Sun Microsystems AUDIOHD_CHECK_2CHANNELS_VOLUME(val);
163088447a05SGarrett D'Amore
163188447a05SGarrett D'Amore mutex_enter(&statep->hda_mutex);
163288447a05SGarrett D'Amore pc->val = val;
163388447a05SGarrett D'Amore audiohd_set_pin_volume(statep, DTYPE_LINE_IN);
163488447a05SGarrett D'Amore mutex_exit(&statep->hda_mutex);
163588447a05SGarrett D'Amore
163688447a05SGarrett D'Amore return (0);
163788447a05SGarrett D'Amore }
163888447a05SGarrett D'Amore
1639e7236f70SZhao Edgar Liu - Sun Microsystems static int
audiohd_set_loopback(void * arg,uint64_t val)1640e7236f70SZhao Edgar Liu - Sun Microsystems audiohd_set_loopback(void *arg, uint64_t val)
1641e7236f70SZhao Edgar Liu - Sun Microsystems {
1642e7236f70SZhao Edgar Liu - Sun Microsystems audiohd_ctrl_t *pc = arg;
1643e7236f70SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = pc->statep;
1644e7236f70SZhao Edgar Liu - Sun Microsystems audiohd_path_t *path = NULL;
1645e7236f70SZhao Edgar Liu - Sun Microsystems audiohd_widget_t *widget = NULL;
1646e7236f70SZhao Edgar Liu - Sun Microsystems audiohd_pin_t *pin = NULL;
1647e7236f70SZhao Edgar Liu - Sun Microsystems wid_t wid;
1648e7236f70SZhao Edgar Liu - Sun Microsystems uint32_t pinctrl;
1649e7236f70SZhao Edgar Liu - Sun Microsystems int i, j;
1650e7236f70SZhao Edgar Liu - Sun Microsystems
1651e7236f70SZhao Edgar Liu - Sun Microsystems mutex_enter(&statep->hda_mutex);
1652e7236f70SZhao Edgar Liu - Sun Microsystems pc->val = val;
1653e7236f70SZhao Edgar Liu - Sun Microsystems
1654e7236f70SZhao Edgar Liu - Sun Microsystems for (i = 0; i < statep->pathnum; i++) {
1655e7236f70SZhao Edgar Liu - Sun Microsystems path = statep->path[i];
1656e7236f70SZhao Edgar Liu - Sun Microsystems if (path == NULL || path->path_type != LOOPBACK)
1657e7236f70SZhao Edgar Liu - Sun Microsystems continue;
1658e7236f70SZhao Edgar Liu - Sun Microsystems
1659e7236f70SZhao Edgar Liu - Sun Microsystems for (j = 0; j < path->pin_nums; j++) {
1660e7236f70SZhao Edgar Liu - Sun Microsystems wid = path->pin_wid[j];
1661e7236f70SZhao Edgar Liu - Sun Microsystems widget = path->codec->widget[wid];
1662e7236f70SZhao Edgar Liu - Sun Microsystems pin = (audiohd_pin_t *)widget->priv;
1663e7236f70SZhao Edgar Liu - Sun Microsystems
1664e7236f70SZhao Edgar Liu - Sun Microsystems if (val == 1) {
1665e7236f70SZhao Edgar Liu - Sun Microsystems /* Turn on loopback recording */
1666e7236f70SZhao Edgar Liu - Sun Microsystems pinctrl = audioha_codec_verb_get(statep,
1667e7236f70SZhao Edgar Liu - Sun Microsystems path->codec->index, wid,
1668e7236f70SZhao Edgar Liu - Sun Microsystems AUDIOHDC_VERB_GET_PIN_CTRL, 0);
1669e7236f70SZhao Edgar Liu - Sun Microsystems (void) audioha_codec_verb_get(statep,
1670e7236f70SZhao Edgar Liu - Sun Microsystems path->codec->index, wid,
1671e7236f70SZhao Edgar Liu - Sun Microsystems AUDIOHDC_VERB_SET_PIN_CTRL,
1672e7236f70SZhao Edgar Liu - Sun Microsystems pinctrl | AUDIOHD_PIN_OUT_ENABLE);
1673e7236f70SZhao Edgar Liu - Sun Microsystems
1674e7236f70SZhao Edgar Liu - Sun Microsystems if (pin->cap & AUDIOHD_EXT_AMP_MASK) {
1675e7236f70SZhao Edgar Liu - Sun Microsystems (void) audioha_codec_verb_get(statep,
1676e7236f70SZhao Edgar Liu - Sun Microsystems path->codec->index,
1677e7236f70SZhao Edgar Liu - Sun Microsystems wid, AUDIOHDC_VERB_SET_EAPD,
1678e7236f70SZhao Edgar Liu - Sun Microsystems AUDIOHD_EXT_AMP_ENABLE);
1679e7236f70SZhao Edgar Liu - Sun Microsystems }
1680e7236f70SZhao Edgar Liu - Sun Microsystems
1681e7236f70SZhao Edgar Liu - Sun Microsystems } else {
1682e7236f70SZhao Edgar Liu - Sun Microsystems /* Turn off loopback recording */
1683e7236f70SZhao Edgar Liu - Sun Microsystems if (pin->device == DTYPE_LINE_IN) {
1684e7236f70SZhao Edgar Liu - Sun Microsystems pinctrl = audioha_codec_verb_get(statep,
1685e7236f70SZhao Edgar Liu - Sun Microsystems path->codec->index, wid,
1686e7236f70SZhao Edgar Liu - Sun Microsystems AUDIOHDC_VERB_GET_PIN_CTRL, 0);
1687e7236f70SZhao Edgar Liu - Sun Microsystems (void) audioha_codec_verb_get(statep,
1688e7236f70SZhao Edgar Liu - Sun Microsystems path->codec->index, wid,
1689e7236f70SZhao Edgar Liu - Sun Microsystems AUDIOHDC_VERB_SET_PIN_CTRL,
1690e7236f70SZhao Edgar Liu - Sun Microsystems pinctrl & ~AUDIOHD_PIN_OUT_ENABLE);
1691e7236f70SZhao Edgar Liu - Sun Microsystems }
1692e7236f70SZhao Edgar Liu - Sun Microsystems }
1693e7236f70SZhao Edgar Liu - Sun Microsystems
1694e7236f70SZhao Edgar Liu - Sun Microsystems }
1695e7236f70SZhao Edgar Liu - Sun Microsystems }
1696e7236f70SZhao Edgar Liu - Sun Microsystems mutex_exit(&statep->hda_mutex);
1697e7236f70SZhao Edgar Liu - Sun Microsystems
1698e7236f70SZhao Edgar Liu - Sun Microsystems return (0);
1699e7236f70SZhao Edgar Liu - Sun Microsystems }
1700e7236f70SZhao Edgar Liu - Sun Microsystems
170188447a05SGarrett D'Amore static int
audiohd_set_mic(void * arg,uint64_t val)170288447a05SGarrett D'Amore audiohd_set_mic(void *arg, uint64_t val)
170388447a05SGarrett D'Amore {
170488447a05SGarrett D'Amore audiohd_ctrl_t *pc = arg;
170588447a05SGarrett D'Amore audiohd_state_t *statep = pc->statep;
1706c7b817cfSZhao Edgar Liu - Sun Microsystems AUDIOHD_CHECK_2CHANNELS_VOLUME(val);
170788447a05SGarrett D'Amore
170888447a05SGarrett D'Amore mutex_enter(&statep->hda_mutex);
170988447a05SGarrett D'Amore pc->val = val;
171088447a05SGarrett D'Amore audiohd_set_pin_volume(statep, DTYPE_MIC_IN);
171188447a05SGarrett D'Amore mutex_exit(&statep->hda_mutex);
171288447a05SGarrett D'Amore
171388447a05SGarrett D'Amore return (0);
171488447a05SGarrett D'Amore }
171588447a05SGarrett D'Amore
171688447a05SGarrett D'Amore static int
audiohd_set_cd(void * arg,uint64_t val)171788447a05SGarrett D'Amore audiohd_set_cd(void *arg, uint64_t val)
171888447a05SGarrett D'Amore {
171988447a05SGarrett D'Amore audiohd_ctrl_t *pc = arg;
172088447a05SGarrett D'Amore audiohd_state_t *statep = pc->statep;
1721c7b817cfSZhao Edgar Liu - Sun Microsystems AUDIOHD_CHECK_2CHANNELS_VOLUME(val);
1722582eadeeSfl
172388447a05SGarrett D'Amore mutex_enter(&statep->hda_mutex);
172488447a05SGarrett D'Amore pc->val = val;
172588447a05SGarrett D'Amore audiohd_set_pin_volume(statep, DTYPE_CD);
1726582eadeeSfl mutex_exit(&statep->hda_mutex);
1727582eadeeSfl
172888447a05SGarrett D'Amore return (0);
172988447a05SGarrett D'Amore }
1730582eadeeSfl
1731582eadeeSfl static int
audiohd_set_mongain(void * arg,uint64_t val)173288447a05SGarrett D'Amore audiohd_set_mongain(void *arg, uint64_t val)
1733582eadeeSfl {
173488447a05SGarrett D'Amore audiohd_ctrl_t *pc = arg;
173588447a05SGarrett D'Amore audiohd_state_t *statep = pc->statep;
1736c7b817cfSZhao Edgar Liu - Sun Microsystems AUDIOHD_CHECK_2CHANNELS_VOLUME(val);
1737582eadeeSfl
1738582eadeeSfl mutex_enter(&statep->hda_mutex);
173988447a05SGarrett D'Amore pc->val = val;
174070feb41cSZhao Edgar Liu - Sun Microsystems audiohd_set_monitor_gain(statep);
174188447a05SGarrett D'Amore mutex_exit(&statep->hda_mutex);
174288447a05SGarrett D'Amore
174388447a05SGarrett D'Amore return (0);
174488447a05SGarrett D'Amore }
174588447a05SGarrett D'Amore
174642c41cf8Slipeng sang - Sun Microsystems - Beijing China static int
audiohd_set_beep(void * arg,uint64_t val)174742c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_set_beep(void *arg, uint64_t val)
174842c41cf8Slipeng sang - Sun Microsystems - Beijing China {
174942c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_ctrl_t *pc = arg;
175042c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_state_t *statep = pc->statep;
1751c7b817cfSZhao Edgar Liu - Sun Microsystems AUDIOHD_CHECK_CHANNEL_VOLUME(val);
175242c41cf8Slipeng sang - Sun Microsystems - Beijing China
175342c41cf8Slipeng sang - Sun Microsystems - Beijing China mutex_enter(&statep->hda_mutex);
175442c41cf8Slipeng sang - Sun Microsystems - Beijing China pc->val = val;
175542c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_set_beep_volume(statep);
175642c41cf8Slipeng sang - Sun Microsystems - Beijing China mutex_exit(&statep->hda_mutex);
175742c41cf8Slipeng sang - Sun Microsystems - Beijing China
175842c41cf8Slipeng sang - Sun Microsystems - Beijing China return (0);
175942c41cf8Slipeng sang - Sun Microsystems - Beijing China }
176042c41cf8Slipeng sang - Sun Microsystems - Beijing China
176188447a05SGarrett D'Amore #define PLAYCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_PLAY)
176288447a05SGarrett D'Amore #define RECCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_REC)
176388447a05SGarrett D'Amore #define MONCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_MONITOR)
176488447a05SGarrett D'Amore #define PCMVOL (PLAYCTL | AUDIO_CTRL_FLAG_PCMVOL)
176588447a05SGarrett D'Amore #define MONVOL (MONCTL | AUDIO_CTRL_FLAG_MONVOL)
176688447a05SGarrett D'Amore #define MAINVOL (PLAYCTL | AUDIO_CTRL_FLAG_MAINVOL)
176788447a05SGarrett D'Amore #define RECVOL (RECCTL | AUDIO_CTRL_FLAG_RECVOL)
176888447a05SGarrett D'Amore
1769c1cfefcdSZhao Edgar Liu - Sun Microsystems static void
audiohd_del_controls(audiohd_state_t * statep)1770c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_del_controls(audiohd_state_t *statep)
177188447a05SGarrett D'Amore {
1772c1cfefcdSZhao Edgar Liu - Sun Microsystems int i;
1773c1cfefcdSZhao Edgar Liu - Sun Microsystems for (i = 0; i < CTL_MAX; i++) {
1774c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_ctrl_t *ac = &statep->ctrls[i];
1775c1cfefcdSZhao Edgar Liu - Sun Microsystems if (ac->ctrl != NULL) {
1776c1cfefcdSZhao Edgar Liu - Sun Microsystems audio_dev_del_control(ac->ctrl);
1777c1cfefcdSZhao Edgar Liu - Sun Microsystems ac->ctrl = NULL;
1778c1cfefcdSZhao Edgar Liu - Sun Microsystems }
1779c1cfefcdSZhao Edgar Liu - Sun Microsystems }
1780c1cfefcdSZhao Edgar Liu - Sun Microsystems }
178188447a05SGarrett D'Amore
1782c1cfefcdSZhao Edgar Liu - Sun Microsystems static void
audiohd_create_mono(audiohd_state_t * statep,int ctl,const char * id,int flags,int defval,audio_ctrl_wr_t fn)1783c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_create_mono(audiohd_state_t *statep, int ctl,
1784c1cfefcdSZhao Edgar Liu - Sun Microsystems const char *id, int flags, int defval, audio_ctrl_wr_t fn)
1785c1cfefcdSZhao Edgar Liu - Sun Microsystems {
1786c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_ctrl_t *ac;
1787c1cfefcdSZhao Edgar Liu - Sun Microsystems audio_ctrl_desc_t desc;
178888447a05SGarrett D'Amore
178988447a05SGarrett D'Amore bzero(&desc, sizeof (desc));
179088447a05SGarrett D'Amore
1791c1cfefcdSZhao Edgar Liu - Sun Microsystems ac = &statep->ctrls[ctl];
1792c1cfefcdSZhao Edgar Liu - Sun Microsystems ac->statep = statep;
1793c1cfefcdSZhao Edgar Liu - Sun Microsystems ac->num = ctl;
1794582eadeeSfl
1795c1cfefcdSZhao Edgar Liu - Sun Microsystems desc.acd_name = id;
1796c1cfefcdSZhao Edgar Liu - Sun Microsystems desc.acd_type = AUDIO_CTRL_TYPE_MONO;
1797c1cfefcdSZhao Edgar Liu - Sun Microsystems desc.acd_minvalue = 0;
1798c1cfefcdSZhao Edgar Liu - Sun Microsystems desc.acd_maxvalue = 100;
1799c1cfefcdSZhao Edgar Liu - Sun Microsystems desc.acd_flags = flags;
1800582eadeeSfl
1801c1cfefcdSZhao Edgar Liu - Sun Microsystems ac->val = defval;
1802c1cfefcdSZhao Edgar Liu - Sun Microsystems ac->ctrl = audio_dev_add_control(statep->adev, &desc,
1803c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_get_control, fn, ac);
1804c1cfefcdSZhao Edgar Liu - Sun Microsystems }
1805582eadeeSfl
1806c1cfefcdSZhao Edgar Liu - Sun Microsystems static void
audiohd_create_stereo(audiohd_state_t * statep,int ctl,const char * id,int flags,int defval,audio_ctrl_wr_t fn)1807c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_create_stereo(audiohd_state_t *statep, int ctl,
1808c1cfefcdSZhao Edgar Liu - Sun Microsystems const char *id, int flags, int defval, audio_ctrl_wr_t fn)
1809c1cfefcdSZhao Edgar Liu - Sun Microsystems {
1810c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_ctrl_t *ac;
1811c1cfefcdSZhao Edgar Liu - Sun Microsystems audio_ctrl_desc_t desc;
1812582eadeeSfl
1813c1cfefcdSZhao Edgar Liu - Sun Microsystems bzero(&desc, sizeof (desc));
1814582eadeeSfl
1815c1cfefcdSZhao Edgar Liu - Sun Microsystems ac = &statep->ctrls[ctl];
1816c1cfefcdSZhao Edgar Liu - Sun Microsystems ac->statep = statep;
1817c1cfefcdSZhao Edgar Liu - Sun Microsystems ac->num = ctl;
1818582eadeeSfl
1819c1cfefcdSZhao Edgar Liu - Sun Microsystems desc.acd_name = id;
1820c1cfefcdSZhao Edgar Liu - Sun Microsystems desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
1821c1cfefcdSZhao Edgar Liu - Sun Microsystems desc.acd_minvalue = 0;
1822c1cfefcdSZhao Edgar Liu - Sun Microsystems desc.acd_maxvalue = 100;
1823c1cfefcdSZhao Edgar Liu - Sun Microsystems desc.acd_flags = flags;
1824582eadeeSfl
1825c1cfefcdSZhao Edgar Liu - Sun Microsystems ac->val = (defval << 8) | defval;
1826c1cfefcdSZhao Edgar Liu - Sun Microsystems ac->ctrl = audio_dev_add_control(statep->adev, &desc,
1827c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_get_control, fn, ac);
1828c1cfefcdSZhao Edgar Liu - Sun Microsystems }
1829582eadeeSfl
1830e7236f70SZhao Edgar Liu - Sun Microsystems static void
audiohd_create_bool(audiohd_state_t * statep,int ctl,const char * id,int defval,audio_ctrl_wr_t fn)1831e7236f70SZhao Edgar Liu - Sun Microsystems audiohd_create_bool(audiohd_state_t *statep, int ctl,
1832e7236f70SZhao Edgar Liu - Sun Microsystems const char *id, int defval, audio_ctrl_wr_t fn)
1833e7236f70SZhao Edgar Liu - Sun Microsystems {
1834e7236f70SZhao Edgar Liu - Sun Microsystems audiohd_ctrl_t *ac;
1835e7236f70SZhao Edgar Liu - Sun Microsystems audio_ctrl_desc_t desc;
1836e7236f70SZhao Edgar Liu - Sun Microsystems
1837e7236f70SZhao Edgar Liu - Sun Microsystems bzero(&desc, sizeof (desc));
1838e7236f70SZhao Edgar Liu - Sun Microsystems
1839e7236f70SZhao Edgar Liu - Sun Microsystems ac = &statep->ctrls[ctl];
1840e7236f70SZhao Edgar Liu - Sun Microsystems ac->statep = statep;
1841e7236f70SZhao Edgar Liu - Sun Microsystems ac->num = ctl;
1842e7236f70SZhao Edgar Liu - Sun Microsystems
1843e7236f70SZhao Edgar Liu - Sun Microsystems desc.acd_name = id;
1844e7236f70SZhao Edgar Liu - Sun Microsystems desc.acd_type = AUDIO_CTRL_TYPE_BOOLEAN;
1845e7236f70SZhao Edgar Liu - Sun Microsystems desc.acd_minvalue = 0;
1846e7236f70SZhao Edgar Liu - Sun Microsystems desc.acd_maxvalue = 1;
1847e7236f70SZhao Edgar Liu - Sun Microsystems desc.acd_flags = RECCTL;
1848e7236f70SZhao Edgar Liu - Sun Microsystems
1849e7236f70SZhao Edgar Liu - Sun Microsystems ac->val = defval;
1850e7236f70SZhao Edgar Liu - Sun Microsystems ac->ctrl = audio_dev_add_control(statep->adev, &desc,
1851e7236f70SZhao Edgar Liu - Sun Microsystems audiohd_get_control, fn, ac);
1852e7236f70SZhao Edgar Liu - Sun Microsystems }
1853e7236f70SZhao Edgar Liu - Sun Microsystems
1854c1cfefcdSZhao Edgar Liu - Sun Microsystems static void
audiohd_create_recsrc(audiohd_state_t * statep)1855c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_create_recsrc(audiohd_state_t *statep)
1856c1cfefcdSZhao Edgar Liu - Sun Microsystems {
1857c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_ctrl_t *ac;
1858c1cfefcdSZhao Edgar Liu - Sun Microsystems audio_ctrl_desc_t desc;
1859582eadeeSfl
1860c1cfefcdSZhao Edgar Liu - Sun Microsystems bzero(&desc, sizeof (desc));
18613a49c214SYang-Rong Jerry Zhou
1862c1cfefcdSZhao Edgar Liu - Sun Microsystems ac = &statep->ctrls[CTL_RECSRC];
1863c1cfefcdSZhao Edgar Liu - Sun Microsystems ac->statep = statep;
1864c1cfefcdSZhao Edgar Liu - Sun Microsystems ac->num = CTL_RECSRC;
186588447a05SGarrett D'Amore
1866c1cfefcdSZhao Edgar Liu - Sun Microsystems desc.acd_name = AUDIO_CTRL_ID_RECSRC;
1867c1cfefcdSZhao Edgar Liu - Sun Microsystems desc.acd_type = AUDIO_CTRL_TYPE_ENUM;
1868e7236f70SZhao Edgar Liu - Sun Microsystems desc.acd_flags = RECVOL;
1869c1cfefcdSZhao Edgar Liu - Sun Microsystems desc.acd_minvalue = statep->inmask;
1870c1cfefcdSZhao Edgar Liu - Sun Microsystems desc.acd_maxvalue = statep->inmask;
1871c1cfefcdSZhao Edgar Liu - Sun Microsystems for (int i = 0; audiohd_dtypes[i]; i++) {
1872c1cfefcdSZhao Edgar Liu - Sun Microsystems desc.acd_enum[i] = audiohd_dtypes[i];
1873582eadeeSfl }
1874582eadeeSfl
1875c1cfefcdSZhao Edgar Liu - Sun Microsystems ac->val = (1U << DTYPE_MIC_IN);
1876c1cfefcdSZhao Edgar Liu - Sun Microsystems ac->ctrl = audio_dev_add_control(statep->adev, &desc,
1877c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_get_control, audiohd_set_recsrc, ac);
187888447a05SGarrett D'Amore }
1879582eadeeSfl
1880582eadeeSfl static void
audiohd_create_controls(audiohd_state_t * statep)1881c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_create_controls(audiohd_state_t *statep)
1882582eadeeSfl {
188388447a05SGarrett D'Amore wid_t wid;
1884c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_widget_t *widget;
1885c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_path_t *path;
188688447a05SGarrett D'Amore hda_codec_t *codec;
1887c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_pin_t *pin;
1888c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_pin_color_t color;
1889c1cfefcdSZhao Edgar Liu - Sun Microsystems int i, j;
1890582eadeeSfl
189113084339SYang-Rong Jerry Zhou /*
1892901f2979SZhao Edgar Liu - Sun Microsystems * We always use soft volume control to adjust PCM volume.
189313084339SYang-Rong Jerry Zhou */
18942c30fa45SGarrett D'Amore audio_dev_add_soft_volume(statep->adev);
1895c1cfefcdSZhao Edgar Liu - Sun Microsystems
1896c1cfefcdSZhao Edgar Liu - Sun Microsystems /* Allocate other controls */
189788447a05SGarrett D'Amore for (i = 0; i < statep->pathnum; i++) {
189888447a05SGarrett D'Amore path = statep->path[i];
1899c1cfefcdSZhao Edgar Liu - Sun Microsystems if (path == NULL)
190088447a05SGarrett D'Amore continue;
190188447a05SGarrett D'Amore codec = path->codec;
190242c41cf8Slipeng sang - Sun Microsystems - Beijing China
190388447a05SGarrett D'Amore for (j = 0; j < path->pin_nums; j++) {
190488447a05SGarrett D'Amore wid = path->pin_wid[j];
190588447a05SGarrett D'Amore widget = codec->widget[wid];
190688447a05SGarrett D'Amore pin = (audiohd_pin_t *)widget->priv;
1907c1cfefcdSZhao Edgar Liu - Sun Microsystems color = (pin->config >> AUDIOHD_PIN_CLR_OFF) &
1908c1cfefcdSZhao Edgar Liu - Sun Microsystems AUDIOHD_PIN_CLR_MASK;
1909c1cfefcdSZhao Edgar Liu - Sun Microsystems if (color == AUDIOHD_PIN_GREEN) {
1910c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_create_stereo(statep, CTL_FRONT,
1911c1cfefcdSZhao Edgar Liu - Sun Microsystems AUDIO_CTRL_ID_FRONT, MAINVOL, 75,
1912c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_set_front);
1913c1cfefcdSZhao Edgar Liu - Sun Microsystems } else if (color == AUDIOHD_PIN_BLACK &&
1914c1cfefcdSZhao Edgar Liu - Sun Microsystems pin->device != DTYPE_HP_OUT &&
1915c1cfefcdSZhao Edgar Liu - Sun Microsystems pin->device != DTYPE_MIC_IN) {
1916c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_create_stereo(statep, CTL_REAR,
1917c1cfefcdSZhao Edgar Liu - Sun Microsystems AUDIO_CTRL_ID_REAR, MAINVOL, 75,
1918c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_set_rear);
1919c1cfefcdSZhao Edgar Liu - Sun Microsystems } else if (color == AUDIOHD_PIN_ORANGE) {
1920c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_create_mono(statep, CTL_CENTER,
1921c1cfefcdSZhao Edgar Liu - Sun Microsystems AUDIO_CTRL_ID_CENTER, MAINVOL, 75,
1922c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_set_center);
1923c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_create_mono(statep, CTL_LFE,
1924c1cfefcdSZhao Edgar Liu - Sun Microsystems AUDIO_CTRL_ID_LFE, MAINVOL, 75,
1925c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_set_lfe);
1926c1cfefcdSZhao Edgar Liu - Sun Microsystems } else if (color == AUDIOHD_PIN_GREY) {
1927c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_create_stereo(statep, CTL_SURROUND,
1928c1cfefcdSZhao Edgar Liu - Sun Microsystems AUDIO_CTRL_ID_SURROUND, MAINVOL, 75,
1929c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_set_surround);
1930c1cfefcdSZhao Edgar Liu - Sun Microsystems }
193165a41de7SYang-Rong Jerry Zhou if (pin->device == DTYPE_SPEAKER) {
1932c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_create_stereo(statep, CTL_SPEAKER,
1933c1cfefcdSZhao Edgar Liu - Sun Microsystems AUDIO_CTRL_ID_SPEAKER, MAINVOL, 75,
1934c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_set_speaker);
193588447a05SGarrett D'Amore } else if (pin->device == DTYPE_HP_OUT) {
1936c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_create_stereo(statep, CTL_HEADPHONE,
1937c1cfefcdSZhao Edgar Liu - Sun Microsystems AUDIO_CTRL_ID_HEADPHONE, MAINVOL, 75,
1938c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_set_headphone);
193988447a05SGarrett D'Amore } else if (pin->device == DTYPE_LINE_IN) {
1940c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_create_stereo(statep, CTL_LINEIN,
1941c1cfefcdSZhao Edgar Liu - Sun Microsystems AUDIO_CTRL_ID_LINEIN, RECVOL, 50,
1942c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_set_linein);
194388447a05SGarrett D'Amore } else if (pin->device == DTYPE_MIC_IN) {
1944c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_create_stereo(statep, CTL_MIC,
1945c1cfefcdSZhao Edgar Liu - Sun Microsystems AUDIO_CTRL_ID_MIC, RECVOL, 50,
1946c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_set_mic);
194788447a05SGarrett D'Amore } else if (pin->device == DTYPE_CD) {
1948c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_create_stereo(statep, CTL_CD,
1949c1cfefcdSZhao Edgar Liu - Sun Microsystems AUDIO_CTRL_ID_CD, RECVOL, 50,
1950c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_set_cd);
195188447a05SGarrett D'Amore }
1952c1cfefcdSZhao Edgar Liu - Sun Microsystems }
1953c1cfefcdSZhao Edgar Liu - Sun Microsystems
1954c1cfefcdSZhao Edgar Liu - Sun Microsystems if (path->path_type == BEEP) {
1955c1cfefcdSZhao Edgar Liu - Sun Microsystems widget = codec->widget[path->beep_wid];
1956c1cfefcdSZhao Edgar Liu - Sun Microsystems if (widget->type == WTYPE_BEEP &&
1957c1cfefcdSZhao Edgar Liu - Sun Microsystems path->gain_wid != 0) {
1958c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_create_mono(statep, CTL_BEEP,
1959e7236f70SZhao Edgar Liu - Sun Microsystems AUDIO_CTRL_ID_BEEP, AUDIO_CTRL_FLAG_RW, 75,
1960c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_set_beep);
1961c1cfefcdSZhao Edgar Liu - Sun Microsystems continue;
196288447a05SGarrett D'Amore }
196388447a05SGarrett D'Amore }
1964582eadeeSfl }
1965582eadeeSfl
1966e7236f70SZhao Edgar Liu - Sun Microsystems if (statep->monitor_supported) {
1967c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_create_stereo(statep, CTL_MONGAIN,
1968c1cfefcdSZhao Edgar Liu - Sun Microsystems AUDIO_CTRL_ID_MONGAIN, MONVOL, 0,
1969c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_set_mongain);
197088447a05SGarrett D'Amore }
1971582eadeeSfl
1972e7236f70SZhao Edgar Liu - Sun Microsystems if (statep->loopback_supported) {
1973e7236f70SZhao Edgar Liu - Sun Microsystems audiohd_create_bool(statep, CTL_LOOP, AUDIO_CTRL_ID_LOOPBACK,
1974e7236f70SZhao Edgar Liu - Sun Microsystems 0, audiohd_set_loopback);
1975e7236f70SZhao Edgar Liu - Sun Microsystems }
1976e7236f70SZhao Edgar Liu - Sun Microsystems
1977c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_create_recsrc(statep);
197888447a05SGarrett D'Amore audiohd_configure_output(statep);
197988447a05SGarrett D'Amore audiohd_configure_input(statep);
198088447a05SGarrett D'Amore }
1981582eadeeSfl
1982582eadeeSfl /*
198388447a05SGarrett D'Amore * quiesce(9E) entry point.
198488447a05SGarrett D'Amore *
198588447a05SGarrett D'Amore * This function is called when the system is single-threaded at high
198688447a05SGarrett D'Amore * PIL with preemption disabled. Therefore, this function must not be
198788447a05SGarrett D'Amore * blocked.
198888447a05SGarrett D'Amore *
198988447a05SGarrett D'Amore * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
199088447a05SGarrett D'Amore * DDI_FAILURE indicates an error condition and should almost never happen.
1991582eadeeSfl */
199288447a05SGarrett D'Amore static int
audiohd_quiesce(dev_info_t * dip)199388447a05SGarrett D'Amore audiohd_quiesce(dev_info_t *dip)
1994582eadeeSfl {
199588447a05SGarrett D'Amore audiohd_state_t *statep;
1996582eadeeSfl
199788447a05SGarrett D'Amore statep = ddi_get_driver_private(dip);
19983a49c214SYang-Rong Jerry Zhou
1999ea463888SZhao Edgar Liu - Sun Microsystems mutex_enter(&statep->hda_mutex);
200088447a05SGarrett D'Amore audiohd_stop_dma(statep);
2001ea463888SZhao Edgar Liu - Sun Microsystems mutex_exit(&statep->hda_mutex);
2002582eadeeSfl
200388447a05SGarrett D'Amore return (DDI_SUCCESS);
200488447a05SGarrett D'Amore }
200542c41cf8Slipeng sang - Sun Microsystems - Beijing China
200642c41cf8Slipeng sang - Sun Microsystems - Beijing China static void
audiohd_beep_on(void * arg)200742c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_beep_on(void *arg)
200842c41cf8Slipeng sang - Sun Microsystems - Beijing China {
200942c41cf8Slipeng sang - Sun Microsystems - Beijing China hda_codec_t *codec = ((audiohd_widget_t *)arg)->codec;
2010ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
201142c41cf8Slipeng sang - Sun Microsystems - Beijing China int caddr = codec->index;
201242c41cf8Slipeng sang - Sun Microsystems - Beijing China wid_t wid = ((audiohd_widget_t *)arg)->wid_wid;
201342c41cf8Slipeng sang - Sun Microsystems - Beijing China
2014ea463888SZhao Edgar Liu - Sun Microsystems mutex_enter(&statep->hda_mutex);
201542c41cf8Slipeng sang - Sun Microsystems - Beijing China (void) audioha_codec_verb_get(statep, caddr, wid,
201642c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_VERB_SET_BEEP_GEN, audiohd_beep_divider);
2017ea463888SZhao Edgar Liu - Sun Microsystems mutex_exit(&statep->hda_mutex);
201842c41cf8Slipeng sang - Sun Microsystems - Beijing China }
201942c41cf8Slipeng sang - Sun Microsystems - Beijing China
202042c41cf8Slipeng sang - Sun Microsystems - Beijing China static void
audiohd_beep_off(void * arg)202142c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_beep_off(void *arg)
202242c41cf8Slipeng sang - Sun Microsystems - Beijing China {
202342c41cf8Slipeng sang - Sun Microsystems - Beijing China hda_codec_t *codec = ((audiohd_widget_t *)arg)->codec;
2024ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
202542c41cf8Slipeng sang - Sun Microsystems - Beijing China int caddr = codec->index;
202642c41cf8Slipeng sang - Sun Microsystems - Beijing China wid_t wid = ((audiohd_widget_t *)arg)->wid_wid;
202742c41cf8Slipeng sang - Sun Microsystems - Beijing China
2028ea463888SZhao Edgar Liu - Sun Microsystems mutex_enter(&statep->hda_mutex);
202942c41cf8Slipeng sang - Sun Microsystems - Beijing China (void) audioha_codec_verb_get(statep, caddr, wid,
203042c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_VERB_SET_BEEP_GEN, AUDIOHDC_MUTE_BEEP_GEN);
2031ea463888SZhao Edgar Liu - Sun Microsystems mutex_exit(&statep->hda_mutex);
203242c41cf8Slipeng sang - Sun Microsystems - Beijing China }
203342c41cf8Slipeng sang - Sun Microsystems - Beijing China
203442c41cf8Slipeng sang - Sun Microsystems - Beijing China static void
audiohd_beep_freq(void * arg,int freq)203542c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_beep_freq(void *arg, int freq)
203642c41cf8Slipeng sang - Sun Microsystems - Beijing China {
20370c240c64SZhao Edgar Liu - Sun Microsystems hda_codec_t *codec = ((audiohd_widget_t *)arg)->codec;
2038ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
20390c240c64SZhao Edgar Liu - Sun Microsystems uint32_t vid = codec->vid >> 16;
2040ea463888SZhao Edgar Liu - Sun Microsystems int divider;
20410c240c64SZhao Edgar Liu - Sun Microsystems
204242c41cf8Slipeng sang - Sun Microsystems - Beijing China _NOTE(ARGUNUSED(arg));
204342c41cf8Slipeng sang - Sun Microsystems - Beijing China if (freq == 0) {
2044ea463888SZhao Edgar Liu - Sun Microsystems divider = 0;
204542c41cf8Slipeng sang - Sun Microsystems - Beijing China } else {
204642c41cf8Slipeng sang - Sun Microsystems - Beijing China if (freq > AUDIOHDC_MAX_BEEP_GEN)
204742c41cf8Slipeng sang - Sun Microsystems - Beijing China freq = AUDIOHDC_MAX_BEEP_GEN;
204842c41cf8Slipeng sang - Sun Microsystems - Beijing China else if (freq < AUDIOHDC_MIX_BEEP_GEN)
204942c41cf8Slipeng sang - Sun Microsystems - Beijing China freq = AUDIOHDC_MIX_BEEP_GEN;
20500c240c64SZhao Edgar Liu - Sun Microsystems
20510c240c64SZhao Edgar Liu - Sun Microsystems switch (vid) {
20520c240c64SZhao Edgar Liu - Sun Microsystems case AUDIOHD_VID_SIGMATEL:
20530c240c64SZhao Edgar Liu - Sun Microsystems /*
20540c240c64SZhao Edgar Liu - Sun Microsystems * Sigmatel HD codec specification:
20550c240c64SZhao Edgar Liu - Sun Microsystems * frequency = 48000 * (257 - Divider) / 1024
20560c240c64SZhao Edgar Liu - Sun Microsystems */
2057ea463888SZhao Edgar Liu - Sun Microsystems divider = 257 - freq * 1024 / AUDIOHDC_SAMPR48000;
20580c240c64SZhao Edgar Liu - Sun Microsystems break;
20590c240c64SZhao Edgar Liu - Sun Microsystems default:
2060ea463888SZhao Edgar Liu - Sun Microsystems divider = AUDIOHDC_SAMPR48000 / freq;
20610c240c64SZhao Edgar Liu - Sun Microsystems break;
20620c240c64SZhao Edgar Liu - Sun Microsystems }
206342c41cf8Slipeng sang - Sun Microsystems - Beijing China }
206442c41cf8Slipeng sang - Sun Microsystems - Beijing China
206542c41cf8Slipeng sang - Sun Microsystems - Beijing China if (audiohd_beep_vol == 0)
2066ea463888SZhao Edgar Liu - Sun Microsystems divider = 0;
2067ea463888SZhao Edgar Liu - Sun Microsystems
2068ea463888SZhao Edgar Liu - Sun Microsystems mutex_enter(&statep->hda_mutex);
2069ea463888SZhao Edgar Liu - Sun Microsystems audiohd_beep_divider = divider;
2070ea463888SZhao Edgar Liu - Sun Microsystems mutex_exit(&statep->hda_mutex);
207142c41cf8Slipeng sang - Sun Microsystems - Beijing China }
207242c41cf8Slipeng sang - Sun Microsystems - Beijing China
2073582eadeeSfl /*
2074582eadeeSfl * audiohd_init_state()
2075582eadeeSfl *
2076582eadeeSfl * Description
2077582eadeeSfl * This routine initailizes soft state of driver instance,
2078582eadeeSfl * also, it requests an interrupt cookie and initializes
2079582eadeeSfl * mutex for soft state.
2080582eadeeSfl */
2081582eadeeSfl /*ARGSUSED*/
2082582eadeeSfl static int
audiohd_init_state(audiohd_state_t * statep,dev_info_t * dip)2083582eadeeSfl audiohd_init_state(audiohd_state_t *statep, dev_info_t *dip)
2084582eadeeSfl {
2085c7b817cfSZhao Edgar Liu - Sun Microsystems audio_dev_t *adev;
2086582eadeeSfl
2087582eadeeSfl statep->hda_dip = dip;
2088c7b817cfSZhao Edgar Liu - Sun Microsystems statep->hda_rirb_rp = 0;
2089582eadeeSfl
209088447a05SGarrett D'Amore if ((adev = audio_dev_alloc(dip, 0)) == NULL) {
2091e7236f70SZhao Edgar Liu - Sun Microsystems audio_dev_warn(NULL, "unable to allocate audio dev");
2092c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
2093582eadeeSfl }
209488447a05SGarrett D'Amore statep->adev = adev;
2095582eadeeSfl
209688447a05SGarrett D'Amore /* set device information */
209788447a05SGarrett D'Amore audio_dev_set_description(adev, AUDIOHD_DEV_CONFIG);
209888447a05SGarrett D'Amore audio_dev_set_version(adev, AUDIOHD_DEV_VERSION);
2099582eadeeSfl
2100c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
2101582eadeeSfl } /* audiohd_init_state() */
2102582eadeeSfl
2103582eadeeSfl /*
2104582eadeeSfl * audiohd_init_pci()
2105582eadeeSfl *
2106582eadeeSfl * Description
2107582eadeeSfl * enable driver to access PCI configure space and memory
2108582eadeeSfl * I/O space.
2109582eadeeSfl */
2110582eadeeSfl static int
audiohd_init_pci(audiohd_state_t * statep,ddi_device_acc_attr_t * acc_attr)2111582eadeeSfl audiohd_init_pci(audiohd_state_t *statep, ddi_device_acc_attr_t *acc_attr)
2112582eadeeSfl {
2113582eadeeSfl uint16_t cmdreg;
2114555989a4Scg uint16_t vid;
2115555989a4Scg uint8_t cTmp;
2116582eadeeSfl dev_info_t *dip = statep->hda_dip;
2117c7b817cfSZhao Edgar Liu - Sun Microsystems audio_dev_t *adev = statep->adev;
2118582eadeeSfl
21193a49c214SYang-Rong Jerry Zhou if (pci_config_setup(dip, &statep->hda_pci_handle) == DDI_FAILURE) {
2120c7b817cfSZhao Edgar Liu - Sun Microsystems audio_dev_warn(adev,
212188447a05SGarrett D'Amore "pci config mapping failed");
2122c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
21233a49c214SYang-Rong Jerry Zhou }
2124582eadeeSfl
21253a49c214SYang-Rong Jerry Zhou if (ddi_regs_map_setup(dip, 1, &statep->hda_reg_base, 0,
21263a49c214SYang-Rong Jerry Zhou 0, acc_attr, &statep->hda_reg_handle) != DDI_SUCCESS) {
2127c7b817cfSZhao Edgar Liu - Sun Microsystems audio_dev_warn(adev,
212888447a05SGarrett D'Amore "memory I/O mapping failed");
2129c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
2130582eadeeSfl }
2131582eadeeSfl
2132582eadeeSfl /*
2133582eadeeSfl * HD audio control uses memory I/O only, enable it here.
2134582eadeeSfl */
2135582eadeeSfl cmdreg = pci_config_get16(statep->hda_pci_handle, PCI_CONF_COMM);
2136582eadeeSfl pci_config_put16(statep->hda_pci_handle, PCI_CONF_COMM,
2137582eadeeSfl cmdreg | PCI_COMM_MAE | PCI_COMM_ME);
2138582eadeeSfl
2139555989a4Scg vid = pci_config_get16(statep->hda_pci_handle, PCI_CONF_VENID);
214014707ff3Scg switch (vid) {
214114707ff3Scg case AUDIOHD_VID_INTEL:
214214707ff3Scg /*
214314707ff3Scg * Currently, Intel (G)MCH and ICHx chipsets support PCI
214414707ff3Scg * Express QoS. It implemenets two VCs(virtual channels)
214514707ff3Scg * and allows OS software to map 8 traffic classes to the
214614707ff3Scg * two VCs. Some BIOSes initialize HD audio hardware to
214714707ff3Scg * use TC7 (traffic class 7) and to map TC7 to VC1 as Intel
214814707ff3Scg * recommended. However, solaris doesn't support PCI express
214914707ff3Scg * QoS yet. As a result, this driver can not work for those
215014707ff3Scg * hardware without touching PCI express control registers.
215114707ff3Scg * Here, we set TCSEL to 0 so as to use TC0/VC0 (VC0 is
215214707ff3Scg * always enabled and TC0 is always mapped to VC0) for all
215314707ff3Scg * Intel HD audio controllers.
215414707ff3Scg */
2155555989a4Scg cTmp = pci_config_get8(statep->hda_pci_handle,
2156555989a4Scg AUDIOHD_INTEL_PCI_TCSEL);
2157555989a4Scg pci_config_put8(statep->hda_pci_handle,
21583a49c214SYang-Rong Jerry Zhou AUDIOHD_INTEL_PCI_TCSEL, (cTmp & AUDIOHD_INTEL_TCS_MASK));
215914707ff3Scg break;
216014707ff3Scg case AUDIOHD_VID_ATI:
216114707ff3Scg /*
216214707ff3Scg * Refer to ATI SB450 datesheet. We set snoop for SB450
216314707ff3Scg * like hardware.
216414707ff3Scg */
216514707ff3Scg cTmp = pci_config_get8(statep->hda_pci_handle,
216614707ff3Scg AUDIOHD_ATI_PCI_MISC2);
216714707ff3Scg pci_config_put8(statep->hda_pci_handle, AUDIOHD_ATI_PCI_MISC2,
21683a49c214SYang-Rong Jerry Zhou (cTmp & AUDIOHD_ATI_MISC2_MASK) | AUDIOHD_ATI_MISC2_SNOOP);
21693a49c214SYang-Rong Jerry Zhou break;
2170989b958fSZhao Edgar Liu - Sun Microsystems case AUDIOHD_VID_NVIDIA:
21713a49c214SYang-Rong Jerry Zhou /*
21723a49c214SYang-Rong Jerry Zhou * Refer to the datasheet, we set snoop for NVIDIA
21733a49c214SYang-Rong Jerry Zhou * like hardware
21743a49c214SYang-Rong Jerry Zhou */
21753a49c214SYang-Rong Jerry Zhou cTmp = pci_config_get8(statep->hda_pci_handle,
21763a49c214SYang-Rong Jerry Zhou AUDIOHD_CORB_SIZE_OFF);
21773a49c214SYang-Rong Jerry Zhou pci_config_put8(statep->hda_pci_handle, AUDIOHD_CORB_SIZE_OFF,
21783a49c214SYang-Rong Jerry Zhou cTmp | AUDIOHD_NVIDIA_SNOOP);
217914707ff3Scg break;
218014707ff3Scg default:
218114707ff3Scg break;
218214707ff3Scg }
2183582eadeeSfl
2184c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
2185582eadeeSfl } /* audiohd_init_pci() */
2186582eadeeSfl
2187582eadeeSfl
2188582eadeeSfl /*
2189582eadeeSfl * audiohd_fini_pci()
2190582eadeeSfl *
2191582eadeeSfl * Description
2192582eadeeSfl * Release mapping for PCI configure space.
2193582eadeeSfl */
2194582eadeeSfl static void
audiohd_fini_pci(audiohd_state_t * statep)2195582eadeeSfl audiohd_fini_pci(audiohd_state_t *statep)
2196582eadeeSfl {
2197582eadeeSfl if (statep->hda_reg_handle != NULL) {
2198582eadeeSfl ddi_regs_map_free(&statep->hda_reg_handle);
2199582eadeeSfl }
2200582eadeeSfl
2201582eadeeSfl if (statep->hda_pci_handle != NULL) {
2202582eadeeSfl pci_config_teardown(&statep->hda_pci_handle);
2203582eadeeSfl }
2204582eadeeSfl
2205582eadeeSfl } /* audiohd_fini_pci() */
2206582eadeeSfl
2207582eadeeSfl /*
2208582eadeeSfl * audiohd_stop_dma()
2209582eadeeSfl *
2210582eadeeSfl * Description
2211582eadeeSfl * Stop all DMA behaviors of controllers, for command I/O
2212582eadeeSfl * and each audio stream.
2213582eadeeSfl */
2214582eadeeSfl static void
audiohd_stop_dma(audiohd_state_t * statep)2215582eadeeSfl audiohd_stop_dma(audiohd_state_t *statep)
2216582eadeeSfl {
2217582eadeeSfl int i;
2218582eadeeSfl uint_t base;
2219582eadeeSfl uint8_t bTmp;
2220582eadeeSfl
2221582eadeeSfl AUDIOHD_REG_SET8(AUDIOHD_REG_CORBCTL, 0);
2222582eadeeSfl AUDIOHD_REG_SET8(AUDIOHD_REG_RIRBCTL, 0);
2223582eadeeSfl
2224582eadeeSfl base = AUDIOHD_REG_SD_BASE;
2225582eadeeSfl for (i = 0; i < statep->hda_streams_nums; i++) {
2226582eadeeSfl bTmp = AUDIOHD_REG_GET8(base + AUDIOHD_SDREG_OFFSET_CTL);
2227582eadeeSfl
2228582eadeeSfl /* for input/output stream, it is the same */
2229582eadeeSfl bTmp &= ~AUDIOHDR_RIRBCTL_DMARUN;
2230582eadeeSfl
2231582eadeeSfl AUDIOHD_REG_SET8(base + AUDIOHD_SDREG_OFFSET_CTL, bTmp);
2232582eadeeSfl base += AUDIOHD_REG_SD_LEN;
2233582eadeeSfl }
2234582eadeeSfl
2235582eadeeSfl /* wait 40us for stream DMA to stop */
2236582eadeeSfl drv_usecwait(40);
2237582eadeeSfl
2238582eadeeSfl } /* audiohd_stop_dma() */
2239582eadeeSfl
2240582eadeeSfl /*
2241582eadeeSfl * audiohd_reset_controller()
2242582eadeeSfl *
2243582eadeeSfl * Description:
2244582eadeeSfl * This routine is just used to reset controller and
2245582eadeeSfl * CODEC as well by HW reset bit in global control
2246582eadeeSfl * register of HD controller.
2247582eadeeSfl */
2248582eadeeSfl static int
audiohd_reset_controller(audiohd_state_t * statep)2249582eadeeSfl audiohd_reset_controller(audiohd_state_t *statep)
2250582eadeeSfl {
2251582eadeeSfl int i;
22523a49c214SYang-Rong Jerry Zhou uint16_t sTmp;
22533a49c214SYang-Rong Jerry Zhou uint32_t gctl;
22543a49c214SYang-Rong Jerry Zhou
22553a49c214SYang-Rong Jerry Zhou /* Reset Status register but preserve the first bit */
22563a49c214SYang-Rong Jerry Zhou sTmp = AUDIOHD_REG_GET16(AUDIOHD_REG_STATESTS);
22573a49c214SYang-Rong Jerry Zhou AUDIOHD_REG_SET16(AUDIOHD_REG_STATESTS, sTmp & 0x8000);
2258582eadeeSfl
2259582eadeeSfl /* reset controller */
22603a49c214SYang-Rong Jerry Zhou gctl = AUDIOHD_REG_GET32(AUDIOHD_REG_GCTL);
22613a49c214SYang-Rong Jerry Zhou gctl &= ~AUDIOHDR_GCTL_CRST;
22623a49c214SYang-Rong Jerry Zhou AUDIOHD_REG_SET32(AUDIOHD_REG_GCTL, gctl); /* entering reset state */
22633a49c214SYang-Rong Jerry Zhou for (i = 0; i < AUDIOHD_RETRY_TIMES; i++) {
22643a49c214SYang-Rong Jerry Zhou /* Empirical testing time: 150 */
22653a49c214SYang-Rong Jerry Zhou drv_usecwait(150);
22663a49c214SYang-Rong Jerry Zhou gctl = AUDIOHD_REG_GET32(AUDIOHD_REG_GCTL);
22673a49c214SYang-Rong Jerry Zhou if ((gctl & AUDIOHDR_GCTL_CRST) == 0)
2268582eadeeSfl break;
2269582eadeeSfl }
2270582eadeeSfl
22713a49c214SYang-Rong Jerry Zhou if ((gctl & AUDIOHDR_GCTL_CRST) != 0) {
227288447a05SGarrett D'Amore audio_dev_warn(statep->adev,
227388447a05SGarrett D'Amore "failed to enter reset state");
2274c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
2275582eadeeSfl }
2276582eadeeSfl
22773a49c214SYang-Rong Jerry Zhou /* Empirical testing time:300 */
2278582eadeeSfl drv_usecwait(300);
2279582eadeeSfl
2280582eadeeSfl /* exit reset state */
22813a49c214SYang-Rong Jerry Zhou AUDIOHD_REG_SET32(AUDIOHD_REG_GCTL, gctl | AUDIOHDR_GCTL_CRST);
2282582eadeeSfl
22833a49c214SYang-Rong Jerry Zhou for (i = 0; i < AUDIOHD_RETRY_TIMES; i++) {
22843a49c214SYang-Rong Jerry Zhou /* Empirical testing time: 150, which works well */
22853a49c214SYang-Rong Jerry Zhou drv_usecwait(150);
22863a49c214SYang-Rong Jerry Zhou gctl = AUDIOHD_REG_GET32(AUDIOHD_REG_GCTL);
22873a49c214SYang-Rong Jerry Zhou if (gctl & AUDIOHDR_GCTL_CRST)
2288582eadeeSfl break;
2289582eadeeSfl }
2290582eadeeSfl
22913a49c214SYang-Rong Jerry Zhou if ((gctl & AUDIOHDR_GCTL_CRST) == 0) {
229288447a05SGarrett D'Amore audio_dev_warn(statep->adev,
229388447a05SGarrett D'Amore "failed to exit reset state");
2294c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
2295582eadeeSfl }
2296582eadeeSfl
22973a49c214SYang-Rong Jerry Zhou /* HD spec requires to wait 250us at least. we use 500us */
22983a49c214SYang-Rong Jerry Zhou drv_usecwait(500);
22993a49c214SYang-Rong Jerry Zhou
2300582eadeeSfl /* enable unsolicited response */
2301582eadeeSfl AUDIOHD_REG_SET32(AUDIOHD_REG_GCTL,
23023a49c214SYang-Rong Jerry Zhou gctl | AUDIOHDR_GCTL_URESPE);
2303582eadeeSfl
2304c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
2305582eadeeSfl
2306582eadeeSfl } /* audiohd_reset_controller() */
2307582eadeeSfl
2308582eadeeSfl /*
2309582eadeeSfl * audiohd_alloc_dma_mem()
2310582eadeeSfl *
2311582eadeeSfl * Description:
2312582eadeeSfl * This is an utility routine. It is used to allocate DMA
2313582eadeeSfl * memory.
2314582eadeeSfl */
2315582eadeeSfl static int
audiohd_alloc_dma_mem(audiohd_state_t * statep,audiohd_dma_t * pdma,size_t memsize,ddi_dma_attr_t * dma_attr_p,uint_t dma_flags)2316582eadeeSfl audiohd_alloc_dma_mem(audiohd_state_t *statep, audiohd_dma_t *pdma,
2317582eadeeSfl size_t memsize, ddi_dma_attr_t *dma_attr_p, uint_t dma_flags)
2318582eadeeSfl {
2319582eadeeSfl ddi_dma_cookie_t cookie;
2320582eadeeSfl uint_t count;
2321582eadeeSfl dev_info_t *dip = statep->hda_dip;
232288447a05SGarrett D'Amore audio_dev_t *ahandle = statep->adev;
2323582eadeeSfl
2324582eadeeSfl if (ddi_dma_alloc_handle(dip, dma_attr_p, DDI_DMA_SLEEP,
232588447a05SGarrett D'Amore NULL, &pdma->ad_dmahdl) != DDI_SUCCESS) {
232688447a05SGarrett D'Amore audio_dev_warn(ahandle,
232788447a05SGarrett D'Amore "ddi_dma_alloc_handle failed");
2328c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
2329582eadeeSfl }
2330582eadeeSfl
2331582eadeeSfl if (ddi_dma_mem_alloc(pdma->ad_dmahdl, memsize, &hda_dev_accattr,
2332582eadeeSfl dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
23333a49c214SYang-Rong Jerry Zhou DDI_DMA_SLEEP, NULL,
23343a49c214SYang-Rong Jerry Zhou (caddr_t *)&pdma->ad_vaddr, &pdma->ad_real_sz,
23353a49c214SYang-Rong Jerry Zhou &pdma->ad_acchdl) != DDI_SUCCESS) {
233688447a05SGarrett D'Amore audio_dev_warn(ahandle,
233788447a05SGarrett D'Amore "ddi_dma_mem_alloc failed");
2338c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
2339582eadeeSfl }
2340582eadeeSfl
2341582eadeeSfl if (ddi_dma_addr_bind_handle(pdma->ad_dmahdl, NULL,
2342582eadeeSfl (caddr_t)pdma->ad_vaddr, pdma->ad_real_sz, dma_flags,
2343582eadeeSfl DDI_DMA_SLEEP, NULL, &cookie, &count) != DDI_DMA_MAPPED) {
234488447a05SGarrett D'Amore audio_dev_warn(ahandle,
234588447a05SGarrett D'Amore "ddi_dma_addr_bind_handle failed");
2346c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
2347582eadeeSfl }
2348582eadeeSfl
2349555989a4Scg pdma->ad_paddr = (uint64_t)(cookie.dmac_laddress);
2350582eadeeSfl pdma->ad_req_sz = memsize;
2351582eadeeSfl
2352c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
2353582eadeeSfl } /* audiohd_alloc_dma_mem() */
2354582eadeeSfl
2355582eadeeSfl /*
2356582eadeeSfl * audiohd_release_dma_mem()
2357582eadeeSfl *
2358582eadeeSfl * Description:
2359582eadeeSfl * Release DMA memory.
2360582eadeeSfl */
2361582eadeeSfl
2362582eadeeSfl static void
audiohd_release_dma_mem(audiohd_dma_t * pdma)2363582eadeeSfl audiohd_release_dma_mem(audiohd_dma_t *pdma)
2364582eadeeSfl {
2365582eadeeSfl if (pdma->ad_dmahdl != NULL) {
2366582eadeeSfl (void) ddi_dma_unbind_handle(pdma->ad_dmahdl);
2367582eadeeSfl }
2368582eadeeSfl
2369582eadeeSfl if (pdma->ad_acchdl != NULL) {
2370582eadeeSfl ddi_dma_mem_free(&pdma->ad_acchdl);
2371582eadeeSfl pdma->ad_acchdl = NULL;
2372582eadeeSfl }
2373582eadeeSfl
2374582eadeeSfl if (pdma->ad_dmahdl != NULL) {
2375582eadeeSfl ddi_dma_free_handle(&pdma->ad_dmahdl);
2376582eadeeSfl pdma->ad_dmahdl = NULL;
2377582eadeeSfl }
2378582eadeeSfl
2379582eadeeSfl } /* audiohd_release_dma_mem() */
2380582eadeeSfl
2381d5247f45Sgs /*
2382d5247f45Sgs * audiohd_reinit_hda()
2383d5247f45Sgs *
2384d5247f45Sgs * Description:
2385d5247f45Sgs * This routine is used to re-initialize HD controller and codec.
2386d5247f45Sgs */
2387d5247f45Sgs static int
audiohd_reinit_hda(audiohd_state_t * statep)2388d5247f45Sgs audiohd_reinit_hda(audiohd_state_t *statep)
2389d5247f45Sgs {
2390d5247f45Sgs uint64_t addr;
2391d5247f45Sgs
2392d5247f45Sgs /* set PCI configure space in case it's not restored OK */
2393d5247f45Sgs (void) audiohd_init_pci(statep, &hda_dev_accattr);
2394d5247f45Sgs
2395d5247f45Sgs /* reset controller */
2396c6e681c0SYang-Rong Jerry Zhou if (audiohd_reset_controller(statep) != DDI_SUCCESS)
2397c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
2398d5247f45Sgs AUDIOHD_REG_SET32(AUDIOHD_REG_SYNC, 0); /* needn't sync stream */
2399d5247f45Sgs
2400d5247f45Sgs /* Initialize controller RIRB */
2401d5247f45Sgs addr = statep->hda_dma_rirb.ad_paddr;
2402d5247f45Sgs AUDIOHD_REG_SET32(AUDIOHD_REG_RIRBLBASE, (uint32_t)addr);
2403d5247f45Sgs AUDIOHD_REG_SET32(AUDIOHD_REG_RIRBUBASE,
2404d5247f45Sgs (uint32_t)(addr >> 32));
2405d5247f45Sgs AUDIOHD_REG_SET16(AUDIOHD_REG_RIRBWP, AUDIOHDR_RIRBWP_RESET);
2406d5247f45Sgs AUDIOHD_REG_SET8(AUDIOHD_REG_RIRBSIZE, AUDIOHDR_RIRBSZ_256);
24073a49c214SYang-Rong Jerry Zhou AUDIOHD_REG_SET8(AUDIOHD_REG_RIRBCTL, AUDIOHDR_RIRBCTL_DMARUN |
24083a49c214SYang-Rong Jerry Zhou AUDIOHDR_RIRBCTL_RINTCTL);
2409d5247f45Sgs
2410d5247f45Sgs /* Initialize controller CORB */
2411d5247f45Sgs addr = statep->hda_dma_corb.ad_paddr;
2412d5247f45Sgs AUDIOHD_REG_SET16(AUDIOHD_REG_CORBRP, AUDIOHDR_CORBRP_RESET);
2413d5247f45Sgs AUDIOHD_REG_SET32(AUDIOHD_REG_CORBLBASE, (uint32_t)addr);
2414d5247f45Sgs AUDIOHD_REG_SET32(AUDIOHD_REG_CORBUBASE,
2415d5247f45Sgs (uint32_t)(addr >> 32));
2416d5247f45Sgs AUDIOHD_REG_SET8(AUDIOHD_REG_CORBSIZE, AUDIOHDR_CORBSZ_256);
2417d5247f45Sgs AUDIOHD_REG_SET16(AUDIOHD_REG_CORBWP, 0);
2418d5247f45Sgs AUDIOHD_REG_SET16(AUDIOHD_REG_CORBRP, 0);
2419d5247f45Sgs AUDIOHD_REG_SET8(AUDIOHD_REG_CORBCTL, AUDIOHDR_CORBCTL_DMARUN);
2420d5247f45Sgs
242116600ba1SYang-Rong Jerry Zhou audiohd_restore_codec_gpio(statep);
24223a49c214SYang-Rong Jerry Zhou audiohd_restore_path(statep);
242388447a05SGarrett D'Amore audiohd_init_path(statep);
242488447a05SGarrett D'Amore
2425c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
24263a49c214SYang-Rong Jerry Zhou } /* audiohd_reinit_hda */
2427d5247f45Sgs
2428582eadeeSfl /*
2429582eadeeSfl * audiohd_init_controller()
2430582eadeeSfl *
2431582eadeeSfl * Description:
2432582eadeeSfl * This routine is used to initialize HD controller. It
2433582eadeeSfl * allocates DMA memory for CORB/RIRB, buffer descriptor
2434582eadeeSfl * list and cylic data buffer for both play and record
2435582eadeeSfl * stream.
2436582eadeeSfl */
2437582eadeeSfl static int
audiohd_init_controller(audiohd_state_t * statep)2438582eadeeSfl audiohd_init_controller(audiohd_state_t *statep)
2439582eadeeSfl {
2440555989a4Scg uint64_t addr;
2441582eadeeSfl uint16_t gcap;
2442582eadeeSfl int retval;
2443582eadeeSfl
2444582eadeeSfl ddi_dma_attr_t dma_attr = {
2445582eadeeSfl DMA_ATTR_V0, /* version */
2446582eadeeSfl 0, /* addr_lo */
2447555989a4Scg 0xffffffffffffffffULL, /* addr_hi */
2448555989a4Scg 0x00000000ffffffffULL, /* count_max */
2449582eadeeSfl 128, /* 128-byte alignment as HD spec */
2450582eadeeSfl 0xfff, /* burstsize */
2451582eadeeSfl 1, /* minxfer */
2452582eadeeSfl 0xffffffff, /* maxxfer */
2453582eadeeSfl 0xffffffff, /* seg */
2454582eadeeSfl 1, /* sgllen */
2455582eadeeSfl 1, /* granular */
2456582eadeeSfl 0 /* flags */
2457582eadeeSfl };
2458582eadeeSfl
2459582eadeeSfl gcap = AUDIOHD_REG_GET16(AUDIOHD_REG_GCAP);
2460555989a4Scg
2461555989a4Scg /*
2462555989a4Scg * If the device doesn't support 64-bit DMA, we should not
2463555989a4Scg * allocate DMA memory from 4G above
2464555989a4Scg */
2465555989a4Scg if ((gcap & AUDIOHDR_GCAP_64OK) == 0)
2466555989a4Scg dma_attr.dma_attr_addr_hi = 0xffffffffUL;
2467555989a4Scg
24683a49c214SYang-Rong Jerry Zhou statep->hda_input_streams = (gcap & AUDIOHDR_GCAP_INSTREAMS) >>
24693a49c214SYang-Rong Jerry Zhou AUDIOHD_INSTR_NUM_OFF;
24703a49c214SYang-Rong Jerry Zhou statep->hda_output_streams = (gcap & AUDIOHDR_GCAP_OUTSTREAMS) >>
24713a49c214SYang-Rong Jerry Zhou AUDIOHD_OUTSTR_NUM_OFF;
2472582eadeeSfl statep->hda_streams_nums = statep->hda_input_streams +
2473582eadeeSfl statep->hda_output_streams;
2474582eadeeSfl
2475582eadeeSfl statep->hda_record_regbase = AUDIOHD_REG_SD_BASE;
2476582eadeeSfl statep->hda_play_regbase = AUDIOHD_REG_SD_BASE + AUDIOHD_REG_SD_LEN *
2477582eadeeSfl statep->hda_input_streams;
2478582eadeeSfl
2479582eadeeSfl /* stop all dma before starting to reset controller */
2480582eadeeSfl audiohd_stop_dma(statep);
2481582eadeeSfl
2482c6e681c0SYang-Rong Jerry Zhou if (audiohd_reset_controller(statep) != DDI_SUCCESS)
2483c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
2484582eadeeSfl
2485582eadeeSfl /* check codec */
2486582eadeeSfl statep->hda_codec_mask = AUDIOHD_REG_GET16(AUDIOHD_REG_STATESTS);
2487c6e681c0SYang-Rong Jerry Zhou if (!statep->hda_codec_mask) {
248888447a05SGarrett D'Amore audio_dev_warn(statep->adev,
248988447a05SGarrett D'Amore "no codec exists");
2490c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
2491582eadeeSfl }
2492582eadeeSfl
2493582eadeeSfl /* allocate DMA for CORB */
2494582eadeeSfl retval = audiohd_alloc_dma_mem(statep, &statep->hda_dma_corb,
2495582eadeeSfl AUDIOHD_CDBIO_CORB_LEN, &dma_attr,
2496a234d95bScg DDI_DMA_WRITE | DDI_DMA_STREAMING);
2497c6e681c0SYang-Rong Jerry Zhou if (retval != DDI_SUCCESS) {
249888447a05SGarrett D'Amore audio_dev_warn(statep->adev,
249988447a05SGarrett D'Amore "failed to alloc DMA for CORB");
2500c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
2501582eadeeSfl }
2502582eadeeSfl
2503582eadeeSfl /* allocate DMA for RIRB */
2504582eadeeSfl retval = audiohd_alloc_dma_mem(statep, &statep->hda_dma_rirb,
2505582eadeeSfl AUDIOHD_CDBIO_RIRB_LEN, &dma_attr,
2506a234d95bScg DDI_DMA_READ | DDI_DMA_STREAMING);
2507c6e681c0SYang-Rong Jerry Zhou if (retval != DDI_SUCCESS) {
250888447a05SGarrett D'Amore audio_dev_warn(statep->adev,
250988447a05SGarrett D'Amore "failed to alloc DMA for RIRB");
2510c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
2511582eadeeSfl }
2512582eadeeSfl
2513582eadeeSfl AUDIOHD_REG_SET32(AUDIOHD_REG_SYNC, 0); /* needn't sync stream */
2514582eadeeSfl
2515582eadeeSfl /* Initialize RIRB */
2516582eadeeSfl addr = statep->hda_dma_rirb.ad_paddr;
2517555989a4Scg AUDIOHD_REG_SET32(AUDIOHD_REG_RIRBLBASE, (uint32_t)addr);
2518c7b817cfSZhao Edgar Liu - Sun Microsystems AUDIOHD_REG_SET32(AUDIOHD_REG_RIRBUBASE, (uint32_t)(addr >> 32));
2519582eadeeSfl AUDIOHD_REG_SET16(AUDIOHD_REG_RIRBWP, AUDIOHDR_RIRBWP_RESET);
2520582eadeeSfl AUDIOHD_REG_SET8(AUDIOHD_REG_RIRBSIZE, AUDIOHDR_RIRBSZ_256);
25213a49c214SYang-Rong Jerry Zhou AUDIOHD_REG_SET8(AUDIOHD_REG_RIRBCTL, AUDIOHDR_RIRBCTL_DMARUN |
25223a49c214SYang-Rong Jerry Zhou AUDIOHDR_RIRBCTL_RINTCTL);
2523582eadeeSfl
2524582eadeeSfl /* initialize CORB */
2525582eadeeSfl addr = statep->hda_dma_corb.ad_paddr;
2526582eadeeSfl AUDIOHD_REG_SET16(AUDIOHD_REG_CORBRP, AUDIOHDR_CORBRP_RESET);
2527555989a4Scg AUDIOHD_REG_SET32(AUDIOHD_REG_CORBLBASE, (uint32_t)addr);
2528c7b817cfSZhao Edgar Liu - Sun Microsystems AUDIOHD_REG_SET32(AUDIOHD_REG_CORBUBASE, (uint32_t)(addr >> 32));
2529582eadeeSfl AUDIOHD_REG_SET8(AUDIOHD_REG_CORBSIZE, AUDIOHDR_CORBSZ_256);
2530582eadeeSfl AUDIOHD_REG_SET16(AUDIOHD_REG_CORBWP, 0);
2531582eadeeSfl AUDIOHD_REG_SET16(AUDIOHD_REG_CORBRP, 0);
2532582eadeeSfl AUDIOHD_REG_SET8(AUDIOHD_REG_CORBCTL, AUDIOHDR_CORBCTL_DMARUN);
2533582eadeeSfl
2534c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
2535582eadeeSfl } /* audiohd_init_controller() */
2536582eadeeSfl
2537582eadeeSfl /*
2538582eadeeSfl * audiohd_fini_controller()
2539582eadeeSfl *
2540582eadeeSfl * Description:
2541582eadeeSfl * Releases DMA memory allocated in audiohd_init_controller()
2542582eadeeSfl */
2543582eadeeSfl static void
audiohd_fini_controller(audiohd_state_t * statep)2544582eadeeSfl audiohd_fini_controller(audiohd_state_t *statep)
2545582eadeeSfl {
2546582eadeeSfl audiohd_release_dma_mem(&statep->hda_dma_rirb);
2547582eadeeSfl audiohd_release_dma_mem(&statep->hda_dma_corb);
2548582eadeeSfl
2549582eadeeSfl } /* audiohd_fini_controller() */
2550582eadeeSfl
25513a49c214SYang-Rong Jerry Zhou /*
25523a49c214SYang-Rong Jerry Zhou * audiohd_get_conns_from_entry()
25533a49c214SYang-Rong Jerry Zhou *
25543a49c214SYang-Rong Jerry Zhou * Description:
25553a49c214SYang-Rong Jerry Zhou * Get connection list from every entry for a widget
25563a49c214SYang-Rong Jerry Zhou */
25573a49c214SYang-Rong Jerry Zhou static void
audiohd_get_conns_from_entry(hda_codec_t * codec,audiohd_widget_t * widget,uint32_t entry,audiohd_entry_prop_t * prop)25583a49c214SYang-Rong Jerry Zhou audiohd_get_conns_from_entry(hda_codec_t *codec, audiohd_widget_t *widget,
25593a49c214SYang-Rong Jerry Zhou uint32_t entry, audiohd_entry_prop_t *prop)
25603a49c214SYang-Rong Jerry Zhou {
25613a49c214SYang-Rong Jerry Zhou int i, k, num;
25623a49c214SYang-Rong Jerry Zhou wid_t input_wid;
25633a49c214SYang-Rong Jerry Zhou
25643a49c214SYang-Rong Jerry Zhou for (i = 0; i < prop->conns_per_entry &&
25653a49c214SYang-Rong Jerry Zhou widget->nconns < prop->conn_len;
25663a49c214SYang-Rong Jerry Zhou i++, entry >>= prop->bits_per_conn) {
25673a49c214SYang-Rong Jerry Zhou ASSERT(widget->nconns < AUDIOHD_MAX_CONN);
25683a49c214SYang-Rong Jerry Zhou input_wid = entry & prop->mask_wid;
25693a49c214SYang-Rong Jerry Zhou if (entry & prop->mask_range) {
25703a49c214SYang-Rong Jerry Zhou if (widget->nconns == 0) {
25713a49c214SYang-Rong Jerry Zhou if (input_wid < codec->first_wid ||
25723a49c214SYang-Rong Jerry Zhou (input_wid > codec->last_wid)) {
25733a49c214SYang-Rong Jerry Zhou break;
25743a49c214SYang-Rong Jerry Zhou }
25753a49c214SYang-Rong Jerry Zhou widget->avail_conn[widget->nconns++] =
25763a49c214SYang-Rong Jerry Zhou input_wid;
25773a49c214SYang-Rong Jerry Zhou } else {
25783a49c214SYang-Rong Jerry Zhou for (k = widget->avail_conn[widget->nconns-1] +
25793a49c214SYang-Rong Jerry Zhou 1; k <= input_wid; k++) {
25803a49c214SYang-Rong Jerry Zhou ASSERT(widget->nconns <
25813a49c214SYang-Rong Jerry Zhou AUDIOHD_MAX_CONN);
25823a49c214SYang-Rong Jerry Zhou if (k < codec->first_wid ||
25833a49c214SYang-Rong Jerry Zhou (k > codec->last_wid)) {
25843a49c214SYang-Rong Jerry Zhou break;
25853a49c214SYang-Rong Jerry Zhou } else {
25863a49c214SYang-Rong Jerry Zhou num = widget->nconns;
25873a49c214SYang-Rong Jerry Zhou widget->avail_conn[num] = k;
25883a49c214SYang-Rong Jerry Zhou widget->nconns++;
25893a49c214SYang-Rong Jerry Zhou }
25903a49c214SYang-Rong Jerry Zhou }
25913a49c214SYang-Rong Jerry Zhou }
25923a49c214SYang-Rong Jerry Zhou } else {
259316600ba1SYang-Rong Jerry Zhou if ((codec->first_wid <= input_wid) && (input_wid <=
259416600ba1SYang-Rong Jerry Zhou codec->last_wid))
259516600ba1SYang-Rong Jerry Zhou widget->avail_conn[widget->nconns++] =
259616600ba1SYang-Rong Jerry Zhou input_wid;
25973a49c214SYang-Rong Jerry Zhou }
25983a49c214SYang-Rong Jerry Zhou }
25993a49c214SYang-Rong Jerry Zhou }
26003a49c214SYang-Rong Jerry Zhou
26013a49c214SYang-Rong Jerry Zhou /*
26023a49c214SYang-Rong Jerry Zhou * audiohd_get_conns()
26033a49c214SYang-Rong Jerry Zhou *
26043a49c214SYang-Rong Jerry Zhou * Description:
26053a49c214SYang-Rong Jerry Zhou * Get all connection list for a widget. The connection list is used for
26063a49c214SYang-Rong Jerry Zhou * build output path, input path, and monitor path
26073a49c214SYang-Rong Jerry Zhou */
26083a49c214SYang-Rong Jerry Zhou static void
audiohd_get_conns(hda_codec_t * codec,wid_t wid)26093a49c214SYang-Rong Jerry Zhou audiohd_get_conns(hda_codec_t *codec, wid_t wid)
26103a49c214SYang-Rong Jerry Zhou {
2611ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
26123a49c214SYang-Rong Jerry Zhou audiohd_widget_t *widget = codec->widget[wid];
26133a49c214SYang-Rong Jerry Zhou uint8_t caddr = codec->index;
26143a49c214SYang-Rong Jerry Zhou uint32_t entry;
26153a49c214SYang-Rong Jerry Zhou audiohd_entry_prop_t prop;
26163a49c214SYang-Rong Jerry Zhou wid_t input_wid;
26173a49c214SYang-Rong Jerry Zhou int i;
26183a49c214SYang-Rong Jerry Zhou
26193a49c214SYang-Rong Jerry Zhou prop.conn_len = audioha_codec_verb_get(statep, caddr, wid,
26203a49c214SYang-Rong Jerry Zhou AUDIOHDC_VERB_GET_PARAM, AUDIOHDC_PAR_CONNLIST_LEN);
26213a49c214SYang-Rong Jerry Zhou
26223a49c214SYang-Rong Jerry Zhou if (prop.conn_len & AUDIOHD_FORM_MASK) {
26233a49c214SYang-Rong Jerry Zhou prop.conns_per_entry = 2;
26243a49c214SYang-Rong Jerry Zhou prop.bits_per_conn = 16;
26253a49c214SYang-Rong Jerry Zhou prop.mask_range = 0x00008000;
26263a49c214SYang-Rong Jerry Zhou prop.mask_wid = 0x00007fff;
26273a49c214SYang-Rong Jerry Zhou } else {
26283a49c214SYang-Rong Jerry Zhou prop.conns_per_entry = 4;
26293a49c214SYang-Rong Jerry Zhou prop.bits_per_conn = 8;
26303a49c214SYang-Rong Jerry Zhou prop.mask_range = 0x00000080;
26313a49c214SYang-Rong Jerry Zhou prop.mask_wid = 0x0000007f;
26323a49c214SYang-Rong Jerry Zhou }
26333a49c214SYang-Rong Jerry Zhou prop.conn_len &= AUDIOHD_LEN_MASK;
26343a49c214SYang-Rong Jerry Zhou
26353a49c214SYang-Rong Jerry Zhou /*
26363a49c214SYang-Rong Jerry Zhou * This should not happen since the ConnectionList bit of
26373a49c214SYang-Rong Jerry Zhou * widget capabilities already told us that this widget
26383a49c214SYang-Rong Jerry Zhou * has a connection list
26393a49c214SYang-Rong Jerry Zhou */
26403a49c214SYang-Rong Jerry Zhou if (prop.conn_len == 0) {
26413a49c214SYang-Rong Jerry Zhou widget->nconns = 0;
264207bec7ccSZhao Edgar Liu - Sun Microsystems audio_dev_warn(statep->adev,
264307bec7ccSZhao Edgar Liu - Sun Microsystems "node %d has 0 connections", wid);
26443a49c214SYang-Rong Jerry Zhou return;
26453a49c214SYang-Rong Jerry Zhou }
26463a49c214SYang-Rong Jerry Zhou
26473a49c214SYang-Rong Jerry Zhou if (prop.conn_len == 1) {
26483a49c214SYang-Rong Jerry Zhou entry = audioha_codec_verb_get(statep, caddr,
26493a49c214SYang-Rong Jerry Zhou wid, AUDIOHDC_VERB_GET_CONN_LIST_ENT, 0);
26503a49c214SYang-Rong Jerry Zhou input_wid = entry & prop.mask_wid;
26513a49c214SYang-Rong Jerry Zhou if ((input_wid < codec->first_wid) ||
26523a49c214SYang-Rong Jerry Zhou (input_wid > codec->last_wid)) {
26533a49c214SYang-Rong Jerry Zhou return;
26543a49c214SYang-Rong Jerry Zhou }
26553a49c214SYang-Rong Jerry Zhou widget->avail_conn[0] = input_wid;
26563a49c214SYang-Rong Jerry Zhou widget->nconns = 1;
26573a49c214SYang-Rong Jerry Zhou return;
26583a49c214SYang-Rong Jerry Zhou }
26593a49c214SYang-Rong Jerry Zhou widget->nconns = 0;
26603a49c214SYang-Rong Jerry Zhou for (i = 0; i < prop.conn_len; i += prop.conns_per_entry) {
26613a49c214SYang-Rong Jerry Zhou entry = audioha_codec_verb_get(statep, caddr, wid,
26623a49c214SYang-Rong Jerry Zhou AUDIOHDC_VERB_GET_CONN_LIST_ENT, i);
26633a49c214SYang-Rong Jerry Zhou audiohd_get_conns_from_entry(codec, widget, entry, &prop);
26643a49c214SYang-Rong Jerry Zhou }
26653a49c214SYang-Rong Jerry Zhou }
26663a49c214SYang-Rong Jerry Zhou
26673a49c214SYang-Rong Jerry Zhou /*
26683a49c214SYang-Rong Jerry Zhou * Read PinCapabilities & default configuration
26693a49c214SYang-Rong Jerry Zhou */
26703a49c214SYang-Rong Jerry Zhou static void
audiohd_get_pin_config(audiohd_widget_t * widget)26713a49c214SYang-Rong Jerry Zhou audiohd_get_pin_config(audiohd_widget_t *widget)
26723a49c214SYang-Rong Jerry Zhou {
26733a49c214SYang-Rong Jerry Zhou hda_codec_t *codec = widget->codec;
2674ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
26753a49c214SYang-Rong Jerry Zhou audiohd_pin_t *pin, *prev, *p;
26763a49c214SYang-Rong Jerry Zhou
26773a49c214SYang-Rong Jerry Zhou int caddr = codec->index;
26783a49c214SYang-Rong Jerry Zhou wid_t wid = widget->wid_wid;
26793a49c214SYang-Rong Jerry Zhou uint32_t cap, config, pinctrl;
2680d5145224SYang-Rong Jerry Zhou uint8_t urctrl, vrefbits;
26813a49c214SYang-Rong Jerry Zhou
26823a49c214SYang-Rong Jerry Zhou cap = audioha_codec_verb_get(statep, caddr, wid,
26833a49c214SYang-Rong Jerry Zhou AUDIOHDC_VERB_GET_PARAM, AUDIOHDC_PAR_PIN_CAP);
26843a49c214SYang-Rong Jerry Zhou config = audioha_codec_verb_get(statep, caddr,
26853a49c214SYang-Rong Jerry Zhou wid, AUDIOHDC_VERB_GET_DEFAULT_CONF, 0);
26863a49c214SYang-Rong Jerry Zhou pinctrl = audioha_codec_verb_get(statep, caddr,
26873a49c214SYang-Rong Jerry Zhou wid, AUDIOHDC_VERB_GET_PIN_CTRL, 0);
26883a49c214SYang-Rong Jerry Zhou
26893a49c214SYang-Rong Jerry Zhou pin = (audiohd_pin_t *)kmem_zalloc(sizeof (audiohd_pin_t), KM_SLEEP);
26903a49c214SYang-Rong Jerry Zhou widget->priv = pin;
26913a49c214SYang-Rong Jerry Zhou
26923a49c214SYang-Rong Jerry Zhou /*
26933a49c214SYang-Rong Jerry Zhou * If the pin has no physical connection for port,
26943a49c214SYang-Rong Jerry Zhou * we won't link it to pin linkage list ???
26953a49c214SYang-Rong Jerry Zhou */
26963a49c214SYang-Rong Jerry Zhou if (((config >> AUDIOHD_PIN_CON_STEP) & AUDIOHD_PIN_CON_MASK) == 0x1) {
26973a49c214SYang-Rong Jerry Zhou pin->no_phys_conn = 1;
26983a49c214SYang-Rong Jerry Zhou }
26993a49c214SYang-Rong Jerry Zhou
27003a49c214SYang-Rong Jerry Zhou /* bit 4:3 are reserved, read-modify-write is needed */
27013a49c214SYang-Rong Jerry Zhou pin->ctrl = pinctrl & AUDIOHD_PIN_IO_MASK;
27023a49c214SYang-Rong Jerry Zhou pin->wid = wid;
27033a49c214SYang-Rong Jerry Zhou pin->cap = cap;
27043a49c214SYang-Rong Jerry Zhou pin->config = config;
27053a49c214SYang-Rong Jerry Zhou pin->num = 0;
27063a49c214SYang-Rong Jerry Zhou pin->finish = 0;
270788447a05SGarrett D'Amore
2708d5145224SYang-Rong Jerry Zhou vrefbits = (cap >> AUDIOHD_PIN_VREF_OFF) & AUDIOHD_PIN_VREF_MASK;
2709d5145224SYang-Rong Jerry Zhou if (vrefbits & AUDIOHD_PIN_VREF_L1)
2710d5145224SYang-Rong Jerry Zhou pin->vrefvalue = 0x5;
2711d5145224SYang-Rong Jerry Zhou else if (vrefbits & AUDIOHD_PIN_VREF_L2)
2712d5145224SYang-Rong Jerry Zhou pin->vrefvalue = 0x4;
2713d5145224SYang-Rong Jerry Zhou else if (vrefbits & AUDIOHD_PIN_VREF_L3)
2714d5145224SYang-Rong Jerry Zhou pin->vrefvalue = 0x2;
2715d5145224SYang-Rong Jerry Zhou else
2716d5145224SYang-Rong Jerry Zhou pin->vrefvalue = 0x1;
27173a49c214SYang-Rong Jerry Zhou
27183a49c214SYang-Rong Jerry Zhou pin->seq = config & AUDIOHD_PIN_SEQ_MASK;
27193a49c214SYang-Rong Jerry Zhou pin->assoc = (config & AUDIOHD_PIN_ASO_MASK) >> AUDIOHD_PIN_ASO_OFF;
27203a49c214SYang-Rong Jerry Zhou pin->device = (config & AUDIOHD_PIN_DEV_MASK) >> AUDIOHD_PIN_DEV_OFF;
27213a49c214SYang-Rong Jerry Zhou
27223a49c214SYang-Rong Jerry Zhou /* enable the unsolicited response of the pin */
272316600ba1SYang-Rong Jerry Zhou if ((widget->widget_cap & AUDIOHD_URCAP_MASK) &&
272416600ba1SYang-Rong Jerry Zhou (pin->cap & AUDIOHD_DTCCAP_MASK) &&
27253a49c214SYang-Rong Jerry Zhou ((pin->device == DTYPE_LINEOUT) ||
27263a49c214SYang-Rong Jerry Zhou (pin->device == DTYPE_SPDIF_OUT) ||
27273a49c214SYang-Rong Jerry Zhou (pin->device == DTYPE_HP_OUT) ||
27283a49c214SYang-Rong Jerry Zhou (pin->device == DTYPE_MIC_IN))) {
27293a49c214SYang-Rong Jerry Zhou urctrl = (uint8_t)(1 << (AUDIOHD_UR_ENABLE_OFF - 1));
27303a49c214SYang-Rong Jerry Zhou urctrl |= (wid & AUDIOHD_UR_TAG_MASK);
27313a49c214SYang-Rong Jerry Zhou (void) audioha_codec_verb_get(statep, caddr,
2732989b958fSZhao Edgar Liu - Sun Microsystems wid, AUDIOHDC_VERB_SET_UNS_ENABLE, urctrl);
27333a49c214SYang-Rong Jerry Zhou }
27343a49c214SYang-Rong Jerry Zhou /* accommodate all the pins in a link list sorted by assoc and seq */
27353a49c214SYang-Rong Jerry Zhou if (codec->first_pin == NULL) {
27363a49c214SYang-Rong Jerry Zhou codec->first_pin = pin;
27373a49c214SYang-Rong Jerry Zhou } else {
27383a49c214SYang-Rong Jerry Zhou prev = NULL;
27393a49c214SYang-Rong Jerry Zhou p = codec->first_pin;
27403a49c214SYang-Rong Jerry Zhou while (p) {
27413a49c214SYang-Rong Jerry Zhou if (p->assoc > pin->assoc)
27423a49c214SYang-Rong Jerry Zhou break;
27433a49c214SYang-Rong Jerry Zhou if ((p->assoc == pin->assoc) &&
27443a49c214SYang-Rong Jerry Zhou (p->seq > pin->seq))
27453a49c214SYang-Rong Jerry Zhou break;
27463a49c214SYang-Rong Jerry Zhou prev = p;
27473a49c214SYang-Rong Jerry Zhou p = p->next;
27483a49c214SYang-Rong Jerry Zhou }
27493a49c214SYang-Rong Jerry Zhou if (prev) {
27503a49c214SYang-Rong Jerry Zhou pin->next = prev->next;
27513a49c214SYang-Rong Jerry Zhou prev->next = pin;
27523a49c214SYang-Rong Jerry Zhou } else {
27533a49c214SYang-Rong Jerry Zhou pin->next = codec->first_pin;
27543a49c214SYang-Rong Jerry Zhou codec->first_pin = pin;
27553a49c214SYang-Rong Jerry Zhou }
27563a49c214SYang-Rong Jerry Zhou }
27573a49c214SYang-Rong Jerry Zhou
27583a49c214SYang-Rong Jerry Zhou } /* audiohd_get_pin_config() */
27593a49c214SYang-Rong Jerry Zhou
27603a49c214SYang-Rong Jerry Zhou /*
27613a49c214SYang-Rong Jerry Zhou * audiohd_create_widgets()
27623a49c214SYang-Rong Jerry Zhou *
27633a49c214SYang-Rong Jerry Zhou * Description:
27643a49c214SYang-Rong Jerry Zhou * All widgets are created and stored in an array of codec
27653a49c214SYang-Rong Jerry Zhou */
27663a49c214SYang-Rong Jerry Zhou static int
audiohd_create_widgets(hda_codec_t * codec)27673a49c214SYang-Rong Jerry Zhou audiohd_create_widgets(hda_codec_t *codec)
27683a49c214SYang-Rong Jerry Zhou {
27693a49c214SYang-Rong Jerry Zhou audiohd_widget_t *widget;
2770ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
27713a49c214SYang-Rong Jerry Zhou wid_t wid;
27723a49c214SYang-Rong Jerry Zhou uint32_t type, widcap;
27733a49c214SYang-Rong Jerry Zhou int caddr = codec->index;
27743a49c214SYang-Rong Jerry Zhou
27753a49c214SYang-Rong Jerry Zhou for (wid = codec->first_wid;
27763a49c214SYang-Rong Jerry Zhou wid <= codec->last_wid; wid++) {
27773a49c214SYang-Rong Jerry Zhou widget = (audiohd_widget_t *)
27783a49c214SYang-Rong Jerry Zhou kmem_zalloc(sizeof (audiohd_widget_t), KM_SLEEP);
27793a49c214SYang-Rong Jerry Zhou codec->widget[wid] = widget;
27803a49c214SYang-Rong Jerry Zhou widget->codec = codec;
2781b96a6eceSZhao Edgar Liu - Sun Microsystems widget->output_path_next = AUDIOHD_NULL_CONN;
2782b96a6eceSZhao Edgar Liu - Sun Microsystems widget->input_path_next = AUDIOHD_NULL_CONN;
2783b96a6eceSZhao Edgar Liu - Sun Microsystems widget->beep_path_next = AUDIOHD_NULL_CONN;
2784e7236f70SZhao Edgar Liu - Sun Microsystems widget->loopback_path_next = AUDIOHD_NULL_CONN;
27853a49c214SYang-Rong Jerry Zhou
27863a49c214SYang-Rong Jerry Zhou widcap = audioha_codec_verb_get(statep, caddr, wid,
27873a49c214SYang-Rong Jerry Zhou AUDIOHDC_VERB_GET_PARAM, AUDIOHDC_PAR_AUDIO_WID_CAP);
27883a49c214SYang-Rong Jerry Zhou type = AUDIOHD_WIDCAP_TO_WIDTYPE(widcap);
27893a49c214SYang-Rong Jerry Zhou widget->wid_wid = wid;
27903a49c214SYang-Rong Jerry Zhou widget->type = type;
27913a49c214SYang-Rong Jerry Zhou widget->widget_cap = widcap;
27923a49c214SYang-Rong Jerry Zhou widget->finish = 0;
27933a49c214SYang-Rong Jerry Zhou widget->used = 0;
27943a49c214SYang-Rong Jerry Zhou
27953a49c214SYang-Rong Jerry Zhou /* if there's connection list */
27963a49c214SYang-Rong Jerry Zhou if (widcap & AUDIOHD_WIDCAP_CONNLIST) {
27973a49c214SYang-Rong Jerry Zhou audiohd_get_conns(codec, wid);
27983a49c214SYang-Rong Jerry Zhou }
27993a49c214SYang-Rong Jerry Zhou
28003a49c214SYang-Rong Jerry Zhou /* if power control, power it up to D0 state */
28013a49c214SYang-Rong Jerry Zhou if (widcap & AUDIOHD_WIDCAP_PWRCTRL) {
28023a49c214SYang-Rong Jerry Zhou (void) audioha_codec_verb_get(statep, caddr, wid,
28033a49c214SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_POWER_STATE, 0);
28043a49c214SYang-Rong Jerry Zhou }
28053a49c214SYang-Rong Jerry Zhou
28063a49c214SYang-Rong Jerry Zhou /*
28073a49c214SYang-Rong Jerry Zhou * if this widget has format override, we read it.
28083a49c214SYang-Rong Jerry Zhou * Otherwise, it uses the format of audio function.
28093a49c214SYang-Rong Jerry Zhou */
28103a49c214SYang-Rong Jerry Zhou if (widcap & AUDIOHD_WIDCAP_FMT_OVRIDE) {
28113a49c214SYang-Rong Jerry Zhou widget->pcm_format =
28123a49c214SYang-Rong Jerry Zhou audioha_codec_verb_get(statep, caddr, wid,
28133a49c214SYang-Rong Jerry Zhou AUDIOHDC_VERB_GET_PARAM, AUDIOHDC_PAR_PCM);
28143a49c214SYang-Rong Jerry Zhou } else {
28153a49c214SYang-Rong Jerry Zhou widget->pcm_format = codec->pcm_format;
28163a49c214SYang-Rong Jerry Zhou }
28173a49c214SYang-Rong Jerry Zhou
28183a49c214SYang-Rong Jerry Zhou /*
28193a49c214SYang-Rong Jerry Zhou * Input amplifier. Has the widget input amplifier ?
28203a49c214SYang-Rong Jerry Zhou */
28213a49c214SYang-Rong Jerry Zhou if (widcap & AUDIOHD_WIDCAP_INAMP) {
28223a49c214SYang-Rong Jerry Zhou /*
28233a49c214SYang-Rong Jerry Zhou * if overrided bit is 0, use the default
28243a49c214SYang-Rong Jerry Zhou * amplifier of audio function as HD spec.
28253a49c214SYang-Rong Jerry Zhou * Otherwise, we read it.
28263a49c214SYang-Rong Jerry Zhou */
28273a49c214SYang-Rong Jerry Zhou if ((widcap & AUDIOHD_WIDCAP_AMP_OVRIDE) == 0)
28283a49c214SYang-Rong Jerry Zhou widget->inamp_cap = codec->inamp_cap;
28293a49c214SYang-Rong Jerry Zhou else
28303a49c214SYang-Rong Jerry Zhou widget->inamp_cap =
28313a49c214SYang-Rong Jerry Zhou audioha_codec_verb_get(statep, caddr, wid,
28323a49c214SYang-Rong Jerry Zhou AUDIOHDC_VERB_GET_PARAM,
28333a49c214SYang-Rong Jerry Zhou AUDIOHDC_PAR_INAMP_CAP);
28343a49c214SYang-Rong Jerry Zhou } else {
28353a49c214SYang-Rong Jerry Zhou widget->inamp_cap = 0;
28363a49c214SYang-Rong Jerry Zhou }
28373a49c214SYang-Rong Jerry Zhou
28383a49c214SYang-Rong Jerry Zhou /*
28393a49c214SYang-Rong Jerry Zhou * output amplifier. Has this widget output amplifier ?
28403a49c214SYang-Rong Jerry Zhou */
28413a49c214SYang-Rong Jerry Zhou if (widcap & AUDIOHD_WIDCAP_OUTAMP) {
28423a49c214SYang-Rong Jerry Zhou if ((widcap & AUDIOHD_WIDCAP_AMP_OVRIDE) == 0)
28433a49c214SYang-Rong Jerry Zhou widget->outamp_cap = codec->outamp_cap;
28443a49c214SYang-Rong Jerry Zhou else
28453a49c214SYang-Rong Jerry Zhou widget->outamp_cap =
28463a49c214SYang-Rong Jerry Zhou audioha_codec_verb_get(statep, caddr, wid,
28473a49c214SYang-Rong Jerry Zhou AUDIOHDC_VERB_GET_PARAM,
28483a49c214SYang-Rong Jerry Zhou AUDIOHDC_PAR_OUTAMP_CAP);
28493a49c214SYang-Rong Jerry Zhou } else {
28503a49c214SYang-Rong Jerry Zhou widget->outamp_cap = 0;
28513a49c214SYang-Rong Jerry Zhou }
28523a49c214SYang-Rong Jerry Zhou
28533a49c214SYang-Rong Jerry Zhou switch (type) {
28543a49c214SYang-Rong Jerry Zhou case WTYPE_AUDIO_OUT:
28553a49c214SYang-Rong Jerry Zhou case WTYPE_AUDIO_IN:
28563a49c214SYang-Rong Jerry Zhou case WTYPE_AUDIO_MIX:
28573a49c214SYang-Rong Jerry Zhou case WTYPE_AUDIO_SEL:
28583a49c214SYang-Rong Jerry Zhou case WTYPE_VENDOR:
28593a49c214SYang-Rong Jerry Zhou case WTYPE_POWER:
28603a49c214SYang-Rong Jerry Zhou case WTYPE_VOL_KNOB:
28613a49c214SYang-Rong Jerry Zhou break;
28623a49c214SYang-Rong Jerry Zhou case WTYPE_PIN:
2863ee97b734SZhao Edgar Liu - Sun Microsystems /*
2864ee97b734SZhao Edgar Liu - Sun Microsystems * Some codec(like ALC262) don't provide beep widget,
2865ee97b734SZhao Edgar Liu - Sun Microsystems * it only has input Pin to connect an external beep
2866ee97b734SZhao Edgar Liu - Sun Microsystems * (maybe in motherboard or elsewhere). So we open
2867ee97b734SZhao Edgar Liu - Sun Microsystems * all PINs here in order to enable external beep
2868ee97b734SZhao Edgar Liu - Sun Microsystems * source.
2869ee97b734SZhao Edgar Liu - Sun Microsystems */
2870ee97b734SZhao Edgar Liu - Sun Microsystems if ((codec->codec_info->flags & EN_PIN_BEEP) == 0) {
2871ee97b734SZhao Edgar Liu - Sun Microsystems (void) audioha_codec_4bit_verb_get(statep,
2872ee97b734SZhao Edgar Liu - Sun Microsystems caddr, widget->wid_wid,
2873ee97b734SZhao Edgar Liu - Sun Microsystems AUDIOHDC_VERB_SET_AMP_MUTE,
2874ee97b734SZhao Edgar Liu - Sun Microsystems AUDIOHDC_AMP_SET_LR_OUTPUT |
2875ee97b734SZhao Edgar Liu - Sun Microsystems AUDIOHDC_GAIN_MAX);
2876ee97b734SZhao Edgar Liu - Sun Microsystems }
2877ee97b734SZhao Edgar Liu - Sun Microsystems
28783a49c214SYang-Rong Jerry Zhou audiohd_get_pin_config(widget);
28793a49c214SYang-Rong Jerry Zhou break;
28803a49c214SYang-Rong Jerry Zhou case WTYPE_BEEP:
288142c41cf8Slipeng sang - Sun Microsystems - Beijing China /*
288242c41cf8Slipeng sang - Sun Microsystems - Beijing China * Get the audiohd_beep_switch value from audiohd.conf,
288342c41cf8Slipeng sang - Sun Microsystems - Beijing China * which is for turning on/off widget beep.
288442c41cf8Slipeng sang - Sun Microsystems - Beijing China */
288542c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_beep = ddi_prop_get_int(DDI_DEV_T_ANY,
288642c41cf8Slipeng sang - Sun Microsystems - Beijing China statep->hda_dip,
288742c41cf8Slipeng sang - Sun Microsystems - Beijing China DDI_PROP_DONTPASS, "audiohd_beep", 1);
288842c41cf8Slipeng sang - Sun Microsystems - Beijing China
288942c41cf8Slipeng sang - Sun Microsystems - Beijing China if (audiohd_beep) {
289042c41cf8Slipeng sang - Sun Microsystems - Beijing China (void) beep_fini();
289142c41cf8Slipeng sang - Sun Microsystems - Beijing China (void) beep_init((void *) widget,
289242c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_beep_on,
289342c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_beep_off,
289442c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_beep_freq);
289542c41cf8Slipeng sang - Sun Microsystems - Beijing China }
28963a49c214SYang-Rong Jerry Zhou break;
28973a49c214SYang-Rong Jerry Zhou default:
28983a49c214SYang-Rong Jerry Zhou break;
28993a49c214SYang-Rong Jerry Zhou }
29003a49c214SYang-Rong Jerry Zhou }
29013a49c214SYang-Rong Jerry Zhou
29023a49c214SYang-Rong Jerry Zhou return (DDI_SUCCESS);
29033a49c214SYang-Rong Jerry Zhou
29043a49c214SYang-Rong Jerry Zhou } /* audiohd_create_widgets() */
29053a49c214SYang-Rong Jerry Zhou
290688447a05SGarrett D'Amore /*
290788447a05SGarrett D'Amore * audiohd_destroy_widgets()
290888447a05SGarrett D'Amore */
290988447a05SGarrett D'Amore static void
audiohd_destroy_widgets(hda_codec_t * codec)291088447a05SGarrett D'Amore audiohd_destroy_widgets(hda_codec_t *codec)
291188447a05SGarrett D'Amore {
291288447a05SGarrett D'Amore for (int i = 0; i < AUDIOHD_MAX_WIDGET; i++) {
291388447a05SGarrett D'Amore if (codec->widget[i]) {
291488447a05SGarrett D'Amore kmem_free(codec->widget[i], sizeof (audiohd_widget_t));
291588447a05SGarrett D'Amore codec->widget[i] = NULL;
291688447a05SGarrett D'Amore }
291788447a05SGarrett D'Amore }
291888447a05SGarrett D'Amore
291988447a05SGarrett D'Amore } /* audiohd_destroy_widgets() */
292088447a05SGarrett D'Amore
2921582eadeeSfl /*
2922582eadeeSfl * audiohd_create_codec()
2923582eadeeSfl *
2924582eadeeSfl * Description:
2925582eadeeSfl * Searching for supported CODEC. If find, allocate memory
2926582eadeeSfl * to hold codec structure.
2927582eadeeSfl */
2928582eadeeSfl static int
audiohd_create_codec(audiohd_state_t * statep)2929582eadeeSfl audiohd_create_codec(audiohd_state_t *statep)
2930582eadeeSfl {
29313a49c214SYang-Rong Jerry Zhou hda_codec_t *codec;
2932582eadeeSfl uint32_t mask, type;
29333a49c214SYang-Rong Jerry Zhou uint32_t nums;
2934cbe6566fSZhao Edgar Liu - Sun Microsystems uint32_t i, j, len;
29353a49c214SYang-Rong Jerry Zhou wid_t wid;
2936cbe6566fSZhao Edgar Liu - Sun Microsystems char buf[128];
2937a33ad26eSZhao Edgar Liu - Sun Microsystems int rate, bits;
2938a33ad26eSZhao Edgar Liu - Sun Microsystems dev_info_t *dip = statep->hda_dip;
2939a33ad26eSZhao Edgar Liu - Sun Microsystems
2940582eadeeSfl
2941582eadeeSfl mask = statep->hda_codec_mask;
2942582eadeeSfl ASSERT(mask != 0);
2943582eadeeSfl
2944582eadeeSfl for (i = 0; i < AUDIOHD_CODEC_MAX; i++) {
2945582eadeeSfl if ((mask & (1 << i)) == 0)
2946582eadeeSfl continue;
29473a49c214SYang-Rong Jerry Zhou codec = (hda_codec_t *)kmem_zalloc(
29483a49c214SYang-Rong Jerry Zhou sizeof (hda_codec_t), KM_SLEEP);
29493a49c214SYang-Rong Jerry Zhou codec->index = i;
29503a49c214SYang-Rong Jerry Zhou codec->vid = audioha_codec_verb_get(statep, i,
2951582eadeeSfl AUDIOHDC_NODE_ROOT, AUDIOHDC_VERB_GET_PARAM,
2952582eadeeSfl AUDIOHDC_PAR_VENDOR_ID);
295326ae4a35SZhao Edgar Liu - Sun Microsystems if (codec->vid == (uint32_t)(-1)) {
295426ae4a35SZhao Edgar Liu - Sun Microsystems kmem_free(codec, sizeof (hda_codec_t));
29550c240c64SZhao Edgar Liu - Sun Microsystems continue;
295626ae4a35SZhao Edgar Liu - Sun Microsystems }
29570c240c64SZhao Edgar Liu - Sun Microsystems
29583a49c214SYang-Rong Jerry Zhou codec->revid =
29593a49c214SYang-Rong Jerry Zhou audioha_codec_verb_get(statep, i,
2960582eadeeSfl AUDIOHDC_NODE_ROOT, AUDIOHDC_VERB_GET_PARAM,
2961582eadeeSfl AUDIOHDC_PAR_REV_ID);
2962582eadeeSfl
29633a49c214SYang-Rong Jerry Zhou nums = audioha_codec_verb_get(statep,
29643a49c214SYang-Rong Jerry Zhou i, AUDIOHDC_NODE_ROOT,
2965582eadeeSfl AUDIOHDC_VERB_GET_PARAM, AUDIOHDC_PAR_NODE_COUNT);
29663a49c214SYang-Rong Jerry Zhou if (nums == (uint32_t)(-1)) {
29673a49c214SYang-Rong Jerry Zhou kmem_free(codec, sizeof (hda_codec_t));
29683a49c214SYang-Rong Jerry Zhou continue;
29693a49c214SYang-Rong Jerry Zhou }
29703a49c214SYang-Rong Jerry Zhou wid = (nums >> AUDIOHD_CODEC_STR_OFF) & AUDIOHD_CODEC_STR_MASK;
29713a49c214SYang-Rong Jerry Zhou nums = nums & AUDIOHD_CODEC_NUM_MASK;
2972582eadeeSfl
29733a49c214SYang-Rong Jerry Zhou /*
29743a49c214SYang-Rong Jerry Zhou * Assume that each codec has just one audio function group
29753a49c214SYang-Rong Jerry Zhou */
29763a49c214SYang-Rong Jerry Zhou for (j = 0; j < nums; j++, wid++) {
29773a49c214SYang-Rong Jerry Zhou type = audioha_codec_verb_get(statep, i, wid,
2978582eadeeSfl AUDIOHDC_VERB_GET_PARAM,
2979582eadeeSfl AUDIOHDC_PAR_FUNCTION_TYPE);
29803a49c214SYang-Rong Jerry Zhou if ((type & AUDIOHD_CODEC_TYPE_MASK) ==
29813a49c214SYang-Rong Jerry Zhou AUDIOHDC_AUDIO_FUNC_GROUP) {
29823a49c214SYang-Rong Jerry Zhou codec->wid_afg = wid;
2983582eadeeSfl break;
2984582eadeeSfl }
2985582eadeeSfl }
2986582eadeeSfl
29873a49c214SYang-Rong Jerry Zhou if (codec->wid_afg == 0) {
29883a49c214SYang-Rong Jerry Zhou kmem_free(codec, sizeof (hda_codec_t));
29893a49c214SYang-Rong Jerry Zhou continue;
29903a49c214SYang-Rong Jerry Zhou }
2991582eadeeSfl
29923a49c214SYang-Rong Jerry Zhou ASSERT(codec->wid_afg == wid);
2993582eadeeSfl
2994cbe6566fSZhao Edgar Liu - Sun Microsystems len = sizeof (audiohd_codecs) / sizeof (audiohd_codec_info_t);
2995cbe6566fSZhao Edgar Liu - Sun Microsystems for (j = 0; j < len-1; j++) {
2996cbe6566fSZhao Edgar Liu - Sun Microsystems if (audiohd_codecs[j].devid == codec->vid) {
2997cbe6566fSZhao Edgar Liu - Sun Microsystems codec->codec_info = &(audiohd_codecs[j]);
2998cbe6566fSZhao Edgar Liu - Sun Microsystems break;
2999cbe6566fSZhao Edgar Liu - Sun Microsystems }
3000cbe6566fSZhao Edgar Liu - Sun Microsystems }
3001cbe6566fSZhao Edgar Liu - Sun Microsystems
3002cbe6566fSZhao Edgar Liu - Sun Microsystems if (codec->codec_info == NULL) {
3003cbe6566fSZhao Edgar Liu - Sun Microsystems codec->codec_info = &(audiohd_codecs[len-1]);
3004cbe6566fSZhao Edgar Liu - Sun Microsystems (void) snprintf(buf, sizeof (buf),
3005cbe6566fSZhao Edgar Liu - Sun Microsystems "Unknown HD codec: 0x%x", codec->vid);
3006cbe6566fSZhao Edgar Liu - Sun Microsystems } else {
3007cbe6566fSZhao Edgar Liu - Sun Microsystems (void) snprintf(buf, sizeof (buf), "HD codec: %s",
3008cbe6566fSZhao Edgar Liu - Sun Microsystems codec->codec_info->buf);
3009cbe6566fSZhao Edgar Liu - Sun Microsystems }
3010cbe6566fSZhao Edgar Liu - Sun Microsystems audio_dev_add_info(statep->adev, buf);
3011cbe6566fSZhao Edgar Liu - Sun Microsystems
30129ba19c87SYang-Rong Jerry Zhou /* work around for Sony VAIO laptop with specific codec */
3013cbe6566fSZhao Edgar Liu - Sun Microsystems if ((codec->codec_info->flags & NO_GPIO) == 0) {
30149ba19c87SYang-Rong Jerry Zhou /*
30159ba19c87SYang-Rong Jerry Zhou * GPIO controls which are laptop specific workarounds
30169ba19c87SYang-Rong Jerry Zhou * and might be changed. Some laptops use GPIO,
30179ba19c87SYang-Rong Jerry Zhou * so we need to enable and set the GPIO correctly.
30189ba19c87SYang-Rong Jerry Zhou */
30199ba19c87SYang-Rong Jerry Zhou (void) audioha_codec_verb_get(statep, i, wid,
30209ba19c87SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_GPIO_MASK, AUDIOHDC_GPIO_ENABLE);
3021989b958fSZhao Edgar Liu - Sun Microsystems (void) audioha_codec_verb_get(statep, i, wid,
3022989b958fSZhao Edgar Liu - Sun Microsystems AUDIOHDC_VERB_SET_UNSOL_ENABLE_MASK,
3023989b958fSZhao Edgar Liu - Sun Microsystems AUDIOHDC_GPIO_ENABLE);
30249ba19c87SYang-Rong Jerry Zhou (void) audioha_codec_verb_get(statep, i, wid,
30259ba19c87SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_GPIO_DIREC, AUDIOHDC_GPIO_DIRECT);
30269ba19c87SYang-Rong Jerry Zhou (void) audioha_codec_verb_get(statep, i, wid,
30279ba19c87SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_GPIO_STCK,
30289ba19c87SYang-Rong Jerry Zhou AUDIOHDC_GPIO_DATA_CTRL);
30299ba19c87SYang-Rong Jerry Zhou (void) audioha_codec_verb_get(statep, i, wid,
30309ba19c87SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_GPIO_DATA,
30319ba19c87SYang-Rong Jerry Zhou AUDIOHDC_GPIO_STCK_CTRL);
30329ba19c87SYang-Rong Jerry Zhou }
30339ba19c87SYang-Rong Jerry Zhou
30343a49c214SYang-Rong Jerry Zhou /* power-up audio function group */
30353a49c214SYang-Rong Jerry Zhou (void) audioha_codec_verb_get(statep, i, wid,
30365ec2209cSZhao Edgar Liu - Sun Microsystems AUDIOHDC_VERB_SET_POWER_STATE, AUDIOHD_PW_D0);
3037582eadeeSfl
30383a49c214SYang-Rong Jerry Zhou /* subsystem id is attached to funtion group */
30393a49c214SYang-Rong Jerry Zhou codec->outamp_cap = audioha_codec_verb_get(statep, i, wid,
30403a49c214SYang-Rong Jerry Zhou AUDIOHDC_VERB_GET_PARAM, AUDIOHDC_PAR_OUTAMP_CAP);
30413a49c214SYang-Rong Jerry Zhou codec->inamp_cap = audioha_codec_verb_get(statep, i, wid,
30423a49c214SYang-Rong Jerry Zhou AUDIOHDC_VERB_GET_PARAM, AUDIOHDC_PAR_INAMP_CAP);
30433a49c214SYang-Rong Jerry Zhou codec->stream_format = audioha_codec_verb_get(statep, i, wid,
30443a49c214SYang-Rong Jerry Zhou AUDIOHDC_VERB_GET_PARAM, AUDIOHDC_PAR_STREAM);
30453a49c214SYang-Rong Jerry Zhou codec->pcm_format = audioha_codec_verb_get(statep, i, wid,
30463a49c214SYang-Rong Jerry Zhou AUDIOHDC_VERB_GET_PARAM, AUDIOHDC_PAR_PCM);
30473a49c214SYang-Rong Jerry Zhou
3048a33ad26eSZhao Edgar Liu - Sun Microsystems statep->sample_rate = 48000;
3049a33ad26eSZhao Edgar Liu - Sun Microsystems rate = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
3050a33ad26eSZhao Edgar Liu - Sun Microsystems DDI_PROP_DONTPASS, "sample-rate", 48000);
3051a33ad26eSZhao Edgar Liu - Sun Microsystems if (rate == 192000 &&
3052a33ad26eSZhao Edgar Liu - Sun Microsystems (codec->pcm_format & AUDIOHD_SAMP_RATE192)) {
3053a33ad26eSZhao Edgar Liu - Sun Microsystems statep->sample_rate = 192000;
3054a33ad26eSZhao Edgar Liu - Sun Microsystems } else if (rate == 96000 &&
3055a33ad26eSZhao Edgar Liu - Sun Microsystems (codec->pcm_format & AUDIOHD_SAMP_RATE96)) {
3056a33ad26eSZhao Edgar Liu - Sun Microsystems statep->sample_rate = 96000;
3057a33ad26eSZhao Edgar Liu - Sun Microsystems } else {
3058a33ad26eSZhao Edgar Liu - Sun Microsystems statep->sample_rate = 48000;
3059a33ad26eSZhao Edgar Liu - Sun Microsystems }
3060a33ad26eSZhao Edgar Liu - Sun Microsystems
3061a33ad26eSZhao Edgar Liu - Sun Microsystems statep->sample_bit_depth = AUDIOHD_BIT_DEPTH16;
3062a33ad26eSZhao Edgar Liu - Sun Microsystems bits = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
3063a33ad26eSZhao Edgar Liu - Sun Microsystems DDI_PROP_DONTPASS, "sample-bits", 16);
3064a33ad26eSZhao Edgar Liu - Sun Microsystems if (bits == 24 &&
3065a33ad26eSZhao Edgar Liu - Sun Microsystems (codec->pcm_format & AUDIOHD_BIT_DEPTH24)) {
3066a33ad26eSZhao Edgar Liu - Sun Microsystems statep->sample_bit_depth = AUDIOHD_BIT_DEPTH24;
3067a33ad26eSZhao Edgar Liu - Sun Microsystems } else {
3068a33ad26eSZhao Edgar Liu - Sun Microsystems statep->sample_bit_depth = AUDIOHD_BIT_DEPTH16;
3069a33ad26eSZhao Edgar Liu - Sun Microsystems }
3070a33ad26eSZhao Edgar Liu - Sun Microsystems
30713a49c214SYang-Rong Jerry Zhou nums = audioha_codec_verb_get(statep, i, wid,
30723a49c214SYang-Rong Jerry Zhou AUDIOHDC_VERB_GET_PARAM,
30733a49c214SYang-Rong Jerry Zhou AUDIOHDC_PAR_NODE_COUNT);
30743a49c214SYang-Rong Jerry Zhou wid = (nums >> AUDIOHD_CODEC_STR_OFF) & AUDIOHD_CODEC_STR_MASK;
30753a49c214SYang-Rong Jerry Zhou nums = nums & AUDIOHD_CODEC_NUM_MASK;
30763a49c214SYang-Rong Jerry Zhou codec->first_wid = wid;
30773a49c214SYang-Rong Jerry Zhou codec->last_wid = wid + nums;
30783a49c214SYang-Rong Jerry Zhou codec->nnodes = nums;
30793a49c214SYang-Rong Jerry Zhou
30803a49c214SYang-Rong Jerry Zhou /*
30813a49c214SYang-Rong Jerry Zhou * We output the codec information to syslog
30823a49c214SYang-Rong Jerry Zhou */
30833a49c214SYang-Rong Jerry Zhou statep->codec[i] = codec;
3084ea463888SZhao Edgar Liu - Sun Microsystems codec->statep = statep;
30853a49c214SYang-Rong Jerry Zhou (void) audiohd_create_widgets(codec);
3086582eadeeSfl }
3087582eadeeSfl
3088c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
3089582eadeeSfl
3090582eadeeSfl } /* audiohd_create_codec() */
3091582eadeeSfl
3092582eadeeSfl /*
3093582eadeeSfl * audiohd_destroy_codec()
3094582eadeeSfl *
3095582eadeeSfl * Description:
30963a49c214SYang-Rong Jerry Zhou * destroy codec structure, and release its memory
3097582eadeeSfl */
3098582eadeeSfl static void
audiohd_destroy_codec(audiohd_state_t * statep)3099582eadeeSfl audiohd_destroy_codec(audiohd_state_t *statep)
3100582eadeeSfl {
310188447a05SGarrett D'Amore int i;
31023a49c214SYang-Rong Jerry Zhou audiohd_pin_t *pin, *npin;
3103582eadeeSfl
310488447a05SGarrett D'Amore for (i = 0; i < AUDIOHD_CODEC_MAX; i++) {
31053a49c214SYang-Rong Jerry Zhou if (statep->codec[i]) {
31063a49c214SYang-Rong Jerry Zhou audiohd_destroy_widgets(statep->codec[i]);
31073a49c214SYang-Rong Jerry Zhou /*
31083a49c214SYang-Rong Jerry Zhou * free pins
31093a49c214SYang-Rong Jerry Zhou */
31103a49c214SYang-Rong Jerry Zhou pin = statep->codec[i]->first_pin;
31113a49c214SYang-Rong Jerry Zhou while (pin) {
31123a49c214SYang-Rong Jerry Zhou npin = pin;
31133a49c214SYang-Rong Jerry Zhou pin = pin->next;
31143a49c214SYang-Rong Jerry Zhou kmem_free(npin, sizeof (audiohd_pin_t));
31153a49c214SYang-Rong Jerry Zhou }
31163a49c214SYang-Rong Jerry Zhou
31173a49c214SYang-Rong Jerry Zhou kmem_free(statep->codec[i], sizeof (hda_codec_t));
31183a49c214SYang-Rong Jerry Zhou statep->codec[i] = NULL;
31193a49c214SYang-Rong Jerry Zhou }
31203a49c214SYang-Rong Jerry Zhou }
3121582eadeeSfl } /* audiohd_destroy_codec() */
3122582eadeeSfl
31237253a143Scg /*
31243a49c214SYang-Rong Jerry Zhou * audiohd_find_dac()
31253a49c214SYang-Rong Jerry Zhou * Description:
31263a49c214SYang-Rong Jerry Zhou * Find a dac for a output path. Then the play data can be sent to the out
31273a49c214SYang-Rong Jerry Zhou * put pin through the output path.
31283a49c214SYang-Rong Jerry Zhou *
31293a49c214SYang-Rong Jerry Zhou * Arguments:
31303a49c214SYang-Rong Jerry Zhou * hda_codec_t *codec where the dac widget exists
31313a49c214SYang-Rong Jerry Zhou * wid_t wid the no. of a widget
31323a49c214SYang-Rong Jerry Zhou * int mixer whether the path need mixer or not
31333a49c214SYang-Rong Jerry Zhou * int *mixernum the total of mixer in the output path
31343a49c214SYang-Rong Jerry Zhou * int exclusive an exclusive path or share path
31353a49c214SYang-Rong Jerry Zhou * int depth the depth of search
31363a49c214SYang-Rong Jerry Zhou *
31373a49c214SYang-Rong Jerry Zhou * Return:
31383a49c214SYang-Rong Jerry Zhou * 1) wid of the first shared widget in the path from
31393a49c214SYang-Rong Jerry Zhou * pin to DAC if exclusive is 0;
31403a49c214SYang-Rong Jerry Zhou * 2) wid of DAC widget;
31413a49c214SYang-Rong Jerry Zhou * 3) 0 if no path
31427253a143Scg */
31433a49c214SYang-Rong Jerry Zhou static wid_t
audiohd_find_dac(hda_codec_t * codec,wid_t wid,int mixer,int * mixernum,int exclusive,int depth)31443a49c214SYang-Rong Jerry Zhou audiohd_find_dac(hda_codec_t *codec, wid_t wid,
31453a49c214SYang-Rong Jerry Zhou int mixer, int *mixernum,
31463a49c214SYang-Rong Jerry Zhou int exclusive, int depth)
31477253a143Scg {
31483a49c214SYang-Rong Jerry Zhou audiohd_widget_t *widget = codec->widget[wid];
3149c6e681c0SYang-Rong Jerry Zhou wid_t wdac = (uint32_t)(DDI_FAILURE);
31503a49c214SYang-Rong Jerry Zhou wid_t retval;
31517253a143Scg
31523a49c214SYang-Rong Jerry Zhou if (depth > AUDIOHD_MAX_DEPTH)
3153c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
31547253a143Scg
315531a3f136SYang-Rong Jerry Zhou if (widget == NULL)
3156c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
315788447a05SGarrett D'Amore
31583a49c214SYang-Rong Jerry Zhou /*
31593a49c214SYang-Rong Jerry Zhou * If exclusive is true, we try to find a path which doesn't
31603a49c214SYang-Rong Jerry Zhou * share any widget with other paths.
31613a49c214SYang-Rong Jerry Zhou */
31623a49c214SYang-Rong Jerry Zhou if (exclusive) {
31633a49c214SYang-Rong Jerry Zhou if (widget->path_flags & AUDIOHD_PATH_DAC)
3164c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
31653a49c214SYang-Rong Jerry Zhou } else {
31663a49c214SYang-Rong Jerry Zhou if (widget->path_flags & AUDIOHD_PATH_DAC)
31673a49c214SYang-Rong Jerry Zhou return (wid);
31683a49c214SYang-Rong Jerry Zhou }
31693a49c214SYang-Rong Jerry Zhou
31703a49c214SYang-Rong Jerry Zhou switch (widget->type) {
31713a49c214SYang-Rong Jerry Zhou case WTYPE_AUDIO_OUT:
31723a49c214SYang-Rong Jerry Zhou /* We need mixer widget, but the the mixer num is 0, failed */
31733a49c214SYang-Rong Jerry Zhou if (mixer && !*mixernum)
3174c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
31753a49c214SYang-Rong Jerry Zhou widget->path_flags |= AUDIOHD_PATH_DAC;
31763a49c214SYang-Rong Jerry Zhou widget->out_weight++;
31773a49c214SYang-Rong Jerry Zhou wdac = widget->wid_wid;
31783a49c214SYang-Rong Jerry Zhou break;
31793a49c214SYang-Rong Jerry Zhou
31803a49c214SYang-Rong Jerry Zhou case WTYPE_AUDIO_MIX:
3181b96a6eceSZhao Edgar Liu - Sun Microsystems (*mixernum)++;
3182b96a6eceSZhao Edgar Liu - Sun Microsystems /* FALLTHRU */
31833a49c214SYang-Rong Jerry Zhou case WTYPE_AUDIO_SEL:
31843a49c214SYang-Rong Jerry Zhou for (int i = 0; i < widget->nconns; i++) {
31853a49c214SYang-Rong Jerry Zhou retval = audiohd_find_dac(codec,
31863a49c214SYang-Rong Jerry Zhou widget->avail_conn[i],
31873a49c214SYang-Rong Jerry Zhou mixer, mixernum,
31883a49c214SYang-Rong Jerry Zhou exclusive, depth + 1);
3189c6e681c0SYang-Rong Jerry Zhou if (retval != (uint32_t)DDI_FAILURE) {
3190b96a6eceSZhao Edgar Liu - Sun Microsystems if (widget->output_path_next ==
3191b96a6eceSZhao Edgar Liu - Sun Microsystems AUDIOHD_NULL_CONN) {
3192b96a6eceSZhao Edgar Liu - Sun Microsystems widget->output_path_next = i;
31933a49c214SYang-Rong Jerry Zhou wdac = retval;
31943a49c214SYang-Rong Jerry Zhou }
31953a49c214SYang-Rong Jerry Zhou widget->path_flags |= AUDIOHD_PATH_DAC;
31963a49c214SYang-Rong Jerry Zhou widget->out_weight++;
31973a49c214SYang-Rong Jerry Zhou
31983a49c214SYang-Rong Jerry Zhou /* return when found a path */
31993a49c214SYang-Rong Jerry Zhou return (wdac);
32003a49c214SYang-Rong Jerry Zhou }
32013a49c214SYang-Rong Jerry Zhou }
32023a49c214SYang-Rong Jerry Zhou default:
32033a49c214SYang-Rong Jerry Zhou break;
32043a49c214SYang-Rong Jerry Zhou }
32053a49c214SYang-Rong Jerry Zhou
32063a49c214SYang-Rong Jerry Zhou return (wdac);
32073a49c214SYang-Rong Jerry Zhou } /* audiohd_find_dac() */
3208582eadeeSfl
3209582eadeeSfl /*
32103a49c214SYang-Rong Jerry Zhou * audiohd_do_build_output_path()
3211582eadeeSfl *
3212582eadeeSfl * Description:
32133a49c214SYang-Rong Jerry Zhou * Search an output path for each pin in the codec.
32143a49c214SYang-Rong Jerry Zhou * Arguments:
32153a49c214SYang-Rong Jerry Zhou * hda_codec_t *codec where the output path exists
3216b96a6eceSZhao Edgar Liu - Sun Microsystems * int mixer whether the path needs mixer widget
32173a49c214SYang-Rong Jerry Zhou * int *mnum total of mixer widget in the path
32183a49c214SYang-Rong Jerry Zhou * int exclusive an exclusive path or shared path
32193a49c214SYang-Rong Jerry Zhou * int depth search depth
3220582eadeeSfl */
3221582eadeeSfl static void
audiohd_do_build_output_path(hda_codec_t * codec,int mixer,int * mnum,int exclusive,int depth)32223a49c214SYang-Rong Jerry Zhou audiohd_do_build_output_path(hda_codec_t *codec, int mixer, int *mnum,
32233a49c214SYang-Rong Jerry Zhou int exclusive, int depth)
3224582eadeeSfl {
32253a49c214SYang-Rong Jerry Zhou audiohd_pin_t *pin;
32263a49c214SYang-Rong Jerry Zhou audiohd_widget_t *widget, *wdac;
3227b96a6eceSZhao Edgar Liu - Sun Microsystems audiohd_path_t *path;
32283a49c214SYang-Rong Jerry Zhou wid_t wid;
3229b96a6eceSZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep;
32303a49c214SYang-Rong Jerry Zhou int i;
3231582eadeeSfl
3232ea463888SZhao Edgar Liu - Sun Microsystems statep = codec->statep;
323388447a05SGarrett D'Amore
32343a49c214SYang-Rong Jerry Zhou for (pin = codec->first_pin; pin; pin = pin->next) {
32353a49c214SYang-Rong Jerry Zhou if ((pin->cap & AUDIOHD_PIN_CAP_MASK) == 0)
32363a49c214SYang-Rong Jerry Zhou continue;
32373a49c214SYang-Rong Jerry Zhou if ((pin->config & AUDIOHD_PIN_CONF_MASK) ==
32383a49c214SYang-Rong Jerry Zhou AUDIOHD_PIN_NO_CONN)
32393a49c214SYang-Rong Jerry Zhou continue;
32403a49c214SYang-Rong Jerry Zhou if ((pin->device != DTYPE_LINEOUT) &&
32413a49c214SYang-Rong Jerry Zhou (pin->device != DTYPE_SPEAKER) &&
32423a49c214SYang-Rong Jerry Zhou (pin->device != DTYPE_SPDIF_OUT) &&
32433a49c214SYang-Rong Jerry Zhou (pin->device != DTYPE_HP_OUT))
32443a49c214SYang-Rong Jerry Zhou continue;
32453a49c214SYang-Rong Jerry Zhou if (pin->finish)
32463a49c214SYang-Rong Jerry Zhou continue;
32473a49c214SYang-Rong Jerry Zhou widget = codec->widget[pin->wid];
3248582eadeeSfl
32493a49c214SYang-Rong Jerry Zhou widget->inamp_cap = 0;
32503a49c214SYang-Rong Jerry Zhou for (i = 0; i < widget->nconns; i++) {
32513a49c214SYang-Rong Jerry Zhou /*
32523a49c214SYang-Rong Jerry Zhou * If a dac found, the return value is the wid of the
32533a49c214SYang-Rong Jerry Zhou * widget on the path, or the return value is
3254c6e681c0SYang-Rong Jerry Zhou * DDI_FAILURE
32553a49c214SYang-Rong Jerry Zhou */
32563a49c214SYang-Rong Jerry Zhou wid = audiohd_find_dac(codec,
32573a49c214SYang-Rong Jerry Zhou widget->avail_conn[i], mixer, mnum, exclusive,
32583a49c214SYang-Rong Jerry Zhou depth);
32593a49c214SYang-Rong Jerry Zhou /*
32603a49c214SYang-Rong Jerry Zhou * A dac was not found
32613a49c214SYang-Rong Jerry Zhou */
3262c6e681c0SYang-Rong Jerry Zhou if (wid == (wid_t)DDI_FAILURE)
32633a49c214SYang-Rong Jerry Zhou continue;
3264c1aa074aSYang-Rong Jerry Zhou if (pin->device != DTYPE_SPEAKER &&
3265c1aa074aSYang-Rong Jerry Zhou pin->device != DTYPE_HP_OUT)
326688447a05SGarrett D'Amore statep->chann[pin->assoc] += 2;
326788447a05SGarrett D'Amore path = (audiohd_path_t *)
326888447a05SGarrett D'Amore kmem_zalloc(sizeof (audiohd_path_t),
32693a49c214SYang-Rong Jerry Zhou KM_SLEEP);
327088447a05SGarrett D'Amore path->adda_wid = wid;
327188447a05SGarrett D'Amore path->pin_wid[0] = widget->wid_wid;
327288447a05SGarrett D'Amore path->pin_nums = 1;
327388447a05SGarrett D'Amore path->path_type = PLAY;
327488447a05SGarrett D'Amore path->codec = codec;
327588447a05SGarrett D'Amore path->statep = statep;
32763a49c214SYang-Rong Jerry Zhou wdac = codec->widget[wid];
327788447a05SGarrett D'Amore wdac->priv = path;
3278e7236f70SZhao Edgar Liu - Sun Microsystems pin->dac_wid = wid;
32793a49c214SYang-Rong Jerry Zhou pin->finish = 1;
32803a49c214SYang-Rong Jerry Zhou widget->path_flags |= AUDIOHD_PATH_DAC;
32813a49c214SYang-Rong Jerry Zhou widget->out_weight++;
3282b96a6eceSZhao Edgar Liu - Sun Microsystems widget->output_path_next = i;
328388447a05SGarrett D'Amore statep->path[statep->pathnum++] = path;
32843a49c214SYang-Rong Jerry Zhou break;
32853a49c214SYang-Rong Jerry Zhou }
32863a49c214SYang-Rong Jerry Zhou }
3287582eadeeSfl
32883a49c214SYang-Rong Jerry Zhou } /* audiohd_do_build_output_path() */
3289582eadeeSfl
3290582eadeeSfl /*
32913a49c214SYang-Rong Jerry Zhou * audiohd_build_output_path()
3292582eadeeSfl *
3293582eadeeSfl * Description:
32943a49c214SYang-Rong Jerry Zhou * Build the output path in the codec for every pin.
32953a49c214SYang-Rong Jerry Zhou * First we try to search output path with mixer widget exclusively
32963a49c214SYang-Rong Jerry Zhou * Then we try to search shared output path with mixer widget.
32973a49c214SYang-Rong Jerry Zhou * Then we try to search output path without mixer widget exclusively.
32983a49c214SYang-Rong Jerry Zhou * At last we try to search shared ouput path for the remained pins
3299582eadeeSfl */
33003a49c214SYang-Rong Jerry Zhou static void
audiohd_build_output_path(hda_codec_t * codec)33013a49c214SYang-Rong Jerry Zhou audiohd_build_output_path(hda_codec_t *codec)
3302582eadeeSfl {
33033a49c214SYang-Rong Jerry Zhou int mnum = 0;
330488447a05SGarrett D'Amore uint8_t mixer_allow = 1;
3305582eadeeSfl
3306f0109389SYang-Rong Jerry Zhou /*
3307368517c9SYang-Rong Jerry Zhou * Work around for laptops which have IDT or AD audio chipset, such as
330807bec7ccSZhao Edgar Liu - Sun Microsystems * HP mini 1000 laptop, Dell Lattitude 6400, Lenovo T60, Lenove R61e.
330907bec7ccSZhao Edgar Liu - Sun Microsystems * We don't allow mixer widget on such path, which leads to speaker
3310368517c9SYang-Rong Jerry Zhou * loud hiss noise.
3311f0109389SYang-Rong Jerry Zhou */
3312cbe6566fSZhao Edgar Liu - Sun Microsystems if (codec->codec_info->flags & NO_MIXER)
331388447a05SGarrett D'Amore mixer_allow = 0;
3314cbe6566fSZhao Edgar Liu - Sun Microsystems
33153a49c214SYang-Rong Jerry Zhou /* search an exclusive mixer widget path. This is preferred */
331688447a05SGarrett D'Amore audiohd_do_build_output_path(codec, mixer_allow, &mnum, 1, 0);
3317582eadeeSfl
33183a49c214SYang-Rong Jerry Zhou /* search a shared mixer widget path for the remained pins */
331988447a05SGarrett D'Amore audiohd_do_build_output_path(codec, mixer_allow, &mnum, 0, 0);
3320582eadeeSfl
33213a49c214SYang-Rong Jerry Zhou /* search an exclusive widget path without mixer for the remained pin */
33223a49c214SYang-Rong Jerry Zhou audiohd_do_build_output_path(codec, 0, &mnum, 1, 0);
3323582eadeeSfl
33243a49c214SYang-Rong Jerry Zhou /* search a shared widget path without mixer for the remained pin */
33253a49c214SYang-Rong Jerry Zhou audiohd_do_build_output_path(codec, 0, &mnum, 0, 0);
3326582eadeeSfl
33273a49c214SYang-Rong Jerry Zhou } /* audiohd_build_output_path */
3328582eadeeSfl
33293a49c214SYang-Rong Jerry Zhou /*
33303a49c214SYang-Rong Jerry Zhou * audiohd_build_output_amp
33313a49c214SYang-Rong Jerry Zhou *
33323a49c214SYang-Rong Jerry Zhou * Description:
33333a49c214SYang-Rong Jerry Zhou * Find the gain control and mute control widget
33343a49c214SYang-Rong Jerry Zhou */
33353a49c214SYang-Rong Jerry Zhou static void
audiohd_build_output_amp(hda_codec_t * codec)33363a49c214SYang-Rong Jerry Zhou audiohd_build_output_amp(hda_codec_t *codec)
33373a49c214SYang-Rong Jerry Zhou {
333888447a05SGarrett D'Amore audiohd_path_t *path;
33393a49c214SYang-Rong Jerry Zhou audiohd_widget_t *w, *widget, *wpin, *wdac;
33403a49c214SYang-Rong Jerry Zhou audiohd_pin_t *pin;
3341b96a6eceSZhao Edgar Liu - Sun Microsystems wid_t wid, next;
33423a49c214SYang-Rong Jerry Zhou int weight;
334388447a05SGarrett D'Amore int i, j;
33443a49c214SYang-Rong Jerry Zhou uint32_t gain;
3345582eadeeSfl
3346ea463888SZhao Edgar Liu - Sun Microsystems for (i = 0; i < codec->statep->pathnum; i++) {
3347ea463888SZhao Edgar Liu - Sun Microsystems path = codec->statep->path[i];
3348b96a6eceSZhao Edgar Liu - Sun Microsystems if (path == NULL || path->path_type != PLAY ||
334988447a05SGarrett D'Amore path->codec != codec)
335088447a05SGarrett D'Amore continue;
335188447a05SGarrett D'Amore for (j = 0; j < path->pin_nums; j++) {
335288447a05SGarrett D'Amore wid = path->pin_wid[j];
33533a49c214SYang-Rong Jerry Zhou wpin = codec->widget[wid];
33543a49c214SYang-Rong Jerry Zhou pin = (audiohd_pin_t *)wpin->priv;
33553a49c214SYang-Rong Jerry Zhou weight = wpin->out_weight;
3356a234d95bScg
33573a49c214SYang-Rong Jerry Zhou /*
33583a49c214SYang-Rong Jerry Zhou * search a node which can mute this pin while
33593a49c214SYang-Rong Jerry Zhou * the mute functionality doesn't effect other
33603a49c214SYang-Rong Jerry Zhou * pins.
33613a49c214SYang-Rong Jerry Zhou */
33623a49c214SYang-Rong Jerry Zhou widget = wpin;
33633a49c214SYang-Rong Jerry Zhou while (widget) {
33643a49c214SYang-Rong Jerry Zhou if (widget->outamp_cap &
33653a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_CAP_MUTE_CAP) {
33663a49c214SYang-Rong Jerry Zhou pin->mute_wid = widget->wid_wid;
33673a49c214SYang-Rong Jerry Zhou pin->mute_dir = AUDIOHDC_AMP_SET_OUTPUT;
33683a49c214SYang-Rong Jerry Zhou break;
33693a49c214SYang-Rong Jerry Zhou }
33703a49c214SYang-Rong Jerry Zhou if (widget->inamp_cap &
33713a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_CAP_MUTE_CAP) {
33723a49c214SYang-Rong Jerry Zhou pin->mute_wid = widget->wid_wid;
33733a49c214SYang-Rong Jerry Zhou pin->mute_dir = AUDIOHDC_AMP_SET_INPUT;
33743a49c214SYang-Rong Jerry Zhou break;
33753a49c214SYang-Rong Jerry Zhou }
3376b96a6eceSZhao Edgar Liu - Sun Microsystems next = widget->output_path_next;
3377b96a6eceSZhao Edgar Liu - Sun Microsystems if (next == AUDIOHD_NULL_CONN)
33783a49c214SYang-Rong Jerry Zhou break;
3379b96a6eceSZhao Edgar Liu - Sun Microsystems wid = widget->avail_conn[next];
33803a49c214SYang-Rong Jerry Zhou widget = codec->widget[wid];
338131a3f136SYang-Rong Jerry Zhou if (widget && widget->out_weight != weight)
33823a49c214SYang-Rong Jerry Zhou break;
3383a234d95bScg }
3384a234d95bScg
3385a234d95bScg /*
33863a49c214SYang-Rong Jerry Zhou * We select the wid which has maxium gain range in
33873a49c214SYang-Rong Jerry Zhou * the output path. Meanwhile, the gain controlling
33883a49c214SYang-Rong Jerry Zhou * of this node doesn't effect other pins if this
33893a49c214SYang-Rong Jerry Zhou * output stream has multiple pins.
3390a234d95bScg */
33913a49c214SYang-Rong Jerry Zhou gain = 0;
33923a49c214SYang-Rong Jerry Zhou widget = wpin;
33933a49c214SYang-Rong Jerry Zhou while (widget) {
33943a49c214SYang-Rong Jerry Zhou gain = (widget->outamp_cap &
33953a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_CAP_STEP_NUMS);
33963a49c214SYang-Rong Jerry Zhou if (gain && gain > pin->gain_bits) {
33973a49c214SYang-Rong Jerry Zhou pin->gain_dir = AUDIOHDC_AMP_SET_OUTPUT;
33983a49c214SYang-Rong Jerry Zhou pin->gain_bits = gain;
33993a49c214SYang-Rong Jerry Zhou pin->gain_wid = widget->wid_wid;
34003a49c214SYang-Rong Jerry Zhou }
34013a49c214SYang-Rong Jerry Zhou gain = widget->inamp_cap &
34023a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_CAP_STEP_NUMS;
34033a49c214SYang-Rong Jerry Zhou if (gain && gain > pin->gain_bits) {
34043a49c214SYang-Rong Jerry Zhou pin->gain_dir = AUDIOHDC_AMP_SET_INPUT;
34053a49c214SYang-Rong Jerry Zhou pin->gain_bits = gain;
34063a49c214SYang-Rong Jerry Zhou pin->gain_wid = widget->wid_wid;
34073a49c214SYang-Rong Jerry Zhou }
3408b96a6eceSZhao Edgar Liu - Sun Microsystems next = widget->output_path_next;
3409b96a6eceSZhao Edgar Liu - Sun Microsystems if (next == AUDIOHD_NULL_CONN)
34103a49c214SYang-Rong Jerry Zhou break;
3411b96a6eceSZhao Edgar Liu - Sun Microsystems wid = widget->avail_conn[next];
34123a49c214SYang-Rong Jerry Zhou widget = codec->widget[wid];
341331a3f136SYang-Rong Jerry Zhou if (widget && widget->out_weight != weight)
34143a49c214SYang-Rong Jerry Zhou break;
34153a49c214SYang-Rong Jerry Zhou }
34163a49c214SYang-Rong Jerry Zhou pin->gain_bits >>= AUDIOHD_GAIN_OFF;
3417a234d95bScg }
3418a234d95bScg
34193a49c214SYang-Rong Jerry Zhou /*
34203a49c214SYang-Rong Jerry Zhou * if this stream has multiple pins, we try to find
34213a49c214SYang-Rong Jerry Zhou * a mute & gain-controlling nodes which can effect
34223a49c214SYang-Rong Jerry Zhou * all output pins of this stream to be used for the
34233a49c214SYang-Rong Jerry Zhou * whole stream
34243a49c214SYang-Rong Jerry Zhou */
342588447a05SGarrett D'Amore if (path->pin_nums == 1) {
342688447a05SGarrett D'Amore path->mute_wid = pin->mute_wid;
342788447a05SGarrett D'Amore path->mute_dir = pin->mute_dir;
342888447a05SGarrett D'Amore path->gain_wid = pin->gain_wid;
342988447a05SGarrett D'Amore path->gain_dir = pin->gain_dir;
343088447a05SGarrett D'Amore path->gain_bits = pin->gain_bits;
34313a49c214SYang-Rong Jerry Zhou } else {
343288447a05SGarrett D'Amore wdac = codec->widget[path->adda_wid];
34333a49c214SYang-Rong Jerry Zhou weight = wdac->out_weight;
343488447a05SGarrett D'Amore wid = path->pin_wid[0];
34353a49c214SYang-Rong Jerry Zhou w = codec->widget[wid];
343631a3f136SYang-Rong Jerry Zhou while (w && w->out_weight != weight) {
3437b96a6eceSZhao Edgar Liu - Sun Microsystems wid = w->avail_conn[w->output_path_next];
34383a49c214SYang-Rong Jerry Zhou w = codec->widget[wid];
34393a49c214SYang-Rong Jerry Zhou }
3440582eadeeSfl
34413a49c214SYang-Rong Jerry Zhou /* find mute controlling node for this stream */
34423a49c214SYang-Rong Jerry Zhou widget = w;
34433a49c214SYang-Rong Jerry Zhou while (widget) {
34443a49c214SYang-Rong Jerry Zhou if (widget->outamp_cap &
34453a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_CAP_MUTE_CAP) {
344688447a05SGarrett D'Amore path->mute_wid = widget->wid_wid;
344788447a05SGarrett D'Amore path->mute_dir =
34483a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_OUTPUT;
34493a49c214SYang-Rong Jerry Zhou break;
34503a49c214SYang-Rong Jerry Zhou }
34513a49c214SYang-Rong Jerry Zhou if (widget->inamp_cap &
34523a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_CAP_MUTE_CAP) {
345388447a05SGarrett D'Amore path->mute_wid = widget->wid_wid;
345488447a05SGarrett D'Amore path->mute_dir =
34553a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_INPUT;
34563a49c214SYang-Rong Jerry Zhou break;
34573a49c214SYang-Rong Jerry Zhou }
3458b96a6eceSZhao Edgar Liu - Sun Microsystems next = widget->output_path_next;
3459b96a6eceSZhao Edgar Liu - Sun Microsystems if (next == AUDIOHD_NULL_CONN)
34603a49c214SYang-Rong Jerry Zhou break;
3461b96a6eceSZhao Edgar Liu - Sun Microsystems wid = widget->avail_conn[next];
34623a49c214SYang-Rong Jerry Zhou widget = codec->widget[wid];
34633a49c214SYang-Rong Jerry Zhou }
3464582eadeeSfl
34653a49c214SYang-Rong Jerry Zhou /* find volume controlling node for this stream */
34663a49c214SYang-Rong Jerry Zhou gain = 0;
34673a49c214SYang-Rong Jerry Zhou widget = w;
34683a49c214SYang-Rong Jerry Zhou while (widget) {
34693a49c214SYang-Rong Jerry Zhou gain = (widget->outamp_cap &
34703a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_CAP_STEP_NUMS);
34713a49c214SYang-Rong Jerry Zhou if (gain && gain > pin->gain_bits) {
347288447a05SGarrett D'Amore path->gain_dir =
34733a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_OUTPUT;
347488447a05SGarrett D'Amore path->gain_bits = gain;
347588447a05SGarrett D'Amore path->gain_wid = widget->wid_wid;
34763a49c214SYang-Rong Jerry Zhou }
34773a49c214SYang-Rong Jerry Zhou gain = widget->inamp_cap &
34783a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_CAP_STEP_NUMS;
34793a49c214SYang-Rong Jerry Zhou if (gain && (gain > pin->gain_bits) &&
34803a49c214SYang-Rong Jerry Zhou (widget->type != WTYPE_AUDIO_MIX)) {
348188447a05SGarrett D'Amore path->gain_dir =
34823a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_INPUT;
348388447a05SGarrett D'Amore path->gain_bits = gain;
348488447a05SGarrett D'Amore path->gain_wid = widget->wid_wid;
34853a49c214SYang-Rong Jerry Zhou }
3486b96a6eceSZhao Edgar Liu - Sun Microsystems next = widget->output_path_next;
3487b96a6eceSZhao Edgar Liu - Sun Microsystems if (next == AUDIOHD_NULL_CONN)
34883a49c214SYang-Rong Jerry Zhou break;
3489b96a6eceSZhao Edgar Liu - Sun Microsystems wid = widget->avail_conn[next];
34903a49c214SYang-Rong Jerry Zhou widget = codec->widget[wid];
34913a49c214SYang-Rong Jerry Zhou }
349288447a05SGarrett D'Amore path->gain_bits >>= AUDIOHD_GAIN_OFF;
34933a49c214SYang-Rong Jerry Zhou }
3494582eadeeSfl
34953a49c214SYang-Rong Jerry Zhou }
3496582eadeeSfl
34973a49c214SYang-Rong Jerry Zhou } /* audiohd_build_output_amp */
3498582eadeeSfl
3499582eadeeSfl /*
35003a49c214SYang-Rong Jerry Zhou * audiohd_finish_output_path()
35017253a143Scg *
35023a49c214SYang-Rong Jerry Zhou * Description:
35033a49c214SYang-Rong Jerry Zhou * Enable the widgets on the output path
3504582eadeeSfl */
35053a49c214SYang-Rong Jerry Zhou static void
audiohd_finish_output_path(hda_codec_t * codec)35063a49c214SYang-Rong Jerry Zhou audiohd_finish_output_path(hda_codec_t *codec)
3507582eadeeSfl {
3508ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
350988447a05SGarrett D'Amore audiohd_path_t *path;
35103a49c214SYang-Rong Jerry Zhou audiohd_widget_t *widget;
35113a49c214SYang-Rong Jerry Zhou audiohd_pin_t *pin;
35123a49c214SYang-Rong Jerry Zhou uint_t caddr = codec->index;
3513b96a6eceSZhao Edgar Liu - Sun Microsystems wid_t wid, next;
351488447a05SGarrett D'Amore int i, j;
3515a234d95bScg
3516ea463888SZhao Edgar Liu - Sun Microsystems for (i = 0; i < codec->statep->pathnum; i++) {
3517ea463888SZhao Edgar Liu - Sun Microsystems path = codec->statep->path[i];
351888447a05SGarrett D'Amore if (!path || path->path_type != PLAY || path->codec != codec)
351988447a05SGarrett D'Amore continue;
352088447a05SGarrett D'Amore for (j = 0; j < path->pin_nums; j++) {
352188447a05SGarrett D'Amore wid = path->pin_wid[j];
35223a49c214SYang-Rong Jerry Zhou widget = codec->widget[wid];
35233a49c214SYang-Rong Jerry Zhou pin = (audiohd_pin_t *)widget->priv;
35243a49c214SYang-Rong Jerry Zhou {
35253a49c214SYang-Rong Jerry Zhou uint32_t lTmp;
35263a49c214SYang-Rong Jerry Zhou
35273a49c214SYang-Rong Jerry Zhou lTmp = audioha_codec_verb_get(statep, caddr, wid,
35283a49c214SYang-Rong Jerry Zhou AUDIOHDC_VERB_GET_PIN_CTRL, 0);
35293a49c214SYang-Rong Jerry Zhou (void) audioha_codec_verb_get(statep, caddr, wid,
35303a49c214SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_PIN_CTRL, (lTmp |
3531d5145224SYang-Rong Jerry Zhou pin->vrefvalue |
35323a49c214SYang-Rong Jerry Zhou AUDIOHDC_PIN_CONTROL_OUT_ENABLE |
35333a49c214SYang-Rong Jerry Zhou AUDIOHDC_PIN_CONTROL_HP_ENABLE) &
35343a49c214SYang-Rong Jerry Zhou ~ AUDIOHDC_PIN_CONTROL_IN_ENABLE);
35353a49c214SYang-Rong Jerry Zhou }
35363a49c214SYang-Rong Jerry Zhou /* If this pin has external amplifier, enable it */
3537feccaf6dSYang-Rong Jerry Zhou if (pin->cap & AUDIOHD_EXT_AMP_MASK)
35383a49c214SYang-Rong Jerry Zhou (void) audioha_codec_verb_get(statep, caddr,
3539feccaf6dSYang-Rong Jerry Zhou wid, AUDIOHDC_VERB_SET_EAPD,
3540feccaf6dSYang-Rong Jerry Zhou AUDIOHD_EXT_AMP_ENABLE);
35411582740eScg
35423a49c214SYang-Rong Jerry Zhou if (widget->outamp_cap) {
35433a49c214SYang-Rong Jerry Zhou (void) audioha_codec_4bit_verb_get(statep,
35443a49c214SYang-Rong Jerry Zhou caddr, wid, AUDIOHDC_VERB_SET_AMP_MUTE,
35453a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_LR_OUTPUT |
35463a49c214SYang-Rong Jerry Zhou AUDIOHDC_GAIN_MAX);
35473a49c214SYang-Rong Jerry Zhou }
3548582eadeeSfl
35493a49c214SYang-Rong Jerry Zhou (void) audioha_codec_verb_get(statep, caddr, wid,
3550b96a6eceSZhao Edgar Liu - Sun Microsystems AUDIOHDC_VERB_SET_CONN_SEL,
3551b96a6eceSZhao Edgar Liu - Sun Microsystems widget->output_path_next);
35523a49c214SYang-Rong Jerry Zhou
3553b96a6eceSZhao Edgar Liu - Sun Microsystems wid = widget->avail_conn[widget->output_path_next];
35543a49c214SYang-Rong Jerry Zhou widget = codec->widget[wid];
35553a49c214SYang-Rong Jerry Zhou
35563a49c214SYang-Rong Jerry Zhou while (widget) {
35573a49c214SYang-Rong Jerry Zhou /*
35583a49c214SYang-Rong Jerry Zhou * Set all amplifiers in this path to
3559b96a6eceSZhao Edgar Liu - Sun Microsystems * the maximum volume and unmute them.
35603a49c214SYang-Rong Jerry Zhou */
35613a49c214SYang-Rong Jerry Zhou if (widget->outamp_cap) {
35623a49c214SYang-Rong Jerry Zhou (void) audioha_codec_4bit_verb_get(
3563b96a6eceSZhao Edgar Liu - Sun Microsystems statep, caddr,
35643a49c214SYang-Rong Jerry Zhou wid, AUDIOHDC_VERB_SET_AMP_MUTE,
35653a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_LR_OUTPUT |
35663a49c214SYang-Rong Jerry Zhou AUDIOHDC_GAIN_MAX);
35673a49c214SYang-Rong Jerry Zhou }
35683a49c214SYang-Rong Jerry Zhou if (widget->inamp_cap) {
35693a49c214SYang-Rong Jerry Zhou (void) audioha_codec_4bit_verb_get(
3570b96a6eceSZhao Edgar Liu - Sun Microsystems statep, caddr,
35713a49c214SYang-Rong Jerry Zhou wid, AUDIOHDC_VERB_SET_AMP_MUTE,
35723a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_LR_INPUT |
35733a49c214SYang-Rong Jerry Zhou AUDIOHDC_GAIN_MAX |
3574b96a6eceSZhao Edgar Liu - Sun Microsystems (widget->output_path_next <<
35753a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_INDEX_OFFSET));
35763a49c214SYang-Rong Jerry Zhou }
35773a49c214SYang-Rong Jerry Zhou
3578b96a6eceSZhao Edgar Liu - Sun Microsystems next = widget->output_path_next;
3579b96a6eceSZhao Edgar Liu - Sun Microsystems if (next == AUDIOHD_NULL_CONN)
35803a49c214SYang-Rong Jerry Zhou break;
35813a49c214SYang-Rong Jerry Zhou /*
35823a49c214SYang-Rong Jerry Zhou * Accoding to HD spec, mixer doesn't support
35833a49c214SYang-Rong Jerry Zhou * "select connection"
35843a49c214SYang-Rong Jerry Zhou */
3585b96a6eceSZhao Edgar Liu - Sun Microsystems if ((widget->type == WTYPE_AUDIO_SEL) &&
35863a49c214SYang-Rong Jerry Zhou (widget->nconns > 1))
35873a49c214SYang-Rong Jerry Zhou (void) audioha_codec_verb_get(statep,
3588b96a6eceSZhao Edgar Liu - Sun Microsystems caddr, wid,
35893a49c214SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_CONN_SEL,
3590b96a6eceSZhao Edgar Liu - Sun Microsystems widget->output_path_next);
35913a49c214SYang-Rong Jerry Zhou
3592b96a6eceSZhao Edgar Liu - Sun Microsystems wid = widget->avail_conn[next];
35933a49c214SYang-Rong Jerry Zhou widget = codec->widget[wid];
35943a49c214SYang-Rong Jerry Zhou }
35953a49c214SYang-Rong Jerry Zhou }
35963a49c214SYang-Rong Jerry Zhou }
35973a49c214SYang-Rong Jerry Zhou } /* audiohd_finish_output_path() */
3598582eadeeSfl
3599582eadeeSfl /*
36003a49c214SYang-Rong Jerry Zhou * audiohd_find_input_pins()
36017253a143Scg *
3602a234d95bScg * Description:
36033a49c214SYang-Rong Jerry Zhou * Here we consider a mixer/selector with multi-input as a real sum
36043a49c214SYang-Rong Jerry Zhou * widget. Only the first real mixer/selector widget is permitted in
36053a49c214SYang-Rong Jerry Zhou * an input path(recording path). If there are more mixers/selectors
36063a49c214SYang-Rong Jerry Zhou * execept the first one, only the first input/connection of those
36073a49c214SYang-Rong Jerry Zhou * widgets will be used by our driver, that means, we ignore other
36083a49c214SYang-Rong Jerry Zhou * inputs of those mixers/selectors.
3609582eadeeSfl */
3610582eadeeSfl static int
audiohd_find_input_pins(hda_codec_t * codec,wid_t wid,int allowmixer,int depth,audiohd_path_t * path)36113a49c214SYang-Rong Jerry Zhou audiohd_find_input_pins(hda_codec_t *codec, wid_t wid, int allowmixer,
361288447a05SGarrett D'Amore int depth, audiohd_path_t *path)
3613582eadeeSfl {
36143a49c214SYang-Rong Jerry Zhou audiohd_widget_t *widget = codec->widget[wid];
36153a49c214SYang-Rong Jerry Zhou audiohd_pin_t *pin;
3616ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
36173a49c214SYang-Rong Jerry Zhou uint_t caddr = codec->index;
36183a49c214SYang-Rong Jerry Zhou int retval = -1;
3619feccaf6dSYang-Rong Jerry Zhou int num, i;
36203a49c214SYang-Rong Jerry Zhou uint32_t pinctrl;
36213a49c214SYang-Rong Jerry Zhou
36223a49c214SYang-Rong Jerry Zhou if (depth > AUDIOHD_MAX_DEPTH)
3623c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
362431a3f136SYang-Rong Jerry Zhou if (widget == NULL)
3625c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
36263a49c214SYang-Rong Jerry Zhou
36273a49c214SYang-Rong Jerry Zhou /* we don't share widgets */
362865a41de7SYang-Rong Jerry Zhou if (widget->path_flags & AUDIOHD_PATH_ADC ||
362965a41de7SYang-Rong Jerry Zhou widget->path_flags & AUDIOHD_PATH_DAC)
3630c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
36313a49c214SYang-Rong Jerry Zhou
36323a49c214SYang-Rong Jerry Zhou switch (widget->type) {
36333a49c214SYang-Rong Jerry Zhou case WTYPE_PIN:
36343a49c214SYang-Rong Jerry Zhou pin = (audiohd_pin_t *)widget->priv;
36353a49c214SYang-Rong Jerry Zhou if (pin->no_phys_conn)
3636c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
36373a49c214SYang-Rong Jerry Zhou /* enable the pins' input capability */
36383a49c214SYang-Rong Jerry Zhou pinctrl = audioha_codec_verb_get(statep, caddr, wid,
36393a49c214SYang-Rong Jerry Zhou AUDIOHDC_VERB_GET_PIN_CTRL, 0);
36403a49c214SYang-Rong Jerry Zhou (void) audioha_codec_verb_get(statep, caddr, wid,
36413a49c214SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_PIN_CTRL,
36423a49c214SYang-Rong Jerry Zhou pinctrl | AUDIOHD_PIN_IN_ENABLE);
364316600ba1SYang-Rong Jerry Zhou if (pin->cap & AUDIOHD_EXT_AMP_MASK) {
364416600ba1SYang-Rong Jerry Zhou (void) audioha_codec_verb_get(statep, caddr,
364516600ba1SYang-Rong Jerry Zhou wid, AUDIOHDC_VERB_SET_EAPD,
364616600ba1SYang-Rong Jerry Zhou AUDIOHD_EXT_AMP_ENABLE);
364716600ba1SYang-Rong Jerry Zhou }
36483a49c214SYang-Rong Jerry Zhou switch (pin->device) {
36493a49c214SYang-Rong Jerry Zhou case DTYPE_CD:
36503a49c214SYang-Rong Jerry Zhou case DTYPE_LINE_IN:
36513a49c214SYang-Rong Jerry Zhou case DTYPE_MIC_IN:
36523a49c214SYang-Rong Jerry Zhou case DTYPE_AUX:
36533a49c214SYang-Rong Jerry Zhou widget->path_flags |= AUDIOHD_PATH_ADC;
36543a49c214SYang-Rong Jerry Zhou widget->in_weight++;
365588447a05SGarrett D'Amore path->pin_wid[path->pin_nums++] = wid;
3656e7236f70SZhao Edgar Liu - Sun Microsystems pin->adc_wid = path->adda_wid;
3657c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
36583a49c214SYang-Rong Jerry Zhou }
3659582eadeeSfl break;
36603a49c214SYang-Rong Jerry Zhou case WTYPE_AUDIO_MIX:
36613a49c214SYang-Rong Jerry Zhou case WTYPE_AUDIO_SEL:
36623a49c214SYang-Rong Jerry Zhou /*
36633a49c214SYang-Rong Jerry Zhou * If the sum widget has only one input, we don't
36643a49c214SYang-Rong Jerry Zhou * consider it as a real sum widget.
36653a49c214SYang-Rong Jerry Zhou */
36663a49c214SYang-Rong Jerry Zhou if (widget->nconns == 1) {
3667b96a6eceSZhao Edgar Liu - Sun Microsystems widget->input_path_next = 0;
36683a49c214SYang-Rong Jerry Zhou retval = audiohd_find_input_pins(codec,
36693a49c214SYang-Rong Jerry Zhou widget->avail_conn[0],
367088447a05SGarrett D'Amore allowmixer, depth + 1, path);
3671b96a6eceSZhao Edgar Liu - Sun Microsystems if (retval == DDI_SUCCESS) {
36723a49c214SYang-Rong Jerry Zhou widget->path_flags |= AUDIOHD_PATH_ADC;
36733a49c214SYang-Rong Jerry Zhou widget->in_weight++;
36743a49c214SYang-Rong Jerry Zhou }
36753a49c214SYang-Rong Jerry Zhou break;
36763a49c214SYang-Rong Jerry Zhou }
3677582eadeeSfl
36783a49c214SYang-Rong Jerry Zhou if (allowmixer) {
36793a49c214SYang-Rong Jerry Zhou /*
36803a49c214SYang-Rong Jerry Zhou * This is a real sum widget, we will reject
36813a49c214SYang-Rong Jerry Zhou * other real sum widget when we find more in
36823a49c214SYang-Rong Jerry Zhou * the following path-searching.
36833a49c214SYang-Rong Jerry Zhou */
36843a49c214SYang-Rong Jerry Zhou for (int i = 0; i < widget->nconns; i++) {
36853a49c214SYang-Rong Jerry Zhou retval = audiohd_find_input_pins(codec,
36863a49c214SYang-Rong Jerry Zhou widget->avail_conn[i], 0, depth + 1,
368788447a05SGarrett D'Amore path);
3688b96a6eceSZhao Edgar Liu - Sun Microsystems if (retval == DDI_SUCCESS) {
3689b96a6eceSZhao Edgar Liu - Sun Microsystems widget->input_path_next = i;
36903a49c214SYang-Rong Jerry Zhou widget->in_weight++;
369188447a05SGarrett D'Amore num = path->pin_nums - 1;
369288447a05SGarrett D'Amore path->sum_selconn[num] = i;
369388447a05SGarrett D'Amore path->sum_wid = wid;
369431a3f136SYang-Rong Jerry Zhou widget->path_flags |=
369531a3f136SYang-Rong Jerry Zhou AUDIOHD_PATH_ADC;
36963a49c214SYang-Rong Jerry Zhou }
36973a49c214SYang-Rong Jerry Zhou }
3698582eadeeSfl
36993a49c214SYang-Rong Jerry Zhou /* return SUCCESS if we found at least one input path */
370088447a05SGarrett D'Amore if (path->pin_nums > 0)
3701c6e681c0SYang-Rong Jerry Zhou retval = DDI_SUCCESS;
37023a49c214SYang-Rong Jerry Zhou } else {
37033a49c214SYang-Rong Jerry Zhou /*
37043a49c214SYang-Rong Jerry Zhou * We had already found a real sum before this one since
3705feccaf6dSYang-Rong Jerry Zhou * allowmixer is 0.
37063a49c214SYang-Rong Jerry Zhou */
3707feccaf6dSYang-Rong Jerry Zhou for (i = 0; i < widget->nconns; i++) {
3708feccaf6dSYang-Rong Jerry Zhou retval = audiohd_find_input_pins(codec,
3709feccaf6dSYang-Rong Jerry Zhou widget->avail_conn[i], 0, depth + 1,
371088447a05SGarrett D'Amore path);
3711b96a6eceSZhao Edgar Liu - Sun Microsystems if (retval == DDI_SUCCESS) {
3712b96a6eceSZhao Edgar Liu - Sun Microsystems widget->input_path_next = i;
3713feccaf6dSYang-Rong Jerry Zhou widget->path_flags |= AUDIOHD_PATH_ADC;
3714feccaf6dSYang-Rong Jerry Zhou widget->in_weight++;
3715feccaf6dSYang-Rong Jerry Zhou break;
3716feccaf6dSYang-Rong Jerry Zhou }
37173a49c214SYang-Rong Jerry Zhou }
37183a49c214SYang-Rong Jerry Zhou }
37193a49c214SYang-Rong Jerry Zhou break;
37203a49c214SYang-Rong Jerry Zhou default:
37213a49c214SYang-Rong Jerry Zhou break;
37223a49c214SYang-Rong Jerry Zhou }
37237253a143Scg
37243a49c214SYang-Rong Jerry Zhou return (retval);
37253a49c214SYang-Rong Jerry Zhou } /* audiohd_find_input_pins */
37267253a143Scg
3727a234d95bScg /*
37283a49c214SYang-Rong Jerry Zhou * audiohd_build_input_path()
37297253a143Scg *
3730a234d95bScg * Description:
37313a49c214SYang-Rong Jerry Zhou * Find input path for the codec
3732a234d95bScg */
3733a234d95bScg static void
audiohd_build_input_path(hda_codec_t * codec)37343a49c214SYang-Rong Jerry Zhou audiohd_build_input_path(hda_codec_t *codec)
3735a234d95bScg {
37363a49c214SYang-Rong Jerry Zhou audiohd_widget_t *widget;
373788447a05SGarrett D'Amore audiohd_path_t *path = NULL;
37383a49c214SYang-Rong Jerry Zhou wid_t wid;
37393a49c214SYang-Rong Jerry Zhou int i;
37403a49c214SYang-Rong Jerry Zhou int retval;
374116600ba1SYang-Rong Jerry Zhou uint8_t rtag = 0;
3742ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
37433a49c214SYang-Rong Jerry Zhou
37443a49c214SYang-Rong Jerry Zhou for (wid = codec->first_wid; wid <= codec->last_wid; wid++) {
37453a49c214SYang-Rong Jerry Zhou
37463a49c214SYang-Rong Jerry Zhou widget = codec->widget[wid];
3747a234d95bScg
37483a49c214SYang-Rong Jerry Zhou /* check if it is an ADC widget */
3749b96a6eceSZhao Edgar Liu - Sun Microsystems if (widget == NULL || widget->type != WTYPE_AUDIO_IN)
37503a49c214SYang-Rong Jerry Zhou continue;
3751a234d95bScg
375288447a05SGarrett D'Amore if (path == NULL)
375388447a05SGarrett D'Amore path = kmem_zalloc(sizeof (audiohd_path_t),
37543a49c214SYang-Rong Jerry Zhou KM_SLEEP);
37553a49c214SYang-Rong Jerry Zhou else
375688447a05SGarrett D'Amore bzero(path, sizeof (audiohd_port_t));
3757a234d95bScg
375888447a05SGarrett D'Amore path->adda_wid = wid;
37597253a143Scg
37603a49c214SYang-Rong Jerry Zhou /*
37613a49c214SYang-Rong Jerry Zhou * Is there any ADC widget which has more than one input ??
37623a49c214SYang-Rong Jerry Zhou * I don't believe. Anyway, we carefully deal with this. But
37633a49c214SYang-Rong Jerry Zhou * if hardware vendors embed a selector in a ADC, we just use
37643a49c214SYang-Rong Jerry Zhou * the first available input, which has connection to input pin
37653a49c214SYang-Rong Jerry Zhou * widget. Because selector cannot perform mixer functionality,
37663a49c214SYang-Rong Jerry Zhou * and we just permit one selector or mixer in a recording path,
37673a49c214SYang-Rong Jerry Zhou * if we use the selector embedded in ADC,we cannot use possible
37683a49c214SYang-Rong Jerry Zhou * mixer during path searching.
37693a49c214SYang-Rong Jerry Zhou */
37703a49c214SYang-Rong Jerry Zhou for (i = 0; i < widget->nconns; i++) {
37713a49c214SYang-Rong Jerry Zhou retval = audiohd_find_input_pins(codec,
377288447a05SGarrett D'Amore widget->avail_conn[i], 1, 0, path);
3773c6e681c0SYang-Rong Jerry Zhou if (retval == DDI_SUCCESS) {
377488447a05SGarrett D'Amore path->codec = codec;
377588447a05SGarrett D'Amore path->statep = statep;
377688447a05SGarrett D'Amore path->path_type = RECORD;
377788447a05SGarrett D'Amore path->tag = ++rtag;
377816600ba1SYang-Rong Jerry Zhou codec->nistream++;
377988447a05SGarrett D'Amore statep->path[statep->pathnum++] = path;
3780b96a6eceSZhao Edgar Liu - Sun Microsystems widget->input_path_next = i;
378188447a05SGarrett D'Amore widget->priv = path;
378288447a05SGarrett D'Amore path = NULL;
37833a49c214SYang-Rong Jerry Zhou break;
37843a49c214SYang-Rong Jerry Zhou }
37853a49c214SYang-Rong Jerry Zhou }
37863a49c214SYang-Rong Jerry Zhou }
378788447a05SGarrett D'Amore if (path)
378888447a05SGarrett D'Amore kmem_free(path, sizeof (audiohd_path_t));
37893a49c214SYang-Rong Jerry Zhou } /* audiohd_build_input_path */
37907253a143Scg
37917253a143Scg /*
37923a49c214SYang-Rong Jerry Zhou * audiohd_build_input_amp()
37933a49c214SYang-Rong Jerry Zhou *
37943a49c214SYang-Rong Jerry Zhou * Description:
37953a49c214SYang-Rong Jerry Zhou * Find gain and mute control widgets on the input path
37967253a143Scg */
37973a49c214SYang-Rong Jerry Zhou static void
audiohd_build_input_amp(hda_codec_t * codec)37983a49c214SYang-Rong Jerry Zhou audiohd_build_input_amp(hda_codec_t *codec)
37997253a143Scg {
380088447a05SGarrett D'Amore audiohd_path_t *path;
38013a49c214SYang-Rong Jerry Zhou audiohd_widget_t *wsum, *wadc, *w;
38023a49c214SYang-Rong Jerry Zhou audiohd_pin_t *pin;
38033a49c214SYang-Rong Jerry Zhou uint_t gain;
3804b96a6eceSZhao Edgar Liu - Sun Microsystems wid_t wid, next;
380588447a05SGarrett D'Amore int i, j;
38063a49c214SYang-Rong Jerry Zhou int weight;
38077253a143Scg
3808ea463888SZhao Edgar Liu - Sun Microsystems for (i = 0; i < codec->statep->pathnum; i++) {
3809ea463888SZhao Edgar Liu - Sun Microsystems path = codec->statep->path[i];
3810a4c3d128SYang-Rong Jerry Zhou if (path == NULL || path->path_type != RECORD ||
381188447a05SGarrett D'Amore path->codec != codec)
381288447a05SGarrett D'Amore continue;
381388447a05SGarrett D'Amore
381488447a05SGarrett D'Amore wid = path->adda_wid;
381588447a05SGarrett D'Amore wadc = path->codec->widget[wid];
38163a49c214SYang-Rong Jerry Zhou weight = wadc->in_weight;
38177253a143Scg
38183a49c214SYang-Rong Jerry Zhou /*
38193a49c214SYang-Rong Jerry Zhou * Search node which has mute functionality for
38203a49c214SYang-Rong Jerry Zhou * the whole input path
38213a49c214SYang-Rong Jerry Zhou */
38223a49c214SYang-Rong Jerry Zhou w = wadc;
38233a49c214SYang-Rong Jerry Zhou while (w) {
38243a49c214SYang-Rong Jerry Zhou if (w->outamp_cap & AUDIOHDC_AMP_CAP_MUTE_CAP) {
382588447a05SGarrett D'Amore path->mute_wid = w->wid_wid;
382688447a05SGarrett D'Amore path->mute_dir = AUDIOHDC_AMP_SET_OUTPUT;
38273a49c214SYang-Rong Jerry Zhou break;
38283a49c214SYang-Rong Jerry Zhou }
38293a49c214SYang-Rong Jerry Zhou if ((w->inamp_cap & AUDIOHDC_AMP_CAP_MUTE_CAP) &&
383088447a05SGarrett D'Amore (w->wid_wid != path->sum_wid)) {
383188447a05SGarrett D'Amore path->mute_wid = w->wid_wid;
383288447a05SGarrett D'Amore path->mute_dir = AUDIOHDC_AMP_SET_INPUT;
38333a49c214SYang-Rong Jerry Zhou break;
38343a49c214SYang-Rong Jerry Zhou }
38357253a143Scg
3836b96a6eceSZhao Edgar Liu - Sun Microsystems next = w->input_path_next;
3837b96a6eceSZhao Edgar Liu - Sun Microsystems if (next == AUDIOHD_NULL_CONN)
38383a49c214SYang-Rong Jerry Zhou break;
3839b96a6eceSZhao Edgar Liu - Sun Microsystems wid = w->avail_conn[next];
384088447a05SGarrett D'Amore w = path->codec->widget[wid];
384131a3f136SYang-Rong Jerry Zhou if (w && w->in_weight != weight)
38423a49c214SYang-Rong Jerry Zhou break;
38433a49c214SYang-Rong Jerry Zhou }
38447253a143Scg
38453a49c214SYang-Rong Jerry Zhou /*
38463a49c214SYang-Rong Jerry Zhou * Search a node for amplifier adjusting for the whole
38473a49c214SYang-Rong Jerry Zhou * input path
38483a49c214SYang-Rong Jerry Zhou */
38493a49c214SYang-Rong Jerry Zhou w = wadc;
38503a49c214SYang-Rong Jerry Zhou gain = 0;
38513a49c214SYang-Rong Jerry Zhou while (w) {
38523a49c214SYang-Rong Jerry Zhou gain = (w->outamp_cap & AUDIOHDC_AMP_CAP_STEP_NUMS);
385388447a05SGarrett D'Amore if (gain && gain > path->gain_bits) {
385488447a05SGarrett D'Amore path->gain_dir = AUDIOHDC_AMP_SET_OUTPUT;
385588447a05SGarrett D'Amore path->gain_bits = gain;
385688447a05SGarrett D'Amore path->gain_wid = w->wid_wid;
38573a49c214SYang-Rong Jerry Zhou }
38583a49c214SYang-Rong Jerry Zhou gain = w->inamp_cap & AUDIOHDC_AMP_CAP_STEP_NUMS;
385988447a05SGarrett D'Amore if (gain && (gain > path->gain_bits) &&
386088447a05SGarrett D'Amore (w->wid_wid != path->sum_wid)) {
386188447a05SGarrett D'Amore path->gain_dir = AUDIOHDC_AMP_SET_INPUT;
386288447a05SGarrett D'Amore path->gain_bits = gain;
386388447a05SGarrett D'Amore path->gain_wid = w->wid_wid;
38643a49c214SYang-Rong Jerry Zhou }
3865b96a6eceSZhao Edgar Liu - Sun Microsystems
3866b96a6eceSZhao Edgar Liu - Sun Microsystems next = w->input_path_next;
3867b96a6eceSZhao Edgar Liu - Sun Microsystems if (next == AUDIOHD_NULL_CONN)
38683a49c214SYang-Rong Jerry Zhou break;
3869b96a6eceSZhao Edgar Liu - Sun Microsystems wid = w->avail_conn[next];
387088447a05SGarrett D'Amore w = path->codec->widget[wid];
38713a49c214SYang-Rong Jerry Zhou }
387288447a05SGarrett D'Amore path->gain_bits >>= AUDIOHD_GAIN_OFF;
38737253a143Scg
38743a49c214SYang-Rong Jerry Zhou /*
38753a49c214SYang-Rong Jerry Zhou * If the input path has one pin only, the mute/amp
38763a49c214SYang-Rong Jerry Zhou * controlling is shared by the whole path and pin
38773a49c214SYang-Rong Jerry Zhou */
387888447a05SGarrett D'Amore if (path->pin_nums == 1) {
387988447a05SGarrett D'Amore wid = path->pin_wid[0];
388088447a05SGarrett D'Amore w = path->codec->widget[wid];
38813a49c214SYang-Rong Jerry Zhou pin = (audiohd_pin_t *)w->priv;
388288447a05SGarrett D'Amore pin->gain_dir = path->gain_dir;
388388447a05SGarrett D'Amore pin->gain_bits = path->gain_bits;
388488447a05SGarrett D'Amore pin->gain_wid = path->gain_wid;
388588447a05SGarrett D'Amore pin->mute_wid = path->mute_wid;
388688447a05SGarrett D'Amore pin->mute_dir = path->mute_dir;
38873a49c214SYang-Rong Jerry Zhou continue;
38883a49c214SYang-Rong Jerry Zhou }
38897253a143Scg
38903a49c214SYang-Rong Jerry Zhou /*
38913a49c214SYang-Rong Jerry Zhou * For multi-pin device, there must be a selector
38923a49c214SYang-Rong Jerry Zhou * or mixer along the input path, and the sum_wid
38933a49c214SYang-Rong Jerry Zhou * is the widget's node id.
38943a49c214SYang-Rong Jerry Zhou */
389588447a05SGarrett D'Amore wid = path->sum_wid;
389688447a05SGarrett D'Amore wsum = path->codec->widget[wid]; /* sum widget */
38973a49c214SYang-Rong Jerry Zhou
389888447a05SGarrett D'Amore for (j = 0; j < path->pin_nums; j++) {
389988447a05SGarrett D'Amore wid = path->pin_wid[j];
390088447a05SGarrett D'Amore w = path->codec->widget[wid];
39013a49c214SYang-Rong Jerry Zhou pin = (audiohd_pin_t *)w->priv;
39023a49c214SYang-Rong Jerry Zhou
39033a49c214SYang-Rong Jerry Zhou /* find node for mute */
39043a49c214SYang-Rong Jerry Zhou if (wsum->inamp_cap & AUDIOHDC_AMP_CAP_MUTE_CAP) {
39053a49c214SYang-Rong Jerry Zhou pin->mute_wid = wsum->wid_wid;
39063a49c214SYang-Rong Jerry Zhou pin->mute_dir = AUDIOHDC_AMP_SET_INPUT;
39073a49c214SYang-Rong Jerry Zhou } else {
390888447a05SGarrett D'Amore wid = wsum->avail_conn[path->sum_selconn[i]];
390988447a05SGarrett D'Amore w = path->codec->widget[wid];
39103a49c214SYang-Rong Jerry Zhou while (w) {
39113a49c214SYang-Rong Jerry Zhou if (w->outamp_cap &
39123a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_CAP_MUTE_CAP) {
39133a49c214SYang-Rong Jerry Zhou pin->mute_wid = w->wid_wid;
39143a49c214SYang-Rong Jerry Zhou pin->mute_dir =
39153a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_OUTPUT;
39163a49c214SYang-Rong Jerry Zhou break;
39173a49c214SYang-Rong Jerry Zhou }
39183a49c214SYang-Rong Jerry Zhou if (w->inamp_cap &
39193a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_CAP_MUTE_CAP) {
39203a49c214SYang-Rong Jerry Zhou pin->mute_wid = w->wid_wid;
39213a49c214SYang-Rong Jerry Zhou pin->mute_dir =
39223a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_INPUT;
39233a49c214SYang-Rong Jerry Zhou break;
39243a49c214SYang-Rong Jerry Zhou }
39253a49c214SYang-Rong Jerry Zhou
3926b96a6eceSZhao Edgar Liu - Sun Microsystems next = w->input_path_next;
3927b96a6eceSZhao Edgar Liu - Sun Microsystems if (next == AUDIOHD_NULL_CONN)
39283a49c214SYang-Rong Jerry Zhou break;
3929b96a6eceSZhao Edgar Liu - Sun Microsystems wid = w->avail_conn[next];
393088447a05SGarrett D'Amore w = path->codec->widget[wid];
39313a49c214SYang-Rong Jerry Zhou }
39323a49c214SYang-Rong Jerry Zhou }
39337253a143Scg
39343a49c214SYang-Rong Jerry Zhou /* find node for amp controlling */
39353a49c214SYang-Rong Jerry Zhou gain = (wsum->inamp_cap & AUDIOHDC_AMP_CAP_STEP_NUMS);
393688447a05SGarrett D'Amore wid = wsum->avail_conn[path->sum_selconn[i]];
393788447a05SGarrett D'Amore w = path->codec->widget[wid];
39383a49c214SYang-Rong Jerry Zhou while (w) {
39393a49c214SYang-Rong Jerry Zhou gain = (w->outamp_cap &
39403a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_CAP_STEP_NUMS);
39413a49c214SYang-Rong Jerry Zhou if (gain && gain > pin->gain_bits) {
39423a49c214SYang-Rong Jerry Zhou pin->gain_dir = AUDIOHDC_AMP_SET_OUTPUT;
39433a49c214SYang-Rong Jerry Zhou pin->gain_bits = gain;
39443a49c214SYang-Rong Jerry Zhou pin->gain_wid = w->wid_wid;
39453a49c214SYang-Rong Jerry Zhou }
39463a49c214SYang-Rong Jerry Zhou gain = w->inamp_cap &
39473a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_CAP_STEP_NUMS;
39483a49c214SYang-Rong Jerry Zhou if (gain && (gain > pin->gain_bits)) {
39493a49c214SYang-Rong Jerry Zhou pin->gain_dir = AUDIOHDC_AMP_SET_INPUT;
39503a49c214SYang-Rong Jerry Zhou pin->gain_bits = gain;
39513a49c214SYang-Rong Jerry Zhou pin->gain_wid = w->wid_wid;
39523a49c214SYang-Rong Jerry Zhou }
3953b96a6eceSZhao Edgar Liu - Sun Microsystems
3954b96a6eceSZhao Edgar Liu - Sun Microsystems next = w->input_path_next;
3955b96a6eceSZhao Edgar Liu - Sun Microsystems if (next == AUDIOHD_NULL_CONN)
39563a49c214SYang-Rong Jerry Zhou break;
3957b96a6eceSZhao Edgar Liu - Sun Microsystems wid = w->avail_conn[next];
395888447a05SGarrett D'Amore w = path->codec->widget[wid];
39593a49c214SYang-Rong Jerry Zhou }
39603a49c214SYang-Rong Jerry Zhou pin->gain_bits >>= AUDIOHD_GAIN_OFF;
39613a49c214SYang-Rong Jerry Zhou }
39623a49c214SYang-Rong Jerry Zhou }
39633a49c214SYang-Rong Jerry Zhou } /* audiohd_build_input_amp() */
39647253a143Scg
3965f90d8383Scg /*
39663a49c214SYang-Rong Jerry Zhou * audiohd_finish_input_path()
39673a49c214SYang-Rong Jerry Zhou *
39683a49c214SYang-Rong Jerry Zhou * Description:
39693a49c214SYang-Rong Jerry Zhou * Enable the widgets on the input path
3970f90d8383Scg */
39713a49c214SYang-Rong Jerry Zhou static void
audiohd_finish_input_path(hda_codec_t * codec)39723a49c214SYang-Rong Jerry Zhou audiohd_finish_input_path(hda_codec_t *codec)
3973f90d8383Scg {
3974ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
397565a41de7SYang-Rong Jerry Zhou audiohd_path_t *path;
39763a49c214SYang-Rong Jerry Zhou audiohd_widget_t *w, *wsum;
39773a49c214SYang-Rong Jerry Zhou uint_t caddr = codec->index;
39783a49c214SYang-Rong Jerry Zhou wid_t wid;
397988447a05SGarrett D'Amore int i, j;
3980f90d8383Scg
3981ea463888SZhao Edgar Liu - Sun Microsystems for (i = 0; i < codec->statep->pathnum; i++) {
3982ea463888SZhao Edgar Liu - Sun Microsystems path = codec->statep->path[i];
3983a4c3d128SYang-Rong Jerry Zhou if (path == NULL || path->path_type != RECORD ||
398488447a05SGarrett D'Amore path->codec != codec)
398588447a05SGarrett D'Amore continue;
398688447a05SGarrett D'Amore wid = path->adda_wid;
398788447a05SGarrett D'Amore w = path->codec->widget[wid];
398888447a05SGarrett D'Amore while (w && (w->wid_wid != path->sum_wid) &&
39893a49c214SYang-Rong Jerry Zhou (w->type != WTYPE_PIN)) {
39903a49c214SYang-Rong Jerry Zhou if ((w->type == WTYPE_AUDIO_SEL) && (w->nconns > 1))
39913a49c214SYang-Rong Jerry Zhou (void) audioha_codec_verb_get(statep, caddr,
3992b96a6eceSZhao Edgar Liu - Sun Microsystems w->wid_wid, AUDIOHDC_VERB_SET_CONN_SEL,
3993b96a6eceSZhao Edgar Liu - Sun Microsystems w->input_path_next);
39943a49c214SYang-Rong Jerry Zhou
39953a49c214SYang-Rong Jerry Zhou if (w->outamp_cap) {
39963a49c214SYang-Rong Jerry Zhou (void) audioha_codec_4bit_verb_get(statep,
39973a49c214SYang-Rong Jerry Zhou caddr,
39983a49c214SYang-Rong Jerry Zhou w->wid_wid, AUDIOHDC_VERB_SET_AMP_MUTE,
39993a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_LR_OUTPUT |
40003a49c214SYang-Rong Jerry Zhou AUDIOHDC_GAIN_MAX);
40013a49c214SYang-Rong Jerry Zhou }
4002f90d8383Scg
40033a49c214SYang-Rong Jerry Zhou if (w->inamp_cap) {
40043a49c214SYang-Rong Jerry Zhou (void) audioha_codec_4bit_verb_get(statep,
40053a49c214SYang-Rong Jerry Zhou caddr,
40063a49c214SYang-Rong Jerry Zhou w->wid_wid, AUDIOHDC_VERB_SET_AMP_MUTE,
40073a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_LR_INPUT |
40083a49c214SYang-Rong Jerry Zhou AUDIOHDC_GAIN_MAX |
4009b96a6eceSZhao Edgar Liu - Sun Microsystems (w->input_path_next <<
40103a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_INDEX_OFFSET));
40113a49c214SYang-Rong Jerry Zhou }
4012f90d8383Scg
4013b96a6eceSZhao Edgar Liu - Sun Microsystems wid = w->avail_conn[w->input_path_next];
401488447a05SGarrett D'Amore w = path->codec->widget[wid];
40153a49c214SYang-Rong Jerry Zhou }
4016f90d8383Scg
40173a49c214SYang-Rong Jerry Zhou /*
40183a49c214SYang-Rong Jerry Zhou * After exiting from the above loop, the widget pointed
40193a49c214SYang-Rong Jerry Zhou * by w can be a pin widget or select/mixer widget. If it
40203a49c214SYang-Rong Jerry Zhou * is a pin widget, we already finish "select connection"
40213a49c214SYang-Rong Jerry Zhou * operation for the whole path.
40223a49c214SYang-Rong Jerry Zhou */
4023e56adb4fSYang-Rong Jerry Zhou if (w && w->type == WTYPE_PIN)
40243a49c214SYang-Rong Jerry Zhou continue;
4025f90d8383Scg
40263a49c214SYang-Rong Jerry Zhou /*
40273a49c214SYang-Rong Jerry Zhou * deal with multi-pin input devices.
40283a49c214SYang-Rong Jerry Zhou */
402988447a05SGarrett D'Amore wid = path->sum_wid;
403088447a05SGarrett D'Amore wsum = path->codec->widget[wid];
4031e56adb4fSYang-Rong Jerry Zhou if (wsum == NULL)
4032e56adb4fSYang-Rong Jerry Zhou continue;
40333a49c214SYang-Rong Jerry Zhou if (wsum->outamp_cap) {
40343a49c214SYang-Rong Jerry Zhou (void) audioha_codec_4bit_verb_get(statep,
40353a49c214SYang-Rong Jerry Zhou caddr,
40363a49c214SYang-Rong Jerry Zhou wsum->wid_wid, AUDIOHDC_VERB_SET_AMP_MUTE,
40373a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_LR_OUTPUT |
40383a49c214SYang-Rong Jerry Zhou AUDIOHDC_GAIN_MAX);
40393a49c214SYang-Rong Jerry Zhou }
4040f90d8383Scg
404188447a05SGarrett D'Amore for (j = 0; j < path->pin_nums; j++) {
40423a49c214SYang-Rong Jerry Zhou if (wsum->inamp_cap) {
40433a49c214SYang-Rong Jerry Zhou (void) audioha_codec_4bit_verb_get(statep,
40443a49c214SYang-Rong Jerry Zhou caddr,
40453a49c214SYang-Rong Jerry Zhou wsum->wid_wid, AUDIOHDC_VERB_SET_AMP_MUTE,
40463a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_LR_INPUT |
40473a49c214SYang-Rong Jerry Zhou AUDIOHDC_GAIN_MAX |
404888447a05SGarrett D'Amore (path->sum_selconn[j] <<
40493a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_INDEX_OFFSET));
40503a49c214SYang-Rong Jerry Zhou }
40513a49c214SYang-Rong Jerry Zhou if (wsum->type == WTYPE_AUDIO_SEL) {
40523a49c214SYang-Rong Jerry Zhou (void) audioha_codec_verb_get(statep, caddr,
40533a49c214SYang-Rong Jerry Zhou wsum->wid_wid,
40543a49c214SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_CONN_SEL,
405588447a05SGarrett D'Amore path->sum_selconn[j]);
40563a49c214SYang-Rong Jerry Zhou }
4057f90d8383Scg
405888447a05SGarrett D'Amore wid = wsum->avail_conn[path->sum_selconn[j]];
405988447a05SGarrett D'Amore w = path->codec->widget[wid];
4060e56adb4fSYang-Rong Jerry Zhou while (w && w->type != WTYPE_PIN) {
40613a49c214SYang-Rong Jerry Zhou if ((w->type != WTYPE_AUDIO_MIX) &&
40623a49c214SYang-Rong Jerry Zhou (w->nconns > 1))
40633a49c214SYang-Rong Jerry Zhou (void) audioha_codec_verb_get(statep,
40643a49c214SYang-Rong Jerry Zhou caddr, w->wid_wid,
40653a49c214SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_CONN_SEL,
4066b96a6eceSZhao Edgar Liu - Sun Microsystems w->input_path_next);
40673a49c214SYang-Rong Jerry Zhou
40683a49c214SYang-Rong Jerry Zhou if (w->outamp_cap) {
40693a49c214SYang-Rong Jerry Zhou (void) audioha_codec_4bit_verb_get(
40703a49c214SYang-Rong Jerry Zhou statep,
40713a49c214SYang-Rong Jerry Zhou caddr,
40723a49c214SYang-Rong Jerry Zhou w->wid_wid,
40733a49c214SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_AMP_MUTE,
40743a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_LR_OUTPUT |
40753a49c214SYang-Rong Jerry Zhou AUDIOHDC_GAIN_MAX);
40763a49c214SYang-Rong Jerry Zhou }
40773a49c214SYang-Rong Jerry Zhou
40783a49c214SYang-Rong Jerry Zhou if (w->inamp_cap) {
40793a49c214SYang-Rong Jerry Zhou (void) audioha_codec_4bit_verb_get(
40803a49c214SYang-Rong Jerry Zhou statep,
40813a49c214SYang-Rong Jerry Zhou caddr,
40823a49c214SYang-Rong Jerry Zhou w->wid_wid,
40833a49c214SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_AMP_MUTE,
40843a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_LR_INPUT |
40853a49c214SYang-Rong Jerry Zhou AUDIOHDC_GAIN_MAX |
4086b96a6eceSZhao Edgar Liu - Sun Microsystems (w->input_path_next <<
40873a49c214SYang-Rong Jerry Zhou AUDIOHDC_AMP_SET_INDEX_OFFSET));
40883a49c214SYang-Rong Jerry Zhou }
4089b96a6eceSZhao Edgar Liu - Sun Microsystems wid = w->avail_conn[w->input_path_next];
409088447a05SGarrett D'Amore w = path->codec->widget[wid];
40913a49c214SYang-Rong Jerry Zhou }
40923a49c214SYang-Rong Jerry Zhou }
40933a49c214SYang-Rong Jerry Zhou } /* end of istream loop */
40943a49c214SYang-Rong Jerry Zhou } /* audiohd_finish_input_path */
4095f90d8383Scg
40963a49c214SYang-Rong Jerry Zhou /*
40973a49c214SYang-Rong Jerry Zhou * audiohd_find_inpin_for_monitor()
40983a49c214SYang-Rong Jerry Zhou *
40993a49c214SYang-Rong Jerry Zhou * Description:
41003a49c214SYang-Rong Jerry Zhou * Find input pin for monitor path.
41013a49c214SYang-Rong Jerry Zhou *
41023a49c214SYang-Rong Jerry Zhou * Arguments:
41033a49c214SYang-Rong Jerry Zhou * hda_codec_t *codec where the monitor path exists
41043a49c214SYang-Rong Jerry Zhou * wid_t id no. of widget being searched
41053a49c214SYang-Rong Jerry Zhou * int mixer share or not
41063a49c214SYang-Rong Jerry Zhou */
41073a49c214SYang-Rong Jerry Zhou static int
audiohd_find_inpin_for_monitor(hda_codec_t * codec,wid_t id,int mixer)410870feb41cSZhao Edgar Liu - Sun Microsystems audiohd_find_inpin_for_monitor(hda_codec_t *codec, wid_t id, int mixer)
41093a49c214SYang-Rong Jerry Zhou {
411065a41de7SYang-Rong Jerry Zhou wid_t wid;
4111b96a6eceSZhao Edgar Liu - Sun Microsystems audiohd_widget_t *widget, *w;
41123a49c214SYang-Rong Jerry Zhou audiohd_pin_t *pin;
41133a49c214SYang-Rong Jerry Zhou int i, find = 0;
41143a49c214SYang-Rong Jerry Zhou
41153a49c214SYang-Rong Jerry Zhou wid = id;
41163a49c214SYang-Rong Jerry Zhou widget = codec->widget[wid];
411731a3f136SYang-Rong Jerry Zhou if (widget == NULL)
4118c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
411931a3f136SYang-Rong Jerry Zhou
41203a49c214SYang-Rong Jerry Zhou if (widget->type == WTYPE_PIN) {
41213a49c214SYang-Rong Jerry Zhou pin = (audiohd_pin_t *)widget->priv;
41223a49c214SYang-Rong Jerry Zhou if (pin->no_phys_conn)
4123c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
41243a49c214SYang-Rong Jerry Zhou switch (pin->device) {
41253a49c214SYang-Rong Jerry Zhou case DTYPE_SPDIF_IN:
41263a49c214SYang-Rong Jerry Zhou case DTYPE_CD:
41273a49c214SYang-Rong Jerry Zhou case DTYPE_LINE_IN:
41283a49c214SYang-Rong Jerry Zhou case DTYPE_MIC_IN:
41293a49c214SYang-Rong Jerry Zhou case DTYPE_AUX:
41303a49c214SYang-Rong Jerry Zhou widget->path_flags |= AUDIOHD_PATH_MON;
4131c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
41323a49c214SYang-Rong Jerry Zhou default:
4133c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
41343a49c214SYang-Rong Jerry Zhou }
41353a49c214SYang-Rong Jerry Zhou }
41363a49c214SYang-Rong Jerry Zhou /* the widget has been visited and can't be directed to input pin */
41373a49c214SYang-Rong Jerry Zhou if (widget->path_flags & AUDIOHD_PATH_NOMON) {
4138c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
41393a49c214SYang-Rong Jerry Zhou }
41403a49c214SYang-Rong Jerry Zhou /* the widget has been used by the monitor path, and we can share it */
41413a49c214SYang-Rong Jerry Zhou if (widget->path_flags & AUDIOHD_PATH_MON) {
41423a49c214SYang-Rong Jerry Zhou if (mixer)
4143c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
41443a49c214SYang-Rong Jerry Zhou else
4145c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
41463a49c214SYang-Rong Jerry Zhou }
41473a49c214SYang-Rong Jerry Zhou switch (widget->type) {
41483a49c214SYang-Rong Jerry Zhou case WTYPE_AUDIO_MIX:
41493a49c214SYang-Rong Jerry Zhou for (i = 0; i < widget->nconns; i++) {
4150b96a6eceSZhao Edgar Liu - Sun Microsystems if (widget->output_path_next == i)
41513a49c214SYang-Rong Jerry Zhou continue;
41523a49c214SYang-Rong Jerry Zhou if (audiohd_find_inpin_for_monitor(codec,
41533a49c214SYang-Rong Jerry Zhou widget->avail_conn[i], mixer) ==
4154c6e681c0SYang-Rong Jerry Zhou DDI_SUCCESS) {
4155b96a6eceSZhao Edgar Liu - Sun Microsystems w = widget;
4156b96a6eceSZhao Edgar Liu - Sun Microsystems w->monitor_path_next[w->used++] = i;
4157b96a6eceSZhao Edgar Liu - Sun Microsystems w->path_flags |= AUDIOHD_PATH_MON;
41583a49c214SYang-Rong Jerry Zhou find = 1;
41593a49c214SYang-Rong Jerry Zhou }
41603a49c214SYang-Rong Jerry Zhou }
41613a49c214SYang-Rong Jerry Zhou break;
41623a49c214SYang-Rong Jerry Zhou case WTYPE_AUDIO_SEL:
41633a49c214SYang-Rong Jerry Zhou for (i = 0; i < widget->nconns; i++) {
4164b96a6eceSZhao Edgar Liu - Sun Microsystems if (widget->output_path_next == i)
41653a49c214SYang-Rong Jerry Zhou continue;
41663a49c214SYang-Rong Jerry Zhou if (audiohd_find_inpin_for_monitor(codec,
4167b96a6eceSZhao Edgar Liu - Sun Microsystems widget->avail_conn[i], mixer) ==
4168c6e681c0SYang-Rong Jerry Zhou DDI_SUCCESS) {
4169b96a6eceSZhao Edgar Liu - Sun Microsystems widget->monitor_path_next[0] = i;
41703a49c214SYang-Rong Jerry Zhou widget->path_flags |= AUDIOHD_PATH_MON;
4171b96a6eceSZhao Edgar Liu - Sun Microsystems find = 1;
4172b96a6eceSZhao Edgar Liu - Sun Microsystems break;
41733a49c214SYang-Rong Jerry Zhou }
41743a49c214SYang-Rong Jerry Zhou }
4175b96a6eceSZhao Edgar Liu - Sun Microsystems break;
41763a49c214SYang-Rong Jerry Zhou default:
41773a49c214SYang-Rong Jerry Zhou break;
41783a49c214SYang-Rong Jerry Zhou }
41793a49c214SYang-Rong Jerry Zhou if (!find) {
41803a49c214SYang-Rong Jerry Zhou widget->path_flags |= AUDIOHD_PATH_NOMON;
4181c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
41823a49c214SYang-Rong Jerry Zhou }
41833a49c214SYang-Rong Jerry Zhou else
4184c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
41853a49c214SYang-Rong Jerry Zhou } /* audiohd_find_inpin_for_monitor */
4186f90d8383Scg
41873a49c214SYang-Rong Jerry Zhou /*
41883a49c214SYang-Rong Jerry Zhou * audiohd_build_monitor_path()
41893a49c214SYang-Rong Jerry Zhou *
41903a49c214SYang-Rong Jerry Zhou * Description:
41913a49c214SYang-Rong Jerry Zhou * The functionality of mixer is to mix inputs, such as CD-IN, MIC,
41923a49c214SYang-Rong Jerry Zhou * Line-in, etc, with DAC outputs, so as to minitor what is being
41933a49c214SYang-Rong Jerry Zhou * recorded and implement "What you hear is what you get". However,
41943a49c214SYang-Rong Jerry Zhou * this functionality are really hardware-dependent: the inputs
41953a49c214SYang-Rong Jerry Zhou * must be directed to MIXER if they can be directed to ADC as
41963a49c214SYang-Rong Jerry Zhou * recording sources.
41973a49c214SYang-Rong Jerry Zhou */
41983a49c214SYang-Rong Jerry Zhou static void
audiohd_build_monitor_path(hda_codec_t * codec)41993a49c214SYang-Rong Jerry Zhou audiohd_build_monitor_path(hda_codec_t *codec)
42003a49c214SYang-Rong Jerry Zhou {
420188447a05SGarrett D'Amore audiohd_path_t *path;
4202b96a6eceSZhao Edgar Liu - Sun Microsystems audiohd_widget_t *widget, *w;
4203ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
4204b96a6eceSZhao Edgar Liu - Sun Microsystems wid_t wid, next;
420588447a05SGarrett D'Amore int i, j, k, l, find;
420688447a05SGarrett D'Amore int mixernum = 0;
4207f90d8383Scg
420888447a05SGarrett D'Amore for (i = 0; i < statep->pathnum; i++) {
420988447a05SGarrett D'Amore path = statep->path[i];
4210b96a6eceSZhao Edgar Liu - Sun Microsystems if (path == NULL || path->codec != codec ||
4211b96a6eceSZhao Edgar Liu - Sun Microsystems path->path_type != PLAY)
421288447a05SGarrett D'Amore continue;
421388447a05SGarrett D'Amore for (j = 0; j < path->pin_nums; j++) {
421488447a05SGarrett D'Amore wid = path->pin_wid[j];
421588447a05SGarrett D'Amore widget = codec->widget[wid];
421688447a05SGarrett D'Amore l = 0;
421788447a05SGarrett D'Amore while (widget) {
421888447a05SGarrett D'Amore while (widget &&
421988447a05SGarrett D'Amore ((widget->type != WTYPE_AUDIO_MIX) ||
422088447a05SGarrett D'Amore (widget->nconns < 2))) {
4221b96a6eceSZhao Edgar Liu - Sun Microsystems next = widget->output_path_next;
4222b96a6eceSZhao Edgar Liu - Sun Microsystems if (next == AUDIOHD_NULL_CONN)
422388447a05SGarrett D'Amore break;
4224b96a6eceSZhao Edgar Liu - Sun Microsystems wid = widget->avail_conn[next];
422588447a05SGarrett D'Amore widget = codec->widget[wid];
422688447a05SGarrett D'Amore }
42273a49c214SYang-Rong Jerry Zhou
42283a49c214SYang-Rong Jerry Zhou /*
422988447a05SGarrett D'Amore * No mixer in this output path, we cannot build
423088447a05SGarrett D'Amore * mixer path for this path, skip it,
4231b96a6eceSZhao Edgar Liu - Sun Microsystems * and continue for next output path.
42323a49c214SYang-Rong Jerry Zhou */
4233b96a6eceSZhao Edgar Liu - Sun Microsystems if (widget == NULL ||
4234b96a6eceSZhao Edgar Liu - Sun Microsystems widget->output_path_next ==
423588447a05SGarrett D'Amore AUDIOHD_NULL_CONN) {
423688447a05SGarrett D'Amore break;
423788447a05SGarrett D'Amore }
423888447a05SGarrett D'Amore mixernum++;
423988447a05SGarrett D'Amore for (k = 0; k < widget->nconns; k++) {
424088447a05SGarrett D'Amore
424188447a05SGarrett D'Amore /*
424288447a05SGarrett D'Amore * this connection must be routined
424388447a05SGarrett D'Amore * to DAC instead of an input pin
424488447a05SGarrett D'Amore * widget, we needn't waste time for
424588447a05SGarrett D'Amore * it
424688447a05SGarrett D'Amore */
4247b96a6eceSZhao Edgar Liu - Sun Microsystems if (widget->output_path_next == k)
424888447a05SGarrett D'Amore continue;
424988447a05SGarrett D'Amore find = 0;
425088447a05SGarrett D'Amore if (audiohd_find_inpin_for_monitor(
425188447a05SGarrett D'Amore codec,
425288447a05SGarrett D'Amore widget->avail_conn[k], 0) ==
4253c6e681c0SYang-Rong Jerry Zhou DDI_SUCCESS) {
425488447a05SGarrett D'Amore path->mon_wid[j][l] = wid;
4255b96a6eceSZhao Edgar Liu - Sun Microsystems w = widget;
4256b96a6eceSZhao Edgar Liu - Sun Microsystems w->monitor_path_next[w->used++]
4257b96a6eceSZhao Edgar Liu - Sun Microsystems = k;
4258b96a6eceSZhao Edgar Liu - Sun Microsystems w->path_flags |=
425988447a05SGarrett D'Amore AUDIOHD_PATH_MON;
426088447a05SGarrett D'Amore find = 1;
426188447a05SGarrett D'Amore } else if (
426288447a05SGarrett D'Amore audiohd_find_inpin_for_monitor(
426388447a05SGarrett D'Amore codec,
426488447a05SGarrett D'Amore widget->avail_conn[k], 1) ==
4265c6e681c0SYang-Rong Jerry Zhou DDI_SUCCESS) {
426688447a05SGarrett D'Amore path->mon_wid[j][l] = wid;
4267b96a6eceSZhao Edgar Liu - Sun Microsystems w = widget;
4268b96a6eceSZhao Edgar Liu - Sun Microsystems w->monitor_path_next[w->used++]
4269b96a6eceSZhao Edgar Liu - Sun Microsystems = k;
4270b96a6eceSZhao Edgar Liu - Sun Microsystems w->path_flags |=
427188447a05SGarrett D'Amore AUDIOHD_PATH_MON;
427288447a05SGarrett D'Amore find = 1;
427388447a05SGarrett D'Amore }
42743a49c214SYang-Rong Jerry Zhou
42753a49c214SYang-Rong Jerry Zhou }
4276f90d8383Scg
427788447a05SGarrett D'Amore /*
4278b96a6eceSZhao Edgar Liu - Sun Microsystems * we needn't check widget->output_path_next
4279b96a6eceSZhao Edgar Liu - Sun Microsystems * here since this widget is a selector or
4280b96a6eceSZhao Edgar Liu - Sun Microsystems * mixer, it cannot be NULL connection.
428188447a05SGarrett D'Amore */
428288447a05SGarrett D'Amore if (!find) {
428370feb41cSZhao Edgar Liu - Sun Microsystems path->mon_wid[j][l] = 0;
428488447a05SGarrett D'Amore widget->path_flags |=
428588447a05SGarrett D'Amore AUDIOHD_PATH_NOMON;
428688447a05SGarrett D'Amore }
4287b96a6eceSZhao Edgar Liu - Sun Microsystems next = widget->output_path_next;
4288b96a6eceSZhao Edgar Liu - Sun Microsystems wid = widget->avail_conn[next];
428988447a05SGarrett D'Amore widget = codec->widget[wid];
429088447a05SGarrett D'Amore l++;
42913a49c214SYang-Rong Jerry Zhou }
429288447a05SGarrett D'Amore path->maxmixer[j] = l;
42933a49c214SYang-Rong Jerry Zhou }
4294f90d8383Scg
42953a49c214SYang-Rong Jerry Zhou }
42963a49c214SYang-Rong Jerry Zhou if (mixernum == 0)
4297e7236f70SZhao Edgar Liu - Sun Microsystems statep->monitor_supported = B_FALSE;
429888447a05SGarrett D'Amore else
4299e7236f70SZhao Edgar Liu - Sun Microsystems statep->monitor_supported = B_TRUE;
43003a49c214SYang-Rong Jerry Zhou } /* audiohd_build_monitor_path */
4301f90d8383Scg
43023a49c214SYang-Rong Jerry Zhou /*
43033a49c214SYang-Rong Jerry Zhou * audiohd_do_finish_monitor_path
43043a49c214SYang-Rong Jerry Zhou *
43053a49c214SYang-Rong Jerry Zhou * Description:
43063a49c214SYang-Rong Jerry Zhou * Enable the widgets on the monitor path
43073a49c214SYang-Rong Jerry Zhou */
43083a49c214SYang-Rong Jerry Zhou static void
audiohd_do_finish_monitor_path(hda_codec_t * codec,audiohd_widget_t * wgt)43093a49c214SYang-Rong Jerry Zhou audiohd_do_finish_monitor_path(hda_codec_t *codec, audiohd_widget_t *wgt)
43103a49c214SYang-Rong Jerry Zhou {
43113a49c214SYang-Rong Jerry Zhou uint_t caddr = codec->index;
43123a49c214SYang-Rong Jerry Zhou audiohd_widget_t *widget = wgt;
43133a49c214SYang-Rong Jerry Zhou audiohd_widget_t *w;
4314ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
43153a49c214SYang-Rong Jerry Zhou wid_t wid;
43163a49c214SYang-Rong Jerry Zhou int i;
43173a49c214SYang-Rong Jerry Zhou int share = 0;
4318f90d8383Scg
431931a3f136SYang-Rong Jerry Zhou if (!widget || widget->finish)
43203a49c214SYang-Rong Jerry Zhou return;
43213a49c214SYang-Rong Jerry Zhou if (widget->path_flags & AUDIOHD_PATH_ADC)
43223a49c214SYang-Rong Jerry Zhou share = 1;
4323b96a6eceSZhao Edgar Liu - Sun Microsystems if ((widget->outamp_cap) && !share)
4324b96a6eceSZhao Edgar Liu - Sun Microsystems (void) audioha_codec_4bit_verb_get(statep, caddr,
4325b96a6eceSZhao Edgar Liu - Sun Microsystems widget->wid_wid, AUDIOHDC_VERB_SET_AMP_MUTE,
4326b96a6eceSZhao Edgar Liu - Sun Microsystems AUDIOHDC_AMP_SET_LR_OUTPUT | AUDIOHDC_GAIN_MAX);
4327b96a6eceSZhao Edgar Liu - Sun Microsystems if ((widget->inamp_cap) && !share) {
43283a49c214SYang-Rong Jerry Zhou for (i = 0; i < widget->used; i++) {
43293a49c214SYang-Rong Jerry Zhou (void) audioha_codec_4bit_verb_get(statep, caddr,
43303a49c214SYang-Rong Jerry Zhou widget->wid_wid, AUDIOHDC_VERB_SET_AMP_MUTE,
4331b96a6eceSZhao Edgar Liu - Sun Microsystems AUDIOHDC_AMP_SET_LR_INPUT | AUDIOHDC_GAIN_MAX |
4332b96a6eceSZhao Edgar Liu - Sun Microsystems (widget->monitor_path_next[i]
4333b96a6eceSZhao Edgar Liu - Sun Microsystems << AUDIOHDC_AMP_SET_INDEX_OFFSET));
43343a49c214SYang-Rong Jerry Zhou }
43353a49c214SYang-Rong Jerry Zhou }
433616600ba1SYang-Rong Jerry Zhou if ((widget->type == WTYPE_AUDIO_SEL) && (widget->nconns > 1) &&
433716600ba1SYang-Rong Jerry Zhou !share) {
4338b96a6eceSZhao Edgar Liu - Sun Microsystems (void) audioha_codec_verb_get(statep, caddr, widget->wid_wid,
4339b96a6eceSZhao Edgar Liu - Sun Microsystems AUDIOHDC_VERB_SET_CONN_SEL, widget->monitor_path_next[0]);
43403a49c214SYang-Rong Jerry Zhou }
43413a49c214SYang-Rong Jerry Zhou widget->finish = 1;
43423a49c214SYang-Rong Jerry Zhou if (widget->used == 0)
43433a49c214SYang-Rong Jerry Zhou return;
43443a49c214SYang-Rong Jerry Zhou if (widget->used > 0) {
43453a49c214SYang-Rong Jerry Zhou for (i = 0; i < widget->used; i++) {
4346b96a6eceSZhao Edgar Liu - Sun Microsystems wid = widget->avail_conn[widget->monitor_path_next[i]];
43473a49c214SYang-Rong Jerry Zhou w = codec->widget[wid];
43483a49c214SYang-Rong Jerry Zhou audiohd_do_finish_monitor_path(codec, w);
43493a49c214SYang-Rong Jerry Zhou }
43503a49c214SYang-Rong Jerry Zhou }
43513a49c214SYang-Rong Jerry Zhou } /* audiohd_do_finish_monitor_path */
4352f90d8383Scg
43537253a143Scg /*
43543a49c214SYang-Rong Jerry Zhou * audiohd_finish_monitor_path
43553a49c214SYang-Rong Jerry Zhou *
43563a49c214SYang-Rong Jerry Zhou * Description:
43573a49c214SYang-Rong Jerry Zhou * Enable the monitor path for every ostream path
43587253a143Scg */
43593a49c214SYang-Rong Jerry Zhou static void
audiohd_finish_monitor_path(hda_codec_t * codec)43603a49c214SYang-Rong Jerry Zhou audiohd_finish_monitor_path(hda_codec_t *codec)
43617253a143Scg {
436288447a05SGarrett D'Amore audiohd_path_t *path;
43633a49c214SYang-Rong Jerry Zhou audiohd_widget_t *widget;
4364ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
43653a49c214SYang-Rong Jerry Zhou wid_t wid;
436688447a05SGarrett D'Amore int i, j, k;
43673a49c214SYang-Rong Jerry Zhou
436888447a05SGarrett D'Amore for (i = 0; i < statep->pathnum; i++) {
436988447a05SGarrett D'Amore path = statep->path[i];
437088447a05SGarrett D'Amore if (!path || path->codec != codec || path->path_type != PLAY)
437188447a05SGarrett D'Amore continue;
437288447a05SGarrett D'Amore for (j = 0; j < path->pin_nums; j++) {
437388447a05SGarrett D'Amore for (k = 0; k < path->maxmixer[j]; k++) {
437488447a05SGarrett D'Amore wid = path->mon_wid[j][k];
43753a49c214SYang-Rong Jerry Zhou if (wid == 0) {
43763a49c214SYang-Rong Jerry Zhou continue;
43773a49c214SYang-Rong Jerry Zhou }
43783a49c214SYang-Rong Jerry Zhou widget = codec->widget[wid];
43793a49c214SYang-Rong Jerry Zhou audiohd_do_finish_monitor_path(codec, widget);
43803a49c214SYang-Rong Jerry Zhou }
43813a49c214SYang-Rong Jerry Zhou }
43823a49c214SYang-Rong Jerry Zhou }
43833a49c214SYang-Rong Jerry Zhou } /* audiohd_finish_monitor_path */
43847253a143Scg
43853a49c214SYang-Rong Jerry Zhou /*
43863a49c214SYang-Rong Jerry Zhou * audiohd_do_build_monit_amp()
43873a49c214SYang-Rong Jerry Zhou *
43883a49c214SYang-Rong Jerry Zhou * Description:
43893a49c214SYang-Rong Jerry Zhou * Search for the gain control widget for the monitor path
43903a49c214SYang-Rong Jerry Zhou */
43913a49c214SYang-Rong Jerry Zhou static void
audiohd_do_build_monitor_amp(hda_codec_t * codec,audiohd_pin_t * pin,audiohd_widget_t * widget)43923a49c214SYang-Rong Jerry Zhou audiohd_do_build_monitor_amp(hda_codec_t *codec, audiohd_pin_t *pin,
43933a49c214SYang-Rong Jerry Zhou audiohd_widget_t *widget)
43943a49c214SYang-Rong Jerry Zhou {
43953a49c214SYang-Rong Jerry Zhou audiohd_widget_t *w = widget;
43963a49c214SYang-Rong Jerry Zhou uint32_t gain;
43973a49c214SYang-Rong Jerry Zhou int i;
43983a49c214SYang-Rong Jerry Zhou wid_t wid;
4399f90d8383Scg
44003a49c214SYang-Rong Jerry Zhou if (!w ||
44013a49c214SYang-Rong Jerry Zhou (w->type == WTYPE_PIN) ||
44023a49c214SYang-Rong Jerry Zhou !w->used ||
44033a49c214SYang-Rong Jerry Zhou (pin->num == AUDIOHD_MAX_CONN) ||
44043a49c214SYang-Rong Jerry Zhou (w->path_flags & AUDIOHD_PATH_ADC))
44053a49c214SYang-Rong Jerry Zhou return;
44063a49c214SYang-Rong Jerry Zhou if (!(w->path_flags & AUDIOHD_PATH_DAC)) {
44073a49c214SYang-Rong Jerry Zhou gain = w->outamp_cap & AUDIOHDC_AMP_CAP_STEP_NUMS;
44083a49c214SYang-Rong Jerry Zhou if (gain) {
44093a49c214SYang-Rong Jerry Zhou pin->mg_dir[pin->num] = AUDIOHDC_AMP_SET_OUTPUT;
44103a49c214SYang-Rong Jerry Zhou pin->mg_gain[pin->num] = gain;
44113a49c214SYang-Rong Jerry Zhou pin->mg_wid[pin->num] = w->wid_wid;
44123a49c214SYang-Rong Jerry Zhou pin->mg_gain[pin->num] >>= AUDIOHD_GAIN_OFF;
44133a49c214SYang-Rong Jerry Zhou pin->num++;
44143a49c214SYang-Rong Jerry Zhou return;
44153a49c214SYang-Rong Jerry Zhou }
44163a49c214SYang-Rong Jerry Zhou gain = w->inamp_cap & AUDIOHDC_AMP_CAP_STEP_NUMS;
44173a49c214SYang-Rong Jerry Zhou if (gain) {
44183a49c214SYang-Rong Jerry Zhou pin->mg_dir[pin->num] = AUDIOHDC_AMP_SET_INPUT;
44193a49c214SYang-Rong Jerry Zhou pin->mg_gain[pin->num] = gain;
44203a49c214SYang-Rong Jerry Zhou pin->mg_wid[pin->num] = w->wid_wid;
44213a49c214SYang-Rong Jerry Zhou pin->mg_gain[pin->num] >>= AUDIOHD_GAIN_OFF;
44223a49c214SYang-Rong Jerry Zhou pin->num++;
44233a49c214SYang-Rong Jerry Zhou return;
4424f90d8383Scg }
44257253a143Scg }
44263a49c214SYang-Rong Jerry Zhou for (i = 0; i < w->used; i++) {
4427b96a6eceSZhao Edgar Liu - Sun Microsystems wid = w->avail_conn[w->monitor_path_next[i]];
44283a49c214SYang-Rong Jerry Zhou audiohd_do_build_monitor_amp(codec, pin, codec->widget[wid]);
44293a49c214SYang-Rong Jerry Zhou }
44307253a143Scg
44317253a143Scg
44323a49c214SYang-Rong Jerry Zhou } /* audiohd_do_build_monitor_amp() */
44337253a143Scg
44347253a143Scg /*
44353a49c214SYang-Rong Jerry Zhou * audiohd_build_monitor_amp()
44363a49c214SYang-Rong Jerry Zhou *
44373a49c214SYang-Rong Jerry Zhou * Description:
44383a49c214SYang-Rong Jerry Zhou * Search gain control widget for every ostream monitor
44397253a143Scg */
44403a49c214SYang-Rong Jerry Zhou static void
audiohd_build_monitor_amp(hda_codec_t * codec)44413a49c214SYang-Rong Jerry Zhou audiohd_build_monitor_amp(hda_codec_t *codec)
44427253a143Scg {
444388447a05SGarrett D'Amore audiohd_path_t *path;
44443a49c214SYang-Rong Jerry Zhou audiohd_widget_t *widget, *w;
4445ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
44463a49c214SYang-Rong Jerry Zhou audiohd_pin_t *pin;
44473a49c214SYang-Rong Jerry Zhou wid_t wid, id;
444888447a05SGarrett D'Amore int i, j, k;
44493a49c214SYang-Rong Jerry Zhou
445088447a05SGarrett D'Amore for (i = 0; i < statep->pathnum; i++) {
445188447a05SGarrett D'Amore path = statep->path[i];
445288447a05SGarrett D'Amore if (!path || path->codec != codec || path->path_type != PLAY)
445388447a05SGarrett D'Amore continue;
445488447a05SGarrett D'Amore for (j = 0; j < path->pin_nums; j++) {
445588447a05SGarrett D'Amore id = path->pin_wid[j];
44563a49c214SYang-Rong Jerry Zhou w = codec->widget[id];
44573a49c214SYang-Rong Jerry Zhou pin = (audiohd_pin_t *)(w->priv);
445888447a05SGarrett D'Amore for (k = 0; k < path->maxmixer[j]; k++) {
445988447a05SGarrett D'Amore wid = path->mon_wid[j][k];
44603a49c214SYang-Rong Jerry Zhou if (!wid)
44613a49c214SYang-Rong Jerry Zhou continue;
44623a49c214SYang-Rong Jerry Zhou widget = codec->widget[wid];
44633a49c214SYang-Rong Jerry Zhou audiohd_do_build_monitor_amp(codec, pin,
44643a49c214SYang-Rong Jerry Zhou widget);
44653a49c214SYang-Rong Jerry Zhou }
44663a49c214SYang-Rong Jerry Zhou }
4467f90d8383Scg }
44683a49c214SYang-Rong Jerry Zhou }
44697253a143Scg
447042c41cf8Slipeng sang - Sun Microsystems - Beijing China /*
447142c41cf8Slipeng sang - Sun Microsystems - Beijing China * audiohd_find_beep()
447242c41cf8Slipeng sang - Sun Microsystems - Beijing China * Description:
447342c41cf8Slipeng sang - Sun Microsystems - Beijing China * Find a beep for a beep path. Then the play data can be sent to the out
447442c41cf8Slipeng sang - Sun Microsystems - Beijing China * put pin through the beep path.
447542c41cf8Slipeng sang - Sun Microsystems - Beijing China *
447642c41cf8Slipeng sang - Sun Microsystems - Beijing China * Arguments:
447742c41cf8Slipeng sang - Sun Microsystems - Beijing China * hda_codec_t *codec where the beep widget exists
447842c41cf8Slipeng sang - Sun Microsystems - Beijing China * wid_t wid the no. of a widget
447942c41cf8Slipeng sang - Sun Microsystems - Beijing China * int depth the depth of search
448042c41cf8Slipeng sang - Sun Microsystems - Beijing China *
448142c41cf8Slipeng sang - Sun Microsystems - Beijing China * Return:
448242c41cf8Slipeng sang - Sun Microsystems - Beijing China * 1) wid of Beep widget;
448342c41cf8Slipeng sang - Sun Microsystems - Beijing China * 2) 0 if no path
448442c41cf8Slipeng sang - Sun Microsystems - Beijing China */
448542c41cf8Slipeng sang - Sun Microsystems - Beijing China static wid_t
audiohd_find_beep(hda_codec_t * codec,wid_t wid,int depth)448642c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_find_beep(hda_codec_t *codec, wid_t wid, int depth)
448742c41cf8Slipeng sang - Sun Microsystems - Beijing China {
448842c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_widget_t *widget = codec->widget[wid];
448942c41cf8Slipeng sang - Sun Microsystems - Beijing China wid_t wbeep = (uint32_t)(DDI_FAILURE);
449042c41cf8Slipeng sang - Sun Microsystems - Beijing China wid_t retval;
449142c41cf8Slipeng sang - Sun Microsystems - Beijing China
449242c41cf8Slipeng sang - Sun Microsystems - Beijing China if (depth > AUDIOHD_MAX_DEPTH)
449342c41cf8Slipeng sang - Sun Microsystems - Beijing China return (uint32_t)(DDI_FAILURE);
449442c41cf8Slipeng sang - Sun Microsystems - Beijing China
449542c41cf8Slipeng sang - Sun Microsystems - Beijing China if (widget == NULL)
449642c41cf8Slipeng sang - Sun Microsystems - Beijing China return (uint32_t)(DDI_FAILURE);
449742c41cf8Slipeng sang - Sun Microsystems - Beijing China
449842c41cf8Slipeng sang - Sun Microsystems - Beijing China switch (widget->type) {
449942c41cf8Slipeng sang - Sun Microsystems - Beijing China case WTYPE_BEEP:
450042c41cf8Slipeng sang - Sun Microsystems - Beijing China widget->path_flags |= AUDIOHD_PATH_BEEP;
450142c41cf8Slipeng sang - Sun Microsystems - Beijing China wbeep = widget->wid_wid;
450242c41cf8Slipeng sang - Sun Microsystems - Beijing China break;
450342c41cf8Slipeng sang - Sun Microsystems - Beijing China case WTYPE_AUDIO_MIX:
450442c41cf8Slipeng sang - Sun Microsystems - Beijing China case WTYPE_AUDIO_SEL:
450542c41cf8Slipeng sang - Sun Microsystems - Beijing China for (int i = 0; i < widget->nconns; i++) {
450642c41cf8Slipeng sang - Sun Microsystems - Beijing China retval = audiohd_find_beep(codec,
450742c41cf8Slipeng sang - Sun Microsystems - Beijing China widget->avail_conn[i], depth + 1);
4508b96a6eceSZhao Edgar Liu - Sun Microsystems if (retval == DDI_SUCCESS) {
4509b96a6eceSZhao Edgar Liu - Sun Microsystems if (widget->output_path_next !=
4510b96a6eceSZhao Edgar Liu - Sun Microsystems AUDIOHD_NULL_CONN)
451142c41cf8Slipeng sang - Sun Microsystems - Beijing China continue;
4512b96a6eceSZhao Edgar Liu - Sun Microsystems widget->beep_path_next = i;
451342c41cf8Slipeng sang - Sun Microsystems - Beijing China wbeep = retval;
451442c41cf8Slipeng sang - Sun Microsystems - Beijing China widget->path_flags |= AUDIOHD_PATH_BEEP;
451542c41cf8Slipeng sang - Sun Microsystems - Beijing China return (wbeep);
451642c41cf8Slipeng sang - Sun Microsystems - Beijing China }
451742c41cf8Slipeng sang - Sun Microsystems - Beijing China }
4518b96a6eceSZhao Edgar Liu - Sun Microsystems break;
451942c41cf8Slipeng sang - Sun Microsystems - Beijing China default:
452042c41cf8Slipeng sang - Sun Microsystems - Beijing China break;
452142c41cf8Slipeng sang - Sun Microsystems - Beijing China }
452242c41cf8Slipeng sang - Sun Microsystems - Beijing China
452342c41cf8Slipeng sang - Sun Microsystems - Beijing China return (wbeep);
452442c41cf8Slipeng sang - Sun Microsystems - Beijing China } /* audiohd_find_beep() */
452542c41cf8Slipeng sang - Sun Microsystems - Beijing China
452642c41cf8Slipeng sang - Sun Microsystems - Beijing China /*
452742c41cf8Slipeng sang - Sun Microsystems - Beijing China * audiohd_build_beep_path()
452842c41cf8Slipeng sang - Sun Microsystems - Beijing China *
452942c41cf8Slipeng sang - Sun Microsystems - Beijing China * Description:
453042c41cf8Slipeng sang - Sun Microsystems - Beijing China * Search an beep path for each pin in the codec.
453142c41cf8Slipeng sang - Sun Microsystems - Beijing China * Arguments:
453242c41cf8Slipeng sang - Sun Microsystems - Beijing China * hda_codec_t *codec where the beep path exists
453342c41cf8Slipeng sang - Sun Microsystems - Beijing China */
453442c41cf8Slipeng sang - Sun Microsystems - Beijing China static void
audiohd_build_beep_path(hda_codec_t * codec)453542c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_build_beep_path(hda_codec_t *codec)
453642c41cf8Slipeng sang - Sun Microsystems - Beijing China {
453742c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_pin_t *pin;
453842c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_widget_t *widget;
453942c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_path_t *path;
454042c41cf8Slipeng sang - Sun Microsystems - Beijing China wid_t wid;
454142c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_state_t *statep;
454242c41cf8Slipeng sang - Sun Microsystems - Beijing China int i;
454342c41cf8Slipeng sang - Sun Microsystems - Beijing China boolean_t beeppath = B_FALSE;
454442c41cf8Slipeng sang - Sun Microsystems - Beijing China
4545ea463888SZhao Edgar Liu - Sun Microsystems statep = codec->statep;
454642c41cf8Slipeng sang - Sun Microsystems - Beijing China
454742c41cf8Slipeng sang - Sun Microsystems - Beijing China for (pin = codec->first_pin; pin; pin = pin->next) {
454842c41cf8Slipeng sang - Sun Microsystems - Beijing China if ((pin->cap & AUDIOHD_PIN_CAP_MASK) == 0)
454942c41cf8Slipeng sang - Sun Microsystems - Beijing China continue;
455042c41cf8Slipeng sang - Sun Microsystems - Beijing China if ((pin->config & AUDIOHD_PIN_CONF_MASK) ==
455142c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHD_PIN_NO_CONN)
455242c41cf8Slipeng sang - Sun Microsystems - Beijing China continue;
455342c41cf8Slipeng sang - Sun Microsystems - Beijing China if ((pin->device != DTYPE_LINEOUT) &&
455442c41cf8Slipeng sang - Sun Microsystems - Beijing China (pin->device != DTYPE_SPEAKER) &&
455542c41cf8Slipeng sang - Sun Microsystems - Beijing China (pin->device != DTYPE_SPDIF_OUT) &&
455642c41cf8Slipeng sang - Sun Microsystems - Beijing China (pin->device != DTYPE_HP_OUT))
455742c41cf8Slipeng sang - Sun Microsystems - Beijing China continue;
455842c41cf8Slipeng sang - Sun Microsystems - Beijing China widget = codec->widget[pin->wid];
455942c41cf8Slipeng sang - Sun Microsystems - Beijing China
456042c41cf8Slipeng sang - Sun Microsystems - Beijing China widget->inamp_cap = 0;
456142c41cf8Slipeng sang - Sun Microsystems - Beijing China for (i = 0; i < widget->nconns; i++) {
456242c41cf8Slipeng sang - Sun Microsystems - Beijing China /*
456342c41cf8Slipeng sang - Sun Microsystems - Beijing China * If a beep found, the return value is the wid of the
456442c41cf8Slipeng sang - Sun Microsystems - Beijing China * widget on the path, or the return value is
456542c41cf8Slipeng sang - Sun Microsystems - Beijing China * DDI_FAILURE
456642c41cf8Slipeng sang - Sun Microsystems - Beijing China */
456742c41cf8Slipeng sang - Sun Microsystems - Beijing China wid = audiohd_find_beep(codec,
456842c41cf8Slipeng sang - Sun Microsystems - Beijing China widget->avail_conn[i], 0);
456942c41cf8Slipeng sang - Sun Microsystems - Beijing China /*
457042c41cf8Slipeng sang - Sun Microsystems - Beijing China * A beep was not found
457142c41cf8Slipeng sang - Sun Microsystems - Beijing China */
457242c41cf8Slipeng sang - Sun Microsystems - Beijing China if (wid == (wid_t)DDI_FAILURE)
457342c41cf8Slipeng sang - Sun Microsystems - Beijing China continue;
4574b96a6eceSZhao Edgar Liu - Sun Microsystems if (widget->output_path_next != AUDIOHD_NULL_CONN)
457542c41cf8Slipeng sang - Sun Microsystems - Beijing China continue;
457642c41cf8Slipeng sang - Sun Microsystems - Beijing China path = (audiohd_path_t *)
457742c41cf8Slipeng sang - Sun Microsystems - Beijing China kmem_zalloc(sizeof (audiohd_path_t),
457842c41cf8Slipeng sang - Sun Microsystems - Beijing China KM_SLEEP);
457942c41cf8Slipeng sang - Sun Microsystems - Beijing China path->beep_wid = wid;
458042c41cf8Slipeng sang - Sun Microsystems - Beijing China path->pin_wid[0] = widget->wid_wid;
458142c41cf8Slipeng sang - Sun Microsystems - Beijing China path->pin_nums = 1;
458242c41cf8Slipeng sang - Sun Microsystems - Beijing China path->path_type = BEEP;
458342c41cf8Slipeng sang - Sun Microsystems - Beijing China beeppath = 1;
458442c41cf8Slipeng sang - Sun Microsystems - Beijing China path->codec = codec;
458542c41cf8Slipeng sang - Sun Microsystems - Beijing China path->statep = statep;
458642c41cf8Slipeng sang - Sun Microsystems - Beijing China widget->path_flags |= AUDIOHD_PATH_BEEP;
4587b96a6eceSZhao Edgar Liu - Sun Microsystems widget->beep_path_next = i;
458842c41cf8Slipeng sang - Sun Microsystems - Beijing China statep->path[statep->pathnum++] = path;
458942c41cf8Slipeng sang - Sun Microsystems - Beijing China break;
459042c41cf8Slipeng sang - Sun Microsystems - Beijing China }
459142c41cf8Slipeng sang - Sun Microsystems - Beijing China }
459242c41cf8Slipeng sang - Sun Microsystems - Beijing China
459342c41cf8Slipeng sang - Sun Microsystems - Beijing China if (!beeppath) {
459442c41cf8Slipeng sang - Sun Microsystems - Beijing China for (int i = 0; i < AUDIOHD_CODEC_MAX; i++) {
459542c41cf8Slipeng sang - Sun Microsystems - Beijing China codec = statep->codec[i];
4596b96a6eceSZhao Edgar Liu - Sun Microsystems if (codec == NULL)
459742c41cf8Slipeng sang - Sun Microsystems - Beijing China continue;
459842c41cf8Slipeng sang - Sun Microsystems - Beijing China for (wid = codec->first_wid; wid <= codec->last_wid;
459942c41cf8Slipeng sang - Sun Microsystems - Beijing China wid++) {
460042c41cf8Slipeng sang - Sun Microsystems - Beijing China widget = codec->widget[wid];
4601ee97b734SZhao Edgar Liu - Sun Microsystems
460242c41cf8Slipeng sang - Sun Microsystems - Beijing China if (widget->type == WTYPE_BEEP) {
460342c41cf8Slipeng sang - Sun Microsystems - Beijing China path = (audiohd_path_t *)
460442c41cf8Slipeng sang - Sun Microsystems - Beijing China kmem_zalloc(sizeof (audiohd_path_t),
460542c41cf8Slipeng sang - Sun Microsystems - Beijing China KM_SLEEP);
460642c41cf8Slipeng sang - Sun Microsystems - Beijing China path->beep_wid = wid;
460742c41cf8Slipeng sang - Sun Microsystems - Beijing China path->pin_nums = 0;
460842c41cf8Slipeng sang - Sun Microsystems - Beijing China path->path_type = BEEP;
460942c41cf8Slipeng sang - Sun Microsystems - Beijing China beeppath = 1;
461042c41cf8Slipeng sang - Sun Microsystems - Beijing China path->codec = codec;
461142c41cf8Slipeng sang - Sun Microsystems - Beijing China path->statep = statep;
461242c41cf8Slipeng sang - Sun Microsystems - Beijing China widget->path_flags |= AUDIOHD_PATH_BEEP;
461342c41cf8Slipeng sang - Sun Microsystems - Beijing China statep->path[statep->pathnum++] = path;
461442c41cf8Slipeng sang - Sun Microsystems - Beijing China break;
461542c41cf8Slipeng sang - Sun Microsystems - Beijing China }
461642c41cf8Slipeng sang - Sun Microsystems - Beijing China }
461742c41cf8Slipeng sang - Sun Microsystems - Beijing China }
461842c41cf8Slipeng sang - Sun Microsystems - Beijing China }
461942c41cf8Slipeng sang - Sun Microsystems - Beijing China } /* audiohd_build_beep_path() */
462042c41cf8Slipeng sang - Sun Microsystems - Beijing China
462142c41cf8Slipeng sang - Sun Microsystems - Beijing China /*
462242c41cf8Slipeng sang - Sun Microsystems - Beijing China * audiohd_build_beep_amp
462342c41cf8Slipeng sang - Sun Microsystems - Beijing China *
462442c41cf8Slipeng sang - Sun Microsystems - Beijing China * Description:
462542c41cf8Slipeng sang - Sun Microsystems - Beijing China * Find the gain control and mute control widget
462642c41cf8Slipeng sang - Sun Microsystems - Beijing China */
462742c41cf8Slipeng sang - Sun Microsystems - Beijing China static void
audiohd_build_beep_amp(hda_codec_t * codec)462842c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_build_beep_amp(hda_codec_t *codec)
462942c41cf8Slipeng sang - Sun Microsystems - Beijing China {
463042c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_path_t *path;
463142c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_widget_t *widget, *wpin, *wbeep;
4632b96a6eceSZhao Edgar Liu - Sun Microsystems wid_t wid, next;
463342c41cf8Slipeng sang - Sun Microsystems - Beijing China int i, j;
463442c41cf8Slipeng sang - Sun Microsystems - Beijing China uint32_t gain;
463542c41cf8Slipeng sang - Sun Microsystems - Beijing China
4636ea463888SZhao Edgar Liu - Sun Microsystems for (i = 0; i < codec->statep->pathnum; i++) {
4637ea463888SZhao Edgar Liu - Sun Microsystems path = codec->statep->path[i];
463842c41cf8Slipeng sang - Sun Microsystems - Beijing China if (path == NULL || path->path_type != BEEP ||
463942c41cf8Slipeng sang - Sun Microsystems - Beijing China path->codec != codec)
464042c41cf8Slipeng sang - Sun Microsystems - Beijing China continue;
464142c41cf8Slipeng sang - Sun Microsystems - Beijing China if (path->pin_nums == 0) {
464242c41cf8Slipeng sang - Sun Microsystems - Beijing China path->mute_wid = path->beep_wid;
464342c41cf8Slipeng sang - Sun Microsystems - Beijing China path->mute_dir = AUDIOHDC_AMP_SET_OUTPUT;
464442c41cf8Slipeng sang - Sun Microsystems - Beijing China wbeep = codec->widget[path->beep_wid];
464542c41cf8Slipeng sang - Sun Microsystems - Beijing China gain = (wbeep->outamp_cap &
464642c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_AMP_CAP_STEP_NUMS);
464742c41cf8Slipeng sang - Sun Microsystems - Beijing China if (gain) {
464842c41cf8Slipeng sang - Sun Microsystems - Beijing China path->gain_dir = AUDIOHDC_AMP_SET_OUTPUT;
464942c41cf8Slipeng sang - Sun Microsystems - Beijing China path->gain_bits = gain;
465042c41cf8Slipeng sang - Sun Microsystems - Beijing China path->gain_wid = path->beep_wid;
465142c41cf8Slipeng sang - Sun Microsystems - Beijing China }
465242c41cf8Slipeng sang - Sun Microsystems - Beijing China path->gain_bits >>= AUDIOHD_GAIN_OFF;
465342c41cf8Slipeng sang - Sun Microsystems - Beijing China break;
465442c41cf8Slipeng sang - Sun Microsystems - Beijing China }
465542c41cf8Slipeng sang - Sun Microsystems - Beijing China for (j = 0; j < path->pin_nums; j++) {
465642c41cf8Slipeng sang - Sun Microsystems - Beijing China wid = path->pin_wid[j];
465742c41cf8Slipeng sang - Sun Microsystems - Beijing China wpin = codec->widget[wid];
465842c41cf8Slipeng sang - Sun Microsystems - Beijing China wbeep = codec->widget[path->beep_wid];
465942c41cf8Slipeng sang - Sun Microsystems - Beijing China
466042c41cf8Slipeng sang - Sun Microsystems - Beijing China widget = wpin;
466142c41cf8Slipeng sang - Sun Microsystems - Beijing China while (widget) {
466242c41cf8Slipeng sang - Sun Microsystems - Beijing China if (widget->out_weight == 0 &&
466342c41cf8Slipeng sang - Sun Microsystems - Beijing China widget->outamp_cap &
466442c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_AMP_CAP_MUTE_CAP) {
466542c41cf8Slipeng sang - Sun Microsystems - Beijing China path->mute_wid = widget->wid_wid;
466642c41cf8Slipeng sang - Sun Microsystems - Beijing China path->mute_dir =
466742c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_AMP_SET_OUTPUT;
466842c41cf8Slipeng sang - Sun Microsystems - Beijing China break;
466942c41cf8Slipeng sang - Sun Microsystems - Beijing China }
4670b96a6eceSZhao Edgar Liu - Sun Microsystems next = widget->beep_path_next;
4671b96a6eceSZhao Edgar Liu - Sun Microsystems if (next == AUDIOHD_NULL_CONN)
467242c41cf8Slipeng sang - Sun Microsystems - Beijing China break;
4673b96a6eceSZhao Edgar Liu - Sun Microsystems wid = widget->avail_conn[next];
467442c41cf8Slipeng sang - Sun Microsystems - Beijing China widget = codec->widget[wid];
467542c41cf8Slipeng sang - Sun Microsystems - Beijing China }
467642c41cf8Slipeng sang - Sun Microsystems - Beijing China
467742c41cf8Slipeng sang - Sun Microsystems - Beijing China gain = 0;
467842c41cf8Slipeng sang - Sun Microsystems - Beijing China widget = wpin;
467942c41cf8Slipeng sang - Sun Microsystems - Beijing China while (widget) {
468042c41cf8Slipeng sang - Sun Microsystems - Beijing China if (widget->out_weight == 0 &&
468142c41cf8Slipeng sang - Sun Microsystems - Beijing China widget->outamp_cap &
468242c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_AMP_CAP_STEP_NUMS) {
468342c41cf8Slipeng sang - Sun Microsystems - Beijing China gain = (widget->outamp_cap &
468442c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_AMP_CAP_STEP_NUMS);
468542c41cf8Slipeng sang - Sun Microsystems - Beijing China if (gain && gain > path->gain_bits) {
468642c41cf8Slipeng sang - Sun Microsystems - Beijing China path->gain_dir =
468742c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_AMP_SET_OUTPUT;
468842c41cf8Slipeng sang - Sun Microsystems - Beijing China path->gain_bits = gain;
468942c41cf8Slipeng sang - Sun Microsystems - Beijing China path->gain_wid =
469042c41cf8Slipeng sang - Sun Microsystems - Beijing China widget->wid_wid;
469142c41cf8Slipeng sang - Sun Microsystems - Beijing China }
469242c41cf8Slipeng sang - Sun Microsystems - Beijing China }
4693b96a6eceSZhao Edgar Liu - Sun Microsystems next = widget->beep_path_next;
4694b96a6eceSZhao Edgar Liu - Sun Microsystems if (next == AUDIOHD_NULL_CONN)
469542c41cf8Slipeng sang - Sun Microsystems - Beijing China break;
4696b96a6eceSZhao Edgar Liu - Sun Microsystems wid = widget->avail_conn[next];
469742c41cf8Slipeng sang - Sun Microsystems - Beijing China widget = codec->widget[wid];
469842c41cf8Slipeng sang - Sun Microsystems - Beijing China }
469942c41cf8Slipeng sang - Sun Microsystems - Beijing China path->gain_bits >>= AUDIOHD_GAIN_OFF;
470042c41cf8Slipeng sang - Sun Microsystems - Beijing China }
470142c41cf8Slipeng sang - Sun Microsystems - Beijing China }
470242c41cf8Slipeng sang - Sun Microsystems - Beijing China } /* audiohd_build_beep_amp */
470342c41cf8Slipeng sang - Sun Microsystems - Beijing China
470442c41cf8Slipeng sang - Sun Microsystems - Beijing China /*
470542c41cf8Slipeng sang - Sun Microsystems - Beijing China * audiohd_finish_beep_path()
470642c41cf8Slipeng sang - Sun Microsystems - Beijing China *
470742c41cf8Slipeng sang - Sun Microsystems - Beijing China * Description:
470842c41cf8Slipeng sang - Sun Microsystems - Beijing China * Enable the widgets on the beep path
470942c41cf8Slipeng sang - Sun Microsystems - Beijing China */
471042c41cf8Slipeng sang - Sun Microsystems - Beijing China static void
audiohd_finish_beep_path(hda_codec_t * codec)471142c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_finish_beep_path(hda_codec_t *codec)
471242c41cf8Slipeng sang - Sun Microsystems - Beijing China {
4713ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
471442c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_path_t *path;
471542c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_widget_t *widget;
471642c41cf8Slipeng sang - Sun Microsystems - Beijing China uint_t caddr = codec->index;
4717b96a6eceSZhao Edgar Liu - Sun Microsystems wid_t wid, next;
471842c41cf8Slipeng sang - Sun Microsystems - Beijing China int i, j;
471942c41cf8Slipeng sang - Sun Microsystems - Beijing China
4720ea463888SZhao Edgar Liu - Sun Microsystems for (i = 0; i < codec->statep->pathnum; i++) {
4721ea463888SZhao Edgar Liu - Sun Microsystems path = codec->statep->path[i];
472242c41cf8Slipeng sang - Sun Microsystems - Beijing China if (!path || path->path_type != BEEP || path->codec != codec)
472342c41cf8Slipeng sang - Sun Microsystems - Beijing China continue;
4724ee97b734SZhao Edgar Liu - Sun Microsystems if (path->pin_nums == 0) {
4725ee97b734SZhao Edgar Liu - Sun Microsystems widget = codec->widget[path->beep_wid];
4726ee97b734SZhao Edgar Liu - Sun Microsystems if (widget->outamp_cap) {
4727ee97b734SZhao Edgar Liu - Sun Microsystems (void) audioha_codec_4bit_verb_get(
4728ee97b734SZhao Edgar Liu - Sun Microsystems statep, caddr,
4729ee97b734SZhao Edgar Liu - Sun Microsystems path->beep_wid, AUDIOHDC_VERB_SET_AMP_MUTE,
4730ee97b734SZhao Edgar Liu - Sun Microsystems AUDIOHDC_AMP_SET_LR_OUTPUT |
4731ee97b734SZhao Edgar Liu - Sun Microsystems AUDIOHDC_GAIN_MAX);
4732ee97b734SZhao Edgar Liu - Sun Microsystems }
4733ee97b734SZhao Edgar Liu - Sun Microsystems if (widget->inamp_cap) {
4734ee97b734SZhao Edgar Liu - Sun Microsystems (void) audioha_codec_4bit_verb_get(
4735ee97b734SZhao Edgar Liu - Sun Microsystems statep, caddr,
4736ee97b734SZhao Edgar Liu - Sun Microsystems path->beep_wid, AUDIOHDC_VERB_SET_AMP_MUTE,
4737ee97b734SZhao Edgar Liu - Sun Microsystems AUDIOHDC_AMP_SET_LR_INPUT |
4738ee97b734SZhao Edgar Liu - Sun Microsystems AUDIOHDC_GAIN_MAX |
4739b96a6eceSZhao Edgar Liu - Sun Microsystems (widget->beep_path_next <<
4740ee97b734SZhao Edgar Liu - Sun Microsystems AUDIOHDC_AMP_SET_INDEX_OFFSET));
4741ee97b734SZhao Edgar Liu - Sun Microsystems }
4742ee97b734SZhao Edgar Liu - Sun Microsystems continue;
4743ee97b734SZhao Edgar Liu - Sun Microsystems }
4744ee97b734SZhao Edgar Liu - Sun Microsystems
474542c41cf8Slipeng sang - Sun Microsystems - Beijing China for (j = 0; j < path->pin_nums; j++) {
474642c41cf8Slipeng sang - Sun Microsystems - Beijing China wid = path->pin_wid[j];
474742c41cf8Slipeng sang - Sun Microsystems - Beijing China widget = codec->widget[wid];
474842c41cf8Slipeng sang - Sun Microsystems - Beijing China
474942c41cf8Slipeng sang - Sun Microsystems - Beijing China (void) audioha_codec_verb_get(statep, caddr, wid,
4750b96a6eceSZhao Edgar Liu - Sun Microsystems AUDIOHDC_VERB_SET_CONN_SEL, widget->beep_path_next);
475142c41cf8Slipeng sang - Sun Microsystems - Beijing China
4752b96a6eceSZhao Edgar Liu - Sun Microsystems wid = widget->avail_conn[widget->beep_path_next];
475342c41cf8Slipeng sang - Sun Microsystems - Beijing China widget = codec->widget[wid];
475442c41cf8Slipeng sang - Sun Microsystems - Beijing China
475542c41cf8Slipeng sang - Sun Microsystems - Beijing China while (widget) {
475642c41cf8Slipeng sang - Sun Microsystems - Beijing China /*
475742c41cf8Slipeng sang - Sun Microsystems - Beijing China * Set all amplifiers in this path to
4758b96a6eceSZhao Edgar Liu - Sun Microsystems * the maximum volume and unmute them.
475942c41cf8Slipeng sang - Sun Microsystems - Beijing China */
476042c41cf8Slipeng sang - Sun Microsystems - Beijing China if (widget->out_weight != 0)
476142c41cf8Slipeng sang - Sun Microsystems - Beijing China continue;
476242c41cf8Slipeng sang - Sun Microsystems - Beijing China if (widget->outamp_cap) {
476342c41cf8Slipeng sang - Sun Microsystems - Beijing China (void) audioha_codec_4bit_verb_get(
4764b96a6eceSZhao Edgar Liu - Sun Microsystems statep, caddr,
476542c41cf8Slipeng sang - Sun Microsystems - Beijing China wid, AUDIOHDC_VERB_SET_AMP_MUTE,
476642c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_AMP_SET_LR_OUTPUT |
476742c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_GAIN_MAX);
4768ee97b734SZhao Edgar Liu - Sun Microsystems }
476942c41cf8Slipeng sang - Sun Microsystems - Beijing China if (widget->inamp_cap) {
477042c41cf8Slipeng sang - Sun Microsystems - Beijing China (void) audioha_codec_4bit_verb_get(
4771b96a6eceSZhao Edgar Liu - Sun Microsystems statep, caddr,
477242c41cf8Slipeng sang - Sun Microsystems - Beijing China wid, AUDIOHDC_VERB_SET_AMP_MUTE,
477342c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_AMP_SET_LR_INPUT |
477442c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_GAIN_MAX |
4775b96a6eceSZhao Edgar Liu - Sun Microsystems (widget->beep_path_next <<
477642c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_AMP_SET_INDEX_OFFSET));
477742c41cf8Slipeng sang - Sun Microsystems - Beijing China }
477842c41cf8Slipeng sang - Sun Microsystems - Beijing China
4779b96a6eceSZhao Edgar Liu - Sun Microsystems next = widget->beep_path_next;
4780b96a6eceSZhao Edgar Liu - Sun Microsystems if (next == AUDIOHD_NULL_CONN)
478142c41cf8Slipeng sang - Sun Microsystems - Beijing China break;
478242c41cf8Slipeng sang - Sun Microsystems - Beijing China /*
478342c41cf8Slipeng sang - Sun Microsystems - Beijing China * Accoding to HD spec, mixer doesn't support
478442c41cf8Slipeng sang - Sun Microsystems - Beijing China * "select connection"
478542c41cf8Slipeng sang - Sun Microsystems - Beijing China */
478642c41cf8Slipeng sang - Sun Microsystems - Beijing China if ((widget->type != WTYPE_AUDIO_MIX) &&
478742c41cf8Slipeng sang - Sun Microsystems - Beijing China (widget->nconns > 1))
478842c41cf8Slipeng sang - Sun Microsystems - Beijing China (void) audioha_codec_verb_get(statep,
4789b96a6eceSZhao Edgar Liu - Sun Microsystems caddr, wid,
479042c41cf8Slipeng sang - Sun Microsystems - Beijing China AUDIOHDC_VERB_SET_CONN_SEL,
4791b96a6eceSZhao Edgar Liu - Sun Microsystems widget->beep_path_next);
479242c41cf8Slipeng sang - Sun Microsystems - Beijing China
4793b96a6eceSZhao Edgar Liu - Sun Microsystems wid = widget->avail_conn[next];
479442c41cf8Slipeng sang - Sun Microsystems - Beijing China widget = codec->widget[wid];
479542c41cf8Slipeng sang - Sun Microsystems - Beijing China }
479642c41cf8Slipeng sang - Sun Microsystems - Beijing China }
479742c41cf8Slipeng sang - Sun Microsystems - Beijing China }
479842c41cf8Slipeng sang - Sun Microsystems - Beijing China } /* audiohd_finish_beep_path */
479988447a05SGarrett D'Amore
4800e7236f70SZhao Edgar Liu - Sun Microsystems static int
audiohd_find_output_pins(hda_codec_t * codec,wid_t wid,int depth,audiohd_path_t * path)4801e7236f70SZhao Edgar Liu - Sun Microsystems audiohd_find_output_pins(hda_codec_t *codec, wid_t wid, int depth,
4802e7236f70SZhao Edgar Liu - Sun Microsystems audiohd_path_t *path)
4803e7236f70SZhao Edgar Liu - Sun Microsystems {
4804e7236f70SZhao Edgar Liu - Sun Microsystems audiohd_widget_t *widget = codec->widget[wid];
4805e7236f70SZhao Edgar Liu - Sun Microsystems audiohd_pin_t *pin = NULL;
4806e7236f70SZhao Edgar Liu - Sun Microsystems int num, retval = (DDI_FAILURE);
4807e7236f70SZhao Edgar Liu - Sun Microsystems
4808e7236f70SZhao Edgar Liu - Sun Microsystems if (depth > AUDIOHD_MAX_DEPTH)
4809e7236f70SZhao Edgar Liu - Sun Microsystems return (retval);
4810e7236f70SZhao Edgar Liu - Sun Microsystems if (widget == NULL)
4811e7236f70SZhao Edgar Liu - Sun Microsystems return (retval);
4812e7236f70SZhao Edgar Liu - Sun Microsystems
4813e7236f70SZhao Edgar Liu - Sun Microsystems switch (widget->type) {
4814e7236f70SZhao Edgar Liu - Sun Microsystems case WTYPE_PIN:
4815e7236f70SZhao Edgar Liu - Sun Microsystems pin = (audiohd_pin_t *)widget->priv;
4816e7236f70SZhao Edgar Liu - Sun Microsystems if (pin->no_phys_conn)
4817e7236f70SZhao Edgar Liu - Sun Microsystems return (DDI_FAILURE);
4818e7236f70SZhao Edgar Liu - Sun Microsystems
4819e7236f70SZhao Edgar Liu - Sun Microsystems switch (pin->device) {
4820e7236f70SZhao Edgar Liu - Sun Microsystems case DTYPE_LINE_IN:
4821e7236f70SZhao Edgar Liu - Sun Microsystems /* Connection between line-in and output pins */
4822e7236f70SZhao Edgar Liu - Sun Microsystems path->pin_wid[path->pin_nums++] = wid;
4823e7236f70SZhao Edgar Liu - Sun Microsystems break;
4824e7236f70SZhao Edgar Liu - Sun Microsystems case DTYPE_LINEOUT:
4825e7236f70SZhao Edgar Liu - Sun Microsystems case DTYPE_HP_OUT:
4826e7236f70SZhao Edgar Liu - Sun Microsystems case DTYPE_SPDIF_OUT:
4827e7236f70SZhao Edgar Liu - Sun Microsystems widget->path_flags |= AUDIOHD_PATH_LOOPBACK;
4828e7236f70SZhao Edgar Liu - Sun Microsystems widget->in_weight++;
4829e7236f70SZhao Edgar Liu - Sun Microsystems pin->adc_wid = path->adda_wid;
4830e7236f70SZhao Edgar Liu - Sun Microsystems path->pin_wid[path->pin_nums++] = wid;
4831e7236f70SZhao Edgar Liu - Sun Microsystems retval = (DDI_SUCCESS);
4832e7236f70SZhao Edgar Liu - Sun Microsystems break;
4833e7236f70SZhao Edgar Liu - Sun Microsystems default:
4834e7236f70SZhao Edgar Liu - Sun Microsystems break;
4835e7236f70SZhao Edgar Liu - Sun Microsystems }
4836e7236f70SZhao Edgar Liu - Sun Microsystems break;
4837e7236f70SZhao Edgar Liu - Sun Microsystems case WTYPE_AUDIO_MIX:
4838e7236f70SZhao Edgar Liu - Sun Microsystems case WTYPE_AUDIO_SEL:
4839e7236f70SZhao Edgar Liu - Sun Microsystems /*
4840e7236f70SZhao Edgar Liu - Sun Microsystems * If the sum widget has only one input, we don't
4841e7236f70SZhao Edgar Liu - Sun Microsystems * consider it as a real sum widget.
4842e7236f70SZhao Edgar Liu - Sun Microsystems */
4843e7236f70SZhao Edgar Liu - Sun Microsystems if (widget->nconns == 1) {
4844e7236f70SZhao Edgar Liu - Sun Microsystems widget->loopback_path_next = 0;
4845e7236f70SZhao Edgar Liu - Sun Microsystems retval = audiohd_find_output_pins(codec,
4846e7236f70SZhao Edgar Liu - Sun Microsystems widget->avail_conn[0], depth + 1, path);
4847e7236f70SZhao Edgar Liu - Sun Microsystems if (retval == (DDI_SUCCESS)) {
4848e7236f70SZhao Edgar Liu - Sun Microsystems widget->path_flags |= AUDIOHD_PATH_LOOPBACK;
4849e7236f70SZhao Edgar Liu - Sun Microsystems widget->in_weight++;
4850e7236f70SZhao Edgar Liu - Sun Microsystems }
4851e7236f70SZhao Edgar Liu - Sun Microsystems break;
4852e7236f70SZhao Edgar Liu - Sun Microsystems }
4853e7236f70SZhao Edgar Liu - Sun Microsystems
4854e7236f70SZhao Edgar Liu - Sun Microsystems for (int i = 0; i < widget->nconns; i++) {
4855e7236f70SZhao Edgar Liu - Sun Microsystems retval = audiohd_find_output_pins(codec,
4856e7236f70SZhao Edgar Liu - Sun Microsystems widget->avail_conn[i], depth + 1, path);
4857e7236f70SZhao Edgar Liu - Sun Microsystems if (retval == (DDI_SUCCESS)) {
4858e7236f70SZhao Edgar Liu - Sun Microsystems widget->loopback_path_next = i;
4859e7236f70SZhao Edgar Liu - Sun Microsystems widget->in_weight++;
4860e7236f70SZhao Edgar Liu - Sun Microsystems num = path->pin_nums - 1;
4861e7236f70SZhao Edgar Liu - Sun Microsystems path->sum_selconn[num] = i;
4862e7236f70SZhao Edgar Liu - Sun Microsystems path->sum_wid = wid;
4863e7236f70SZhao Edgar Liu - Sun Microsystems widget->path_flags |= AUDIOHD_PATH_LOOPBACK;
4864e7236f70SZhao Edgar Liu - Sun Microsystems break;
4865e7236f70SZhao Edgar Liu - Sun Microsystems }
4866e7236f70SZhao Edgar Liu - Sun Microsystems }
4867e7236f70SZhao Edgar Liu - Sun Microsystems break;
4868e7236f70SZhao Edgar Liu - Sun Microsystems default:
4869e7236f70SZhao Edgar Liu - Sun Microsystems break;
4870e7236f70SZhao Edgar Liu - Sun Microsystems }
4871e7236f70SZhao Edgar Liu - Sun Microsystems
4872e7236f70SZhao Edgar Liu - Sun Microsystems return (retval);
4873e7236f70SZhao Edgar Liu - Sun Microsystems }
4874e7236f70SZhao Edgar Liu - Sun Microsystems
4875e7236f70SZhao Edgar Liu - Sun Microsystems static void
audiohd_build_loopback_path(hda_codec_t * codec)4876e7236f70SZhao Edgar Liu - Sun Microsystems audiohd_build_loopback_path(hda_codec_t *codec)
4877e7236f70SZhao Edgar Liu - Sun Microsystems {
4878e7236f70SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
4879e7236f70SZhao Edgar Liu - Sun Microsystems audiohd_widget_t *widget;
4880e7236f70SZhao Edgar Liu - Sun Microsystems audiohd_path_t *path = NULL;
4881e7236f70SZhao Edgar Liu - Sun Microsystems wid_t wid;
4882e7236f70SZhao Edgar Liu - Sun Microsystems int i, retval;
4883e7236f70SZhao Edgar Liu - Sun Microsystems uint8_t rtag = 0;
4884e7236f70SZhao Edgar Liu - Sun Microsystems
4885e7236f70SZhao Edgar Liu - Sun Microsystems for (wid = codec->first_wid; wid <= codec->last_wid; wid++) {
4886e7236f70SZhao Edgar Liu - Sun Microsystems widget = codec->widget[wid];
4887e7236f70SZhao Edgar Liu - Sun Microsystems
4888e7236f70SZhao Edgar Liu - Sun Microsystems /* check if it is an ADC widget */
4889e7236f70SZhao Edgar Liu - Sun Microsystems if (widget == NULL || widget->type != WTYPE_AUDIO_IN)
4890e7236f70SZhao Edgar Liu - Sun Microsystems continue;
4891e7236f70SZhao Edgar Liu - Sun Microsystems
4892e7236f70SZhao Edgar Liu - Sun Microsystems if (path == NULL)
4893e7236f70SZhao Edgar Liu - Sun Microsystems path = kmem_zalloc(sizeof (audiohd_path_t), KM_SLEEP);
4894e7236f70SZhao Edgar Liu - Sun Microsystems else
4895e7236f70SZhao Edgar Liu - Sun Microsystems bzero(path, sizeof (audiohd_port_t));
4896e7236f70SZhao Edgar Liu - Sun Microsystems path->adda_wid = wid;
4897e7236f70SZhao Edgar Liu - Sun Microsystems
4898e7236f70SZhao Edgar Liu - Sun Microsystems for (i = 0; i < widget->nconns; i++) {
4899e7236f70SZhao Edgar Liu - Sun Microsystems retval = audiohd_find_output_pins(codec,
4900e7236f70SZhao Edgar Liu - Sun Microsystems widget->avail_conn[i], 0, path);
4901e7236f70SZhao Edgar Liu - Sun Microsystems if (retval == (DDI_SUCCESS)) {
4902e7236f70SZhao Edgar Liu - Sun Microsystems path->codec = codec;
4903e7236f70SZhao Edgar Liu - Sun Microsystems path->statep = statep;
4904e7236f70SZhao Edgar Liu - Sun Microsystems path->path_type = LOOPBACK;
4905e7236f70SZhao Edgar Liu - Sun Microsystems path->tag = ++rtag;
4906e7236f70SZhao Edgar Liu - Sun Microsystems codec->nistream++;
4907e7236f70SZhao Edgar Liu - Sun Microsystems statep->path[statep->pathnum++] = path;
4908e7236f70SZhao Edgar Liu - Sun Microsystems widget->loopback_path_next = i;
4909e7236f70SZhao Edgar Liu - Sun Microsystems widget->priv = path;
4910e7236f70SZhao Edgar Liu - Sun Microsystems path = NULL;
4911e7236f70SZhao Edgar Liu - Sun Microsystems statep->loopback_supported = B_TRUE;
4912e7236f70SZhao Edgar Liu - Sun Microsystems break;
4913e7236f70SZhao Edgar Liu - Sun Microsystems }
4914e7236f70SZhao Edgar Liu - Sun Microsystems }
4915e7236f70SZhao Edgar Liu - Sun Microsystems }
4916e7236f70SZhao Edgar Liu - Sun Microsystems
4917e7236f70SZhao Edgar Liu - Sun Microsystems
4918e7236f70SZhao Edgar Liu - Sun Microsystems if (path)
4919e7236f70SZhao Edgar Liu - Sun Microsystems kmem_free(path, sizeof (audiohd_path_t));
4920e7236f70SZhao Edgar Liu - Sun Microsystems } /* audiohd_build_loopback_path() */
4921e7236f70SZhao Edgar Liu - Sun Microsystems
49223a49c214SYang-Rong Jerry Zhou /*
49233a49c214SYang-Rong Jerry Zhou * audiohd_build_path()
49243a49c214SYang-Rong Jerry Zhou *
49253a49c214SYang-Rong Jerry Zhou * Description:
49263a49c214SYang-Rong Jerry Zhou * Here we build the output, input, monitor path.
49273a49c214SYang-Rong Jerry Zhou * And also enable the path in default.
49283a49c214SYang-Rong Jerry Zhou * Search for the gain and mute control for the path
49293a49c214SYang-Rong Jerry Zhou */
49303a49c214SYang-Rong Jerry Zhou static void
audiohd_build_path(audiohd_state_t * statep)49313a49c214SYang-Rong Jerry Zhou audiohd_build_path(audiohd_state_t *statep)
49323a49c214SYang-Rong Jerry Zhou {
49333a49c214SYang-Rong Jerry Zhou int i;
49347253a143Scg
49353a49c214SYang-Rong Jerry Zhou for (i = 0; i < AUDIOHD_CODEC_MAX; i++) {
49363a49c214SYang-Rong Jerry Zhou if (statep->codec[i]) {
49373a49c214SYang-Rong Jerry Zhou audiohd_build_output_path(statep->codec[i]);
49383a49c214SYang-Rong Jerry Zhou audiohd_build_output_amp(statep->codec[i]);
49393a49c214SYang-Rong Jerry Zhou audiohd_finish_output_path(statep->codec[i]);
49403a49c214SYang-Rong Jerry Zhou
49413a49c214SYang-Rong Jerry Zhou audiohd_build_input_path(statep->codec[i]);
49423a49c214SYang-Rong Jerry Zhou audiohd_build_input_amp(statep->codec[i]);
49433a49c214SYang-Rong Jerry Zhou audiohd_finish_input_path(statep->codec[i]);
49443a49c214SYang-Rong Jerry Zhou
49453a49c214SYang-Rong Jerry Zhou audiohd_build_monitor_path(statep->codec[i]);
49463a49c214SYang-Rong Jerry Zhou audiohd_build_monitor_amp(statep->codec[i]);
49473a49c214SYang-Rong Jerry Zhou audiohd_finish_monitor_path(statep->codec[i]);
494842c41cf8Slipeng sang - Sun Microsystems - Beijing China
494942c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_build_beep_path(statep->codec[i]);
495042c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_build_beep_amp(statep->codec[i]);
495142c41cf8Slipeng sang - Sun Microsystems - Beijing China audiohd_finish_beep_path(statep->codec[i]);
4952e7236f70SZhao Edgar Liu - Sun Microsystems
4953e7236f70SZhao Edgar Liu - Sun Microsystems audiohd_build_loopback_path(statep->codec[i]);
49547253a143Scg }
49557253a143Scg }
495688447a05SGarrett D'Amore } /* audiohd_build_path */
495788447a05SGarrett D'Amore
495888447a05SGarrett D'Amore /*
495988447a05SGarrett D'Amore * audiohd_allocate_port()
496088447a05SGarrett D'Amore */
496188447a05SGarrett D'Amore static int
audiohd_allocate_port(audiohd_state_t * statep)496288447a05SGarrett D'Amore audiohd_allocate_port(audiohd_state_t *statep)
496388447a05SGarrett D'Amore {
496488447a05SGarrett D'Amore int i, j;
496588447a05SGarrett D'Amore audiohd_port_t *port;
496688447a05SGarrett D'Amore int dir;
496788447a05SGarrett D'Amore unsigned caps;
496888447a05SGarrett D'Amore int rc;
496988447a05SGarrett D'Amore audio_dev_t *adev;
497088447a05SGarrett D'Amore dev_info_t *dip;
497188447a05SGarrett D'Amore ddi_dma_cookie_t cookie;
497288447a05SGarrett D'Amore uint_t count;
497388447a05SGarrett D'Amore uint64_t buf_phys_addr;
497488447a05SGarrett D'Amore sd_bdle_t *entry;
497588447a05SGarrett D'Amore uint16_t gcap;
497688447a05SGarrett D'Amore size_t real_size;
497788447a05SGarrett D'Amore
497888447a05SGarrett D'Amore adev = statep->adev;
497988447a05SGarrett D'Amore dip = statep->hda_dip;
498088447a05SGarrett D'Amore
498188447a05SGarrett D'Amore ddi_dma_attr_t dma_attr = {
498288447a05SGarrett D'Amore DMA_ATTR_V0, /* version */
498388447a05SGarrett D'Amore 0, /* addr_lo */
498488447a05SGarrett D'Amore 0xffffffffffffffffULL, /* addr_hi */
498588447a05SGarrett D'Amore 0x00000000ffffffffULL, /* count_max */
498688447a05SGarrett D'Amore 128, /* 128-byte alignment as HD spec */
498788447a05SGarrett D'Amore 0xfff, /* burstsize */
498888447a05SGarrett D'Amore 1, /* minxfer */
498988447a05SGarrett D'Amore 0xffffffff, /* maxxfer */
499088447a05SGarrett D'Amore 0xffffffff, /* seg */
499188447a05SGarrett D'Amore 1, /* sgllen */
499288447a05SGarrett D'Amore 1, /* granular */
499388447a05SGarrett D'Amore 0 /* flags */
499488447a05SGarrett D'Amore };
499588447a05SGarrett D'Amore
499688447a05SGarrett D'Amore gcap = AUDIOHD_REG_GET16(AUDIOHD_REG_GCAP);
499788447a05SGarrett D'Amore if ((gcap & AUDIOHDR_GCAP_64OK) == 0)
499888447a05SGarrett D'Amore dma_attr.dma_attr_addr_hi = 0xffffffffUL;
499988447a05SGarrett D'Amore
500088447a05SGarrett D'Amore for (i = 0; i < PORT_MAX; i++) {
500188447a05SGarrett D'Amore port = kmem_zalloc(sizeof (*port), KM_SLEEP);
500288447a05SGarrett D'Amore statep->port[i] = port;
500388447a05SGarrett D'Amore port->statep = statep;
500488447a05SGarrett D'Amore switch (i) {
500588447a05SGarrett D'Amore case PORT_ADC:
500688447a05SGarrett D'Amore dir = DDI_DMA_READ | DDI_DMA_CONSISTENT;
500788447a05SGarrett D'Amore caps = ENGINE_INPUT_CAP;
500888447a05SGarrett D'Amore port->sync_dir = DDI_DMA_SYNC_FORKERNEL;
500988447a05SGarrett D'Amore port->nchan = statep->rchan;
501088447a05SGarrett D'Amore port->index = 1;
501188447a05SGarrett D'Amore port->regoff = AUDIOHD_REG_SD_BASE;
501288447a05SGarrett D'Amore break;
501388447a05SGarrett D'Amore case PORT_DAC:
501488447a05SGarrett D'Amore dir = DDI_DMA_WRITE | DDI_DMA_CONSISTENT;
501588447a05SGarrett D'Amore caps = ENGINE_OUTPUT_CAP;
501688447a05SGarrett D'Amore port->sync_dir = DDI_DMA_SYNC_FORDEV;
501788447a05SGarrett D'Amore port->nchan = statep->pchan;
501888447a05SGarrett D'Amore port->index = statep->hda_input_streams + 1;
501988447a05SGarrett D'Amore port->regoff = AUDIOHD_REG_SD_BASE +
502088447a05SGarrett D'Amore AUDIOHD_REG_SD_LEN *
502188447a05SGarrett D'Amore statep->hda_input_streams;
502288447a05SGarrett D'Amore break;
502388447a05SGarrett D'Amore default:
502488447a05SGarrett D'Amore return (DDI_FAILURE);
502588447a05SGarrett D'Amore }
502688447a05SGarrett D'Amore
5027a33ad26eSZhao Edgar Liu - Sun Microsystems switch (statep->sample_rate) {
5028a33ad26eSZhao Edgar Liu - Sun Microsystems case 192000:
5029a33ad26eSZhao Edgar Liu - Sun Microsystems port->format = 0x18 << 4;
5030a33ad26eSZhao Edgar Liu - Sun Microsystems break;
5031a33ad26eSZhao Edgar Liu - Sun Microsystems case 96000:
5032a33ad26eSZhao Edgar Liu - Sun Microsystems port->format = 0x08 << 4;
5033a33ad26eSZhao Edgar Liu - Sun Microsystems break;
5034a33ad26eSZhao Edgar Liu - Sun Microsystems case 48000:
5035a33ad26eSZhao Edgar Liu - Sun Microsystems default: /* 48kHz is default */
5036a33ad26eSZhao Edgar Liu - Sun Microsystems port->format = 0x00;
5037a33ad26eSZhao Edgar Liu - Sun Microsystems break;
5038a33ad26eSZhao Edgar Liu - Sun Microsystems }
5039a33ad26eSZhao Edgar Liu - Sun Microsystems
5040a33ad26eSZhao Edgar Liu - Sun Microsystems switch (statep->sample_bit_depth) {
5041a33ad26eSZhao Edgar Liu - Sun Microsystems case AUDIOHD_BIT_DEPTH24:
5042a33ad26eSZhao Edgar Liu - Sun Microsystems port->format |= 0x3;
5043a33ad26eSZhao Edgar Liu - Sun Microsystems statep->sample_packed_bytes = 4;
5044a33ad26eSZhao Edgar Liu - Sun Microsystems break;
5045a33ad26eSZhao Edgar Liu - Sun Microsystems case AUDIOHD_BIT_DEPTH16:
5046a33ad26eSZhao Edgar Liu - Sun Microsystems default: /* 16 bits is default */
5047a33ad26eSZhao Edgar Liu - Sun Microsystems port->format |= 0x1;
5048a33ad26eSZhao Edgar Liu - Sun Microsystems statep->sample_packed_bytes = 2;
5049a33ad26eSZhao Edgar Liu - Sun Microsystems break;
5050a33ad26eSZhao Edgar Liu - Sun Microsystems }
5051a33ad26eSZhao Edgar Liu - Sun Microsystems
5052a33ad26eSZhao Edgar Liu - Sun Microsystems port->nframes = 1024 * AUDIOHD_BDLE_NUMS *
5053a33ad26eSZhao Edgar Liu - Sun Microsystems statep->sample_rate / 48000;
5054a33ad26eSZhao Edgar Liu - Sun Microsystems port->fragsize = 1024 * port->nchan *
5055a33ad26eSZhao Edgar Liu - Sun Microsystems statep->sample_packed_bytes *
5056a33ad26eSZhao Edgar Liu - Sun Microsystems statep->sample_rate / 48000;
5057a33ad26eSZhao Edgar Liu - Sun Microsystems port->bufsize = port->nframes * port->nchan *
5058a33ad26eSZhao Edgar Liu - Sun Microsystems statep->sample_packed_bytes;
505988447a05SGarrett D'Amore
506088447a05SGarrett D'Amore /* allocate dma handle */
506188447a05SGarrett D'Amore rc = ddi_dma_alloc_handle(dip, &dma_attr, DDI_DMA_SLEEP,
506288447a05SGarrett D'Amore NULL, &port->samp_dmah);
506388447a05SGarrett D'Amore if (rc != DDI_SUCCESS) {
506488447a05SGarrett D'Amore audio_dev_warn(adev, "ddi_dma_alloc_handle failed: %d",
506588447a05SGarrett D'Amore rc);
5066c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
506788447a05SGarrett D'Amore }
50680c240c64SZhao Edgar Liu - Sun Microsystems
5069c0e48486SYang-Rong Jerry Zhou /*
5070c0e48486SYang-Rong Jerry Zhou * Warning: please be noted that allocating the dma memory
5071c0e48486SYang-Rong Jerry Zhou * with the flag IOMEM_DATA_UNCACHED is a hack due
5072c0e48486SYang-Rong Jerry Zhou * to an incorrect cache synchronization on NVidia MCP79
5073c0e48486SYang-Rong Jerry Zhou * chipset which causes the audio distortion problem,
5074c0e48486SYang-Rong Jerry Zhou * and that it should be fixed later. There should be
5075c0e48486SYang-Rong Jerry Zhou * no reason you have to allocate UNCACHED memory. In
5076c0e48486SYang-Rong Jerry Zhou * complex architectures with nested IO caches,
5077c0e48486SYang-Rong Jerry Zhou * reliance on this flag might lead to failure.
5078c0e48486SYang-Rong Jerry Zhou */
507968c47f65SGarrett D'Amore rc = ddi_dma_mem_alloc(port->samp_dmah, port->bufsize,
508068c47f65SGarrett D'Amore &hda_dev_accattr, DDI_DMA_CONSISTENT | IOMEM_DATA_UNCACHED,
508188447a05SGarrett D'Amore DDI_DMA_SLEEP, NULL, &port->samp_kaddr,
508288447a05SGarrett D'Amore &real_size, &port->samp_acch);
508388447a05SGarrett D'Amore if (rc == DDI_FAILURE) {
508468c47f65SGarrett D'Amore if (ddi_dma_mem_alloc(port->samp_dmah, port->bufsize,
508568c47f65SGarrett D'Amore &hda_dev_accattr, DDI_DMA_CONSISTENT,
5086c0e48486SYang-Rong Jerry Zhou DDI_DMA_SLEEP, NULL,
5087c0e48486SYang-Rong Jerry Zhou &port->samp_kaddr, &real_size,
5088c0e48486SYang-Rong Jerry Zhou &port->samp_acch) != DDI_SUCCESS) {
5089c0e48486SYang-Rong Jerry Zhou audio_dev_warn(adev,
5090c0e48486SYang-Rong Jerry Zhou "ddi_dma_mem_alloc failed");
5091c0e48486SYang-Rong Jerry Zhou return (DDI_FAILURE);
5092c0e48486SYang-Rong Jerry Zhou }
509388447a05SGarrett D'Amore }
509488447a05SGarrett D'Amore
509588447a05SGarrett D'Amore /* bind DMA buffer */
509688447a05SGarrett D'Amore rc = ddi_dma_addr_bind_handle(port->samp_dmah, NULL,
509788447a05SGarrett D'Amore port->samp_kaddr, real_size, dir,
509888447a05SGarrett D'Amore DDI_DMA_SLEEP, NULL, &cookie, &count);
509988447a05SGarrett D'Amore if ((rc != DDI_DMA_MAPPED) || (count != 1)) {
510088447a05SGarrett D'Amore audio_dev_warn(adev,
510188447a05SGarrett D'Amore "ddi_dma_addr_bind_handle failed: %d", rc);
5102c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
510388447a05SGarrett D'Amore }
510488447a05SGarrett D'Amore port->samp_paddr = (uint64_t)cookie.dmac_laddress;
510588447a05SGarrett D'Amore
510688447a05SGarrett D'Amore /*
510788447a05SGarrett D'Amore * now, from here we allocate DMA
510888447a05SGarrett D'Amore * memory for buffer descriptor list.
510988447a05SGarrett D'Amore * we allocate adjacent DMA memory for all DMA engines.
511088447a05SGarrett D'Amore */
511188447a05SGarrett D'Amore rc = ddi_dma_alloc_handle(dip, &dma_attr, DDI_DMA_SLEEP,
511288447a05SGarrett D'Amore NULL, &port->bdl_dmah);
511388447a05SGarrett D'Amore if (rc != DDI_SUCCESS) {
511488447a05SGarrett D'Amore audio_dev_warn(adev,
511588447a05SGarrett D'Amore "ddi_dma_alloc_handle(bdlist) failed");
5116c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
511788447a05SGarrett D'Amore }
511888447a05SGarrett D'Amore
511988447a05SGarrett D'Amore /*
512088447a05SGarrett D'Amore * we allocate all buffer descriptors lists in continuous
512188447a05SGarrett D'Amore * dma memory.
512288447a05SGarrett D'Amore */
512388447a05SGarrett D'Amore port->bdl_size = sizeof (sd_bdle_t) * AUDIOHD_BDLE_NUMS;
512488447a05SGarrett D'Amore rc = ddi_dma_mem_alloc(port->bdl_dmah, port->bdl_size,
512588447a05SGarrett D'Amore &hda_dev_accattr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
512688447a05SGarrett D'Amore &port->bdl_kaddr, &real_size, &port->bdl_acch);
512788447a05SGarrett D'Amore if (rc != DDI_SUCCESS) {
512888447a05SGarrett D'Amore audio_dev_warn(adev,
512988447a05SGarrett D'Amore "ddi_dma_mem_alloc(bdlist) failed");
5130c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
513188447a05SGarrett D'Amore }
513288447a05SGarrett D'Amore
513388447a05SGarrett D'Amore rc = ddi_dma_addr_bind_handle(port->bdl_dmah, NULL,
513488447a05SGarrett D'Amore port->bdl_kaddr,
513588447a05SGarrett D'Amore real_size, DDI_DMA_WRITE | DDI_DMA_CONSISTENT,
513688447a05SGarrett D'Amore DDI_DMA_SLEEP,
513788447a05SGarrett D'Amore NULL, &cookie, &count);
513888447a05SGarrett D'Amore if ((rc != DDI_DMA_MAPPED) || (count != 1)) {
513988447a05SGarrett D'Amore audio_dev_warn(adev, "addr_bind_handle failed");
5140c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
514188447a05SGarrett D'Amore }
514288447a05SGarrett D'Amore port->bdl_paddr = (uint64_t)cookie.dmac_laddress;
514388447a05SGarrett D'Amore
514488447a05SGarrett D'Amore entry = (sd_bdle_t *)port->bdl_kaddr;
514588447a05SGarrett D'Amore buf_phys_addr = port->samp_paddr;
514688447a05SGarrett D'Amore
514788447a05SGarrett D'Amore for (j = 0; j < AUDIOHD_BDLE_NUMS; j++) {
514888447a05SGarrett D'Amore entry->sbde_addr = buf_phys_addr;
514968c47f65SGarrett D'Amore entry->sbde_len = port->fragsize;
515088447a05SGarrett D'Amore entry->sbde_ioc = 1;
515168c47f65SGarrett D'Amore buf_phys_addr += port->fragsize;
515288447a05SGarrett D'Amore entry++;
515388447a05SGarrett D'Amore }
515488447a05SGarrett D'Amore (void) ddi_dma_sync(port->bdl_dmah, 0, sizeof (sd_bdle_t) *
515588447a05SGarrett D'Amore AUDIOHD_BDLE_NUMS, DDI_DMA_SYNC_FORDEV);
515688447a05SGarrett D'Amore port->curpos = 0;
515788447a05SGarrett D'Amore
515888447a05SGarrett D'Amore port->engine = audio_engine_alloc(&audiohd_engine_ops, caps);
515988447a05SGarrett D'Amore if (port->engine == NULL) {
5160c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
516188447a05SGarrett D'Amore }
516288447a05SGarrett D'Amore
516388447a05SGarrett D'Amore audio_engine_set_private(port->engine, port);
516488447a05SGarrett D'Amore audio_dev_add_engine(adev, port->engine);
516588447a05SGarrett D'Amore }
516688447a05SGarrett D'Amore
516788447a05SGarrett D'Amore return (DDI_SUCCESS);
516888447a05SGarrett D'Amore }
516988447a05SGarrett D'Amore
517088447a05SGarrett D'Amore static void
audiohd_free_port(audiohd_state_t * statep)517188447a05SGarrett D'Amore audiohd_free_port(audiohd_state_t *statep)
517288447a05SGarrett D'Amore {
517388447a05SGarrett D'Amore int i;
517488447a05SGarrett D'Amore audiohd_port_t *port;
517588447a05SGarrett D'Amore
517688447a05SGarrett D'Amore for (i = 0; i < PORT_MAX; i++) {
517788447a05SGarrett D'Amore port = statep->port[i];
517888447a05SGarrett D'Amore if (port == NULL)
517988447a05SGarrett D'Amore continue;
518088447a05SGarrett D'Amore if (port->engine) {
518188447a05SGarrett D'Amore audio_dev_remove_engine(statep->adev,
518288447a05SGarrett D'Amore port->engine);
518388447a05SGarrett D'Amore audio_engine_free(port->engine);
518488447a05SGarrett D'Amore }
518588447a05SGarrett D'Amore if (port->samp_dmah) {
518688447a05SGarrett D'Amore (void) ddi_dma_unbind_handle(port->samp_dmah);
518788447a05SGarrett D'Amore }
518888447a05SGarrett D'Amore if (port->samp_acch) {
518988447a05SGarrett D'Amore ddi_dma_mem_free(&port->samp_acch);
519088447a05SGarrett D'Amore }
519188447a05SGarrett D'Amore if (port->samp_dmah) {
519288447a05SGarrett D'Amore ddi_dma_free_handle(&port->samp_dmah);
519388447a05SGarrett D'Amore }
519488447a05SGarrett D'Amore if (port->bdl_dmah) {
519588447a05SGarrett D'Amore (void) ddi_dma_unbind_handle(port->bdl_dmah);
519688447a05SGarrett D'Amore }
519788447a05SGarrett D'Amore if (port->bdl_acch) {
519888447a05SGarrett D'Amore ddi_dma_mem_free(&port->bdl_acch);
519988447a05SGarrett D'Amore }
520088447a05SGarrett D'Amore if (port->bdl_dmah) {
520188447a05SGarrett D'Amore ddi_dma_free_handle(&port->bdl_dmah);
520288447a05SGarrett D'Amore }
520388447a05SGarrett D'Amore
520488447a05SGarrett D'Amore kmem_free(port, sizeof (audiohd_port_t));
520588447a05SGarrett D'Amore }
520688447a05SGarrett D'Amore }
52077253a143Scg
52087253a143Scg /*
52095ec2209cSZhao Edgar Liu - Sun Microsystems * audiohd_change_widget_power_state(audiohd_state_t *statep, int state)
52103a49c214SYang-Rong Jerry Zhou * Description:
521188447a05SGarrett D'Amore * This routine is used to change the widget power betwen D0 and D2.
521288447a05SGarrett D'Amore * D0 is fully on; D2 allows the lowest possible power consuming state
521388447a05SGarrett D'Amore * from which it can return to the fully on state: D0.
52147253a143Scg */
521588447a05SGarrett D'Amore static void
audiohd_change_widget_power_state(audiohd_state_t * statep,int state)52165ec2209cSZhao Edgar Liu - Sun Microsystems audiohd_change_widget_power_state(audiohd_state_t *statep, int state)
52177253a143Scg {
521888447a05SGarrett D'Amore int i;
521988447a05SGarrett D'Amore wid_t wid;
522088447a05SGarrett D'Amore hda_codec_t *codec;
522188447a05SGarrett D'Amore audiohd_widget_t *widget;
52223a49c214SYang-Rong Jerry Zhou
52235ec2209cSZhao Edgar Liu - Sun Microsystems for (i = 0; i < AUDIOHD_CODEC_MAX; i++) {
52245ec2209cSZhao Edgar Liu - Sun Microsystems codec = statep->codec[i];
52255ec2209cSZhao Edgar Liu - Sun Microsystems if (codec == NULL)
52265ec2209cSZhao Edgar Liu - Sun Microsystems continue;
52275ec2209cSZhao Edgar Liu - Sun Microsystems for (wid = codec->first_wid; wid <= codec->last_wid;
52285ec2209cSZhao Edgar Liu - Sun Microsystems wid++) {
52295ec2209cSZhao Edgar Liu - Sun Microsystems widget = codec->widget[wid];
52305ec2209cSZhao Edgar Liu - Sun Microsystems if (widget->widget_cap &
52315ec2209cSZhao Edgar Liu - Sun Microsystems AUDIOHD_WIDCAP_PWRCTRL) {
52325ec2209cSZhao Edgar Liu - Sun Microsystems (void) audioha_codec_verb_get(statep,
52335ec2209cSZhao Edgar Liu - Sun Microsystems codec->index, wid,
52345ec2209cSZhao Edgar Liu - Sun Microsystems AUDIOHDC_VERB_SET_POWER_STATE,
52355ec2209cSZhao Edgar Liu - Sun Microsystems state);
523688447a05SGarrett D'Amore }
5237f90d8383Scg }
52387253a143Scg }
523988447a05SGarrett D'Amore }
52403a49c214SYang-Rong Jerry Zhou /*
524188447a05SGarrett D'Amore * audiohd_restore_path()
52423a49c214SYang-Rong Jerry Zhou * Description:
524388447a05SGarrett D'Amore * This routine is used to restore the path on the codec.
52443a49c214SYang-Rong Jerry Zhou */
52453a49c214SYang-Rong Jerry Zhou static void
audiohd_restore_path(audiohd_state_t * statep)524688447a05SGarrett D'Amore audiohd_restore_path(audiohd_state_t *statep)
52473a49c214SYang-Rong Jerry Zhou {
524888447a05SGarrett D'Amore int i;
524988447a05SGarrett D'Amore hda_codec_t *codec;
52507253a143Scg
525188447a05SGarrett D'Amore for (i = 0; i < AUDIOHD_CODEC_MAX; i++) {
525288447a05SGarrett D'Amore codec = statep->codec[i];
52535ec2209cSZhao Edgar Liu - Sun Microsystems if (codec == NULL)
525488447a05SGarrett D'Amore continue;
525588447a05SGarrett D'Amore audiohd_finish_output_path(statep->codec[i]);
525688447a05SGarrett D'Amore audiohd_finish_input_path(statep->codec[i]);
525788447a05SGarrett D'Amore audiohd_finish_monitor_path(statep->codec[i]);
5258e7236f70SZhao Edgar Liu - Sun Microsystems audiohd_finish_beep_path(statep->codec[i]);
52597253a143Scg }
526088447a05SGarrett D'Amore }
52617253a143Scg
52627253a143Scg /*
526388447a05SGarrett D'Amore * audiohd_reset_pins_ur_cap()
52643a49c214SYang-Rong Jerry Zhou * Description:
526588447a05SGarrett D'Amore * Enable the unsolicited response of the pins which have the unsolicited
526688447a05SGarrett D'Amore * response capability
52677253a143Scg */
52683a49c214SYang-Rong Jerry Zhou static void
audiohd_reset_pins_ur_cap(audiohd_state_t * statep)526988447a05SGarrett D'Amore audiohd_reset_pins_ur_cap(audiohd_state_t *statep)
52707253a143Scg {
527188447a05SGarrett D'Amore hda_codec_t *codec;
527288447a05SGarrett D'Amore audiohd_pin_t *pin;
527388447a05SGarrett D'Amore audiohd_widget_t *widget;
527488447a05SGarrett D'Amore uint32_t urctrl;
527588447a05SGarrett D'Amore int i;
52767253a143Scg
5277ffdc8841SYang-Rong Jerry Zhou for (i = 0; i < AUDIOHD_CODEC_MAX; i++) {
527888447a05SGarrett D'Amore codec = statep->codec[i];
52795ec2209cSZhao Edgar Liu - Sun Microsystems if (codec == NULL)
528088447a05SGarrett D'Amore continue;
528188447a05SGarrett D'Amore pin = codec->first_pin;
528288447a05SGarrett D'Amore while (pin) {
528388447a05SGarrett D'Amore /* enable the unsolicited response of the pin */
528488447a05SGarrett D'Amore widget = codec->widget[pin->wid];
528588447a05SGarrett D'Amore if ((widget->widget_cap &
528688447a05SGarrett D'Amore (AUDIOHD_URCAP_MASK) &&
528788447a05SGarrett D'Amore (pin->cap & AUDIOHD_DTCCAP_MASK)) &&
528888447a05SGarrett D'Amore ((pin->device == DTYPE_LINEOUT) ||
528988447a05SGarrett D'Amore (pin->device == DTYPE_SPDIF_OUT) ||
529088447a05SGarrett D'Amore (pin->device == DTYPE_HP_OUT) ||
529188447a05SGarrett D'Amore (pin->device == DTYPE_MIC_IN))) {
529288447a05SGarrett D'Amore urctrl = (uint8_t)(1 <<
529388447a05SGarrett D'Amore (AUDIOHD_UR_ENABLE_OFF - 1));
529488447a05SGarrett D'Amore urctrl |= (pin->wid & AUDIOHD_UR_TAG_MASK);
529588447a05SGarrett D'Amore (void) audioha_codec_verb_get(statep,
529688447a05SGarrett D'Amore codec->index,
529788447a05SGarrett D'Amore pin->wid,
5298989b958fSZhao Edgar Liu - Sun Microsystems AUDIOHDC_VERB_SET_UNS_ENABLE, urctrl);
529988447a05SGarrett D'Amore }
530088447a05SGarrett D'Amore pin = pin->next;
530188447a05SGarrett D'Amore }
5302f90d8383Scg }
530388447a05SGarrett D'Amore }
530488447a05SGarrett D'Amore static void
audiohd_restore_codec_gpio(audiohd_state_t * statep)530588447a05SGarrett D'Amore audiohd_restore_codec_gpio(audiohd_state_t *statep)
5306644f3c1fScg {
53073a49c214SYang-Rong Jerry Zhou int i;
530888447a05SGarrett D'Amore wid_t wid;
530988447a05SGarrett D'Amore hda_codec_t *codec;
5310644f3c1fScg
531188447a05SGarrett D'Amore for (i = 0; i < AUDIOHD_CODEC_MAX; i++) {
531288447a05SGarrett D'Amore codec = statep->codec[i];
531388447a05SGarrett D'Amore if (codec == NULL)
531488447a05SGarrett D'Amore continue;
531588447a05SGarrett D'Amore wid = codec->wid_afg;
5316644f3c1fScg
531788447a05SGarrett D'Amore /* power-up audio function group */
531888447a05SGarrett D'Amore (void) audioha_codec_verb_get(statep, i, wid,
53195ec2209cSZhao Edgar Liu - Sun Microsystems AUDIOHDC_VERB_SET_POWER_STATE, AUDIOHD_PW_D0);
53205ec2209cSZhao Edgar Liu - Sun Microsystems
532188447a05SGarrett D'Amore /* work around for Sony VAIO laptop with specific codec */
5322cbe6566fSZhao Edgar Liu - Sun Microsystems if ((codec->codec_info->flags & NO_GPIO) == 0) {
53239ba19c87SYang-Rong Jerry Zhou /*
53249ba19c87SYang-Rong Jerry Zhou * GPIO controls which are laptop specific workarounds
53259ba19c87SYang-Rong Jerry Zhou * and might be changed. Some laptops use GPIO,
53269ba19c87SYang-Rong Jerry Zhou * so we need to enable and set the GPIO correctly.
53279ba19c87SYang-Rong Jerry Zhou */
53289ba19c87SYang-Rong Jerry Zhou (void) audioha_codec_verb_get(statep, i, wid,
53299ba19c87SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_GPIO_MASK, AUDIOHDC_GPIO_ENABLE);
53309ba19c87SYang-Rong Jerry Zhou (void) audioha_codec_verb_get(statep, i, wid,
53319ba19c87SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_GPIO_DIREC, AUDIOHDC_GPIO_DIRECT);
53329ba19c87SYang-Rong Jerry Zhou (void) audioha_codec_verb_get(statep, i, wid,
53339ba19c87SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_GPIO_STCK,
53349ba19c87SYang-Rong Jerry Zhou AUDIOHDC_GPIO_DATA_CTRL);
53359ba19c87SYang-Rong Jerry Zhou (void) audioha_codec_verb_get(statep, i, wid,
53369ba19c87SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_GPIO_DATA,
53379ba19c87SYang-Rong Jerry Zhou AUDIOHDC_GPIO_STCK_CTRL);
53389ba19c87SYang-Rong Jerry Zhou }
533988447a05SGarrett D'Amore }
534088447a05SGarrett D'Amore }
53413a49c214SYang-Rong Jerry Zhou /*
534288447a05SGarrett D'Amore * audiohd_resume()
53433a49c214SYang-Rong Jerry Zhou */
534488447a05SGarrett D'Amore static int
audiohd_resume(audiohd_state_t * statep)534588447a05SGarrett D'Amore audiohd_resume(audiohd_state_t *statep)
53463a49c214SYang-Rong Jerry Zhou {
534788447a05SGarrett D'Amore uint8_t rirbsts;
5348644f3c1fScg
53493a49c214SYang-Rong Jerry Zhou mutex_enter(&statep->hda_mutex);
535088447a05SGarrett D'Amore statep->suspended = B_FALSE;
535188447a05SGarrett D'Amore /* Restore the hda state */
5352c6e681c0SYang-Rong Jerry Zhou if (audiohd_reinit_hda(statep) == DDI_FAILURE) {
535388447a05SGarrett D'Amore audio_dev_warn(statep->adev,
535488447a05SGarrett D'Amore "hda reinit failed");
53553a49c214SYang-Rong Jerry Zhou mutex_exit(&statep->hda_mutex);
53565ec2209cSZhao Edgar Liu - Sun Microsystems return (DDI_FAILURE);
53573a49c214SYang-Rong Jerry Zhou }
535888447a05SGarrett D'Amore /* reset to enable the capability of unsolicited response for pin */
535988447a05SGarrett D'Amore audiohd_reset_pins_ur_cap(statep);
536088447a05SGarrett D'Amore /* clear the unsolicited response interrupt */
536188447a05SGarrett D'Amore rirbsts = AUDIOHD_REG_GET8(AUDIOHD_REG_RIRBSTS);
536288447a05SGarrett D'Amore AUDIOHD_REG_SET8(AUDIOHD_REG_RIRBSTS, rirbsts);
536368c47f65SGarrett D'Amore /* set widget power to D0 */
536468c47f65SGarrett D'Amore audiohd_change_widget_power_state(statep, AUDIOHD_PW_D0);
536588447a05SGarrett D'Amore
536688447a05SGarrett D'Amore audiohd_configure_output(statep);
536788447a05SGarrett D'Amore audiohd_configure_input(statep);
536868c47f65SGarrett D'Amore mutex_exit(&statep->hda_mutex);
5369644f3c1fScg
537068c47f65SGarrett D'Amore audio_dev_resume(statep->adev);
5371644f3c1fScg
537288447a05SGarrett D'Amore return (DDI_SUCCESS);
537388447a05SGarrett D'Amore } /* audiohd_resume */
5374644f3c1fScg
5375644f3c1fScg /*
537688447a05SGarrett D'Amore * audiohd_suspend()
5377644f3c1fScg */
537888447a05SGarrett D'Amore static int
audiohd_suspend(audiohd_state_t * statep)537988447a05SGarrett D'Amore audiohd_suspend(audiohd_state_t *statep)
5380644f3c1fScg {
538168c47f65SGarrett D'Amore audio_dev_suspend(statep->adev);
538268c47f65SGarrett D'Amore
538388447a05SGarrett D'Amore mutex_enter(&statep->hda_mutex);
538488447a05SGarrett D'Amore statep->suspended = B_TRUE;
5385644f3c1fScg
538688447a05SGarrett D'Amore /* set widget power to D2 */
53875ec2209cSZhao Edgar Liu - Sun Microsystems audiohd_change_widget_power_state(statep, AUDIOHD_PW_D2);
538888447a05SGarrett D'Amore /* Disable h/w */
538988447a05SGarrett D'Amore audiohd_stop_dma(statep);
539072a6cf5eSGarrett D'Amore audiohd_fini_pci(statep);
539188447a05SGarrett D'Amore mutex_exit(&statep->hda_mutex);
53923a49c214SYang-Rong Jerry Zhou
539388447a05SGarrett D'Amore return (DDI_SUCCESS);
539488447a05SGarrett D'Amore } /* audiohd_suspend */
5395644f3c1fScg
539688447a05SGarrett D'Amore /*
539788447a05SGarrett D'Amore * audiohd_disable_pin()
539888447a05SGarrett D'Amore */
539968c47f65SGarrett D'Amore static void
audiohd_disable_pin(audiohd_state_t * statep,int caddr,wid_t wid)540088447a05SGarrett D'Amore audiohd_disable_pin(audiohd_state_t *statep, int caddr, wid_t wid)
540188447a05SGarrett D'Amore {
540268c47f65SGarrett D'Amore uint32_t tmp;
540368c47f65SGarrett D'Amore
540468c47f65SGarrett D'Amore tmp = audioha_codec_verb_get(statep, caddr, wid,
540568c47f65SGarrett D'Amore AUDIOHDC_VERB_GET_PIN_CTRL, 0);
540668c47f65SGarrett D'Amore if (tmp == AUDIOHD_CODEC_FAILURE)
540768c47f65SGarrett D'Amore return;
540868c47f65SGarrett D'Amore tmp = audioha_codec_verb_get(statep, caddr, wid,
540968c47f65SGarrett D'Amore AUDIOHDC_VERB_SET_PIN_CTRL,
541068c47f65SGarrett D'Amore (tmp & ~AUDIOHDC_PIN_CONTROL_OUT_ENABLE));
541188447a05SGarrett D'Amore }
5412644f3c1fScg
5413644f3c1fScg /*
541488447a05SGarrett D'Amore * audiohd_enable_pin()
5415644f3c1fScg */
541668c47f65SGarrett D'Amore static void
audiohd_enable_pin(audiohd_state_t * statep,int caddr,wid_t wid)541788447a05SGarrett D'Amore audiohd_enable_pin(audiohd_state_t *statep, int caddr, wid_t wid)
541888447a05SGarrett D'Amore {
541968c47f65SGarrett D'Amore uint32_t tmp;
542068c47f65SGarrett D'Amore
542168c47f65SGarrett D'Amore tmp = audioha_codec_verb_get(statep, caddr, wid,
542268c47f65SGarrett D'Amore AUDIOHDC_VERB_GET_PIN_CTRL, 0);
542368c47f65SGarrett D'Amore if (tmp == AUDIOHD_CODEC_FAILURE)
542468c47f65SGarrett D'Amore return;
542568c47f65SGarrett D'Amore tmp = audioha_codec_verb_get(statep, caddr, wid,
542668c47f65SGarrett D'Amore AUDIOHDC_VERB_SET_PIN_CTRL,
542768c47f65SGarrett D'Amore tmp | AUDIOHDC_PIN_CONTROL_OUT_ENABLE |
542868c47f65SGarrett D'Amore AUDIOHDC_PIN_CONTROL_HP_ENABLE);
542988447a05SGarrett D'Amore }
543068c47f65SGarrett D'Amore
543188447a05SGarrett D'Amore /*
543288447a05SGarrett D'Amore * audiohd_change_speaker_state()
543388447a05SGarrett D'Amore */
543488447a05SGarrett D'Amore static void
audiohd_change_speaker_state(audiohd_state_t * statep,int on)543588447a05SGarrett D'Amore audiohd_change_speaker_state(audiohd_state_t *statep, int on)
5436644f3c1fScg {
543788447a05SGarrett D'Amore audiohd_path_t *path;
543888447a05SGarrett D'Amore audiohd_widget_t *widget;
54393a49c214SYang-Rong Jerry Zhou audiohd_pin_t *pin;
544088447a05SGarrett D'Amore int i, j;
544188447a05SGarrett D'Amore wid_t wid;
54423a49c214SYang-Rong Jerry Zhou
544388447a05SGarrett D'Amore for (i = 0; i < statep->pathnum; i++) {
544488447a05SGarrett D'Amore path = statep->path[i];
544588447a05SGarrett D'Amore if (!path || path->path_type != PLAY)
544688447a05SGarrett D'Amore continue;
544788447a05SGarrett D'Amore if (on) {
544888447a05SGarrett D'Amore for (j = 0; j < path->pin_nums; j++) {
544988447a05SGarrett D'Amore wid = path->pin_wid[j];
545088447a05SGarrett D'Amore widget = path->codec->widget[wid];
545188447a05SGarrett D'Amore pin = (audiohd_pin_t *)widget->priv;
545288447a05SGarrett D'Amore if (pin->device == DTYPE_SPEAKER) {
545368c47f65SGarrett D'Amore audiohd_enable_pin(statep,
545488447a05SGarrett D'Amore path->codec->index,
545588447a05SGarrett D'Amore pin->wid);
54563a49c214SYang-Rong Jerry Zhou }
54573a49c214SYang-Rong Jerry Zhou }
54583a49c214SYang-Rong Jerry Zhou
54593a49c214SYang-Rong Jerry Zhou } else {
546088447a05SGarrett D'Amore for (j = 0; j < path->pin_nums; j++) {
546188447a05SGarrett D'Amore wid = path->pin_wid[j];
546288447a05SGarrett D'Amore widget = path->codec->widget[wid];
546388447a05SGarrett D'Amore pin = (audiohd_pin_t *)widget->priv;
546488447a05SGarrett D'Amore if (pin->device == DTYPE_SPEAKER) {
546568c47f65SGarrett D'Amore audiohd_disable_pin(statep,
546688447a05SGarrett D'Amore path->codec->index,
546788447a05SGarrett D'Amore pin->wid);
54683a49c214SYang-Rong Jerry Zhou }
54693a49c214SYang-Rong Jerry Zhou }
54703a49c214SYang-Rong Jerry Zhou }
54713a49c214SYang-Rong Jerry Zhou }
547288447a05SGarrett D'Amore }
5473644f3c1fScg /*
547488447a05SGarrett D'Amore * audiohd_select_mic()
54753a49c214SYang-Rong Jerry Zhou *
54763a49c214SYang-Rong Jerry Zhou * Description:
547788447a05SGarrett D'Amore * This function is used for the recording path which has a selector
547888447a05SGarrett D'Amore * as the sumwidget. We select the external MIC if it is plugged into the
547988447a05SGarrett D'Amore * MIC jack, otherwise the internal integrated MIC is selected.
5480644f3c1fScg */
548188447a05SGarrett D'Amore static void
audiohd_select_mic(audiohd_state_t * statep,uint8_t index,uint8_t id,int select)548288447a05SGarrett D'Amore audiohd_select_mic(audiohd_state_t *statep, uint8_t index,
548388447a05SGarrett D'Amore uint8_t id, int select)
5484644f3c1fScg {
54853a49c214SYang-Rong Jerry Zhou hda_codec_t *codec;
548688447a05SGarrett D'Amore audiohd_path_t *path;
5487aa5c9fd8SZhao Edgar Liu - Sun Microsystems audiohd_widget_t *widget, *sumwgt = NULL;
548888447a05SGarrett D'Amore audiohd_pin_t *pin;
548988447a05SGarrett D'Amore int i, j;
549088447a05SGarrett D'Amore wid_t wid;
54913a49c214SYang-Rong Jerry Zhou
549288447a05SGarrett D'Amore codec = statep->codec[index];
54933a49c214SYang-Rong Jerry Zhou if (codec == NULL)
549488447a05SGarrett D'Amore return;
5495aa5c9fd8SZhao Edgar Liu - Sun Microsystems
549688447a05SGarrett D'Amore for (i = 0; i < statep->pathnum; i++) {
549788447a05SGarrett D'Amore path = statep->path[i];
549888447a05SGarrett D'Amore if (path->codec != codec || path->path_type != RECORD)
549988447a05SGarrett D'Amore continue;
550088447a05SGarrett D'Amore sumwgt = codec->widget[path->sum_wid];
5501aa5c9fd8SZhao Edgar Liu - Sun Microsystems
5502aa5c9fd8SZhao Edgar Liu - Sun Microsystems for (j = 0; j < path->pin_nums; j++) {
5503aa5c9fd8SZhao Edgar Liu - Sun Microsystems wid = path->pin_wid[j];
5504aa5c9fd8SZhao Edgar Liu - Sun Microsystems widget = codec->widget[wid];
5505aa5c9fd8SZhao Edgar Liu - Sun Microsystems pin = (audiohd_pin_t *)widget->priv;
5506aa5c9fd8SZhao Edgar Liu - Sun Microsystems
5507aa5c9fd8SZhao Edgar Liu - Sun Microsystems if (pin->device != DTYPE_MIC_IN)
5508aa5c9fd8SZhao Edgar Liu - Sun Microsystems continue;
5509aa5c9fd8SZhao Edgar Liu - Sun Microsystems
5510aa5c9fd8SZhao Edgar Liu - Sun Microsystems if (sumwgt != NULL &&
5511aa5c9fd8SZhao Edgar Liu - Sun Microsystems sumwgt->type == WTYPE_AUDIO_SEL) {
5512aa5c9fd8SZhao Edgar Liu - Sun Microsystems /* Have a selector to choose input pin */
5513aa5c9fd8SZhao Edgar Liu - Sun Microsystems
5514aa5c9fd8SZhao Edgar Liu - Sun Microsystems if (select && pin->wid == id &&
551588447a05SGarrett D'Amore (((pin->config >>
551688447a05SGarrett D'Amore AUDIOHD_PIN_CONTP_OFF) &
551788447a05SGarrett D'Amore AUDIOHD_PIN_CONTP_MASK) ==
551888447a05SGarrett D'Amore AUDIOHD_PIN_CON_JACK)) {
551988447a05SGarrett D'Amore (void) audioha_codec_verb_get(
552088447a05SGarrett D'Amore statep,
552188447a05SGarrett D'Amore index,
552288447a05SGarrett D'Amore path->sum_wid,
552388447a05SGarrett D'Amore AUDIOHDC_VERB_SET_CONN_SEL,
552488447a05SGarrett D'Amore path->sum_selconn[j]);
552588447a05SGarrett D'Amore statep->port[PORT_ADC]->index =
552688447a05SGarrett D'Amore path->tag;
552788447a05SGarrett D'Amore return;
5528aa5c9fd8SZhao Edgar Liu - Sun Microsystems } else if (!select && pin->wid != id &&
552988447a05SGarrett D'Amore (((pin->config >>
553088447a05SGarrett D'Amore AUDIOHD_PIN_CONTP_OFF) &
553188447a05SGarrett D'Amore AUDIOHD_PIN_CONTP_MASK) ==
5532aa5c9fd8SZhao Edgar Liu - Sun Microsystems AUDIOHD_PIN_CON_FIXED)) {
553388447a05SGarrett D'Amore (void) audioha_codec_verb_get(
553488447a05SGarrett D'Amore statep,
553588447a05SGarrett D'Amore index,
553688447a05SGarrett D'Amore path->sum_wid,
553788447a05SGarrett D'Amore AUDIOHDC_VERB_SET_CONN_SEL,
553888447a05SGarrett D'Amore path->sum_selconn[j]);
553988447a05SGarrett D'Amore statep->port[PORT_ADC]->index =
554088447a05SGarrett D'Amore path->tag;
554188447a05SGarrett D'Amore return;
55423a49c214SYang-Rong Jerry Zhou }
5543aa5c9fd8SZhao Edgar Liu - Sun Microsystems } else {
5544aa5c9fd8SZhao Edgar Liu - Sun Microsystems /*
5545aa5c9fd8SZhao Edgar Liu - Sun Microsystems * No selector widget in the path,
5546aa5c9fd8SZhao Edgar Liu - Sun Microsystems * mute unselected input pin
5547aa5c9fd8SZhao Edgar Liu - Sun Microsystems */
5548aa5c9fd8SZhao Edgar Liu - Sun Microsystems
5549aa5c9fd8SZhao Edgar Liu - Sun Microsystems /* Open all input pin, and then mute others */
5550aa5c9fd8SZhao Edgar Liu - Sun Microsystems audiohd_set_pin_volume(statep, DTYPE_MIC_IN);
5551aa5c9fd8SZhao Edgar Liu - Sun Microsystems
5552aa5c9fd8SZhao Edgar Liu - Sun Microsystems if (select == 1) {
5553aa5c9fd8SZhao Edgar Liu - Sun Microsystems /* Select external mic, mute internal */
5554aa5c9fd8SZhao Edgar Liu - Sun Microsystems if (wid != id) {
5555aa5c9fd8SZhao Edgar Liu - Sun Microsystems (void)
5556aa5c9fd8SZhao Edgar Liu - Sun Microsystems audioha_codec_4bit_verb_get(
5557aa5c9fd8SZhao Edgar Liu - Sun Microsystems statep, path->codec->index,
5558aa5c9fd8SZhao Edgar Liu - Sun Microsystems wid,
5559aa5c9fd8SZhao Edgar Liu - Sun Microsystems AUDIOHDC_VERB_SET_AMP_MUTE,
5560aa5c9fd8SZhao Edgar Liu - Sun Microsystems path->mute_dir |
5561aa5c9fd8SZhao Edgar Liu - Sun Microsystems AUDIOHDC_AMP_SET_LNR |
5562aa5c9fd8SZhao Edgar Liu - Sun Microsystems AUDIOHDC_AMP_SET_MUTE);
5563aa5c9fd8SZhao Edgar Liu - Sun Microsystems }
5564aa5c9fd8SZhao Edgar Liu - Sun Microsystems } else {
5565aa5c9fd8SZhao Edgar Liu - Sun Microsystems /* Select internal mic, mute external */
5566aa5c9fd8SZhao Edgar Liu - Sun Microsystems if (wid == id) {
5567aa5c9fd8SZhao Edgar Liu - Sun Microsystems (void)
5568aa5c9fd8SZhao Edgar Liu - Sun Microsystems audioha_codec_4bit_verb_get(
5569aa5c9fd8SZhao Edgar Liu - Sun Microsystems statep, path->codec->index,
5570aa5c9fd8SZhao Edgar Liu - Sun Microsystems wid,
5571aa5c9fd8SZhao Edgar Liu - Sun Microsystems AUDIOHDC_VERB_SET_AMP_MUTE,
5572aa5c9fd8SZhao Edgar Liu - Sun Microsystems path->mute_dir |
5573aa5c9fd8SZhao Edgar Liu - Sun Microsystems AUDIOHDC_AMP_SET_LNR |
5574aa5c9fd8SZhao Edgar Liu - Sun Microsystems AUDIOHDC_AMP_SET_MUTE);
5575aa5c9fd8SZhao Edgar Liu - Sun Microsystems }
5576aa5c9fd8SZhao Edgar Liu - Sun Microsystems }
55773a49c214SYang-Rong Jerry Zhou }
5578644f3c1fScg }
5579644f3c1fScg }
5580aa5c9fd8SZhao Edgar Liu - Sun Microsystems
55813a49c214SYang-Rong Jerry Zhou /*
558288447a05SGarrett D'Amore * If the input istream > 1, we should set the record stream tag
558388447a05SGarrett D'Amore * respectively. All the input streams sharing one tag may make the
558488447a05SGarrett D'Amore * record sound distorted.
55853a49c214SYang-Rong Jerry Zhou */
558688447a05SGarrett D'Amore if (codec->nistream > 1) {
558788447a05SGarrett D'Amore for (i = 0; i < statep->pathnum; i++) {
558888447a05SGarrett D'Amore path = statep->path[i];
558988447a05SGarrett D'Amore if (!path || path->path_type != RECORD)
559088447a05SGarrett D'Amore continue;
559188447a05SGarrett D'Amore for (j = 0; j < path->pin_nums; j++) {
559288447a05SGarrett D'Amore wid = path->pin_wid[j];
559388447a05SGarrett D'Amore widget = codec->widget[wid];
559488447a05SGarrett D'Amore if (widget == NULL)
559588447a05SGarrett D'Amore return;
559688447a05SGarrett D'Amore pin = (audiohd_pin_t *)widget->priv;
559788447a05SGarrett D'Amore if (select &&
559888447a05SGarrett D'Amore pin->device == DTYPE_MIC_IN &&
559988447a05SGarrett D'Amore pin->wid == id &&
560088447a05SGarrett D'Amore (((pin->config >>
560188447a05SGarrett D'Amore AUDIOHD_PIN_CONTP_OFF) &
560288447a05SGarrett D'Amore AUDIOHD_PIN_CONTP_MASK) ==
560388447a05SGarrett D'Amore AUDIOHD_PIN_CON_JACK)) {
560488447a05SGarrett D'Amore statep->port[PORT_ADC]->index =
560588447a05SGarrett D'Amore path->tag;
560688447a05SGarrett D'Amore return;
560788447a05SGarrett D'Amore } else if (!select &&
560888447a05SGarrett D'Amore pin->device == DTYPE_MIC_IN &&
560988447a05SGarrett D'Amore (((pin->config >>
561088447a05SGarrett D'Amore AUDIOHD_PIN_CONTP_OFF) &
561188447a05SGarrett D'Amore AUDIOHD_PIN_CONTP_MASK) ==
561288447a05SGarrett D'Amore AUDIOHD_PIN_CON_FIXED)) {
561388447a05SGarrett D'Amore statep->port[PORT_ADC]->index =
561488447a05SGarrett D'Amore path->tag;
561588447a05SGarrett D'Amore return;
56163a49c214SYang-Rong Jerry Zhou }
56173a49c214SYang-Rong Jerry Zhou }
56183a49c214SYang-Rong Jerry Zhou }
5619644f3c1fScg }
562088447a05SGarrett D'Amore }
5621644f3c1fScg /*
562288447a05SGarrett D'Amore * audiohd_pin_sense()
5623644f3c1fScg *
562488447a05SGarrett D'Amore * Description
562588447a05SGarrett D'Amore *
562688447a05SGarrett D'Amore * When the earphone is plugged into the jack associtated with the pin
562788447a05SGarrett D'Amore * complex, we disable the built in speaker. When the earphone is plugged
562888447a05SGarrett D'Amore * out of the jack, we enable the built in speaker.
5629644f3c1fScg */
5630644f3c1fScg static void
audiohd_pin_sense(audiohd_state_t * statep,uint32_t resp,uint32_t respex)563188447a05SGarrett D'Amore audiohd_pin_sense(audiohd_state_t *statep, uint32_t resp, uint32_t respex)
5632644f3c1fScg {
563388447a05SGarrett D'Amore uint8_t index;
563488447a05SGarrett D'Amore uint8_t id;
563588447a05SGarrett D'Amore uint32_t rs;
563688447a05SGarrett D'Amore audiohd_widget_t *widget;
563788447a05SGarrett D'Amore audiohd_pin_t *pin;
56383a49c214SYang-Rong Jerry Zhou hda_codec_t *codec;
5639644f3c1fScg
564088447a05SGarrett D'Amore index = respex & AUDIOHD_RIRB_CODEC_MASK;
564188447a05SGarrett D'Amore id = resp >> (AUDIOHD_RIRB_WID_OFF - 1);
564288447a05SGarrett D'Amore
564388447a05SGarrett D'Amore codec = statep->codec[index];
564488447a05SGarrett D'Amore if (codec == NULL)
564588447a05SGarrett D'Amore return;
564688447a05SGarrett D'Amore widget = codec->widget[id];
564788447a05SGarrett D'Amore if (widget == NULL)
564888447a05SGarrett D'Amore return;
564988447a05SGarrett D'Amore
565088447a05SGarrett D'Amore rs = audioha_codec_verb_get(statep, index, id,
565188447a05SGarrett D'Amore AUDIOHDC_VERB_GET_PIN_SENSE, 0);
5652989b958fSZhao Edgar Liu - Sun Microsystems if (rs & AUDIOHD_PIN_PRES_MASK) {
565388447a05SGarrett D'Amore /* A MIC is plugged in, we select the MIC as input */
565488447a05SGarrett D'Amore if ((widget->type == WTYPE_PIN) &&
565588447a05SGarrett D'Amore (pin = (audiohd_pin_t *)widget->priv) &&
565688447a05SGarrett D'Amore (pin->device == DTYPE_MIC_IN)) {
565788447a05SGarrett D'Amore audiohd_select_mic(statep, index, id, 1);
565888447a05SGarrett D'Amore return;
565988447a05SGarrett D'Amore }
566088447a05SGarrett D'Amore /* output pin is plugged */
566188447a05SGarrett D'Amore audiohd_change_speaker_state(statep, AUDIOHD_SP_OFF);
566288447a05SGarrett D'Amore } else {
566388447a05SGarrett D'Amore /*
566488447a05SGarrett D'Amore * A MIC is unplugged, we select the built in MIC
566588447a05SGarrett D'Amore * as input.
566688447a05SGarrett D'Amore */
566788447a05SGarrett D'Amore if ((widget->type == WTYPE_PIN) &&
566888447a05SGarrett D'Amore (pin = (audiohd_pin_t *)widget->priv) &&
566988447a05SGarrett D'Amore (pin->device == DTYPE_MIC_IN)) {
567088447a05SGarrett D'Amore audiohd_select_mic(statep, index, id, 0);
567188447a05SGarrett D'Amore return;
56723a49c214SYang-Rong Jerry Zhou }
567388447a05SGarrett D'Amore /* output pin is unplugged */
567488447a05SGarrett D'Amore audiohd_change_speaker_state(statep, AUDIOHD_SP_ON);
56753a49c214SYang-Rong Jerry Zhou }
5676644f3c1fScg
567788447a05SGarrett D'Amore }
567888447a05SGarrett D'Amore
5679644f3c1fScg /*
568088447a05SGarrett D'Amore * audiohd_disable_intr()
56813a49c214SYang-Rong Jerry Zhou *
56823a49c214SYang-Rong Jerry Zhou * Description:
568388447a05SGarrett D'Amore * Disable all possible interrupts.
5684644f3c1fScg */
568588447a05SGarrett D'Amore static void
audiohd_disable_intr(audiohd_state_t * statep)568688447a05SGarrett D'Amore audiohd_disable_intr(audiohd_state_t *statep)
5687644f3c1fScg {
568888447a05SGarrett D'Amore int i;
568988447a05SGarrett D'Amore uint32_t base;
5690644f3c1fScg
569188447a05SGarrett D'Amore AUDIOHD_REG_SET32(AUDIOHD_REG_INTCTL, 0);
569288447a05SGarrett D'Amore base = AUDIOHD_REG_SD_BASE;
569388447a05SGarrett D'Amore for (i = 0; i < statep->hda_streams_nums; i++) {
569488447a05SGarrett D'Amore AUDIOHD_REG_SET8(base + AUDIOHD_SDREG_OFFSET_STS,
569588447a05SGarrett D'Amore AUDIOHDR_SD_STS_INTRS);
569688447a05SGarrett D'Amore base += AUDIOHD_REG_SD_LEN;
56973a49c214SYang-Rong Jerry Zhou }
569888447a05SGarrett D'Amore AUDIOHD_REG_SET32(AUDIOHD_REG_INTSTS, (uint32_t)(-1));
5699644f3c1fScg
570088447a05SGarrett D'Amore } /* audiohd_disable_intr() */
5701644f3c1fScg
5702644f3c1fScg
57033a49c214SYang-Rong Jerry Zhou /*
57043a49c214SYang-Rong Jerry Zhou * audiohd_12bit_verb_to_codec()
57053a49c214SYang-Rong Jerry Zhou *
57063a49c214SYang-Rong Jerry Zhou * Description:
57073a49c214SYang-Rong Jerry Zhou *
57083a49c214SYang-Rong Jerry Zhou */
57093a49c214SYang-Rong Jerry Zhou static int
audiohd_12bit_verb_to_codec(audiohd_state_t * statep,uint8_t caddr,uint8_t wid,uint16_t cmd,uint8_t param)57103a49c214SYang-Rong Jerry Zhou audiohd_12bit_verb_to_codec(audiohd_state_t *statep, uint8_t caddr,
57113a49c214SYang-Rong Jerry Zhou uint8_t wid,
57123a49c214SYang-Rong Jerry Zhou uint16_t cmd, uint8_t param)
57133a49c214SYang-Rong Jerry Zhou {
57143a49c214SYang-Rong Jerry Zhou uint32_t verb;
57153a49c214SYang-Rong Jerry Zhou uint16_t wptr;
57163a49c214SYang-Rong Jerry Zhou uint16_t rptr;
5717644f3c1fScg
57183a49c214SYang-Rong Jerry Zhou ASSERT((cmd & AUDIOHDC_12BIT_VERB_MASK) == 0);
5719644f3c1fScg
57203a49c214SYang-Rong Jerry Zhou wptr = AUDIOHD_REG_GET16(AUDIOHD_REG_CORBWP) & AUDIOHD_CMDIO_ENT_MASK;
57213a49c214SYang-Rong Jerry Zhou rptr = AUDIOHD_REG_GET16(AUDIOHD_REG_CORBRP) & AUDIOHD_CMDIO_ENT_MASK;
5722644f3c1fScg
57233a49c214SYang-Rong Jerry Zhou wptr++;
57243a49c214SYang-Rong Jerry Zhou wptr &= AUDIOHD_CMDIO_ENT_MASK;
5725644f3c1fScg
57263a49c214SYang-Rong Jerry Zhou /* overflow */
57273a49c214SYang-Rong Jerry Zhou if (wptr == rptr) {
5728c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
57293a49c214SYang-Rong Jerry Zhou }
5730644f3c1fScg
57313a49c214SYang-Rong Jerry Zhou verb = (caddr & 0x0f) << AUDIOHD_VERB_ADDR_OFF;
57323a49c214SYang-Rong Jerry Zhou verb |= wid << AUDIOHD_VERB_NID_OFF;
57333a49c214SYang-Rong Jerry Zhou verb |= cmd << AUDIOHD_VERB_CMD_OFF;
57343a49c214SYang-Rong Jerry Zhou verb |= param;
5735644f3c1fScg
57363a49c214SYang-Rong Jerry Zhou *((uint32_t *)(statep->hda_dma_corb.ad_vaddr) + wptr) = verb;
57373a49c214SYang-Rong Jerry Zhou (void) ddi_dma_sync(statep->hda_dma_corb.ad_dmahdl, 0,
57383a49c214SYang-Rong Jerry Zhou sizeof (sd_bdle_t) * AUDIOHD_BDLE_NUMS, DDI_DMA_SYNC_FORDEV);
57393a49c214SYang-Rong Jerry Zhou AUDIOHD_REG_SET16(AUDIOHD_REG_CORBWP, wptr);
5740644f3c1fScg
5741c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
57423a49c214SYang-Rong Jerry Zhou
57433a49c214SYang-Rong Jerry Zhou } /* audiohd_12bit_verb_to_codec() */
5744644f3c1fScg
5745644f3c1fScg /*
57463a49c214SYang-Rong Jerry Zhou * audiohd_4bit_verb_to_codec()
57473a49c214SYang-Rong Jerry Zhou *
57483a49c214SYang-Rong Jerry Zhou * Description:
57493a49c214SYang-Rong Jerry Zhou *
5750644f3c1fScg */
5751644f3c1fScg static int
audiohd_4bit_verb_to_codec(audiohd_state_t * statep,uint8_t caddr,uint8_t wid,uint32_t cmd,uint16_t param)57523a49c214SYang-Rong Jerry Zhou audiohd_4bit_verb_to_codec(audiohd_state_t *statep, uint8_t caddr,
57533a49c214SYang-Rong Jerry Zhou uint8_t wid,
57543a49c214SYang-Rong Jerry Zhou uint32_t cmd, uint16_t param)
5755644f3c1fScg {
57563a49c214SYang-Rong Jerry Zhou uint32_t verb;
57573a49c214SYang-Rong Jerry Zhou uint16_t wptr;
57583a49c214SYang-Rong Jerry Zhou uint16_t rptr;
5759644f3c1fScg
57603a49c214SYang-Rong Jerry Zhou ASSERT((cmd & AUDIOHDC_4BIT_VERB_MASK) == 0);
5761644f3c1fScg
57623a49c214SYang-Rong Jerry Zhou wptr = AUDIOHD_REG_GET16(AUDIOHD_REG_CORBWP) & AUDIOHD_CMDIO_ENT_MASK;
57633a49c214SYang-Rong Jerry Zhou rptr = AUDIOHD_REG_GET16(AUDIOHD_REG_CORBRP) & AUDIOHD_CMDIO_ENT_MASK;
5764644f3c1fScg
57653a49c214SYang-Rong Jerry Zhou wptr++;
57663a49c214SYang-Rong Jerry Zhou wptr &= AUDIOHD_CMDIO_ENT_MASK;
5767644f3c1fScg
57683a49c214SYang-Rong Jerry Zhou /* overflow */
57693a49c214SYang-Rong Jerry Zhou if (wptr == rptr) {
5770c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
5771644f3c1fScg }
5772644f3c1fScg
57733a49c214SYang-Rong Jerry Zhou verb = (caddr & 0x0f) << AUDIOHD_VERB_ADDR_OFF;
57743a49c214SYang-Rong Jerry Zhou verb |= wid << AUDIOHD_VERB_NID_OFF;
57753a49c214SYang-Rong Jerry Zhou verb |= cmd << AUDIOHD_VERB_CMD16_OFF;
57763a49c214SYang-Rong Jerry Zhou verb |= param;
57773a49c214SYang-Rong Jerry Zhou
57783a49c214SYang-Rong Jerry Zhou *((uint32_t *)(statep->hda_dma_corb.ad_vaddr) + wptr) = verb;
57793a49c214SYang-Rong Jerry Zhou AUDIOHD_REG_SET16(AUDIOHD_REG_CORBWP, wptr);
57803a49c214SYang-Rong Jerry Zhou
5781c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
5782644f3c1fScg
57833a49c214SYang-Rong Jerry Zhou } /* audiohd_4bit_verb_to_codec() */
5784644f3c1fScg
5785644f3c1fScg /*
57863a49c214SYang-Rong Jerry Zhou * audiohd_response_from_codec()
57873a49c214SYang-Rong Jerry Zhou *
57883a49c214SYang-Rong Jerry Zhou * Description:
57893a49c214SYang-Rong Jerry Zhou *
5790644f3c1fScg */
5791644f3c1fScg static int
audiohd_response_from_codec(audiohd_state_t * statep,uint32_t * resp,uint32_t * respex)57923a49c214SYang-Rong Jerry Zhou audiohd_response_from_codec(audiohd_state_t *statep, uint32_t *resp,
57933a49c214SYang-Rong Jerry Zhou uint32_t *respex)
5794644f3c1fScg {
57953a49c214SYang-Rong Jerry Zhou uint16_t wptr;
57963a49c214SYang-Rong Jerry Zhou uint16_t rptr;
57973a49c214SYang-Rong Jerry Zhou uint32_t *lp;
5798644f3c1fScg
57993a49c214SYang-Rong Jerry Zhou wptr = AUDIOHD_REG_GET16(AUDIOHD_REG_RIRBWP) & 0x00ff;
58003a49c214SYang-Rong Jerry Zhou rptr = statep->hda_rirb_rp;
5801644f3c1fScg
58023a49c214SYang-Rong Jerry Zhou if (rptr == wptr) {
5803c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
5804644f3c1fScg }
5805644f3c1fScg
58063a49c214SYang-Rong Jerry Zhou rptr++;
58073a49c214SYang-Rong Jerry Zhou rptr &= AUDIOHD_RING_MAX_SIZE;
5808644f3c1fScg
58093a49c214SYang-Rong Jerry Zhou lp = (uint32_t *)(statep->hda_dma_rirb.ad_vaddr) + (rptr << 1);
58103a49c214SYang-Rong Jerry Zhou *resp = *(lp);
58113a49c214SYang-Rong Jerry Zhou *respex = *(lp + 1);
5812644f3c1fScg
58133a49c214SYang-Rong Jerry Zhou statep->hda_rirb_rp = rptr;
5814644f3c1fScg
5815c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
5816644f3c1fScg
58173a49c214SYang-Rong Jerry Zhou } /* audiohd_response_from_codec() */
58183a49c214SYang-Rong Jerry Zhou
5819644f3c1fScg
5820644f3c1fScg /*
58213a49c214SYang-Rong Jerry Zhou * audioha_codec_verb_get()
5822644f3c1fScg */
58233a49c214SYang-Rong Jerry Zhou static uint32_t
audioha_codec_verb_get(void * arg,uint8_t caddr,uint8_t wid,uint16_t verb,uint8_t param)58243a49c214SYang-Rong Jerry Zhou audioha_codec_verb_get(void *arg, uint8_t caddr, uint8_t wid,
58253a49c214SYang-Rong Jerry Zhou uint16_t verb,
58263a49c214SYang-Rong Jerry Zhou uint8_t param)
5827644f3c1fScg {
58283a49c214SYang-Rong Jerry Zhou audiohd_state_t *statep = (audiohd_state_t *)arg;
58293a49c214SYang-Rong Jerry Zhou uint32_t resp;
58303a49c214SYang-Rong Jerry Zhou uint32_t respex;
58313a49c214SYang-Rong Jerry Zhou int ret;
58323a49c214SYang-Rong Jerry Zhou int i;
5833644f3c1fScg
58343a49c214SYang-Rong Jerry Zhou ret = audiohd_12bit_verb_to_codec(statep, caddr, wid, verb, param);
5835c6e681c0SYang-Rong Jerry Zhou if (ret != DDI_SUCCESS) {
58363a49c214SYang-Rong Jerry Zhou return (uint32_t)(-1);
58373a49c214SYang-Rong Jerry Zhou }
58383a49c214SYang-Rong Jerry Zhou
58393a49c214SYang-Rong Jerry Zhou /*
58403a49c214SYang-Rong Jerry Zhou * Empirical testing times. 50 times is enough for audiohd spec 1.0.
58413a49c214SYang-Rong Jerry Zhou * But we need to make it work for audiohd spec 0.9, which is just a
58423a49c214SYang-Rong Jerry Zhou * draft version and requires more time to wait.
58433a49c214SYang-Rong Jerry Zhou */
58443a49c214SYang-Rong Jerry Zhou for (i = 0; i < 500; i++) {
58453a49c214SYang-Rong Jerry Zhou ret = audiohd_response_from_codec(statep, &resp, &respex);
58463a49c214SYang-Rong Jerry Zhou if (((respex & AUDIOHD_BDLE_RIRB_SDI) == caddr) &&
58473a49c214SYang-Rong Jerry Zhou ((respex & AUDIOHD_BDLE_RIRB_UNSOLICIT) == 0) &&
5848c6e681c0SYang-Rong Jerry Zhou (ret == DDI_SUCCESS))
58493a49c214SYang-Rong Jerry Zhou break;
585013084339SYang-Rong Jerry Zhou /* Empirical testing time, which works well */
585113084339SYang-Rong Jerry Zhou drv_usecwait(30);
58523a49c214SYang-Rong Jerry Zhou }
5853644f3c1fScg
5854c6e681c0SYang-Rong Jerry Zhou if (ret == DDI_SUCCESS) {
58553a49c214SYang-Rong Jerry Zhou return (resp);
5856644f3c1fScg }
5857644f3c1fScg
58580c240c64SZhao Edgar Liu - Sun Microsystems if (wid != AUDIOHDC_NODE_ROOT && param != AUDIOHDC_PAR_VENDOR_ID) {
58590c240c64SZhao Edgar Liu - Sun Microsystems audio_dev_warn(statep->adev, "timeout when get "
58600c240c64SZhao Edgar Liu - Sun Microsystems "response from codec: wid=%d, verb=0x%04x, param=0x%04x",
58610c240c64SZhao Edgar Liu - Sun Microsystems wid, verb, param);
58620c240c64SZhao Edgar Liu - Sun Microsystems }
5863644f3c1fScg
58643a49c214SYang-Rong Jerry Zhou return ((uint32_t)(-1));
5865644f3c1fScg
58663a49c214SYang-Rong Jerry Zhou } /* audioha_codec_verb_get() */
5867644f3c1fScg
5868644f3c1fScg
5869644f3c1fScg /*
58703a49c214SYang-Rong Jerry Zhou * audioha_codec_4bit_verb_get()
5871644f3c1fScg */
58723a49c214SYang-Rong Jerry Zhou static uint32_t
audioha_codec_4bit_verb_get(void * arg,uint8_t caddr,uint8_t wid,uint16_t verb,uint16_t param)58733a49c214SYang-Rong Jerry Zhou audioha_codec_4bit_verb_get(void *arg, uint8_t caddr, uint8_t wid,
58743a49c214SYang-Rong Jerry Zhou uint16_t verb, uint16_t param)
5875644f3c1fScg {
58763a49c214SYang-Rong Jerry Zhou audiohd_state_t *statep = (audiohd_state_t *)arg;
58773a49c214SYang-Rong Jerry Zhou uint32_t resp;
58783a49c214SYang-Rong Jerry Zhou uint32_t respex;
58793a49c214SYang-Rong Jerry Zhou int ret;
58803a49c214SYang-Rong Jerry Zhou int i;
5881644f3c1fScg
58823a49c214SYang-Rong Jerry Zhou ret = audiohd_4bit_verb_to_codec(statep, caddr, wid, verb, param);
5883c6e681c0SYang-Rong Jerry Zhou if (ret != DDI_SUCCESS) {
58843a49c214SYang-Rong Jerry Zhou return (uint32_t)(-1);
58853a49c214SYang-Rong Jerry Zhou }
5886644f3c1fScg
58873a49c214SYang-Rong Jerry Zhou for (i = 0; i < 500; i++) {
58883a49c214SYang-Rong Jerry Zhou ret = audiohd_response_from_codec(statep, &resp, &respex);
58893a49c214SYang-Rong Jerry Zhou if (((respex & AUDIOHD_BDLE_RIRB_SDI) == caddr) &&
58903a49c214SYang-Rong Jerry Zhou ((respex & AUDIOHD_BDLE_RIRB_UNSOLICIT) == 0) &&
5891c6e681c0SYang-Rong Jerry Zhou (ret == DDI_SUCCESS))
58923a49c214SYang-Rong Jerry Zhou break;
589313084339SYang-Rong Jerry Zhou /* Empirical testing time, which works well */
589413084339SYang-Rong Jerry Zhou drv_usecwait(30);
58953a49c214SYang-Rong Jerry Zhou }
5896644f3c1fScg
5897c6e681c0SYang-Rong Jerry Zhou if (ret == DDI_SUCCESS) {
58983a49c214SYang-Rong Jerry Zhou return (resp);
58993a49c214SYang-Rong Jerry Zhou }
5900644f3c1fScg
590188447a05SGarrett D'Amore audio_dev_warn(statep->adev, "timeout when get "
59020c240c64SZhao Edgar Liu - Sun Microsystems "response from codec: wid=%d, verb=0x%04x, param=0x%04x",
590388447a05SGarrett D'Amore wid, verb, param);
5904644f3c1fScg
59053a49c214SYang-Rong Jerry Zhou return ((uint32_t)(-1));
5906644f3c1fScg
59073a49c214SYang-Rong Jerry Zhou } /* audioha_codec_4bit_verb_get() */
5908