188447a05SGarrett D'Amore /*
288447a05SGarrett D'Amore * CDDL HEADER START
388447a05SGarrett D'Amore *
488447a05SGarrett D'Amore * The contents of this file are subject to the terms of the
588447a05SGarrett D'Amore * Common Development and Distribution License (the "License").
688447a05SGarrett D'Amore * You may not use this file except in compliance with the License.
788447a05SGarrett D'Amore *
888447a05SGarrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
988447a05SGarrett D'Amore * or http://www.opensolaris.org/os/licensing.
1088447a05SGarrett D'Amore * See the License for the specific language governing permissions
1188447a05SGarrett D'Amore * and limitations under the License.
1288447a05SGarrett D'Amore *
1388447a05SGarrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
1488447a05SGarrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1588447a05SGarrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
1688447a05SGarrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
1788447a05SGarrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
1888447a05SGarrett D'Amore *
1988447a05SGarrett D'Amore * CDDL HEADER END
2088447a05SGarrett D'Amore */
2188447a05SGarrett D'Amore /*
222c30fa45SGarrett D'Amore * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
2388447a05SGarrett D'Amore */
2488447a05SGarrett D'Amore
2588447a05SGarrett D'Amore #include <sys/audio/audio_driver.h>
2688447a05SGarrett D'Amore #include <sys/note.h>
2742c41cf8Slipeng sang - Sun Microsystems - Beijing China #include <sys/beep.h>
2888447a05SGarrett D'Amore #include <sys/pci.h>
2988447a05SGarrett D'Amore #include "audiohd.h"
3088447a05SGarrett D'Amore
3188447a05SGarrett D'Amore #define DRVNAME "audiohd"
3268c47f65SGarrett D'Amore
3388447a05SGarrett D'Amore /*
3488447a05SGarrett D'Amore * Module linkage routines for the kernel
3588447a05SGarrett D'Amore */
3688447a05SGarrett D'Amore static int audiohd_attach(dev_info_t *, ddi_attach_cmd_t);
3788447a05SGarrett D'Amore static int audiohd_detach(dev_info_t *, ddi_detach_cmd_t);
3888447a05SGarrett D'Amore static int audiohd_quiesce(dev_info_t *);
3988447a05SGarrett D'Amore static int audiohd_resume(audiohd_state_t *);
4088447a05SGarrett D'Amore static int audiohd_suspend(audiohd_state_t *);
4188447a05SGarrett D'Amore
4288447a05SGarrett D'Amore /*
4388447a05SGarrett D'Amore * Local routines
4488447a05SGarrett D'Amore */
4588447a05SGarrett D'Amore static int audiohd_init_state(audiohd_state_t *, dev_info_t *);
4688447a05SGarrett D'Amore static int audiohd_init_pci(audiohd_state_t *, ddi_device_acc_attr_t *);
4788447a05SGarrett D'Amore static void audiohd_fini_pci(audiohd_state_t *);
4888447a05SGarrett D'Amore static int audiohd_reset_controller(audiohd_state_t *);
4988447a05SGarrett D'Amore static int audiohd_init_controller(audiohd_state_t *);
5088447a05SGarrett D'Amore static void audiohd_fini_controller(audiohd_state_t *);
5188447a05SGarrett D'Amore static void audiohd_stop_dma(audiohd_state_t *);
5288447a05SGarrett D'Amore static void audiohd_disable_intr(audiohd_state_t *);
5388447a05SGarrett D'Amore static int audiohd_create_codec(audiohd_state_t *);
5488447a05SGarrett D'Amore static void audiohd_build_path(audiohd_state_t *);
5588447a05SGarrett D'Amore static void audiohd_destroy_codec(audiohd_state_t *);
5688447a05SGarrett D'Amore static int audiohd_alloc_dma_mem(audiohd_state_t *, audiohd_dma_t *,
5788447a05SGarrett D'Amore size_t, ddi_dma_attr_t *, uint_t);
585ec2209cSZhao Edgar Liu - Sun Microsystems static void audiohd_finish_output_path(hda_codec_t *);
5988447a05SGarrett D'Amore static uint32_t audioha_codec_verb_get(void *, uint8_t,
6088447a05SGarrett D'Amore uint8_t, uint16_t, uint8_t);
6188447a05SGarrett D'Amore static uint32_t audioha_codec_4bit_verb_get(void *, uint8_t,
6288447a05SGarrett D'Amore uint8_t, uint16_t, uint16_t);
6388447a05SGarrett D'Amore 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;
9288447a05SGarrett D'Amore
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
9888447a05SGarrett D'Amore static ddi_device_acc_attr_t hda_dev_accattr = {
9988447a05SGarrett D'Amore DDI_DEVICE_ATTR_V0,
10088447a05SGarrett D'Amore DDI_STRUCTURE_LE_ACC,
10188447a05SGarrett D'Amore DDI_STRICTORDER_ACC
10288447a05SGarrett D'Amore };
10388447a05SGarrett D'Amore
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,
12288447a05SGarrett D'Amore NULL,
12388447a05SGarrett D'Amore };
12488447a05SGarrett D'Amore
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)
20388447a05SGarrett D'Amore {
20488447a05SGarrett D'Amore uint32_t devid;
20588447a05SGarrett D'Amore const char *name;
20688447a05SGarrett D'Amore const char *vers;
20788447a05SGarrett D'Amore
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;
21288447a05SGarrett D'Amore
21388447a05SGarrett D'Amore name = AUDIOHD_DEV_CONFIG;
21488447a05SGarrett D'Amore vers = AUDIOHD_DEV_VERSION;
21588447a05SGarrett D'Amore
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";
27288447a05SGarrett D'Amore 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;
29788447a05SGarrett D'Amore }
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 }
30288447a05SGarrett D'Amore
30388447a05SGarrett D'Amore static int
audiohd_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)30488447a05SGarrett D'Amore audiohd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
30588447a05SGarrett D'Amore {
30688447a05SGarrett D'Amore audiohd_state_t *statep;
30788447a05SGarrett D'Amore int instance;
30888447a05SGarrett D'Amore
30988447a05SGarrett D'Amore instance = ddi_get_instance(dip);
31088447a05SGarrett D'Amore switch (cmd) {
31188447a05SGarrett D'Amore case DDI_ATTACH:
31288447a05SGarrett D'Amore break;
31388447a05SGarrett D'Amore
31488447a05SGarrett D'Amore case DDI_RESUME:
31588447a05SGarrett D'Amore statep = ddi_get_driver_private(dip);
31688447a05SGarrett D'Amore ASSERT(statep != NULL);
31788447a05SGarrett D'Amore return (audiohd_resume(statep));
31888447a05SGarrett D'Amore
31988447a05SGarrett D'Amore default:
32088447a05SGarrett D'Amore return (DDI_FAILURE);
32188447a05SGarrett D'Amore }
32288447a05SGarrett D'Amore
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);
32688447a05SGarrett D'Amore
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
33088447a05SGarrett D'Amore /* 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;
33488447a05SGarrett D'Amore }
33588447a05SGarrett D'Amore
33688447a05SGarrett D'Amore /* 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;
34188447a05SGarrett D'Amore }
34288447a05SGarrett D'Amore
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;
34988447a05SGarrett D'Amore }
35088447a05SGarrett D'Amore
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;
35588447a05SGarrett D'Amore }
35688447a05SGarrett D'Amore
35788447a05SGarrett D'Amore audiohd_build_path(statep);
35888447a05SGarrett D'Amore
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;
36388447a05SGarrett D'Amore }
36488447a05SGarrett D'Amore audiohd_init_path(statep);
36588447a05SGarrett D'Amore /* set up kernel statistics */
36688447a05SGarrett D'Amore if ((statep->hda_ksp = kstat_create(DRVNAME, instance,
36788447a05SGarrett D'Amore DRVNAME, "controller", KSTAT_TYPE_INTR, 1,
36888447a05SGarrett D'Amore KSTAT_FLAG_PERSISTENT)) != NULL) {
36988447a05SGarrett D'Amore kstat_install(statep->hda_ksp);
37088447a05SGarrett D'Amore }
37188447a05SGarrett D'Amore
37288447a05SGarrett D'Amore /* disable interrupts and clear interrupt status */
37388447a05SGarrett D'Amore audiohd_disable_intr(statep);
37488447a05SGarrett D'Amore
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 }
38588447a05SGarrett D'Amore ddi_report_dev(dip);
38688447a05SGarrett D'Amore
387ea463888SZhao Edgar Liu - Sun Microsystems mutex_exit(&statep->hda_mutex);
38888447a05SGarrett D'Amore 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);
39288447a05SGarrett D'Amore return (DDI_FAILURE);
39388447a05SGarrett D'Amore }
39488447a05SGarrett D'Amore
39588447a05SGarrett D'Amore static int
audiohd_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)39688447a05SGarrett D'Amore audiohd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
39788447a05SGarrett D'Amore {
39888447a05SGarrett D'Amore audiohd_state_t *statep;
39988447a05SGarrett D'Amore
40088447a05SGarrett D'Amore statep = ddi_get_driver_private(dip);
40188447a05SGarrett D'Amore ASSERT(statep != NULL);
40288447a05SGarrett D'Amore
40388447a05SGarrett D'Amore switch (cmd) {
40488447a05SGarrett D'Amore case DDI_DETACH:
40588447a05SGarrett D'Amore break;
40688447a05SGarrett D'Amore
40788447a05SGarrett D'Amore case DDI_SUSPEND:
40888447a05SGarrett D'Amore return (audiohd_suspend(statep));
40988447a05SGarrett D'Amore
41088447a05SGarrett D'Amore default:
41188447a05SGarrett D'Amore return (DDI_FAILURE);
41288447a05SGarrett D'Amore }
41388447a05SGarrett D'Amore if (audio_dev_unregister(statep->adev) != DDI_SUCCESS)
41488447a05SGarrett D'Amore return (DDI_FAILURE);
41588447a05SGarrett D'Amore
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);
41988447a05SGarrett D'Amore 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 }
45988447a05SGarrett D'Amore
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 }
47688447a05SGarrett D'Amore
47788447a05SGarrett D'Amore /*
47888447a05SGarrett D'Amore * Audio routines
47988447a05SGarrett D'Amore */
48088447a05SGarrett D'Amore
48188447a05SGarrett D'Amore static int
audiohd_engine_format(void * arg)48288447a05SGarrett D'Amore audiohd_engine_format(void *arg)
48388447a05SGarrett D'Amore {
484a33ad26eSZhao Edgar Liu - Sun Microsystems audiohd_port_t *port = arg;
485a33ad26eSZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = port->statep;
48688447a05SGarrett D'Amore
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:
49288447a05SGarrett D'Amore return (AUDIO_FORMAT_S16_LE);
49388447a05SGarrett D'Amore }
494a33ad26eSZhao Edgar Liu - Sun Microsystems }
49588447a05SGarrett D'Amore
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;
50088447a05SGarrett D'Amore
50188447a05SGarrett D'Amore return (port->nchan);
50288447a05SGarrett D'Amore }
50388447a05SGarrett D'Amore
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);
51188447a05SGarrett D'Amore }
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;
51788447a05SGarrett D'Amore
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 }
54488447a05SGarrett D'Amore /*
54588447a05SGarrett D'Amore * get the max channels the hardware supported
54688447a05SGarrett D'Amore */
54788447a05SGarrett D'Amore static void
audiohd_get_channels(audiohd_state_t * statep)54888447a05SGarrett D'Amore audiohd_get_channels(audiohd_state_t *statep)
54988447a05SGarrett D'Amore {
55088447a05SGarrett D'Amore int i;
55188447a05SGarrett D'Amore uint8_t maxp, assoc;
55288447a05SGarrett D'Amore
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;
55888447a05SGarrett D'Amore }
55988447a05SGarrett D'Amore }
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;
56488447a05SGarrett D'Amore }
56588447a05SGarrett D'Amore static void
audiohd_init_play_path(audiohd_path_t * path)56688447a05SGarrett D'Amore audiohd_init_play_path(audiohd_path_t *path)
56788447a05SGarrett D'Amore {
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;
60965a41de7SYang-Rong Jerry Zhou }
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);
66888447a05SGarrett D'Amore }
66988447a05SGarrett D'Amore }
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;
67988447a05SGarrett D'Amore
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
73488447a05SGarrett D'Amore 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) {
74588447a05SGarrett D'Amore case PLAY:
74688447a05SGarrett D'Amore audiohd_init_play_path(path);
74788447a05SGarrett D'Amore break;
74888447a05SGarrett D'Amore case RECORD:
74988447a05SGarrett D'Amore audiohd_init_record_path(path);
75088447a05SGarrett D'Amore break;
75188447a05SGarrett D'Amore default:
75288447a05SGarrett 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)
76088447a05SGarrett D'Amore {
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 }
81888447a05SGarrett D'Amore
81988447a05SGarrett D'Amore AUDIOHD_REG_SET32(regbase + AUDIOHD_SDREG_OFFSET_BDLPL,
82088447a05SGarrett D'Amore (uint32_t)port->bdl_paddr);
82188447a05SGarrett D'Amore AUDIOHD_REG_SET32(regbase + AUDIOHD_SDREG_OFFSET_BDLPU,
82288447a05SGarrett D'Amore (uint32_t)(port->bdl_paddr >> 32));
82388447a05SGarrett D'Amore AUDIOHD_REG_SET16(regbase + AUDIOHD_SDREG_OFFSET_LVI,
82488447a05SGarrett D'Amore AUDIOHD_BDLE_NUMS - 1);
82568c47f65SGarrett D'Amore AUDIOHD_REG_SET32(regbase + AUDIOHD_SDREG_OFFSET_CBL, port->bufsize);
82688447a05SGarrett D'Amore
82788447a05SGarrett D'Amore AUDIOHD_REG_SET16(regbase + AUDIOHD_SDREG_OFFSET_FORMAT,
82888447a05SGarrett D'Amore port->format << 4 | port->nchan - 1);
82988447a05SGarrett D'Amore
83088447a05SGarrett D'Amore /* clear status */
83188447a05SGarrett D'Amore AUDIOHD_REG_SET8(regbase + AUDIOHD_SDREG_OFFSET_STS,
83288447a05SGarrett D'Amore AUDIOHDR_SD_STS_BCIS | AUDIOHDR_SD_STS_FIFOE |
83388447a05SGarrett D'Amore AUDIOHDR_SD_STS_DESE);
83488447a05SGarrett D'Amore
83588447a05SGarrett D'Amore /* set stream tag */
83688447a05SGarrett D'Amore AUDIOHD_REG_SET8(regbase + AUDIOHD_SDREG_OFFSET_CTL +
83788447a05SGarrett D'Amore AUDIOHD_PLAY_CTL_OFF,
83888447a05SGarrett D'Amore (port->index) << AUDIOHD_PLAY_TAG_OFF);
83988447a05SGarrett D'Amore
84088447a05SGarrett D'Amore return (0);
84188447a05SGarrett D'Amore }
84288447a05SGarrett D'Amore
84368c47f65SGarrett 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 {
84668c47f65SGarrett D'Amore audiohd_port_t *port = arg;
847ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = port->statep;
84888447a05SGarrett D'Amore
84968c47f65SGarrett D'Amore _NOTE(ARGUNUSED(flag));
85088447a05SGarrett D'Amore
851ea463888SZhao Edgar Liu - Sun Microsystems mutex_enter(&statep->hda_mutex);
85268c47f65SGarrett D'Amore port->count = 0;
85368c47f65SGarrett D'Amore port->curpos = 0;
85468c47f65SGarrett D'Amore *nframes = port->nframes;
85568c47f65SGarrett D'Amore *bufp = port->samp_kaddr;
856ea463888SZhao Edgar Liu - Sun Microsystems mutex_exit(&statep->hda_mutex);
85788447a05SGarrett D'Amore
85868c47f65SGarrett D'Amore return (0);
85988447a05SGarrett D'Amore }
86088447a05SGarrett D'Amore
86188447a05SGarrett D'Amore static int
audiohd_engine_start(void * arg)86288447a05SGarrett D'Amore audiohd_engine_start(void *arg)
86388447a05SGarrett D'Amore {
86488447a05SGarrett D'Amore audiohd_port_t *port = arg;
86588447a05SGarrett D'Amore audiohd_state_t *statep = port->statep;
86668c47f65SGarrett D'Amore int rv;
86788447a05SGarrett D'Amore
86888447a05SGarrett D'Amore 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);
87388447a05SGarrett D'Amore }
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
87888447a05SGarrett D'Amore mutex_exit(&statep->hda_mutex);
87988447a05SGarrett D'Amore return (0);
88088447a05SGarrett D'Amore }
88188447a05SGarrett D'Amore
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;
88788447a05SGarrett D'Amore
88888447a05SGarrett D'Amore mutex_enter(&statep->hda_mutex);
88968c47f65SGarrett D'Amore AUDIOHD_REG_SET8(port->regoff + AUDIOHD_SDREG_OFFSET_CTL, 0);
89088447a05SGarrett D'Amore mutex_exit(&statep->hda_mutex);
89188447a05SGarrett D'Amore }
89288447a05SGarrett D'Amore
89388447a05SGarrett D'Amore static void
audiohd_update_port(audiohd_port_t * port)89488447a05SGarrett D'Amore audiohd_update_port(audiohd_port_t *port)
89588447a05SGarrett D'Amore {
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;
91188447a05SGarrett D'Amore }
91288447a05SGarrett D'Amore
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)
96088447a05SGarrett D'Amore {
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);
96688447a05SGarrett 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);
97088447a05SGarrett D'Amore }
97188447a05SGarrett D'Amore
97288447a05SGarrett D'Amore static void
audiohd_engine_close(void * arg)97388447a05SGarrett D'Amore audiohd_engine_close(void *arg)
97488447a05SGarrett D'Amore {
97568c47f65SGarrett D'Amore _NOTE(ARGUNUSED(arg));
97688447a05SGarrett D'Amore }
97788447a05SGarrett D'Amore
97888447a05SGarrett D'Amore static void
audiohd_engine_sync(void * arg,unsigned nframes)97988447a05SGarrett D'Amore audiohd_engine_sync(void *arg, unsigned nframes)
98088447a05SGarrett D'Amore {
98188447a05SGarrett D'Amore audiohd_port_t *port = arg;
98288447a05SGarrett D'Amore
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
101888447a05SGarrett D'Amore 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 |
104688447a05SGarrett D'Amore 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 }
107588447a05SGarrett D'Amore
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);
113888447a05SGarrett D'Amore }
113988447a05SGarrett D'Amore }
114088447a05SGarrett D'Amore }
114188447a05SGarrett D'Amore }
114288447a05SGarrett D'Amore
114388447a05SGarrett D'Amore
114488447a05SGarrett D'Amore 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)
114788447a05SGarrett D'Amore {
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;
115388447a05SGarrett D'Amore 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;
121488447a05SGarrett D'Amore 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;
122088447a05SGarrett D'Amore
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];
123588447a05SGarrett D'Amore 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);
124688447a05SGarrett D'Amore }
124788447a05SGarrett D'Amore }
124888447a05SGarrett D'Amore break;
124988447a05SGarrett D'Amore default:
125088447a05SGarrett D'Amore break;
125188447a05SGarrett D'Amore }
125288447a05SGarrett D'Amore }
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) {
1271a4c3d128SYang-Rong Jerry Zhou (void) audioha_codec_verb_get(
1272a4c3d128SYang-Rong Jerry Zhou statep, codec->index, path->sum_wid,
1273a4c3d128SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_CONN_SEL,
1274a4c3d128SYang-Rong Jerry Zhou path->sum_selconn[i]);
1275e7236f70SZhao Edgar Liu - Sun Microsystems break;
1276a4c3d128SYang-Rong Jerry Zhou }
1277a4c3d128SYang-Rong Jerry Zhou }
1278e7236f70SZhao Edgar Liu - Sun Microsystems }
1279e7236f70SZhao Edgar Liu - Sun Microsystems }
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);
133588447a05SGarrett D'Amore }
133688447a05SGarrett D'Amore }
133788447a05SGarrett D'Amore }
133888447a05SGarrett D'Amore }
133988447a05SGarrett D'Amore
134088447a05SGarrett D'Amore static void
audiohd_set_monitor_gain(audiohd_state_t * statep)134188447a05SGarrett D'Amore audiohd_set_monitor_gain(audiohd_state_t *statep)
134288447a05SGarrett D'Amore {
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;
134888447a05SGarrett D'Amore audiohd_pin_t *pin;
1349c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_ctrl_t ctrl;
135088447a05SGarrett D'Amore uint64_t val;
135188447a05SGarrett D'Amore
1352c1cfefcdSZhao Edgar Liu - Sun Microsystems ctrl = statep->ctrls[CTL_MONGAIN];
1353c1cfefcdSZhao Edgar Liu - Sun Microsystems val = ctrl.val;
135488447a05SGarrett D'Amore
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);
136688447a05SGarrett D'Amore }
136788447a05SGarrett D'Amore }
136888447a05SGarrett D'Amore
136988447a05SGarrett D'Amore }
137088447a05SGarrett D'Amore
137188447a05SGarrett D'Amore 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
148242c41cf8Slipeng sang - Sun Microsystems - Beijing China static void
audiohd_configure_output(audiohd_state_t * statep)1483211ec5c5SYang-Rong Jerry Zhou audiohd_configure_output(audiohd_state_t *statep)
148488447a05SGarrett D'Amore {
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;
151088447a05SGarrett D'Amore
151188447a05SGarrett D'Amore if (val & ~(statep->inmask))
151288447a05SGarrett D'Amore return (EINVAL);
151388447a05SGarrett D'Amore
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 }
152088447a05SGarrett D'Amore
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);
152788447a05SGarrett D'Amore
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);
154688447a05SGarrett D'Amore mutex_exit(&statep->hda_mutex);
154788447a05SGarrett D'Amore
154888447a05SGarrett D'Amore return (0);
154988447a05SGarrett D'Amore }
155088447a05SGarrett D'Amore
155188447a05SGarrett D'Amore static int
audiohd_set_surround(void * arg,uint64_t val)155288447a05SGarrett D'Amore audiohd_set_surround(void *arg, uint64_t val)
155388447a05SGarrett D'Amore {
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);
155788447a05SGarrett D'Amore
155888447a05SGarrett D'Amore 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);
156288447a05SGarrett D'Amore
156388447a05SGarrett D'Amore return (0);
156488447a05SGarrett D'Amore }
156588447a05SGarrett D'Amore
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);
157288447a05SGarrett D'Amore
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);
157788447a05SGarrett D'Amore
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);
158688447a05SGarrett D'Amore
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
163988447a05SGarrett D'Amore 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
1701e7236f70SZhao Edgar Liu - Sun Microsystems 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);
172288447a05SGarrett D'Amore
172388447a05SGarrett D'Amore mutex_enter(&statep->hda_mutex);
172488447a05SGarrett D'Amore pc->val = val;
172588447a05SGarrett D'Amore audiohd_set_pin_volume(statep, DTYPE_CD);
172688447a05SGarrett D'Amore mutex_exit(&statep->hda_mutex);
172788447a05SGarrett D'Amore
172888447a05SGarrett D'Amore return (0);
172988447a05SGarrett D'Amore }
173088447a05SGarrett D'Amore
173188447a05SGarrett D'Amore static int
audiohd_set_mongain(void * arg,uint64_t val)173288447a05SGarrett D'Amore audiohd_set_mongain(void *arg, uint64_t val)
173388447a05SGarrett D'Amore {
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);
173788447a05SGarrett D'Amore
173888447a05SGarrett D'Amore 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
176988447a05SGarrett D'Amore static void
audiohd_del_controls(audiohd_state_t * statep)177088447a05SGarrett D'Amore audiohd_del_controls(audiohd_state_t *statep)
177188447a05SGarrett D'Amore {
177288447a05SGarrett D'Amore 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 }
177988447a05SGarrett D'Amore }
178088447a05SGarrett D'Amore }
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)
178588447a05SGarrett D'Amore {
1786c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_ctrl_t *ac;
1787c1cfefcdSZhao Edgar Liu - Sun Microsystems audio_ctrl_desc_t desc;
178888447a05SGarrett D'Amore
1789c1cfefcdSZhao Edgar Liu - Sun Microsystems bzero(&desc, sizeof (desc));
1790c1cfefcdSZhao Edgar Liu - Sun Microsystems
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;
1794c1cfefcdSZhao Edgar Liu - Sun Microsystems
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;
1800c1cfefcdSZhao Edgar Liu - Sun Microsystems
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);
180488447a05SGarrett D'Amore }
180588447a05SGarrett D'Amore
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;
1812c1cfefcdSZhao Edgar Liu - Sun Microsystems
1813c1cfefcdSZhao Edgar Liu - Sun Microsystems bzero(&desc, sizeof (desc));
1814c1cfefcdSZhao Edgar Liu - Sun Microsystems
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;
1818c1cfefcdSZhao Edgar Liu - Sun Microsystems
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;
1824c1cfefcdSZhao Edgar Liu - Sun Microsystems
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 }
1829c1cfefcdSZhao Edgar Liu - Sun Microsystems
1830c1cfefcdSZhao 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
1854e7236f70SZhao 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;
1859c1cfefcdSZhao Edgar Liu - Sun Microsystems
1860c1cfefcdSZhao Edgar Liu - Sun Microsystems bzero(&desc, sizeof (desc));
1861c1cfefcdSZhao Edgar Liu - Sun Microsystems
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;
1865c1cfefcdSZhao Edgar Liu - Sun Microsystems
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];
1873c1cfefcdSZhao Edgar Liu - Sun Microsystems }
1874c1cfefcdSZhao Edgar Liu - Sun Microsystems
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);
1878c1cfefcdSZhao Edgar Liu - Sun Microsystems }
1879c1cfefcdSZhao Edgar Liu - Sun Microsystems
1880c1cfefcdSZhao Edgar Liu - Sun Microsystems static void
audiohd_create_controls(audiohd_state_t * statep)1881c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_create_controls(audiohd_state_t *statep)
1882c1cfefcdSZhao Edgar Liu - Sun Microsystems {
1883c1cfefcdSZhao Edgar Liu - Sun Microsystems wid_t wid;
1884c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_widget_t *widget;
1885c1cfefcdSZhao Edgar Liu - Sun Microsystems audiohd_path_t *path;
1886c1cfefcdSZhao Edgar Liu - Sun Microsystems 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;
1890c1cfefcdSZhao Edgar Liu - Sun Microsystems
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) &
190888447a05SGarrett D'Amore 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 &&
191488447a05SGarrett D'Amore pin->device != DTYPE_HP_OUT &&
191588447a05SGarrett D'Amore 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 }
1931c1cfefcdSZhao Edgar Liu - Sun Microsystems 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);
1935c1cfefcdSZhao Edgar Liu - Sun Microsystems } 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);
1939c1cfefcdSZhao Edgar Liu - Sun Microsystems } 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);
1943c1cfefcdSZhao Edgar Liu - Sun Microsystems } 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);
1947c1cfefcdSZhao Edgar Liu - Sun Microsystems } 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);
1951c1cfefcdSZhao Edgar Liu - Sun Microsystems }
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 }
196488447a05SGarrett D'Amore }
196588447a05SGarrett D'Amore
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 }
197188447a05SGarrett D'Amore
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 }
198188447a05SGarrett D'Amore
198288447a05SGarrett D'Amore /*
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.
199188447a05SGarrett D'Amore */
199288447a05SGarrett D'Amore static int
audiohd_quiesce(dev_info_t * dip)199388447a05SGarrett D'Amore audiohd_quiesce(dev_info_t *dip)
199488447a05SGarrett D'Amore {
199588447a05SGarrett D'Amore audiohd_state_t *statep;
199688447a05SGarrett D'Amore
199788447a05SGarrett D'Amore statep = ddi_get_driver_private(dip);
199888447a05SGarrett D'Amore
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);
200288447a05SGarrett D'Amore
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
207388447a05SGarrett D'Amore /*
207488447a05SGarrett D'Amore * audiohd_init_state()
207588447a05SGarrett D'Amore *
207688447a05SGarrett D'Amore * Description
207788447a05SGarrett D'Amore * This routine initailizes soft state of driver instance,
207888447a05SGarrett D'Amore * also, it requests an interrupt cookie and initializes
207988447a05SGarrett D'Amore * mutex for soft state.
208088447a05SGarrett D'Amore */
208188447a05SGarrett D'Amore /*ARGSUSED*/
208288447a05SGarrett D'Amore static int
audiohd_init_state(audiohd_state_t * statep,dev_info_t * dip)208388447a05SGarrett D'Amore audiohd_init_state(audiohd_state_t *statep, dev_info_t *dip)
208488447a05SGarrett D'Amore {
208588447a05SGarrett D'Amore audio_dev_t *adev;
208688447a05SGarrett D'Amore
208788447a05SGarrett D'Amore statep->hda_dip = dip;
2088c7b817cfSZhao Edgar Liu - Sun Microsystems statep->hda_rirb_rp = 0;
208988447a05SGarrett D'Amore
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);
209388447a05SGarrett D'Amore }
209488447a05SGarrett D'Amore statep->adev = adev;
209588447a05SGarrett D'Amore
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);
209988447a05SGarrett D'Amore
2100c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
210188447a05SGarrett D'Amore } /* audiohd_init_state() */
210288447a05SGarrett D'Amore
210388447a05SGarrett D'Amore /*
210488447a05SGarrett D'Amore * audiohd_init_pci()
210588447a05SGarrett D'Amore *
210688447a05SGarrett D'Amore * Description
210788447a05SGarrett D'Amore * enable driver to access PCI configure space and memory
210888447a05SGarrett D'Amore * I/O space.
210988447a05SGarrett D'Amore */
211088447a05SGarrett D'Amore static int
audiohd_init_pci(audiohd_state_t * statep,ddi_device_acc_attr_t * acc_attr)211188447a05SGarrett D'Amore audiohd_init_pci(audiohd_state_t *statep, ddi_device_acc_attr_t *acc_attr)
211288447a05SGarrett D'Amore {
211388447a05SGarrett D'Amore uint16_t cmdreg;
211488447a05SGarrett D'Amore uint16_t vid;
211588447a05SGarrett D'Amore uint8_t cTmp;
211688447a05SGarrett D'Amore dev_info_t *dip = statep->hda_dip;
2117c7b817cfSZhao Edgar Liu - Sun Microsystems audio_dev_t *adev = statep->adev;
211888447a05SGarrett D'Amore
211988447a05SGarrett D'Amore 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);
212388447a05SGarrett D'Amore }
212488447a05SGarrett D'Amore
212588447a05SGarrett D'Amore if (ddi_regs_map_setup(dip, 1, &statep->hda_reg_base, 0,
212688447a05SGarrett D'Amore 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);
213088447a05SGarrett D'Amore }
213188447a05SGarrett D'Amore
213288447a05SGarrett D'Amore /*
213388447a05SGarrett D'Amore * HD audio control uses memory I/O only, enable it here.
213488447a05SGarrett D'Amore */
213588447a05SGarrett D'Amore cmdreg = pci_config_get16(statep->hda_pci_handle, PCI_CONF_COMM);
213688447a05SGarrett D'Amore pci_config_put16(statep->hda_pci_handle, PCI_CONF_COMM,
213788447a05SGarrett D'Amore cmdreg | PCI_COMM_MAE | PCI_COMM_ME);
213888447a05SGarrett D'Amore
213988447a05SGarrett D'Amore vid = pci_config_get16(statep->hda_pci_handle, PCI_CONF_VENID);
214088447a05SGarrett D'Amore switch (vid) {
214188447a05SGarrett D'Amore case AUDIOHD_VID_INTEL:
214288447a05SGarrett D'Amore /*
214388447a05SGarrett D'Amore * Currently, Intel (G)MCH and ICHx chipsets support PCI
214488447a05SGarrett D'Amore * Express QoS. It implemenets two VCs(virtual channels)
214588447a05SGarrett D'Amore * and allows OS software to map 8 traffic classes to the
214688447a05SGarrett D'Amore * two VCs. Some BIOSes initialize HD audio hardware to
214788447a05SGarrett D'Amore * use TC7 (traffic class 7) and to map TC7 to VC1 as Intel
214888447a05SGarrett D'Amore * recommended. However, solaris doesn't support PCI express
214988447a05SGarrett D'Amore * QoS yet. As a result, this driver can not work for those
215088447a05SGarrett D'Amore * hardware without touching PCI express control registers.
215188447a05SGarrett D'Amore * Here, we set TCSEL to 0 so as to use TC0/VC0 (VC0 is
215288447a05SGarrett D'Amore * always enabled and TC0 is always mapped to VC0) for all
215388447a05SGarrett D'Amore * Intel HD audio controllers.
215488447a05SGarrett D'Amore */
215588447a05SGarrett D'Amore cTmp = pci_config_get8(statep->hda_pci_handle,
215688447a05SGarrett D'Amore AUDIOHD_INTEL_PCI_TCSEL);
215788447a05SGarrett D'Amore pci_config_put8(statep->hda_pci_handle,
215888447a05SGarrett D'Amore AUDIOHD_INTEL_PCI_TCSEL, (cTmp & AUDIOHD_INTEL_TCS_MASK));
215988447a05SGarrett D'Amore break;
216088447a05SGarrett D'Amore case AUDIOHD_VID_ATI:
216188447a05SGarrett D'Amore /*
216288447a05SGarrett D'Amore * Refer to ATI SB450 datesheet. We set snoop for SB450
216388447a05SGarrett D'Amore * like hardware.
216488447a05SGarrett D'Amore */
216588447a05SGarrett D'Amore cTmp = pci_config_get8(statep->hda_pci_handle,
216688447a05SGarrett D'Amore AUDIOHD_ATI_PCI_MISC2);
216788447a05SGarrett D'Amore pci_config_put8(statep->hda_pci_handle, AUDIOHD_ATI_PCI_MISC2,
216888447a05SGarrett D'Amore (cTmp & AUDIOHD_ATI_MISC2_MASK) | AUDIOHD_ATI_MISC2_SNOOP);
216988447a05SGarrett D'Amore break;
2170989b958fSZhao Edgar Liu - Sun Microsystems case AUDIOHD_VID_NVIDIA:
217188447a05SGarrett D'Amore /*
217288447a05SGarrett D'Amore * Refer to the datasheet, we set snoop for NVIDIA
217388447a05SGarrett D'Amore * like hardware
217488447a05SGarrett D'Amore */
217588447a05SGarrett D'Amore cTmp = pci_config_get8(statep->hda_pci_handle,
217688447a05SGarrett D'Amore AUDIOHD_CORB_SIZE_OFF);
217788447a05SGarrett D'Amore pci_config_put8(statep->hda_pci_handle, AUDIOHD_CORB_SIZE_OFF,
217888447a05SGarrett D'Amore cTmp | AUDIOHD_NVIDIA_SNOOP);
217988447a05SGarrett D'Amore break;
218088447a05SGarrett D'Amore default:
218188447a05SGarrett D'Amore break;
218288447a05SGarrett D'Amore }
218388447a05SGarrett D'Amore
2184c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
218588447a05SGarrett D'Amore } /* audiohd_init_pci() */
218688447a05SGarrett D'Amore
218788447a05SGarrett D'Amore
218888447a05SGarrett D'Amore /*
218988447a05SGarrett D'Amore * audiohd_fini_pci()
219088447a05SGarrett D'Amore *
219188447a05SGarrett D'Amore * Description
219288447a05SGarrett D'Amore * Release mapping for PCI configure space.
219388447a05SGarrett D'Amore */
219488447a05SGarrett D'Amore static void
audiohd_fini_pci(audiohd_state_t * statep)219588447a05SGarrett D'Amore audiohd_fini_pci(audiohd_state_t *statep)
219688447a05SGarrett D'Amore {
219788447a05SGarrett D'Amore if (statep->hda_reg_handle != NULL) {
219888447a05SGarrett D'Amore ddi_regs_map_free(&statep->hda_reg_handle);
219988447a05SGarrett D'Amore }
220088447a05SGarrett D'Amore
220188447a05SGarrett D'Amore if (statep->hda_pci_handle != NULL) {
220288447a05SGarrett D'Amore pci_config_teardown(&statep->hda_pci_handle);
220388447a05SGarrett D'Amore }
220488447a05SGarrett D'Amore
220588447a05SGarrett D'Amore } /* audiohd_fini_pci() */
220688447a05SGarrett D'Amore
220788447a05SGarrett D'Amore /*
220888447a05SGarrett D'Amore * audiohd_stop_dma()
220988447a05SGarrett D'Amore *
221088447a05SGarrett D'Amore * Description
221188447a05SGarrett D'Amore * Stop all DMA behaviors of controllers, for command I/O
221288447a05SGarrett D'Amore * and each audio stream.
221388447a05SGarrett D'Amore */
221488447a05SGarrett D'Amore static void
audiohd_stop_dma(audiohd_state_t * statep)221588447a05SGarrett D'Amore audiohd_stop_dma(audiohd_state_t *statep)
221688447a05SGarrett D'Amore {
221788447a05SGarrett D'Amore int i;
221888447a05SGarrett D'Amore uint_t base;
221988447a05SGarrett D'Amore uint8_t bTmp;
222088447a05SGarrett D'Amore
222188447a05SGarrett D'Amore AUDIOHD_REG_SET8(AUDIOHD_REG_CORBCTL, 0);
222288447a05SGarrett D'Amore AUDIOHD_REG_SET8(AUDIOHD_REG_RIRBCTL, 0);
222388447a05SGarrett D'Amore
222488447a05SGarrett D'Amore base = AUDIOHD_REG_SD_BASE;
222588447a05SGarrett D'Amore for (i = 0; i < statep->hda_streams_nums; i++) {
222688447a05SGarrett D'Amore bTmp = AUDIOHD_REG_GET8(base + AUDIOHD_SDREG_OFFSET_CTL);
222788447a05SGarrett D'Amore
222888447a05SGarrett D'Amore /* for input/output stream, it is the same */
222988447a05SGarrett D'Amore bTmp &= ~AUDIOHDR_RIRBCTL_DMARUN;
223088447a05SGarrett D'Amore
223188447a05SGarrett D'Amore AUDIOHD_REG_SET8(base + AUDIOHD_SDREG_OFFSET_CTL, bTmp);
223288447a05SGarrett D'Amore base += AUDIOHD_REG_SD_LEN;
223388447a05SGarrett D'Amore }
223488447a05SGarrett D'Amore
223588447a05SGarrett D'Amore /* wait 40us for stream DMA to stop */
223688447a05SGarrett D'Amore drv_usecwait(40);
223788447a05SGarrett D'Amore
223888447a05SGarrett D'Amore } /* audiohd_stop_dma() */
223988447a05SGarrett D'Amore
224088447a05SGarrett D'Amore /*
224188447a05SGarrett D'Amore * audiohd_reset_controller()
224288447a05SGarrett D'Amore *
224388447a05SGarrett D'Amore * Description:
224488447a05SGarrett D'Amore * This routine is just used to reset controller and
224588447a05SGarrett D'Amore * CODEC as well by HW reset bit in global control
224688447a05SGarrett D'Amore * register of HD controller.
224788447a05SGarrett D'Amore */
224888447a05SGarrett D'Amore static int
audiohd_reset_controller(audiohd_state_t * statep)224988447a05SGarrett D'Amore audiohd_reset_controller(audiohd_state_t *statep)
225088447a05SGarrett D'Amore {
225188447a05SGarrett D'Amore int i;
225288447a05SGarrett D'Amore uint16_t sTmp;
225388447a05SGarrett D'Amore uint32_t gctl;
225488447a05SGarrett D'Amore
225588447a05SGarrett D'Amore /* Reset Status register but preserve the first bit */
225688447a05SGarrett D'Amore sTmp = AUDIOHD_REG_GET16(AUDIOHD_REG_STATESTS);
225788447a05SGarrett D'Amore AUDIOHD_REG_SET16(AUDIOHD_REG_STATESTS, sTmp & 0x8000);
225888447a05SGarrett D'Amore
225988447a05SGarrett D'Amore /* reset controller */
226088447a05SGarrett D'Amore gctl = AUDIOHD_REG_GET32(AUDIOHD_REG_GCTL);
226188447a05SGarrett D'Amore gctl &= ~AUDIOHDR_GCTL_CRST;
226288447a05SGarrett D'Amore AUDIOHD_REG_SET32(AUDIOHD_REG_GCTL, gctl); /* entering reset state */
226388447a05SGarrett D'Amore for (i = 0; i < AUDIOHD_RETRY_TIMES; i++) {
226488447a05SGarrett D'Amore /* Empirical testing time: 150 */
226588447a05SGarrett D'Amore drv_usecwait(150);
226688447a05SGarrett D'Amore gctl = AUDIOHD_REG_GET32(AUDIOHD_REG_GCTL);
226788447a05SGarrett D'Amore if ((gctl & AUDIOHDR_GCTL_CRST) == 0)
226888447a05SGarrett D'Amore break;
226988447a05SGarrett D'Amore }
227088447a05SGarrett D'Amore
227188447a05SGarrett D'Amore 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);
227588447a05SGarrett D'Amore }
227688447a05SGarrett D'Amore
227788447a05SGarrett D'Amore /* Empirical testing time:300 */
227888447a05SGarrett D'Amore drv_usecwait(300);
227988447a05SGarrett D'Amore
228088447a05SGarrett D'Amore /* exit reset state */
228188447a05SGarrett D'Amore AUDIOHD_REG_SET32(AUDIOHD_REG_GCTL, gctl | AUDIOHDR_GCTL_CRST);
228288447a05SGarrett D'Amore
228388447a05SGarrett D'Amore for (i = 0; i < AUDIOHD_RETRY_TIMES; i++) {
228488447a05SGarrett D'Amore /* Empirical testing time: 150, which works well */
228588447a05SGarrett D'Amore drv_usecwait(150);
228688447a05SGarrett D'Amore gctl = AUDIOHD_REG_GET32(AUDIOHD_REG_GCTL);
228788447a05SGarrett D'Amore if (gctl & AUDIOHDR_GCTL_CRST)
228888447a05SGarrett D'Amore break;
228988447a05SGarrett D'Amore }
229088447a05SGarrett D'Amore
229188447a05SGarrett D'Amore 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);
229588447a05SGarrett D'Amore }
229688447a05SGarrett D'Amore
229788447a05SGarrett D'Amore /* HD spec requires to wait 250us at least. we use 500us */
229888447a05SGarrett D'Amore drv_usecwait(500);
229988447a05SGarrett D'Amore
230088447a05SGarrett D'Amore /* enable unsolicited response */
230188447a05SGarrett D'Amore AUDIOHD_REG_SET32(AUDIOHD_REG_GCTL,
230288447a05SGarrett D'Amore gctl | AUDIOHDR_GCTL_URESPE);
230388447a05SGarrett D'Amore
2304c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
230588447a05SGarrett D'Amore
230688447a05SGarrett D'Amore } /* audiohd_reset_controller() */
230788447a05SGarrett D'Amore
230888447a05SGarrett D'Amore /*
230988447a05SGarrett D'Amore * audiohd_alloc_dma_mem()
231088447a05SGarrett D'Amore *
231188447a05SGarrett D'Amore * Description:
231288447a05SGarrett D'Amore * This is an utility routine. It is used to allocate DMA
231388447a05SGarrett D'Amore * memory.
231488447a05SGarrett D'Amore */
231588447a05SGarrett D'Amore 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)231688447a05SGarrett D'Amore audiohd_alloc_dma_mem(audiohd_state_t *statep, audiohd_dma_t *pdma,
231788447a05SGarrett D'Amore size_t memsize, ddi_dma_attr_t *dma_attr_p, uint_t dma_flags)
231888447a05SGarrett D'Amore {
231988447a05SGarrett D'Amore ddi_dma_cookie_t cookie;
232088447a05SGarrett D'Amore uint_t count;
232188447a05SGarrett D'Amore dev_info_t *dip = statep->hda_dip;
232288447a05SGarrett D'Amore audio_dev_t *ahandle = statep->adev;
232388447a05SGarrett D'Amore
232488447a05SGarrett D'Amore 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);
232988447a05SGarrett D'Amore }
233088447a05SGarrett D'Amore
233188447a05SGarrett D'Amore if (ddi_dma_mem_alloc(pdma->ad_dmahdl, memsize, &hda_dev_accattr,
233288447a05SGarrett D'Amore dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
233388447a05SGarrett D'Amore DDI_DMA_SLEEP, NULL,
233488447a05SGarrett D'Amore (caddr_t *)&pdma->ad_vaddr, &pdma->ad_real_sz,
233588447a05SGarrett D'Amore &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);
233988447a05SGarrett D'Amore }
234088447a05SGarrett D'Amore
234188447a05SGarrett D'Amore if (ddi_dma_addr_bind_handle(pdma->ad_dmahdl, NULL,
234288447a05SGarrett D'Amore (caddr_t)pdma->ad_vaddr, pdma->ad_real_sz, dma_flags,
234388447a05SGarrett D'Amore 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);
234788447a05SGarrett D'Amore }
234888447a05SGarrett D'Amore
234988447a05SGarrett D'Amore pdma->ad_paddr = (uint64_t)(cookie.dmac_laddress);
235088447a05SGarrett D'Amore pdma->ad_req_sz = memsize;
235188447a05SGarrett D'Amore
2352c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
235388447a05SGarrett D'Amore } /* audiohd_alloc_dma_mem() */
235488447a05SGarrett D'Amore
235588447a05SGarrett D'Amore /*
235688447a05SGarrett D'Amore * audiohd_release_dma_mem()
235788447a05SGarrett D'Amore *
235888447a05SGarrett D'Amore * Description:
235988447a05SGarrett D'Amore * Release DMA memory.
236088447a05SGarrett D'Amore */
236188447a05SGarrett D'Amore
236288447a05SGarrett D'Amore static void
audiohd_release_dma_mem(audiohd_dma_t * pdma)236388447a05SGarrett D'Amore audiohd_release_dma_mem(audiohd_dma_t *pdma)
236488447a05SGarrett D'Amore {
236588447a05SGarrett D'Amore if (pdma->ad_dmahdl != NULL) {
236688447a05SGarrett D'Amore (void) ddi_dma_unbind_handle(pdma->ad_dmahdl);
236788447a05SGarrett D'Amore }
236888447a05SGarrett D'Amore
236988447a05SGarrett D'Amore if (pdma->ad_acchdl != NULL) {
237088447a05SGarrett D'Amore ddi_dma_mem_free(&pdma->ad_acchdl);
237188447a05SGarrett D'Amore pdma->ad_acchdl = NULL;
237288447a05SGarrett D'Amore }
237388447a05SGarrett D'Amore
237488447a05SGarrett D'Amore if (pdma->ad_dmahdl != NULL) {
237588447a05SGarrett D'Amore ddi_dma_free_handle(&pdma->ad_dmahdl);
237688447a05SGarrett D'Amore pdma->ad_dmahdl = NULL;
237788447a05SGarrett D'Amore }
237888447a05SGarrett D'Amore
237988447a05SGarrett D'Amore } /* audiohd_release_dma_mem() */
238088447a05SGarrett D'Amore
238188447a05SGarrett D'Amore /*
238288447a05SGarrett D'Amore * audiohd_reinit_hda()
238388447a05SGarrett D'Amore *
238488447a05SGarrett D'Amore * Description:
238588447a05SGarrett D'Amore * This routine is used to re-initialize HD controller and codec.
238688447a05SGarrett D'Amore */
238788447a05SGarrett D'Amore static int
audiohd_reinit_hda(audiohd_state_t * statep)238888447a05SGarrett D'Amore audiohd_reinit_hda(audiohd_state_t *statep)
238988447a05SGarrett D'Amore {
239088447a05SGarrett D'Amore uint64_t addr;
239188447a05SGarrett D'Amore
239288447a05SGarrett D'Amore /* set PCI configure space in case it's not restored OK */
239388447a05SGarrett D'Amore (void) audiohd_init_pci(statep, &hda_dev_accattr);
239488447a05SGarrett D'Amore
239588447a05SGarrett D'Amore /* reset controller */
2396c6e681c0SYang-Rong Jerry Zhou if (audiohd_reset_controller(statep) != DDI_SUCCESS)
2397c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
239888447a05SGarrett D'Amore AUDIOHD_REG_SET32(AUDIOHD_REG_SYNC, 0); /* needn't sync stream */
239988447a05SGarrett D'Amore
240088447a05SGarrett D'Amore /* Initialize controller RIRB */
240188447a05SGarrett D'Amore addr = statep->hda_dma_rirb.ad_paddr;
240288447a05SGarrett D'Amore AUDIOHD_REG_SET32(AUDIOHD_REG_RIRBLBASE, (uint32_t)addr);
240388447a05SGarrett D'Amore AUDIOHD_REG_SET32(AUDIOHD_REG_RIRBUBASE,
240488447a05SGarrett D'Amore (uint32_t)(addr >> 32));
240588447a05SGarrett D'Amore AUDIOHD_REG_SET16(AUDIOHD_REG_RIRBWP, AUDIOHDR_RIRBWP_RESET);
240688447a05SGarrett D'Amore AUDIOHD_REG_SET8(AUDIOHD_REG_RIRBSIZE, AUDIOHDR_RIRBSZ_256);
240788447a05SGarrett D'Amore AUDIOHD_REG_SET8(AUDIOHD_REG_RIRBCTL, AUDIOHDR_RIRBCTL_DMARUN |
240888447a05SGarrett D'Amore AUDIOHDR_RIRBCTL_RINTCTL);
240988447a05SGarrett D'Amore
241088447a05SGarrett D'Amore /* Initialize controller CORB */
241188447a05SGarrett D'Amore addr = statep->hda_dma_corb.ad_paddr;
241288447a05SGarrett D'Amore AUDIOHD_REG_SET16(AUDIOHD_REG_CORBRP, AUDIOHDR_CORBRP_RESET);
241388447a05SGarrett D'Amore AUDIOHD_REG_SET32(AUDIOHD_REG_CORBLBASE, (uint32_t)addr);
241488447a05SGarrett D'Amore AUDIOHD_REG_SET32(AUDIOHD_REG_CORBUBASE,
241588447a05SGarrett D'Amore (uint32_t)(addr >> 32));
241688447a05SGarrett D'Amore AUDIOHD_REG_SET8(AUDIOHD_REG_CORBSIZE, AUDIOHDR_CORBSZ_256);
241788447a05SGarrett D'Amore AUDIOHD_REG_SET16(AUDIOHD_REG_CORBWP, 0);
241888447a05SGarrett D'Amore AUDIOHD_REG_SET16(AUDIOHD_REG_CORBRP, 0);
241988447a05SGarrett D'Amore AUDIOHD_REG_SET8(AUDIOHD_REG_CORBCTL, AUDIOHDR_CORBCTL_DMARUN);
242088447a05SGarrett D'Amore
242188447a05SGarrett D'Amore audiohd_restore_codec_gpio(statep);
242288447a05SGarrett D'Amore audiohd_restore_path(statep);
242388447a05SGarrett D'Amore audiohd_init_path(statep);
242488447a05SGarrett D'Amore
2425c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
242688447a05SGarrett D'Amore } /* audiohd_reinit_hda */
242788447a05SGarrett D'Amore
242888447a05SGarrett D'Amore /*
242988447a05SGarrett D'Amore * audiohd_init_controller()
243088447a05SGarrett D'Amore *
243188447a05SGarrett D'Amore * Description:
243288447a05SGarrett D'Amore * This routine is used to initialize HD controller. It
243388447a05SGarrett D'Amore * allocates DMA memory for CORB/RIRB, buffer descriptor
243488447a05SGarrett D'Amore * list and cylic data buffer for both play and record
243588447a05SGarrett D'Amore * stream.
243688447a05SGarrett D'Amore */
243788447a05SGarrett D'Amore static int
audiohd_init_controller(audiohd_state_t * statep)243888447a05SGarrett D'Amore audiohd_init_controller(audiohd_state_t *statep)
243988447a05SGarrett D'Amore {
244088447a05SGarrett D'Amore uint64_t addr;
244188447a05SGarrett D'Amore uint16_t gcap;
244288447a05SGarrett D'Amore int retval;
244388447a05SGarrett D'Amore
244488447a05SGarrett D'Amore ddi_dma_attr_t dma_attr = {
244588447a05SGarrett D'Amore DMA_ATTR_V0, /* version */
244688447a05SGarrett D'Amore 0, /* addr_lo */
244788447a05SGarrett D'Amore 0xffffffffffffffffULL, /* addr_hi */
244888447a05SGarrett D'Amore 0x00000000ffffffffULL, /* count_max */
244988447a05SGarrett D'Amore 128, /* 128-byte alignment as HD spec */
245088447a05SGarrett D'Amore 0xfff, /* burstsize */
245188447a05SGarrett D'Amore 1, /* minxfer */
245288447a05SGarrett D'Amore 0xffffffff, /* maxxfer */
245388447a05SGarrett D'Amore 0xffffffff, /* seg */
245488447a05SGarrett D'Amore 1, /* sgllen */
245588447a05SGarrett D'Amore 1, /* granular */
245688447a05SGarrett D'Amore 0 /* flags */
245788447a05SGarrett D'Amore };
245888447a05SGarrett D'Amore
245988447a05SGarrett D'Amore gcap = AUDIOHD_REG_GET16(AUDIOHD_REG_GCAP);
246088447a05SGarrett D'Amore
246188447a05SGarrett D'Amore /*
246288447a05SGarrett D'Amore * If the device doesn't support 64-bit DMA, we should not
246388447a05SGarrett D'Amore * allocate DMA memory from 4G above
246488447a05SGarrett D'Amore */
246588447a05SGarrett D'Amore if ((gcap & AUDIOHDR_GCAP_64OK) == 0)
246688447a05SGarrett D'Amore dma_attr.dma_attr_addr_hi = 0xffffffffUL;
246788447a05SGarrett D'Amore
246888447a05SGarrett D'Amore statep->hda_input_streams = (gcap & AUDIOHDR_GCAP_INSTREAMS) >>
246988447a05SGarrett D'Amore AUDIOHD_INSTR_NUM_OFF;
247088447a05SGarrett D'Amore statep->hda_output_streams = (gcap & AUDIOHDR_GCAP_OUTSTREAMS) >>
247188447a05SGarrett D'Amore AUDIOHD_OUTSTR_NUM_OFF;
247288447a05SGarrett D'Amore statep->hda_streams_nums = statep->hda_input_streams +
247388447a05SGarrett D'Amore statep->hda_output_streams;
247488447a05SGarrett D'Amore
247588447a05SGarrett D'Amore statep->hda_record_regbase = AUDIOHD_REG_SD_BASE;
247688447a05SGarrett D'Amore statep->hda_play_regbase = AUDIOHD_REG_SD_BASE + AUDIOHD_REG_SD_LEN *
247788447a05SGarrett D'Amore statep->hda_input_streams;
247888447a05SGarrett D'Amore
247988447a05SGarrett D'Amore /* stop all dma before starting to reset controller */
248088447a05SGarrett D'Amore audiohd_stop_dma(statep);
248188447a05SGarrett D'Amore
2482c6e681c0SYang-Rong Jerry Zhou if (audiohd_reset_controller(statep) != DDI_SUCCESS)
2483c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
248488447a05SGarrett D'Amore
248588447a05SGarrett D'Amore /* check codec */
248688447a05SGarrett D'Amore statep->hda_codec_mask = AUDIOHD_REG_GET16(AUDIOHD_REG_STATESTS);
248788447a05SGarrett D'Amore 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);
249188447a05SGarrett D'Amore }
249288447a05SGarrett D'Amore
249388447a05SGarrett D'Amore /* allocate DMA for CORB */
249488447a05SGarrett D'Amore retval = audiohd_alloc_dma_mem(statep, &statep->hda_dma_corb,
249588447a05SGarrett D'Amore AUDIOHD_CDBIO_CORB_LEN, &dma_attr,
249688447a05SGarrett D'Amore 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);
250188447a05SGarrett D'Amore }
250288447a05SGarrett D'Amore
250388447a05SGarrett D'Amore /* allocate DMA for RIRB */
250488447a05SGarrett D'Amore retval = audiohd_alloc_dma_mem(statep, &statep->hda_dma_rirb,
250588447a05SGarrett D'Amore AUDIOHD_CDBIO_RIRB_LEN, &dma_attr,
250688447a05SGarrett D'Amore 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);
251188447a05SGarrett D'Amore }
251288447a05SGarrett D'Amore
251388447a05SGarrett D'Amore AUDIOHD_REG_SET32(AUDIOHD_REG_SYNC, 0); /* needn't sync stream */
251488447a05SGarrett D'Amore
251588447a05SGarrett D'Amore /* Initialize RIRB */
251688447a05SGarrett D'Amore addr = statep->hda_dma_rirb.ad_paddr;
251788447a05SGarrett D'Amore AUDIOHD_REG_SET32(AUDIOHD_REG_RIRBLBASE, (uint32_t)addr);
2518c7b817cfSZhao Edgar Liu - Sun Microsystems AUDIOHD_REG_SET32(AUDIOHD_REG_RIRBUBASE, (uint32_t)(addr >> 32));
251988447a05SGarrett D'Amore AUDIOHD_REG_SET16(AUDIOHD_REG_RIRBWP, AUDIOHDR_RIRBWP_RESET);
252088447a05SGarrett D'Amore AUDIOHD_REG_SET8(AUDIOHD_REG_RIRBSIZE, AUDIOHDR_RIRBSZ_256);
252188447a05SGarrett D'Amore AUDIOHD_REG_SET8(AUDIOHD_REG_RIRBCTL, AUDIOHDR_RIRBCTL_DMARUN |
252288447a05SGarrett D'Amore AUDIOHDR_RIRBCTL_RINTCTL);
252388447a05SGarrett D'Amore
252488447a05SGarrett D'Amore /* initialize CORB */
252588447a05SGarrett D'Amore addr = statep->hda_dma_corb.ad_paddr;
252688447a05SGarrett D'Amore AUDIOHD_REG_SET16(AUDIOHD_REG_CORBRP, AUDIOHDR_CORBRP_RESET);
252788447a05SGarrett D'Amore AUDIOHD_REG_SET32(AUDIOHD_REG_CORBLBASE, (uint32_t)addr);
2528c7b817cfSZhao Edgar Liu - Sun Microsystems AUDIOHD_REG_SET32(AUDIOHD_REG_CORBUBASE, (uint32_t)(addr >> 32));
252988447a05SGarrett D'Amore AUDIOHD_REG_SET8(AUDIOHD_REG_CORBSIZE, AUDIOHDR_CORBSZ_256);
253088447a05SGarrett D'Amore AUDIOHD_REG_SET16(AUDIOHD_REG_CORBWP, 0);
253188447a05SGarrett D'Amore AUDIOHD_REG_SET16(AUDIOHD_REG_CORBRP, 0);
253288447a05SGarrett D'Amore AUDIOHD_REG_SET8(AUDIOHD_REG_CORBCTL, AUDIOHDR_CORBCTL_DMARUN);
253388447a05SGarrett D'Amore
2534c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
253588447a05SGarrett D'Amore } /* audiohd_init_controller() */
253688447a05SGarrett D'Amore
253788447a05SGarrett D'Amore /*
253888447a05SGarrett D'Amore * audiohd_fini_controller()
253988447a05SGarrett D'Amore *
254088447a05SGarrett D'Amore * Description:
254188447a05SGarrett D'Amore * Releases DMA memory allocated in audiohd_init_controller()
254288447a05SGarrett D'Amore */
254388447a05SGarrett D'Amore static void
audiohd_fini_controller(audiohd_state_t * statep)254488447a05SGarrett D'Amore audiohd_fini_controller(audiohd_state_t *statep)
254588447a05SGarrett D'Amore {
254688447a05SGarrett D'Amore audiohd_release_dma_mem(&statep->hda_dma_rirb);
254788447a05SGarrett D'Amore audiohd_release_dma_mem(&statep->hda_dma_corb);
254888447a05SGarrett D'Amore
254988447a05SGarrett D'Amore } /* audiohd_fini_controller() */
255088447a05SGarrett D'Amore
255188447a05SGarrett D'Amore /*
255288447a05SGarrett D'Amore * audiohd_get_conns_from_entry()
255388447a05SGarrett D'Amore *
255488447a05SGarrett D'Amore * Description:
255588447a05SGarrett D'Amore * Get connection list from every entry for a widget
255688447a05SGarrett D'Amore */
255788447a05SGarrett D'Amore static void
audiohd_get_conns_from_entry(hda_codec_t * codec,audiohd_widget_t * widget,uint32_t entry,audiohd_entry_prop_t * prop)255888447a05SGarrett D'Amore audiohd_get_conns_from_entry(hda_codec_t *codec, audiohd_widget_t *widget,
255988447a05SGarrett D'Amore uint32_t entry, audiohd_entry_prop_t *prop)
256088447a05SGarrett D'Amore {
256188447a05SGarrett D'Amore int i, k, num;
256288447a05SGarrett D'Amore wid_t input_wid;
256388447a05SGarrett D'Amore
256488447a05SGarrett D'Amore for (i = 0; i < prop->conns_per_entry &&
256588447a05SGarrett D'Amore widget->nconns < prop->conn_len;
256688447a05SGarrett D'Amore i++, entry >>= prop->bits_per_conn) {
256788447a05SGarrett D'Amore ASSERT(widget->nconns < AUDIOHD_MAX_CONN);
256888447a05SGarrett D'Amore input_wid = entry & prop->mask_wid;
256988447a05SGarrett D'Amore if (entry & prop->mask_range) {
257088447a05SGarrett D'Amore if (widget->nconns == 0) {
257188447a05SGarrett D'Amore if (input_wid < codec->first_wid ||
257288447a05SGarrett D'Amore (input_wid > codec->last_wid)) {
257388447a05SGarrett D'Amore break;
257488447a05SGarrett D'Amore }
257588447a05SGarrett D'Amore widget->avail_conn[widget->nconns++] =
257688447a05SGarrett D'Amore input_wid;
257788447a05SGarrett D'Amore } else {
257888447a05SGarrett D'Amore for (k = widget->avail_conn[widget->nconns-1] +
257988447a05SGarrett D'Amore 1; k <= input_wid; k++) {
258088447a05SGarrett D'Amore ASSERT(widget->nconns <
258188447a05SGarrett D'Amore AUDIOHD_MAX_CONN);
258288447a05SGarrett D'Amore if (k < codec->first_wid ||
258388447a05SGarrett D'Amore (k > codec->last_wid)) {
258488447a05SGarrett D'Amore break;
258588447a05SGarrett D'Amore } else {
258688447a05SGarrett D'Amore num = widget->nconns;
258788447a05SGarrett D'Amore widget->avail_conn[num] = k;
258888447a05SGarrett D'Amore widget->nconns++;
258988447a05SGarrett D'Amore }
259088447a05SGarrett D'Amore }
259188447a05SGarrett D'Amore }
259288447a05SGarrett D'Amore } else {
259388447a05SGarrett D'Amore if ((codec->first_wid <= input_wid) && (input_wid <=
259488447a05SGarrett D'Amore codec->last_wid))
259588447a05SGarrett D'Amore widget->avail_conn[widget->nconns++] =
259688447a05SGarrett D'Amore input_wid;
259788447a05SGarrett D'Amore }
259888447a05SGarrett D'Amore }
259988447a05SGarrett D'Amore }
260088447a05SGarrett D'Amore
260188447a05SGarrett D'Amore /*
260288447a05SGarrett D'Amore * audiohd_get_conns()
260388447a05SGarrett D'Amore *
260488447a05SGarrett D'Amore * Description:
260588447a05SGarrett D'Amore * Get all connection list for a widget. The connection list is used for
260688447a05SGarrett D'Amore * build output path, input path, and monitor path
260788447a05SGarrett D'Amore */
260888447a05SGarrett D'Amore static void
audiohd_get_conns(hda_codec_t * codec,wid_t wid)260988447a05SGarrett D'Amore audiohd_get_conns(hda_codec_t *codec, wid_t wid)
261088447a05SGarrett D'Amore {
2611ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
261288447a05SGarrett D'Amore audiohd_widget_t *widget = codec->widget[wid];
261388447a05SGarrett D'Amore uint8_t caddr = codec->index;
261488447a05SGarrett D'Amore uint32_t entry;
261588447a05SGarrett D'Amore audiohd_entry_prop_t prop;
261688447a05SGarrett D'Amore wid_t input_wid;
261788447a05SGarrett D'Amore int i;
261888447a05SGarrett D'Amore
261988447a05SGarrett D'Amore prop.conn_len = audioha_codec_verb_get(statep, caddr, wid,
262088447a05SGarrett D'Amore AUDIOHDC_VERB_GET_PARAM, AUDIOHDC_PAR_CONNLIST_LEN);
262188447a05SGarrett D'Amore
262288447a05SGarrett D'Amore if (prop.conn_len & AUDIOHD_FORM_MASK) {
262388447a05SGarrett D'Amore prop.conns_per_entry = 2;
262488447a05SGarrett D'Amore prop.bits_per_conn = 16;
262588447a05SGarrett D'Amore prop.mask_range = 0x00008000;
262688447a05SGarrett D'Amore prop.mask_wid = 0x00007fff;
262788447a05SGarrett D'Amore } else {
262888447a05SGarrett D'Amore prop.conns_per_entry = 4;
262988447a05SGarrett D'Amore prop.bits_per_conn = 8;
263088447a05SGarrett D'Amore prop.mask_range = 0x00000080;
263188447a05SGarrett D'Amore prop.mask_wid = 0x0000007f;
263288447a05SGarrett D'Amore }
263388447a05SGarrett D'Amore prop.conn_len &= AUDIOHD_LEN_MASK;
263488447a05SGarrett D'Amore
263588447a05SGarrett D'Amore /*
263688447a05SGarrett D'Amore * This should not happen since the ConnectionList bit of
263788447a05SGarrett D'Amore * widget capabilities already told us that this widget
263888447a05SGarrett D'Amore * has a connection list
263988447a05SGarrett D'Amore */
264088447a05SGarrett D'Amore if (prop.conn_len == 0) {
264188447a05SGarrett D'Amore widget->nconns = 0;
264207bec7ccSZhao Edgar Liu - Sun Microsystems audio_dev_warn(statep->adev,
264307bec7ccSZhao Edgar Liu - Sun Microsystems "node %d has 0 connections", wid);
264488447a05SGarrett D'Amore return;
264588447a05SGarrett D'Amore }
264688447a05SGarrett D'Amore
264788447a05SGarrett D'Amore if (prop.conn_len == 1) {
264888447a05SGarrett D'Amore entry = audioha_codec_verb_get(statep, caddr,
264988447a05SGarrett D'Amore wid, AUDIOHDC_VERB_GET_CONN_LIST_ENT, 0);
265088447a05SGarrett D'Amore input_wid = entry & prop.mask_wid;
265188447a05SGarrett D'Amore if ((input_wid < codec->first_wid) ||
265288447a05SGarrett D'Amore (input_wid > codec->last_wid)) {
265388447a05SGarrett D'Amore return;
265488447a05SGarrett D'Amore }
265588447a05SGarrett D'Amore widget->avail_conn[0] = input_wid;
265688447a05SGarrett D'Amore widget->nconns = 1;
265788447a05SGarrett D'Amore return;
265888447a05SGarrett D'Amore }
265988447a05SGarrett D'Amore widget->nconns = 0;
266088447a05SGarrett D'Amore for (i = 0; i < prop.conn_len; i += prop.conns_per_entry) {
266188447a05SGarrett D'Amore entry = audioha_codec_verb_get(statep, caddr, wid,
266288447a05SGarrett D'Amore AUDIOHDC_VERB_GET_CONN_LIST_ENT, i);
266388447a05SGarrett D'Amore audiohd_get_conns_from_entry(codec, widget, entry, &prop);
266488447a05SGarrett D'Amore }
266588447a05SGarrett D'Amore }
266688447a05SGarrett D'Amore
266788447a05SGarrett D'Amore /*
266888447a05SGarrett D'Amore * Read PinCapabilities & default configuration
266988447a05SGarrett D'Amore */
267088447a05SGarrett D'Amore static void
audiohd_get_pin_config(audiohd_widget_t * widget)267188447a05SGarrett D'Amore audiohd_get_pin_config(audiohd_widget_t *widget)
267288447a05SGarrett D'Amore {
267388447a05SGarrett D'Amore hda_codec_t *codec = widget->codec;
2674ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
267588447a05SGarrett D'Amore audiohd_pin_t *pin, *prev, *p;
267688447a05SGarrett D'Amore
267788447a05SGarrett D'Amore int caddr = codec->index;
267888447a05SGarrett D'Amore wid_t wid = widget->wid_wid;
267988447a05SGarrett D'Amore uint32_t cap, config, pinctrl;
268088447a05SGarrett D'Amore uint8_t urctrl, vrefbits;
268188447a05SGarrett D'Amore
268288447a05SGarrett D'Amore cap = audioha_codec_verb_get(statep, caddr, wid,
268388447a05SGarrett D'Amore AUDIOHDC_VERB_GET_PARAM, AUDIOHDC_PAR_PIN_CAP);
268488447a05SGarrett D'Amore config = audioha_codec_verb_get(statep, caddr,
268588447a05SGarrett D'Amore wid, AUDIOHDC_VERB_GET_DEFAULT_CONF, 0);
268688447a05SGarrett D'Amore pinctrl = audioha_codec_verb_get(statep, caddr,
268788447a05SGarrett D'Amore wid, AUDIOHDC_VERB_GET_PIN_CTRL, 0);
268888447a05SGarrett D'Amore
268988447a05SGarrett D'Amore pin = (audiohd_pin_t *)kmem_zalloc(sizeof (audiohd_pin_t), KM_SLEEP);
269088447a05SGarrett D'Amore widget->priv = pin;
269188447a05SGarrett D'Amore
269288447a05SGarrett D'Amore /*
269388447a05SGarrett D'Amore * If the pin has no physical connection for port,
269488447a05SGarrett D'Amore * we won't link it to pin linkage list ???
269588447a05SGarrett D'Amore */
269688447a05SGarrett D'Amore if (((config >> AUDIOHD_PIN_CON_STEP) & AUDIOHD_PIN_CON_MASK) == 0x1) {
269788447a05SGarrett D'Amore pin->no_phys_conn = 1;
269888447a05SGarrett D'Amore }
269988447a05SGarrett D'Amore
270088447a05SGarrett D'Amore /* bit 4:3 are reserved, read-modify-write is needed */
270188447a05SGarrett D'Amore pin->ctrl = pinctrl & AUDIOHD_PIN_IO_MASK;
270288447a05SGarrett D'Amore pin->wid = wid;
270388447a05SGarrett D'Amore pin->cap = cap;
270488447a05SGarrett D'Amore pin->config = config;
270588447a05SGarrett D'Amore pin->num = 0;
270688447a05SGarrett D'Amore pin->finish = 0;
270788447a05SGarrett D'Amore
270888447a05SGarrett D'Amore vrefbits = (cap >> AUDIOHD_PIN_VREF_OFF) & AUDIOHD_PIN_VREF_MASK;
270988447a05SGarrett D'Amore if (vrefbits & AUDIOHD_PIN_VREF_L1)
271088447a05SGarrett D'Amore pin->vrefvalue = 0x5;
271188447a05SGarrett D'Amore else if (vrefbits & AUDIOHD_PIN_VREF_L2)
271288447a05SGarrett D'Amore pin->vrefvalue = 0x4;
271388447a05SGarrett D'Amore else if (vrefbits & AUDIOHD_PIN_VREF_L3)
271488447a05SGarrett D'Amore pin->vrefvalue = 0x2;
271588447a05SGarrett D'Amore else
271688447a05SGarrett D'Amore pin->vrefvalue = 0x1;
271788447a05SGarrett D'Amore
271888447a05SGarrett D'Amore pin->seq = config & AUDIOHD_PIN_SEQ_MASK;
271988447a05SGarrett D'Amore pin->assoc = (config & AUDIOHD_PIN_ASO_MASK) >> AUDIOHD_PIN_ASO_OFF;
272088447a05SGarrett D'Amore pin->device = (config & AUDIOHD_PIN_DEV_MASK) >> AUDIOHD_PIN_DEV_OFF;
272188447a05SGarrett D'Amore
272288447a05SGarrett D'Amore /* enable the unsolicited response of the pin */
272388447a05SGarrett D'Amore if ((widget->widget_cap & AUDIOHD_URCAP_MASK) &&
272488447a05SGarrett D'Amore (pin->cap & AUDIOHD_DTCCAP_MASK) &&
272588447a05SGarrett D'Amore ((pin->device == DTYPE_LINEOUT) ||
272688447a05SGarrett D'Amore (pin->device == DTYPE_SPDIF_OUT) ||
272788447a05SGarrett D'Amore (pin->device == DTYPE_HP_OUT) ||
272888447a05SGarrett D'Amore (pin->device == DTYPE_MIC_IN))) {
272988447a05SGarrett D'Amore urctrl = (uint8_t)(1 << (AUDIOHD_UR_ENABLE_OFF - 1));
273088447a05SGarrett D'Amore urctrl |= (wid & AUDIOHD_UR_TAG_MASK);
273188447a05SGarrett D'Amore (void) audioha_codec_verb_get(statep, caddr,
2732989b958fSZhao Edgar Liu - Sun Microsystems wid, AUDIOHDC_VERB_SET_UNS_ENABLE, urctrl);
273388447a05SGarrett D'Amore }
273488447a05SGarrett D'Amore /* accommodate all the pins in a link list sorted by assoc and seq */
273588447a05SGarrett D'Amore if (codec->first_pin == NULL) {
273688447a05SGarrett D'Amore codec->first_pin = pin;
273788447a05SGarrett D'Amore } else {
273888447a05SGarrett D'Amore prev = NULL;
273988447a05SGarrett D'Amore p = codec->first_pin;
274088447a05SGarrett D'Amore while (p) {
274188447a05SGarrett D'Amore if (p->assoc > pin->assoc)
274288447a05SGarrett D'Amore break;
274388447a05SGarrett D'Amore if ((p->assoc == pin->assoc) &&
274488447a05SGarrett D'Amore (p->seq > pin->seq))
274588447a05SGarrett D'Amore break;
274688447a05SGarrett D'Amore prev = p;
274788447a05SGarrett D'Amore p = p->next;
274888447a05SGarrett D'Amore }
274988447a05SGarrett D'Amore if (prev) {
275088447a05SGarrett D'Amore pin->next = prev->next;
275188447a05SGarrett D'Amore prev->next = pin;
275288447a05SGarrett D'Amore } else {
275388447a05SGarrett D'Amore pin->next = codec->first_pin;
275488447a05SGarrett D'Amore codec->first_pin = pin;
275588447a05SGarrett D'Amore }
275688447a05SGarrett D'Amore }
275788447a05SGarrett D'Amore
275888447a05SGarrett D'Amore } /* audiohd_get_pin_config() */
275988447a05SGarrett D'Amore
276088447a05SGarrett D'Amore /*
276188447a05SGarrett D'Amore * audiohd_create_widgets()
276288447a05SGarrett D'Amore *
276388447a05SGarrett D'Amore * Description:
276488447a05SGarrett D'Amore * All widgets are created and stored in an array of codec
276588447a05SGarrett D'Amore */
276688447a05SGarrett D'Amore static int
audiohd_create_widgets(hda_codec_t * codec)276788447a05SGarrett D'Amore audiohd_create_widgets(hda_codec_t *codec)
276888447a05SGarrett D'Amore {
276988447a05SGarrett D'Amore audiohd_widget_t *widget;
2770ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
277188447a05SGarrett D'Amore wid_t wid;
277288447a05SGarrett D'Amore uint32_t type, widcap;
277388447a05SGarrett D'Amore int caddr = codec->index;
277488447a05SGarrett D'Amore
277588447a05SGarrett D'Amore for (wid = codec->first_wid;
277688447a05SGarrett D'Amore wid <= codec->last_wid; wid++) {
277788447a05SGarrett D'Amore widget = (audiohd_widget_t *)
277888447a05SGarrett D'Amore kmem_zalloc(sizeof (audiohd_widget_t), KM_SLEEP);
277988447a05SGarrett D'Amore codec->widget[wid] = widget;
278088447a05SGarrett D'Amore 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;
278588447a05SGarrett D'Amore
278688447a05SGarrett D'Amore widcap = audioha_codec_verb_get(statep, caddr, wid,
278788447a05SGarrett D'Amore AUDIOHDC_VERB_GET_PARAM, AUDIOHDC_PAR_AUDIO_WID_CAP);
278888447a05SGarrett D'Amore type = AUDIOHD_WIDCAP_TO_WIDTYPE(widcap);
278988447a05SGarrett D'Amore widget->wid_wid = wid;
279088447a05SGarrett D'Amore widget->type = type;
279188447a05SGarrett D'Amore widget->widget_cap = widcap;
279288447a05SGarrett D'Amore widget->finish = 0;
279388447a05SGarrett D'Amore widget->used = 0;
279488447a05SGarrett D'Amore
279588447a05SGarrett D'Amore /* if there's connection list */
279688447a05SGarrett D'Amore if (widcap & AUDIOHD_WIDCAP_CONNLIST) {
279788447a05SGarrett D'Amore audiohd_get_conns(codec, wid);
279888447a05SGarrett D'Amore }
279988447a05SGarrett D'Amore
280088447a05SGarrett D'Amore /* if power control, power it up to D0 state */
280188447a05SGarrett D'Amore if (widcap & AUDIOHD_WIDCAP_PWRCTRL) {
280288447a05SGarrett D'Amore (void) audioha_codec_verb_get(statep, caddr, wid,
280388447a05SGarrett D'Amore AUDIOHDC_VERB_SET_POWER_STATE, 0);
280488447a05SGarrett D'Amore }
280588447a05SGarrett D'Amore
280688447a05SGarrett D'Amore /*
280788447a05SGarrett D'Amore * if this widget has format override, we read it.
280888447a05SGarrett D'Amore * Otherwise, it uses the format of audio function.
280988447a05SGarrett D'Amore */
281088447a05SGarrett D'Amore if (widcap & AUDIOHD_WIDCAP_FMT_OVRIDE) {
281188447a05SGarrett D'Amore widget->pcm_format =
281288447a05SGarrett D'Amore audioha_codec_verb_get(statep, caddr, wid,
281388447a05SGarrett D'Amore AUDIOHDC_VERB_GET_PARAM, AUDIOHDC_PAR_PCM);
281488447a05SGarrett D'Amore } else {
281588447a05SGarrett D'Amore widget->pcm_format = codec->pcm_format;
281688447a05SGarrett D'Amore }
281788447a05SGarrett D'Amore
281888447a05SGarrett D'Amore /*
281988447a05SGarrett D'Amore * Input amplifier. Has the widget input amplifier ?
282088447a05SGarrett D'Amore */
282188447a05SGarrett D'Amore if (widcap & AUDIOHD_WIDCAP_INAMP) {
282288447a05SGarrett D'Amore /*
282388447a05SGarrett D'Amore * if overrided bit is 0, use the default
282488447a05SGarrett D'Amore * amplifier of audio function as HD spec.
282588447a05SGarrett D'Amore * Otherwise, we read it.
282688447a05SGarrett D'Amore */
282788447a05SGarrett D'Amore if ((widcap & AUDIOHD_WIDCAP_AMP_OVRIDE) == 0)
282888447a05SGarrett D'Amore widget->inamp_cap = codec->inamp_cap;
282988447a05SGarrett D'Amore else
283088447a05SGarrett D'Amore widget->inamp_cap =
283188447a05SGarrett D'Amore audioha_codec_verb_get(statep, caddr, wid,
283288447a05SGarrett D'Amore AUDIOHDC_VERB_GET_PARAM,
283388447a05SGarrett D'Amore AUDIOHDC_PAR_INAMP_CAP);
283488447a05SGarrett D'Amore } else {
283588447a05SGarrett D'Amore widget->inamp_cap = 0;
283688447a05SGarrett D'Amore }
283788447a05SGarrett D'Amore
283888447a05SGarrett D'Amore /*
283988447a05SGarrett D'Amore * output amplifier. Has this widget output amplifier ?
284088447a05SGarrett D'Amore */
284188447a05SGarrett D'Amore if (widcap & AUDIOHD_WIDCAP_OUTAMP) {
284288447a05SGarrett D'Amore if ((widcap & AUDIOHD_WIDCAP_AMP_OVRIDE) == 0)
284388447a05SGarrett D'Amore widget->outamp_cap = codec->outamp_cap;
284488447a05SGarrett D'Amore else
284588447a05SGarrett D'Amore widget->outamp_cap =
284688447a05SGarrett D'Amore audioha_codec_verb_get(statep, caddr, wid,
284788447a05SGarrett D'Amore AUDIOHDC_VERB_GET_PARAM,
284888447a05SGarrett D'Amore AUDIOHDC_PAR_OUTAMP_CAP);
284988447a05SGarrett D'Amore } else {
285088447a05SGarrett D'Amore widget->outamp_cap = 0;
285188447a05SGarrett D'Amore }
285288447a05SGarrett D'Amore
285388447a05SGarrett D'Amore switch (type) {
285488447a05SGarrett D'Amore case WTYPE_AUDIO_OUT:
285588447a05SGarrett D'Amore case WTYPE_AUDIO_IN:
285688447a05SGarrett D'Amore case WTYPE_AUDIO_MIX:
285788447a05SGarrett D'Amore case WTYPE_AUDIO_SEL:
285888447a05SGarrett D'Amore case WTYPE_VENDOR:
285988447a05SGarrett D'Amore case WTYPE_POWER:
286088447a05SGarrett D'Amore case WTYPE_VOL_KNOB:
286188447a05SGarrett D'Amore break;
286288447a05SGarrett D'Amore 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
287888447a05SGarrett D'Amore audiohd_get_pin_config(widget);
287988447a05SGarrett D'Amore break;
288088447a05SGarrett D'Amore 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 }
289688447a05SGarrett D'Amore break;
289788447a05SGarrett D'Amore default:
289888447a05SGarrett D'Amore break;
289988447a05SGarrett D'Amore }
290088447a05SGarrett D'Amore }
290188447a05SGarrett D'Amore
290288447a05SGarrett D'Amore return (DDI_SUCCESS);
290388447a05SGarrett D'Amore
290488447a05SGarrett D'Amore } /* audiohd_create_widgets() */
290588447a05SGarrett D'Amore
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
292188447a05SGarrett D'Amore /*
292288447a05SGarrett D'Amore * audiohd_create_codec()
292388447a05SGarrett D'Amore *
292488447a05SGarrett D'Amore * Description:
292588447a05SGarrett D'Amore * Searching for supported CODEC. If find, allocate memory
292688447a05SGarrett D'Amore * to hold codec structure.
292788447a05SGarrett D'Amore */
292888447a05SGarrett D'Amore static int
audiohd_create_codec(audiohd_state_t * statep)292988447a05SGarrett D'Amore audiohd_create_codec(audiohd_state_t *statep)
293088447a05SGarrett D'Amore {
293188447a05SGarrett D'Amore hda_codec_t *codec;
293288447a05SGarrett D'Amore uint32_t mask, type;
293388447a05SGarrett D'Amore uint32_t nums;
2934cbe6566fSZhao Edgar Liu - Sun Microsystems uint32_t i, j, len;
293588447a05SGarrett D'Amore 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
294088447a05SGarrett D'Amore
294188447a05SGarrett D'Amore mask = statep->hda_codec_mask;
294288447a05SGarrett D'Amore ASSERT(mask != 0);
294388447a05SGarrett D'Amore
294488447a05SGarrett D'Amore for (i = 0; i < AUDIOHD_CODEC_MAX; i++) {
294588447a05SGarrett D'Amore if ((mask & (1 << i)) == 0)
294688447a05SGarrett D'Amore continue;
294788447a05SGarrett D'Amore codec = (hda_codec_t *)kmem_zalloc(
294888447a05SGarrett D'Amore sizeof (hda_codec_t), KM_SLEEP);
294988447a05SGarrett D'Amore codec->index = i;
295088447a05SGarrett D'Amore codec->vid = audioha_codec_verb_get(statep, i,
295188447a05SGarrett D'Amore AUDIOHDC_NODE_ROOT, AUDIOHDC_VERB_GET_PARAM,
295288447a05SGarrett D'Amore 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
295888447a05SGarrett D'Amore codec->revid =
295988447a05SGarrett D'Amore audioha_codec_verb_get(statep, i,
296088447a05SGarrett D'Amore AUDIOHDC_NODE_ROOT, AUDIOHDC_VERB_GET_PARAM,
296188447a05SGarrett D'Amore AUDIOHDC_PAR_REV_ID);
296288447a05SGarrett D'Amore
296388447a05SGarrett D'Amore nums = audioha_codec_verb_get(statep,
296488447a05SGarrett D'Amore i, AUDIOHDC_NODE_ROOT,
296588447a05SGarrett D'Amore AUDIOHDC_VERB_GET_PARAM, AUDIOHDC_PAR_NODE_COUNT);
296688447a05SGarrett D'Amore if (nums == (uint32_t)(-1)) {
296788447a05SGarrett D'Amore kmem_free(codec, sizeof (hda_codec_t));
296888447a05SGarrett D'Amore continue;
296988447a05SGarrett D'Amore }
297088447a05SGarrett D'Amore wid = (nums >> AUDIOHD_CODEC_STR_OFF) & AUDIOHD_CODEC_STR_MASK;
297188447a05SGarrett D'Amore nums = nums & AUDIOHD_CODEC_NUM_MASK;
297288447a05SGarrett D'Amore
297388447a05SGarrett D'Amore /*
297488447a05SGarrett D'Amore * Assume that each codec has just one audio function group
297588447a05SGarrett D'Amore */
297688447a05SGarrett D'Amore for (j = 0; j < nums; j++, wid++) {
297788447a05SGarrett D'Amore type = audioha_codec_verb_get(statep, i, wid,
297888447a05SGarrett D'Amore AUDIOHDC_VERB_GET_PARAM,
297988447a05SGarrett D'Amore AUDIOHDC_PAR_FUNCTION_TYPE);
298088447a05SGarrett D'Amore if ((type & AUDIOHD_CODEC_TYPE_MASK) ==
298188447a05SGarrett D'Amore AUDIOHDC_AUDIO_FUNC_GROUP) {
298288447a05SGarrett D'Amore codec->wid_afg = wid;
298388447a05SGarrett D'Amore break;
298488447a05SGarrett D'Amore }
298588447a05SGarrett D'Amore }
298688447a05SGarrett D'Amore
298788447a05SGarrett D'Amore if (codec->wid_afg == 0) {
298888447a05SGarrett D'Amore kmem_free(codec, sizeof (hda_codec_t));
298988447a05SGarrett D'Amore continue;
299088447a05SGarrett D'Amore }
299188447a05SGarrett D'Amore
299288447a05SGarrett D'Amore ASSERT(codec->wid_afg == wid);
299388447a05SGarrett D'Amore
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);
30219ba19c87SYang-Rong Jerry Zhou (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);
3024989b958fSZhao Edgar Liu - Sun Microsystems (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
303488447a05SGarrett D'Amore /* power-up audio function group */
303588447a05SGarrett D'Amore (void) audioha_codec_verb_get(statep, i, wid,
30365ec2209cSZhao Edgar Liu - Sun Microsystems AUDIOHDC_VERB_SET_POWER_STATE, AUDIOHD_PW_D0);
303788447a05SGarrett D'Amore
303888447a05SGarrett D'Amore /* subsystem id is attached to funtion group */
303988447a05SGarrett D'Amore codec->outamp_cap = audioha_codec_verb_get(statep, i, wid,
304088447a05SGarrett D'Amore AUDIOHDC_VERB_GET_PARAM, AUDIOHDC_PAR_OUTAMP_CAP);
304188447a05SGarrett D'Amore codec->inamp_cap = audioha_codec_verb_get(statep, i, wid,
304288447a05SGarrett D'Amore AUDIOHDC_VERB_GET_PARAM, AUDIOHDC_PAR_INAMP_CAP);
304388447a05SGarrett D'Amore codec->stream_format = audioha_codec_verb_get(statep, i, wid,
304488447a05SGarrett D'Amore AUDIOHDC_VERB_GET_PARAM, AUDIOHDC_PAR_STREAM);
304588447a05SGarrett D'Amore codec->pcm_format = audioha_codec_verb_get(statep, i, wid,
304688447a05SGarrett D'Amore AUDIOHDC_VERB_GET_PARAM, AUDIOHDC_PAR_PCM);
304788447a05SGarrett D'Amore
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
307188447a05SGarrett D'Amore nums = audioha_codec_verb_get(statep, i, wid,
307288447a05SGarrett D'Amore AUDIOHDC_VERB_GET_PARAM,
307388447a05SGarrett D'Amore AUDIOHDC_PAR_NODE_COUNT);
307488447a05SGarrett D'Amore wid = (nums >> AUDIOHD_CODEC_STR_OFF) & AUDIOHD_CODEC_STR_MASK;
307588447a05SGarrett D'Amore nums = nums & AUDIOHD_CODEC_NUM_MASK;
307688447a05SGarrett D'Amore codec->first_wid = wid;
307788447a05SGarrett D'Amore codec->last_wid = wid + nums;
307888447a05SGarrett D'Amore codec->nnodes = nums;
307988447a05SGarrett D'Amore
308088447a05SGarrett D'Amore /*
308188447a05SGarrett D'Amore * We output the codec information to syslog
308288447a05SGarrett D'Amore */
308388447a05SGarrett D'Amore statep->codec[i] = codec;
3084ea463888SZhao Edgar Liu - Sun Microsystems codec->statep = statep;
308588447a05SGarrett D'Amore (void) audiohd_create_widgets(codec);
308688447a05SGarrett D'Amore }
308788447a05SGarrett D'Amore
3088c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
308988447a05SGarrett D'Amore
309088447a05SGarrett D'Amore } /* audiohd_create_codec() */
309188447a05SGarrett D'Amore
309288447a05SGarrett D'Amore /*
309388447a05SGarrett D'Amore * audiohd_destroy_codec()
309488447a05SGarrett D'Amore *
309588447a05SGarrett D'Amore * Description:
309688447a05SGarrett D'Amore * destroy codec structure, and release its memory
309788447a05SGarrett D'Amore */
309888447a05SGarrett D'Amore static void
audiohd_destroy_codec(audiohd_state_t * statep)309988447a05SGarrett D'Amore audiohd_destroy_codec(audiohd_state_t *statep)
310088447a05SGarrett D'Amore {
310188447a05SGarrett D'Amore int i;
310288447a05SGarrett D'Amore audiohd_pin_t *pin, *npin;
310388447a05SGarrett D'Amore
310488447a05SGarrett D'Amore for (i = 0; i < AUDIOHD_CODEC_MAX; i++) {
310588447a05SGarrett D'Amore if (statep->codec[i]) {
310688447a05SGarrett D'Amore audiohd_destroy_widgets(statep->codec[i]);
310788447a05SGarrett D'Amore /*
310888447a05SGarrett D'Amore * free pins
310988447a05SGarrett D'Amore */
311088447a05SGarrett D'Amore pin = statep->codec[i]->first_pin;
311188447a05SGarrett D'Amore while (pin) {
311288447a05SGarrett D'Amore npin = pin;
311388447a05SGarrett D'Amore pin = pin->next;
311488447a05SGarrett D'Amore kmem_free(npin, sizeof (audiohd_pin_t));
311588447a05SGarrett D'Amore }
311688447a05SGarrett D'Amore
311788447a05SGarrett D'Amore kmem_free(statep->codec[i], sizeof (hda_codec_t));
311888447a05SGarrett D'Amore statep->codec[i] = NULL;
311988447a05SGarrett D'Amore }
312088447a05SGarrett D'Amore }
312188447a05SGarrett D'Amore } /* audiohd_destroy_codec() */
312288447a05SGarrett D'Amore
312388447a05SGarrett D'Amore /*
312488447a05SGarrett D'Amore * audiohd_find_dac()
312588447a05SGarrett D'Amore * Description:
312688447a05SGarrett D'Amore * Find a dac for a output path. Then the play data can be sent to the out
312788447a05SGarrett D'Amore * put pin through the output path.
312888447a05SGarrett D'Amore *
312988447a05SGarrett D'Amore * Arguments:
313088447a05SGarrett D'Amore * hda_codec_t *codec where the dac widget exists
313188447a05SGarrett D'Amore * wid_t wid the no. of a widget
313288447a05SGarrett D'Amore * int mixer whether the path need mixer or not
313388447a05SGarrett D'Amore * int *mixernum the total of mixer in the output path
313488447a05SGarrett D'Amore * int exclusive an exclusive path or share path
313588447a05SGarrett D'Amore * int depth the depth of search
313688447a05SGarrett D'Amore *
313788447a05SGarrett D'Amore * Return:
313888447a05SGarrett D'Amore * 1) wid of the first shared widget in the path from
313988447a05SGarrett D'Amore * pin to DAC if exclusive is 0;
314088447a05SGarrett D'Amore * 2) wid of DAC widget;
314188447a05SGarrett D'Amore * 3) 0 if no path
314288447a05SGarrett D'Amore */
314388447a05SGarrett D'Amore static wid_t
audiohd_find_dac(hda_codec_t * codec,wid_t wid,int mixer,int * mixernum,int exclusive,int depth)314488447a05SGarrett D'Amore audiohd_find_dac(hda_codec_t *codec, wid_t wid,
314588447a05SGarrett D'Amore int mixer, int *mixernum,
314688447a05SGarrett D'Amore int exclusive, int depth)
314788447a05SGarrett D'Amore {
314888447a05SGarrett D'Amore audiohd_widget_t *widget = codec->widget[wid];
3149c6e681c0SYang-Rong Jerry Zhou wid_t wdac = (uint32_t)(DDI_FAILURE);
315088447a05SGarrett D'Amore wid_t retval;
315188447a05SGarrett D'Amore
315288447a05SGarrett D'Amore if (depth > AUDIOHD_MAX_DEPTH)
3153c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
315488447a05SGarrett D'Amore
315588447a05SGarrett D'Amore if (widget == NULL)
3156c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
315788447a05SGarrett D'Amore
315888447a05SGarrett D'Amore /*
315988447a05SGarrett D'Amore * If exclusive is true, we try to find a path which doesn't
316088447a05SGarrett D'Amore * share any widget with other paths.
316188447a05SGarrett D'Amore */
316288447a05SGarrett D'Amore if (exclusive) {
316388447a05SGarrett D'Amore if (widget->path_flags & AUDIOHD_PATH_DAC)
3164c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
316588447a05SGarrett D'Amore } else {
316688447a05SGarrett D'Amore if (widget->path_flags & AUDIOHD_PATH_DAC)
316788447a05SGarrett D'Amore return (wid);
316888447a05SGarrett D'Amore }
316988447a05SGarrett D'Amore
317088447a05SGarrett D'Amore switch (widget->type) {
317188447a05SGarrett D'Amore case WTYPE_AUDIO_OUT:
317288447a05SGarrett D'Amore /* We need mixer widget, but the the mixer num is 0, failed */
317388447a05SGarrett D'Amore if (mixer && !*mixernum)
3174c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
317588447a05SGarrett D'Amore widget->path_flags |= AUDIOHD_PATH_DAC;
317688447a05SGarrett D'Amore widget->out_weight++;
317788447a05SGarrett D'Amore wdac = widget->wid_wid;
317888447a05SGarrett D'Amore break;
317988447a05SGarrett D'Amore
318088447a05SGarrett D'Amore case WTYPE_AUDIO_MIX:
318188447a05SGarrett D'Amore (*mixernum)++;
3182b96a6eceSZhao Edgar Liu - Sun Microsystems /* FALLTHRU */
3183b96a6eceSZhao Edgar Liu - Sun Microsystems case WTYPE_AUDIO_SEL:
318488447a05SGarrett D'Amore for (int i = 0; i < widget->nconns; i++) {
318588447a05SGarrett D'Amore retval = audiohd_find_dac(codec,
318688447a05SGarrett D'Amore widget->avail_conn[i],
318788447a05SGarrett D'Amore mixer, mixernum,
318888447a05SGarrett D'Amore 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;
319388447a05SGarrett D'Amore wdac = retval;
319488447a05SGarrett D'Amore }
319588447a05SGarrett D'Amore widget->path_flags |= AUDIOHD_PATH_DAC;
319688447a05SGarrett D'Amore widget->out_weight++;
319788447a05SGarrett D'Amore
319888447a05SGarrett D'Amore /* return when found a path */
319988447a05SGarrett D'Amore return (wdac);
320088447a05SGarrett D'Amore }
320188447a05SGarrett D'Amore }
320288447a05SGarrett D'Amore default:
320388447a05SGarrett D'Amore break;
320488447a05SGarrett D'Amore }
320588447a05SGarrett D'Amore
320688447a05SGarrett D'Amore return (wdac);
320788447a05SGarrett D'Amore } /* audiohd_find_dac() */
320888447a05SGarrett D'Amore
320988447a05SGarrett D'Amore /*
321088447a05SGarrett D'Amore * audiohd_do_build_output_path()
321188447a05SGarrett D'Amore *
321288447a05SGarrett D'Amore * Description:
321388447a05SGarrett D'Amore * Search an output path for each pin in the codec.
321488447a05SGarrett D'Amore * Arguments:
321588447a05SGarrett D'Amore * hda_codec_t *codec where the output path exists
3216b96a6eceSZhao Edgar Liu - Sun Microsystems * int mixer whether the path needs mixer widget
321788447a05SGarrett D'Amore * int *mnum total of mixer widget in the path
321888447a05SGarrett D'Amore * int exclusive an exclusive path or shared path
321988447a05SGarrett D'Amore * int depth search depth
322088447a05SGarrett D'Amore */
322188447a05SGarrett D'Amore static void
audiohd_do_build_output_path(hda_codec_t * codec,int mixer,int * mnum,int exclusive,int depth)322288447a05SGarrett D'Amore audiohd_do_build_output_path(hda_codec_t *codec, int mixer, int *mnum,
322388447a05SGarrett D'Amore int exclusive, int depth)
322488447a05SGarrett D'Amore {
322588447a05SGarrett D'Amore audiohd_pin_t *pin;
322688447a05SGarrett D'Amore audiohd_widget_t *widget, *wdac;
322788447a05SGarrett D'Amore audiohd_path_t *path;
322888447a05SGarrett D'Amore wid_t wid;
322988447a05SGarrett D'Amore audiohd_state_t *statep;
323088447a05SGarrett D'Amore int i;
323188447a05SGarrett D'Amore
3232ea463888SZhao Edgar Liu - Sun Microsystems statep = codec->statep;
323388447a05SGarrett D'Amore
323488447a05SGarrett D'Amore for (pin = codec->first_pin; pin; pin = pin->next) {
323588447a05SGarrett D'Amore if ((pin->cap & AUDIOHD_PIN_CAP_MASK) == 0)
323688447a05SGarrett D'Amore continue;
323788447a05SGarrett D'Amore if ((pin->config & AUDIOHD_PIN_CONF_MASK) ==
323888447a05SGarrett D'Amore AUDIOHD_PIN_NO_CONN)
323988447a05SGarrett D'Amore continue;
324088447a05SGarrett D'Amore if ((pin->device != DTYPE_LINEOUT) &&
324188447a05SGarrett D'Amore (pin->device != DTYPE_SPEAKER) &&
324288447a05SGarrett D'Amore (pin->device != DTYPE_SPDIF_OUT) &&
324388447a05SGarrett D'Amore (pin->device != DTYPE_HP_OUT))
324488447a05SGarrett D'Amore continue;
324588447a05SGarrett D'Amore if (pin->finish)
324688447a05SGarrett D'Amore continue;
324788447a05SGarrett D'Amore widget = codec->widget[pin->wid];
324888447a05SGarrett D'Amore
324988447a05SGarrett D'Amore widget->inamp_cap = 0;
325088447a05SGarrett D'Amore for (i = 0; i < widget->nconns; i++) {
325188447a05SGarrett D'Amore /*
325288447a05SGarrett D'Amore * If a dac found, the return value is the wid of the
325388447a05SGarrett D'Amore * widget on the path, or the return value is
3254c6e681c0SYang-Rong Jerry Zhou * DDI_FAILURE
325588447a05SGarrett D'Amore */
325688447a05SGarrett D'Amore wid = audiohd_find_dac(codec,
325788447a05SGarrett D'Amore widget->avail_conn[i], mixer, mnum, exclusive,
325888447a05SGarrett D'Amore depth);
325988447a05SGarrett D'Amore /*
326088447a05SGarrett D'Amore * A dac was not found
326188447a05SGarrett D'Amore */
3262c6e681c0SYang-Rong Jerry Zhou if (wid == (wid_t)DDI_FAILURE)
326388447a05SGarrett D'Amore 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),
326988447a05SGarrett D'Amore 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;
327688447a05SGarrett D'Amore wdac = codec->widget[wid];
327788447a05SGarrett D'Amore wdac->priv = path;
3278e7236f70SZhao Edgar Liu - Sun Microsystems pin->dac_wid = wid;
327988447a05SGarrett D'Amore pin->finish = 1;
328088447a05SGarrett D'Amore widget->path_flags |= AUDIOHD_PATH_DAC;
328188447a05SGarrett D'Amore widget->out_weight++;
3282b96a6eceSZhao Edgar Liu - Sun Microsystems widget->output_path_next = i;
328388447a05SGarrett D'Amore statep->path[statep->pathnum++] = path;
328488447a05SGarrett D'Amore break;
328588447a05SGarrett D'Amore }
328688447a05SGarrett D'Amore }
328788447a05SGarrett D'Amore
328888447a05SGarrett D'Amore } /* audiohd_do_build_output_path() */
328988447a05SGarrett D'Amore
329088447a05SGarrett D'Amore /*
329188447a05SGarrett D'Amore * audiohd_build_output_path()
329288447a05SGarrett D'Amore *
329388447a05SGarrett D'Amore * Description:
329488447a05SGarrett D'Amore * Build the output path in the codec for every pin.
329588447a05SGarrett D'Amore * First we try to search output path with mixer widget exclusively
329688447a05SGarrett D'Amore * Then we try to search shared output path with mixer widget.
329788447a05SGarrett D'Amore * Then we try to search output path without mixer widget exclusively.
329888447a05SGarrett D'Amore * At last we try to search shared ouput path for the remained pins
329988447a05SGarrett D'Amore */
330088447a05SGarrett D'Amore static void
audiohd_build_output_path(hda_codec_t * codec)330188447a05SGarrett D'Amore audiohd_build_output_path(hda_codec_t *codec)
330288447a05SGarrett D'Amore {
330388447a05SGarrett D'Amore int mnum = 0;
330488447a05SGarrett D'Amore uint8_t mixer_allow = 1;
330588447a05SGarrett D'Amore
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
331588447a05SGarrett D'Amore /* search an exclusive mixer widget path. This is preferred */
331688447a05SGarrett D'Amore audiohd_do_build_output_path(codec, mixer_allow, &mnum, 1, 0);
331788447a05SGarrett D'Amore
331888447a05SGarrett D'Amore /* search a shared mixer widget path for the remained pins */
331988447a05SGarrett D'Amore audiohd_do_build_output_path(codec, mixer_allow, &mnum, 0, 0);
332088447a05SGarrett D'Amore
332188447a05SGarrett D'Amore /* search an exclusive widget path without mixer for the remained pin */
332288447a05SGarrett D'Amore audiohd_do_build_output_path(codec, 0, &mnum, 1, 0);
332388447a05SGarrett D'Amore
332488447a05SGarrett D'Amore /* search a shared widget path without mixer for the remained pin */
332588447a05SGarrett D'Amore audiohd_do_build_output_path(codec, 0, &mnum, 0, 0);
332688447a05SGarrett D'Amore
332788447a05SGarrett D'Amore } /* audiohd_build_output_path */
332888447a05SGarrett D'Amore
332988447a05SGarrett D'Amore /*
333088447a05SGarrett D'Amore * audiohd_build_output_amp
333188447a05SGarrett D'Amore *
333288447a05SGarrett D'Amore * Description:
333388447a05SGarrett D'Amore * Find the gain control and mute control widget
333488447a05SGarrett D'Amore */
333588447a05SGarrett D'Amore static void
audiohd_build_output_amp(hda_codec_t * codec)333688447a05SGarrett D'Amore audiohd_build_output_amp(hda_codec_t *codec)
333788447a05SGarrett D'Amore {
333888447a05SGarrett D'Amore audiohd_path_t *path;
333988447a05SGarrett D'Amore audiohd_widget_t *w, *widget, *wpin, *wdac;
334088447a05SGarrett D'Amore audiohd_pin_t *pin;
3341b96a6eceSZhao Edgar Liu - Sun Microsystems wid_t wid, next;
334288447a05SGarrett D'Amore int weight;
334388447a05SGarrett D'Amore int i, j;
334488447a05SGarrett D'Amore uint32_t gain;
334588447a05SGarrett D'Amore
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];
335388447a05SGarrett D'Amore wpin = codec->widget[wid];
335488447a05SGarrett D'Amore pin = (audiohd_pin_t *)wpin->priv;
335588447a05SGarrett D'Amore weight = wpin->out_weight;
335688447a05SGarrett D'Amore
335788447a05SGarrett D'Amore /*
335888447a05SGarrett D'Amore * search a node which can mute this pin while
335988447a05SGarrett D'Amore * the mute functionality doesn't effect other
336088447a05SGarrett D'Amore * pins.
336188447a05SGarrett D'Amore */
336288447a05SGarrett D'Amore widget = wpin;
336388447a05SGarrett D'Amore while (widget) {
336488447a05SGarrett D'Amore if (widget->outamp_cap &
336588447a05SGarrett D'Amore AUDIOHDC_AMP_CAP_MUTE_CAP) {
336688447a05SGarrett D'Amore pin->mute_wid = widget->wid_wid;
336788447a05SGarrett D'Amore pin->mute_dir = AUDIOHDC_AMP_SET_OUTPUT;
336888447a05SGarrett D'Amore break;
336988447a05SGarrett D'Amore }
337088447a05SGarrett D'Amore if (widget->inamp_cap &
337188447a05SGarrett D'Amore AUDIOHDC_AMP_CAP_MUTE_CAP) {
337288447a05SGarrett D'Amore pin->mute_wid = widget->wid_wid;
337388447a05SGarrett D'Amore pin->mute_dir = AUDIOHDC_AMP_SET_INPUT;
337488447a05SGarrett D'Amore break;
337588447a05SGarrett D'Amore }
3376b96a6eceSZhao Edgar Liu - Sun Microsystems next = widget->output_path_next;
3377b96a6eceSZhao Edgar Liu - Sun Microsystems if (next == AUDIOHD_NULL_CONN)
337888447a05SGarrett D'Amore break;
3379b96a6eceSZhao Edgar Liu - Sun Microsystems wid = widget->avail_conn[next];
338088447a05SGarrett D'Amore widget = codec->widget[wid];
338188447a05SGarrett D'Amore if (widget && widget->out_weight != weight)
338288447a05SGarrett D'Amore break;
338388447a05SGarrett D'Amore }
338488447a05SGarrett D'Amore
338588447a05SGarrett D'Amore /*
338688447a05SGarrett D'Amore * We select the wid which has maxium gain range in
338788447a05SGarrett D'Amore * the output path. Meanwhile, the gain controlling
338888447a05SGarrett D'Amore * of this node doesn't effect other pins if this
338988447a05SGarrett D'Amore * output stream has multiple pins.
339088447a05SGarrett D'Amore */
339188447a05SGarrett D'Amore gain = 0;
339288447a05SGarrett D'Amore widget = wpin;
339388447a05SGarrett D'Amore while (widget) {
339488447a05SGarrett D'Amore gain = (widget->outamp_cap &
339588447a05SGarrett D'Amore AUDIOHDC_AMP_CAP_STEP_NUMS);
339688447a05SGarrett D'Amore if (gain && gain > pin->gain_bits) {
339788447a05SGarrett D'Amore pin->gain_dir = AUDIOHDC_AMP_SET_OUTPUT;
339888447a05SGarrett D'Amore pin->gain_bits = gain;
339988447a05SGarrett D'Amore pin->gain_wid = widget->wid_wid;
340088447a05SGarrett D'Amore }
340188447a05SGarrett D'Amore gain = widget->inamp_cap &
340288447a05SGarrett D'Amore AUDIOHDC_AMP_CAP_STEP_NUMS;
340388447a05SGarrett D'Amore if (gain && gain > pin->gain_bits) {
340488447a05SGarrett D'Amore pin->gain_dir = AUDIOHDC_AMP_SET_INPUT;
340588447a05SGarrett D'Amore pin->gain_bits = gain;
340688447a05SGarrett D'Amore pin->gain_wid = widget->wid_wid;
340788447a05SGarrett D'Amore }
3408b96a6eceSZhao Edgar Liu - Sun Microsystems next = widget->output_path_next;
3409b96a6eceSZhao Edgar Liu - Sun Microsystems if (next == AUDIOHD_NULL_CONN)
341088447a05SGarrett D'Amore break;
3411b96a6eceSZhao Edgar Liu - Sun Microsystems wid = widget->avail_conn[next];
341288447a05SGarrett D'Amore widget = codec->widget[wid];
341388447a05SGarrett D'Amore if (widget && widget->out_weight != weight)
341488447a05SGarrett D'Amore break;
341588447a05SGarrett D'Amore }
341688447a05SGarrett D'Amore pin->gain_bits >>= AUDIOHD_GAIN_OFF;
341788447a05SGarrett D'Amore }
341888447a05SGarrett D'Amore
341988447a05SGarrett D'Amore /*
342088447a05SGarrett D'Amore * if this stream has multiple pins, we try to find
342188447a05SGarrett D'Amore * a mute & gain-controlling nodes which can effect
342288447a05SGarrett D'Amore * all output pins of this stream to be used for the
342388447a05SGarrett D'Amore * whole stream
342488447a05SGarrett D'Amore */
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;
343188447a05SGarrett D'Amore } else {
343288447a05SGarrett D'Amore wdac = codec->widget[path->adda_wid];
343388447a05SGarrett D'Amore weight = wdac->out_weight;
343488447a05SGarrett D'Amore wid = path->pin_wid[0];
343588447a05SGarrett D'Amore w = codec->widget[wid];
343688447a05SGarrett D'Amore while (w && w->out_weight != weight) {
3437b96a6eceSZhao Edgar Liu - Sun Microsystems wid = w->avail_conn[w->output_path_next];
343888447a05SGarrett D'Amore w = codec->widget[wid];
343988447a05SGarrett D'Amore }
344088447a05SGarrett D'Amore
344188447a05SGarrett D'Amore /* find mute controlling node for this stream */
344288447a05SGarrett D'Amore widget = w;
344388447a05SGarrett D'Amore while (widget) {
344488447a05SGarrett D'Amore if (widget->outamp_cap &
344588447a05SGarrett D'Amore AUDIOHDC_AMP_CAP_MUTE_CAP) {
344688447a05SGarrett D'Amore path->mute_wid = widget->wid_wid;
344788447a05SGarrett D'Amore path->mute_dir =
344888447a05SGarrett D'Amore AUDIOHDC_AMP_SET_OUTPUT;
344988447a05SGarrett D'Amore break;
345088447a05SGarrett D'Amore }
345188447a05SGarrett D'Amore if (widget->inamp_cap &
345288447a05SGarrett D'Amore AUDIOHDC_AMP_CAP_MUTE_CAP) {
345388447a05SGarrett D'Amore path->mute_wid = widget->wid_wid;
345488447a05SGarrett D'Amore path->mute_dir =
345588447a05SGarrett D'Amore AUDIOHDC_AMP_SET_INPUT;
345688447a05SGarrett D'Amore break;
345788447a05SGarrett D'Amore }
3458b96a6eceSZhao Edgar Liu - Sun Microsystems next = widget->output_path_next;
3459b96a6eceSZhao Edgar Liu - Sun Microsystems if (next == AUDIOHD_NULL_CONN)
346088447a05SGarrett D'Amore break;
3461b96a6eceSZhao Edgar Liu - Sun Microsystems wid = widget->avail_conn[next];
346288447a05SGarrett D'Amore widget = codec->widget[wid];
346388447a05SGarrett D'Amore }
346488447a05SGarrett D'Amore
346588447a05SGarrett D'Amore /* find volume controlling node for this stream */
346688447a05SGarrett D'Amore gain = 0;
346788447a05SGarrett D'Amore widget = w;
346888447a05SGarrett D'Amore while (widget) {
346988447a05SGarrett D'Amore gain = (widget->outamp_cap &
347088447a05SGarrett D'Amore AUDIOHDC_AMP_CAP_STEP_NUMS);
347188447a05SGarrett D'Amore if (gain && gain > pin->gain_bits) {
347288447a05SGarrett D'Amore path->gain_dir =
347388447a05SGarrett D'Amore AUDIOHDC_AMP_SET_OUTPUT;
347488447a05SGarrett D'Amore path->gain_bits = gain;
347588447a05SGarrett D'Amore path->gain_wid = widget->wid_wid;
347688447a05SGarrett D'Amore }
347788447a05SGarrett D'Amore gain = widget->inamp_cap &
347888447a05SGarrett D'Amore AUDIOHDC_AMP_CAP_STEP_NUMS;
347988447a05SGarrett D'Amore if (gain && (gain > pin->gain_bits) &&
348088447a05SGarrett D'Amore (widget->type != WTYPE_AUDIO_MIX)) {
348188447a05SGarrett D'Amore path->gain_dir =
348288447a05SGarrett D'Amore AUDIOHDC_AMP_SET_INPUT;
348388447a05SGarrett D'Amore path->gain_bits = gain;
348488447a05SGarrett D'Amore path->gain_wid = widget->wid_wid;
348588447a05SGarrett D'Amore }
3486b96a6eceSZhao Edgar Liu - Sun Microsystems next = widget->output_path_next;
3487b96a6eceSZhao Edgar Liu - Sun Microsystems if (next == AUDIOHD_NULL_CONN)
348888447a05SGarrett D'Amore break;
3489b96a6eceSZhao Edgar Liu - Sun Microsystems wid = widget->avail_conn[next];
349088447a05SGarrett D'Amore widget = codec->widget[wid];
349188447a05SGarrett D'Amore }
349288447a05SGarrett D'Amore path->gain_bits >>= AUDIOHD_GAIN_OFF;
349388447a05SGarrett D'Amore }
349488447a05SGarrett D'Amore
349588447a05SGarrett D'Amore }
349688447a05SGarrett D'Amore
349788447a05SGarrett D'Amore } /* audiohd_build_output_amp */
349888447a05SGarrett D'Amore
349988447a05SGarrett D'Amore /*
350088447a05SGarrett D'Amore * audiohd_finish_output_path()
350188447a05SGarrett D'Amore *
350288447a05SGarrett D'Amore * Description:
350388447a05SGarrett D'Amore * Enable the widgets on the output path
350488447a05SGarrett D'Amore */
350588447a05SGarrett D'Amore static void
audiohd_finish_output_path(hda_codec_t * codec)350688447a05SGarrett D'Amore audiohd_finish_output_path(hda_codec_t *codec)
350788447a05SGarrett D'Amore {
3508ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
350988447a05SGarrett D'Amore audiohd_path_t *path;
351088447a05SGarrett D'Amore audiohd_widget_t *widget;
351188447a05SGarrett D'Amore audiohd_pin_t *pin;
351288447a05SGarrett D'Amore uint_t caddr = codec->index;
3513b96a6eceSZhao Edgar Liu - Sun Microsystems wid_t wid, next;
351488447a05SGarrett D'Amore int i, j;
351588447a05SGarrett D'Amore
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];
352288447a05SGarrett D'Amore widget = codec->widget[wid];
352388447a05SGarrett D'Amore pin = (audiohd_pin_t *)widget->priv;
352488447a05SGarrett D'Amore {
352588447a05SGarrett D'Amore uint32_t lTmp;
352688447a05SGarrett D'Amore
352788447a05SGarrett D'Amore lTmp = audioha_codec_verb_get(statep, caddr, wid,
352888447a05SGarrett D'Amore AUDIOHDC_VERB_GET_PIN_CTRL, 0);
352988447a05SGarrett D'Amore (void) audioha_codec_verb_get(statep, caddr, wid,
353088447a05SGarrett D'Amore AUDIOHDC_VERB_SET_PIN_CTRL, (lTmp |
353188447a05SGarrett D'Amore pin->vrefvalue |
353288447a05SGarrett D'Amore AUDIOHDC_PIN_CONTROL_OUT_ENABLE |
353388447a05SGarrett D'Amore AUDIOHDC_PIN_CONTROL_HP_ENABLE) &
353488447a05SGarrett D'Amore ~ AUDIOHDC_PIN_CONTROL_IN_ENABLE);
353588447a05SGarrett D'Amore }
353688447a05SGarrett D'Amore /* If this pin has external amplifier, enable it */
353788447a05SGarrett D'Amore if (pin->cap & AUDIOHD_EXT_AMP_MASK)
353888447a05SGarrett D'Amore (void) audioha_codec_verb_get(statep, caddr,
353988447a05SGarrett D'Amore wid, AUDIOHDC_VERB_SET_EAPD,
354088447a05SGarrett D'Amore AUDIOHD_EXT_AMP_ENABLE);
354188447a05SGarrett D'Amore
354288447a05SGarrett D'Amore if (widget->outamp_cap) {
354388447a05SGarrett D'Amore (void) audioha_codec_4bit_verb_get(statep,
354488447a05SGarrett D'Amore caddr, wid, AUDIOHDC_VERB_SET_AMP_MUTE,
354588447a05SGarrett D'Amore AUDIOHDC_AMP_SET_LR_OUTPUT |
354688447a05SGarrett D'Amore AUDIOHDC_GAIN_MAX);
354788447a05SGarrett D'Amore }
354888447a05SGarrett D'Amore
354988447a05SGarrett D'Amore (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);
355288447a05SGarrett D'Amore
3553b96a6eceSZhao Edgar Liu - Sun Microsystems wid = widget->avail_conn[widget->output_path_next];
355488447a05SGarrett D'Amore widget = codec->widget[wid];
355588447a05SGarrett D'Amore
355688447a05SGarrett D'Amore while (widget) {
355788447a05SGarrett D'Amore /*
355888447a05SGarrett D'Amore * Set all amplifiers in this path to
3559b96a6eceSZhao Edgar Liu - Sun Microsystems * the maximum volume and unmute them.
356088447a05SGarrett D'Amore */
356188447a05SGarrett D'Amore if (widget->outamp_cap) {
356288447a05SGarrett D'Amore (void) audioha_codec_4bit_verb_get(
3563b96a6eceSZhao Edgar Liu - Sun Microsystems statep, caddr,
356488447a05SGarrett D'Amore wid, AUDIOHDC_VERB_SET_AMP_MUTE,
356588447a05SGarrett D'Amore AUDIOHDC_AMP_SET_LR_OUTPUT |
356688447a05SGarrett D'Amore AUDIOHDC_GAIN_MAX);
356788447a05SGarrett D'Amore }
356888447a05SGarrett D'Amore if (widget->inamp_cap) {
356988447a05SGarrett D'Amore (void) audioha_codec_4bit_verb_get(
3570b96a6eceSZhao Edgar Liu - Sun Microsystems statep, caddr,
357188447a05SGarrett D'Amore wid, AUDIOHDC_VERB_SET_AMP_MUTE,
357288447a05SGarrett D'Amore AUDIOHDC_AMP_SET_LR_INPUT |
357388447a05SGarrett D'Amore AUDIOHDC_GAIN_MAX |
3574b96a6eceSZhao Edgar Liu - Sun Microsystems (widget->output_path_next <<
357588447a05SGarrett D'Amore AUDIOHDC_AMP_SET_INDEX_OFFSET));
357688447a05SGarrett D'Amore }
357788447a05SGarrett D'Amore
3578b96a6eceSZhao Edgar Liu - Sun Microsystems next = widget->output_path_next;
3579b96a6eceSZhao Edgar Liu - Sun Microsystems if (next == AUDIOHD_NULL_CONN)
358088447a05SGarrett D'Amore break;
358188447a05SGarrett D'Amore /*
358288447a05SGarrett D'Amore * Accoding to HD spec, mixer doesn't support
358388447a05SGarrett D'Amore * "select connection"
358488447a05SGarrett D'Amore */
3585b96a6eceSZhao Edgar Liu - Sun Microsystems if ((widget->type == WTYPE_AUDIO_SEL) &&
358688447a05SGarrett D'Amore (widget->nconns > 1))
358788447a05SGarrett D'Amore (void) audioha_codec_verb_get(statep,
3588b96a6eceSZhao Edgar Liu - Sun Microsystems caddr, wid,
358988447a05SGarrett D'Amore AUDIOHDC_VERB_SET_CONN_SEL,
3590b96a6eceSZhao Edgar Liu - Sun Microsystems widget->output_path_next);
359188447a05SGarrett D'Amore
3592b96a6eceSZhao Edgar Liu - Sun Microsystems wid = widget->avail_conn[next];
359388447a05SGarrett D'Amore widget = codec->widget[wid];
359488447a05SGarrett D'Amore }
359588447a05SGarrett D'Amore }
359688447a05SGarrett D'Amore }
359788447a05SGarrett D'Amore } /* audiohd_finish_output_path() */
359888447a05SGarrett D'Amore
359988447a05SGarrett D'Amore /*
360088447a05SGarrett D'Amore * audiohd_find_input_pins()
360188447a05SGarrett D'Amore *
360288447a05SGarrett D'Amore * Description:
360388447a05SGarrett D'Amore * Here we consider a mixer/selector with multi-input as a real sum
360488447a05SGarrett D'Amore * widget. Only the first real mixer/selector widget is permitted in
360588447a05SGarrett D'Amore * an input path(recording path). If there are more mixers/selectors
360688447a05SGarrett D'Amore * execept the first one, only the first input/connection of those
360788447a05SGarrett D'Amore * widgets will be used by our driver, that means, we ignore other
360888447a05SGarrett D'Amore * inputs of those mixers/selectors.
360988447a05SGarrett D'Amore */
361088447a05SGarrett D'Amore static int
audiohd_find_input_pins(hda_codec_t * codec,wid_t wid,int allowmixer,int depth,audiohd_path_t * path)361188447a05SGarrett D'Amore audiohd_find_input_pins(hda_codec_t *codec, wid_t wid, int allowmixer,
361288447a05SGarrett D'Amore int depth, audiohd_path_t *path)
361388447a05SGarrett D'Amore {
361488447a05SGarrett D'Amore audiohd_widget_t *widget = codec->widget[wid];
361588447a05SGarrett D'Amore audiohd_pin_t *pin;
3616ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
361788447a05SGarrett D'Amore uint_t caddr = codec->index;
361888447a05SGarrett D'Amore int retval = -1;
361988447a05SGarrett D'Amore int num, i;
362088447a05SGarrett D'Amore uint32_t pinctrl;
362188447a05SGarrett D'Amore
362288447a05SGarrett D'Amore if (depth > AUDIOHD_MAX_DEPTH)
3623c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
362488447a05SGarrett D'Amore if (widget == NULL)
3625c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
362688447a05SGarrett D'Amore
362788447a05SGarrett D'Amore /* 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);
363188447a05SGarrett D'Amore
363288447a05SGarrett D'Amore switch (widget->type) {
363388447a05SGarrett D'Amore case WTYPE_PIN:
363488447a05SGarrett D'Amore pin = (audiohd_pin_t *)widget->priv;
363588447a05SGarrett D'Amore if (pin->no_phys_conn)
3636c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
363788447a05SGarrett D'Amore /* enable the pins' input capability */
363888447a05SGarrett D'Amore pinctrl = audioha_codec_verb_get(statep, caddr, wid,
363988447a05SGarrett D'Amore AUDIOHDC_VERB_GET_PIN_CTRL, 0);
364088447a05SGarrett D'Amore (void) audioha_codec_verb_get(statep, caddr, wid,
364188447a05SGarrett D'Amore AUDIOHDC_VERB_SET_PIN_CTRL,
364288447a05SGarrett D'Amore pinctrl | AUDIOHD_PIN_IN_ENABLE);
364388447a05SGarrett D'Amore if (pin->cap & AUDIOHD_EXT_AMP_MASK) {
364488447a05SGarrett D'Amore (void) audioha_codec_verb_get(statep, caddr,
364588447a05SGarrett D'Amore wid, AUDIOHDC_VERB_SET_EAPD,
364688447a05SGarrett D'Amore AUDIOHD_EXT_AMP_ENABLE);
364788447a05SGarrett D'Amore }
364888447a05SGarrett D'Amore switch (pin->device) {
364988447a05SGarrett D'Amore case DTYPE_CD:
365088447a05SGarrett D'Amore case DTYPE_LINE_IN:
365188447a05SGarrett D'Amore case DTYPE_MIC_IN:
365288447a05SGarrett D'Amore case DTYPE_AUX:
365388447a05SGarrett D'Amore widget->path_flags |= AUDIOHD_PATH_ADC;
365488447a05SGarrett D'Amore 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);
365888447a05SGarrett D'Amore }
365988447a05SGarrett D'Amore break;
366088447a05SGarrett D'Amore case WTYPE_AUDIO_MIX:
366188447a05SGarrett D'Amore case WTYPE_AUDIO_SEL:
366288447a05SGarrett D'Amore /*
366388447a05SGarrett D'Amore * If the sum widget has only one input, we don't
366488447a05SGarrett D'Amore * consider it as a real sum widget.
366588447a05SGarrett D'Amore */
366688447a05SGarrett D'Amore if (widget->nconns == 1) {
3667b96a6eceSZhao Edgar Liu - Sun Microsystems widget->input_path_next = 0;
366888447a05SGarrett D'Amore retval = audiohd_find_input_pins(codec,
366988447a05SGarrett D'Amore widget->avail_conn[0],
367088447a05SGarrett D'Amore allowmixer, depth + 1, path);
3671b96a6eceSZhao Edgar Liu - Sun Microsystems if (retval == DDI_SUCCESS) {
367288447a05SGarrett D'Amore widget->path_flags |= AUDIOHD_PATH_ADC;
367388447a05SGarrett D'Amore widget->in_weight++;
367488447a05SGarrett D'Amore }
367588447a05SGarrett D'Amore break;
367688447a05SGarrett D'Amore }
367788447a05SGarrett D'Amore
367888447a05SGarrett D'Amore if (allowmixer) {
367988447a05SGarrett D'Amore /*
368088447a05SGarrett D'Amore * This is a real sum widget, we will reject
368188447a05SGarrett D'Amore * other real sum widget when we find more in
368288447a05SGarrett D'Amore * the following path-searching.
368388447a05SGarrett D'Amore */
368488447a05SGarrett D'Amore for (int i = 0; i < widget->nconns; i++) {
368588447a05SGarrett D'Amore retval = audiohd_find_input_pins(codec,
368688447a05SGarrett D'Amore 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;
369088447a05SGarrett D'Amore 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;
369488447a05SGarrett D'Amore widget->path_flags |=
369588447a05SGarrett D'Amore AUDIOHD_PATH_ADC;
369688447a05SGarrett D'Amore }
369788447a05SGarrett D'Amore }
369888447a05SGarrett D'Amore
369988447a05SGarrett D'Amore /* 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;
370288447a05SGarrett D'Amore } else {
370388447a05SGarrett D'Amore /*
370488447a05SGarrett D'Amore * We had already found a real sum before this one since
370588447a05SGarrett D'Amore * allowmixer is 0.
370688447a05SGarrett D'Amore */
370788447a05SGarrett D'Amore for (i = 0; i < widget->nconns; i++) {
370888447a05SGarrett D'Amore retval = audiohd_find_input_pins(codec,
370988447a05SGarrett D'Amore 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;
371388447a05SGarrett D'Amore widget->path_flags |= AUDIOHD_PATH_ADC;
371488447a05SGarrett D'Amore widget->in_weight++;
371588447a05SGarrett D'Amore break;
371688447a05SGarrett D'Amore }
371788447a05SGarrett D'Amore }
371888447a05SGarrett D'Amore }
371988447a05SGarrett D'Amore break;
372088447a05SGarrett D'Amore default:
372188447a05SGarrett D'Amore break;
372288447a05SGarrett D'Amore }
372388447a05SGarrett D'Amore
372488447a05SGarrett D'Amore return (retval);
372588447a05SGarrett D'Amore } /* audiohd_find_input_pins */
372688447a05SGarrett D'Amore
372788447a05SGarrett D'Amore /*
372888447a05SGarrett D'Amore * audiohd_build_input_path()
372988447a05SGarrett D'Amore *
373088447a05SGarrett D'Amore * Description:
373188447a05SGarrett D'Amore * Find input path for the codec
373288447a05SGarrett D'Amore */
373388447a05SGarrett D'Amore static void
audiohd_build_input_path(hda_codec_t * codec)373488447a05SGarrett D'Amore audiohd_build_input_path(hda_codec_t *codec)
373588447a05SGarrett D'Amore {
373688447a05SGarrett D'Amore audiohd_widget_t *widget;
373788447a05SGarrett D'Amore audiohd_path_t *path = NULL;
373888447a05SGarrett D'Amore wid_t wid;
373988447a05SGarrett D'Amore int i;
374088447a05SGarrett D'Amore int retval;
374188447a05SGarrett D'Amore uint8_t rtag = 0;
3742ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
374388447a05SGarrett D'Amore
374488447a05SGarrett D'Amore for (wid = codec->first_wid; wid <= codec->last_wid; wid++) {
374588447a05SGarrett D'Amore
374688447a05SGarrett D'Amore widget = codec->widget[wid];
374788447a05SGarrett D'Amore
374888447a05SGarrett D'Amore /* check if it is an ADC widget */
3749b96a6eceSZhao Edgar Liu - Sun Microsystems if (widget == NULL || widget->type != WTYPE_AUDIO_IN)
375088447a05SGarrett D'Amore continue;
375188447a05SGarrett D'Amore
375288447a05SGarrett D'Amore if (path == NULL)
375388447a05SGarrett D'Amore path = kmem_zalloc(sizeof (audiohd_path_t),
375488447a05SGarrett D'Amore KM_SLEEP);
375588447a05SGarrett D'Amore else
375688447a05SGarrett D'Amore bzero(path, sizeof (audiohd_port_t));
375788447a05SGarrett D'Amore
375888447a05SGarrett D'Amore path->adda_wid = wid;
375988447a05SGarrett D'Amore
376088447a05SGarrett D'Amore /*
376188447a05SGarrett D'Amore * Is there any ADC widget which has more than one input ??
376288447a05SGarrett D'Amore * I don't believe. Anyway, we carefully deal with this. But
376388447a05SGarrett D'Amore * if hardware vendors embed a selector in a ADC, we just use
376488447a05SGarrett D'Amore * the first available input, which has connection to input pin
376588447a05SGarrett D'Amore * widget. Because selector cannot perform mixer functionality,
376688447a05SGarrett D'Amore * and we just permit one selector or mixer in a recording path,
376788447a05SGarrett D'Amore * if we use the selector embedded in ADC,we cannot use possible
376888447a05SGarrett D'Amore * mixer during path searching.
376988447a05SGarrett D'Amore */
377088447a05SGarrett D'Amore for (i = 0; i < widget->nconns; i++) {
377188447a05SGarrett D'Amore 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;
377888447a05SGarrett D'Amore 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;
378388447a05SGarrett D'Amore break;
378488447a05SGarrett D'Amore }
378588447a05SGarrett D'Amore }
378688447a05SGarrett D'Amore }
378788447a05SGarrett D'Amore if (path)
378888447a05SGarrett D'Amore kmem_free(path, sizeof (audiohd_path_t));
378988447a05SGarrett D'Amore } /* audiohd_build_input_path */
379088447a05SGarrett D'Amore
379188447a05SGarrett D'Amore /*
379288447a05SGarrett D'Amore * audiohd_build_input_amp()
379388447a05SGarrett D'Amore *
379488447a05SGarrett D'Amore * Description:
379588447a05SGarrett D'Amore * Find gain and mute control widgets on the input path
379688447a05SGarrett D'Amore */
379788447a05SGarrett D'Amore static void
audiohd_build_input_amp(hda_codec_t * codec)379888447a05SGarrett D'Amore audiohd_build_input_amp(hda_codec_t *codec)
379988447a05SGarrett D'Amore {
380088447a05SGarrett D'Amore audiohd_path_t *path;
380188447a05SGarrett D'Amore audiohd_widget_t *wsum, *wadc, *w;
380288447a05SGarrett D'Amore audiohd_pin_t *pin;
380388447a05SGarrett D'Amore uint_t gain;
3804b96a6eceSZhao Edgar Liu - Sun Microsystems wid_t wid, next;
380588447a05SGarrett D'Amore int i, j;
380688447a05SGarrett D'Amore int weight;
380788447a05SGarrett D'Amore
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];
381688447a05SGarrett D'Amore weight = wadc->in_weight;
381788447a05SGarrett D'Amore
381888447a05SGarrett D'Amore /*
381988447a05SGarrett D'Amore * Search node which has mute functionality for
382088447a05SGarrett D'Amore * the whole input path
382188447a05SGarrett D'Amore */
382288447a05SGarrett D'Amore w = wadc;
382388447a05SGarrett D'Amore while (w) {
382488447a05SGarrett D'Amore 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;
382788447a05SGarrett D'Amore break;
382888447a05SGarrett D'Amore }
382988447a05SGarrett D'Amore 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;
383388447a05SGarrett D'Amore break;
383488447a05SGarrett D'Amore }
383588447a05SGarrett D'Amore
3836b96a6eceSZhao Edgar Liu - Sun Microsystems next = w->input_path_next;
3837b96a6eceSZhao Edgar Liu - Sun Microsystems if (next == AUDIOHD_NULL_CONN)
383888447a05SGarrett D'Amore break;
3839b96a6eceSZhao Edgar Liu - Sun Microsystems wid = w->avail_conn[next];
384088447a05SGarrett D'Amore w = path->codec->widget[wid];
384188447a05SGarrett D'Amore if (w && w->in_weight != weight)
384288447a05SGarrett D'Amore break;
384388447a05SGarrett D'Amore }
384488447a05SGarrett D'Amore
384588447a05SGarrett D'Amore /*
384688447a05SGarrett D'Amore * Search a node for amplifier adjusting for the whole
384788447a05SGarrett D'Amore * input path
384888447a05SGarrett D'Amore */
384988447a05SGarrett D'Amore w = wadc;
385088447a05SGarrett D'Amore gain = 0;
385188447a05SGarrett D'Amore while (w) {
385288447a05SGarrett D'Amore 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;
385788447a05SGarrett D'Amore }
385888447a05SGarrett D'Amore 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;
386488447a05SGarrett D'Amore }
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)
386888447a05SGarrett D'Amore break;
3869b96a6eceSZhao Edgar Liu - Sun Microsystems wid = w->avail_conn[next];
387088447a05SGarrett D'Amore w = path->codec->widget[wid];
387188447a05SGarrett D'Amore }
387288447a05SGarrett D'Amore path->gain_bits >>= AUDIOHD_GAIN_OFF;
387388447a05SGarrett D'Amore
387488447a05SGarrett D'Amore /*
387588447a05SGarrett D'Amore * If the input path has one pin only, the mute/amp
387688447a05SGarrett D'Amore * controlling is shared by the whole path and pin
387788447a05SGarrett D'Amore */
387888447a05SGarrett D'Amore if (path->pin_nums == 1) {
387988447a05SGarrett D'Amore wid = path->pin_wid[0];
388088447a05SGarrett D'Amore w = path->codec->widget[wid];
388188447a05SGarrett D'Amore 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;
388788447a05SGarrett D'Amore continue;
388888447a05SGarrett D'Amore }
388988447a05SGarrett D'Amore
389088447a05SGarrett D'Amore /*
389188447a05SGarrett D'Amore * For multi-pin device, there must be a selector
389288447a05SGarrett D'Amore * or mixer along the input path, and the sum_wid
389388447a05SGarrett D'Amore * is the widget's node id.
389488447a05SGarrett D'Amore */
389588447a05SGarrett D'Amore wid = path->sum_wid;
389688447a05SGarrett D'Amore wsum = path->codec->widget[wid]; /* sum widget */
389788447a05SGarrett D'Amore
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];
390188447a05SGarrett D'Amore pin = (audiohd_pin_t *)w->priv;
390288447a05SGarrett D'Amore
390388447a05SGarrett D'Amore /* find node for mute */
390488447a05SGarrett D'Amore if (wsum->inamp_cap & AUDIOHDC_AMP_CAP_MUTE_CAP) {
390588447a05SGarrett D'Amore pin->mute_wid = wsum->wid_wid;
390688447a05SGarrett D'Amore pin->mute_dir = AUDIOHDC_AMP_SET_INPUT;
390788447a05SGarrett D'Amore } else {
390888447a05SGarrett D'Amore wid = wsum->avail_conn[path->sum_selconn[i]];
390988447a05SGarrett D'Amore w = path->codec->widget[wid];
391088447a05SGarrett D'Amore while (w) {
391188447a05SGarrett D'Amore if (w->outamp_cap &
391288447a05SGarrett D'Amore AUDIOHDC_AMP_CAP_MUTE_CAP) {
391388447a05SGarrett D'Amore pin->mute_wid = w->wid_wid;
391488447a05SGarrett D'Amore pin->mute_dir =
391588447a05SGarrett D'Amore AUDIOHDC_AMP_SET_OUTPUT;
391688447a05SGarrett D'Amore break;
391788447a05SGarrett D'Amore }
391888447a05SGarrett D'Amore if (w->inamp_cap &
391988447a05SGarrett D'Amore AUDIOHDC_AMP_CAP_MUTE_CAP) {
392088447a05SGarrett D'Amore pin->mute_wid = w->wid_wid;
392188447a05SGarrett D'Amore pin->mute_dir =
392288447a05SGarrett D'Amore AUDIOHDC_AMP_SET_INPUT;
392388447a05SGarrett D'Amore break;
392488447a05SGarrett D'Amore }
392588447a05SGarrett D'Amore
3926b96a6eceSZhao Edgar Liu - Sun Microsystems next = w->input_path_next;
3927b96a6eceSZhao Edgar Liu - Sun Microsystems if (next == AUDIOHD_NULL_CONN)
392888447a05SGarrett D'Amore break;
3929b96a6eceSZhao Edgar Liu - Sun Microsystems wid = w->avail_conn[next];
393088447a05SGarrett D'Amore w = path->codec->widget[wid];
393188447a05SGarrett D'Amore }
393288447a05SGarrett D'Amore }
393388447a05SGarrett D'Amore
393488447a05SGarrett D'Amore /* find node for amp controlling */
393588447a05SGarrett D'Amore 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];
393888447a05SGarrett D'Amore while (w) {
393988447a05SGarrett D'Amore gain = (w->outamp_cap &
394088447a05SGarrett D'Amore AUDIOHDC_AMP_CAP_STEP_NUMS);
394188447a05SGarrett D'Amore if (gain && gain > pin->gain_bits) {
394288447a05SGarrett D'Amore pin->gain_dir = AUDIOHDC_AMP_SET_OUTPUT;
394388447a05SGarrett D'Amore pin->gain_bits = gain;
394488447a05SGarrett D'Amore pin->gain_wid = w->wid_wid;
394588447a05SGarrett D'Amore }
394688447a05SGarrett D'Amore gain = w->inamp_cap &
394788447a05SGarrett D'Amore AUDIOHDC_AMP_CAP_STEP_NUMS;
394888447a05SGarrett D'Amore if (gain && (gain > pin->gain_bits)) {
394988447a05SGarrett D'Amore pin->gain_dir = AUDIOHDC_AMP_SET_INPUT;
395088447a05SGarrett D'Amore pin->gain_bits = gain;
395188447a05SGarrett D'Amore pin->gain_wid = w->wid_wid;
395288447a05SGarrett D'Amore }
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)
395688447a05SGarrett D'Amore break;
3957b96a6eceSZhao Edgar Liu - Sun Microsystems wid = w->avail_conn[next];
395888447a05SGarrett D'Amore w = path->codec->widget[wid];
395988447a05SGarrett D'Amore }
396088447a05SGarrett D'Amore pin->gain_bits >>= AUDIOHD_GAIN_OFF;
396188447a05SGarrett D'Amore }
396288447a05SGarrett D'Amore }
396388447a05SGarrett D'Amore } /* audiohd_build_input_amp() */
396488447a05SGarrett D'Amore
396588447a05SGarrett D'Amore /*
396688447a05SGarrett D'Amore * audiohd_finish_input_path()
396788447a05SGarrett D'Amore *
396888447a05SGarrett D'Amore * Description:
396988447a05SGarrett D'Amore * Enable the widgets on the input path
397088447a05SGarrett D'Amore */
397188447a05SGarrett D'Amore static void
audiohd_finish_input_path(hda_codec_t * codec)397288447a05SGarrett D'Amore audiohd_finish_input_path(hda_codec_t *codec)
397388447a05SGarrett D'Amore {
3974ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
397588447a05SGarrett D'Amore audiohd_path_t *path;
397688447a05SGarrett D'Amore audiohd_widget_t *w, *wsum;
397788447a05SGarrett D'Amore uint_t caddr = codec->index;
397888447a05SGarrett D'Amore wid_t wid;
397988447a05SGarrett D'Amore int i, j;
398088447a05SGarrett D'Amore
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) &&
398988447a05SGarrett D'Amore (w->type != WTYPE_PIN)) {
399088447a05SGarrett D'Amore if ((w->type == WTYPE_AUDIO_SEL) && (w->nconns > 1))
399188447a05SGarrett D'Amore (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);
399488447a05SGarrett D'Amore
399588447a05SGarrett D'Amore if (w->outamp_cap) {
399688447a05SGarrett D'Amore (void) audioha_codec_4bit_verb_get(statep,
399788447a05SGarrett D'Amore caddr,
399888447a05SGarrett D'Amore w->wid_wid, AUDIOHDC_VERB_SET_AMP_MUTE,
399988447a05SGarrett D'Amore AUDIOHDC_AMP_SET_LR_OUTPUT |
400088447a05SGarrett D'Amore AUDIOHDC_GAIN_MAX);
400188447a05SGarrett D'Amore }
400288447a05SGarrett D'Amore
400388447a05SGarrett D'Amore if (w->inamp_cap) {
400488447a05SGarrett D'Amore (void) audioha_codec_4bit_verb_get(statep,
400588447a05SGarrett D'Amore caddr,
400688447a05SGarrett D'Amore w->wid_wid, AUDIOHDC_VERB_SET_AMP_MUTE,
400788447a05SGarrett D'Amore AUDIOHDC_AMP_SET_LR_INPUT |
400888447a05SGarrett D'Amore AUDIOHDC_GAIN_MAX |
4009b96a6eceSZhao Edgar Liu - Sun Microsystems (w->input_path_next <<
401088447a05SGarrett D'Amore AUDIOHDC_AMP_SET_INDEX_OFFSET));
401188447a05SGarrett D'Amore }
401288447a05SGarrett D'Amore
4013b96a6eceSZhao Edgar Liu - Sun Microsystems wid = w->avail_conn[w->input_path_next];
401488447a05SGarrett D'Amore w = path->codec->widget[wid];
401588447a05SGarrett D'Amore }
401688447a05SGarrett D'Amore
401788447a05SGarrett D'Amore /*
401888447a05SGarrett D'Amore * After exiting from the above loop, the widget pointed
401988447a05SGarrett D'Amore * by w can be a pin widget or select/mixer widget. If it
402088447a05SGarrett D'Amore * is a pin widget, we already finish "select connection"
402188447a05SGarrett D'Amore * operation for the whole path.
402288447a05SGarrett D'Amore */
402388447a05SGarrett D'Amore if (w && w->type == WTYPE_PIN)
402488447a05SGarrett D'Amore continue;
402588447a05SGarrett D'Amore
402688447a05SGarrett D'Amore /*
402788447a05SGarrett D'Amore * deal with multi-pin input devices.
402888447a05SGarrett D'Amore */
402988447a05SGarrett D'Amore wid = path->sum_wid;
403088447a05SGarrett D'Amore wsum = path->codec->widget[wid];
403188447a05SGarrett D'Amore if (wsum == NULL)
403288447a05SGarrett D'Amore continue;
403388447a05SGarrett D'Amore if (wsum->outamp_cap) {
403488447a05SGarrett D'Amore (void) audioha_codec_4bit_verb_get(statep,
403588447a05SGarrett D'Amore caddr,
403688447a05SGarrett D'Amore wsum->wid_wid, AUDIOHDC_VERB_SET_AMP_MUTE,
403788447a05SGarrett D'Amore AUDIOHDC_AMP_SET_LR_OUTPUT |
403888447a05SGarrett D'Amore AUDIOHDC_GAIN_MAX);
403988447a05SGarrett D'Amore }
404088447a05SGarrett D'Amore
404188447a05SGarrett D'Amore for (j = 0; j < path->pin_nums; j++) {
404288447a05SGarrett D'Amore if (wsum->inamp_cap) {
404388447a05SGarrett D'Amore (void) audioha_codec_4bit_verb_get(statep,
404488447a05SGarrett D'Amore caddr,
404588447a05SGarrett D'Amore wsum->wid_wid, AUDIOHDC_VERB_SET_AMP_MUTE,
404688447a05SGarrett D'Amore AUDIOHDC_AMP_SET_LR_INPUT |
404788447a05SGarrett D'Amore AUDIOHDC_GAIN_MAX |
404888447a05SGarrett D'Amore (path->sum_selconn[j] <<
404988447a05SGarrett D'Amore AUDIOHDC_AMP_SET_INDEX_OFFSET));
405088447a05SGarrett D'Amore }
405188447a05SGarrett D'Amore if (wsum->type == WTYPE_AUDIO_SEL) {
405288447a05SGarrett D'Amore (void) audioha_codec_verb_get(statep, caddr,
405388447a05SGarrett D'Amore wsum->wid_wid,
405488447a05SGarrett D'Amore AUDIOHDC_VERB_SET_CONN_SEL,
405588447a05SGarrett D'Amore path->sum_selconn[j]);
405688447a05SGarrett D'Amore }
405788447a05SGarrett D'Amore
405888447a05SGarrett D'Amore wid = wsum->avail_conn[path->sum_selconn[j]];
405988447a05SGarrett D'Amore w = path->codec->widget[wid];
406088447a05SGarrett D'Amore while (w && w->type != WTYPE_PIN) {
406188447a05SGarrett D'Amore if ((w->type != WTYPE_AUDIO_MIX) &&
406288447a05SGarrett D'Amore (w->nconns > 1))
406388447a05SGarrett D'Amore (void) audioha_codec_verb_get(statep,
406488447a05SGarrett D'Amore caddr, w->wid_wid,
406588447a05SGarrett D'Amore AUDIOHDC_VERB_SET_CONN_SEL,
4066b96a6eceSZhao Edgar Liu - Sun Microsystems w->input_path_next);
406788447a05SGarrett D'Amore
406888447a05SGarrett D'Amore if (w->outamp_cap) {
406988447a05SGarrett D'Amore (void) audioha_codec_4bit_verb_get(
407088447a05SGarrett D'Amore statep,
407188447a05SGarrett D'Amore caddr,
407288447a05SGarrett D'Amore w->wid_wid,
407388447a05SGarrett D'Amore AUDIOHDC_VERB_SET_AMP_MUTE,
407488447a05SGarrett D'Amore AUDIOHDC_AMP_SET_LR_OUTPUT |
407588447a05SGarrett D'Amore AUDIOHDC_GAIN_MAX);
407688447a05SGarrett D'Amore }
407788447a05SGarrett D'Amore
407888447a05SGarrett D'Amore if (w->inamp_cap) {
407988447a05SGarrett D'Amore (void) audioha_codec_4bit_verb_get(
408088447a05SGarrett D'Amore statep,
408188447a05SGarrett D'Amore caddr,
408288447a05SGarrett D'Amore w->wid_wid,
408388447a05SGarrett D'Amore AUDIOHDC_VERB_SET_AMP_MUTE,
408488447a05SGarrett D'Amore AUDIOHDC_AMP_SET_LR_INPUT |
408588447a05SGarrett D'Amore AUDIOHDC_GAIN_MAX |
4086b96a6eceSZhao Edgar Liu - Sun Microsystems (w->input_path_next <<
408788447a05SGarrett D'Amore AUDIOHDC_AMP_SET_INDEX_OFFSET));
408888447a05SGarrett D'Amore }
4089b96a6eceSZhao Edgar Liu - Sun Microsystems wid = w->avail_conn[w->input_path_next];
409088447a05SGarrett D'Amore w = path->codec->widget[wid];
409188447a05SGarrett D'Amore }
409288447a05SGarrett D'Amore }
409388447a05SGarrett D'Amore } /* end of istream loop */
409488447a05SGarrett D'Amore } /* audiohd_finish_input_path */
409588447a05SGarrett D'Amore
409688447a05SGarrett D'Amore /*
409788447a05SGarrett D'Amore * audiohd_find_inpin_for_monitor()
409888447a05SGarrett D'Amore *
409988447a05SGarrett D'Amore * Description:
410088447a05SGarrett D'Amore * Find input pin for monitor path.
410188447a05SGarrett D'Amore *
410288447a05SGarrett D'Amore * Arguments:
410388447a05SGarrett D'Amore * hda_codec_t *codec where the monitor path exists
410488447a05SGarrett D'Amore * wid_t id no. of widget being searched
410588447a05SGarrett D'Amore * int mixer share or not
410688447a05SGarrett D'Amore */
410788447a05SGarrett D'Amore 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)
410988447a05SGarrett D'Amore {
411088447a05SGarrett D'Amore wid_t wid;
4111b96a6eceSZhao Edgar Liu - Sun Microsystems audiohd_widget_t *widget, *w;
411288447a05SGarrett D'Amore audiohd_pin_t *pin;
411388447a05SGarrett D'Amore int i, find = 0;
411488447a05SGarrett D'Amore
411588447a05SGarrett D'Amore wid = id;
411688447a05SGarrett D'Amore widget = codec->widget[wid];
411788447a05SGarrett D'Amore if (widget == NULL)
4118c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
411988447a05SGarrett D'Amore
412088447a05SGarrett D'Amore if (widget->type == WTYPE_PIN) {
412188447a05SGarrett D'Amore pin = (audiohd_pin_t *)widget->priv;
412288447a05SGarrett D'Amore if (pin->no_phys_conn)
4123c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
412488447a05SGarrett D'Amore switch (pin->device) {
412588447a05SGarrett D'Amore case DTYPE_SPDIF_IN:
412688447a05SGarrett D'Amore case DTYPE_CD:
412788447a05SGarrett D'Amore case DTYPE_LINE_IN:
412888447a05SGarrett D'Amore case DTYPE_MIC_IN:
412988447a05SGarrett D'Amore case DTYPE_AUX:
413088447a05SGarrett D'Amore widget->path_flags |= AUDIOHD_PATH_MON;
4131c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
413288447a05SGarrett D'Amore default:
4133c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
413488447a05SGarrett D'Amore }
413588447a05SGarrett D'Amore }
413688447a05SGarrett D'Amore /* the widget has been visited and can't be directed to input pin */
413788447a05SGarrett D'Amore if (widget->path_flags & AUDIOHD_PATH_NOMON) {
4138c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
413988447a05SGarrett D'Amore }
414088447a05SGarrett D'Amore /* the widget has been used by the monitor path, and we can share it */
414188447a05SGarrett D'Amore if (widget->path_flags & AUDIOHD_PATH_MON) {
414288447a05SGarrett D'Amore if (mixer)
4143c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
414488447a05SGarrett D'Amore else
4145c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
414688447a05SGarrett D'Amore }
414788447a05SGarrett D'Amore switch (widget->type) {
414888447a05SGarrett D'Amore case WTYPE_AUDIO_MIX:
414988447a05SGarrett D'Amore for (i = 0; i < widget->nconns; i++) {
4150b96a6eceSZhao Edgar Liu - Sun Microsystems if (widget->output_path_next == i)
415188447a05SGarrett D'Amore continue;
415288447a05SGarrett D'Amore if (audiohd_find_inpin_for_monitor(codec,
415388447a05SGarrett D'Amore 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;
415888447a05SGarrett D'Amore find = 1;
415988447a05SGarrett D'Amore }
416088447a05SGarrett D'Amore }
416188447a05SGarrett D'Amore break;
416288447a05SGarrett D'Amore case WTYPE_AUDIO_SEL:
416388447a05SGarrett D'Amore for (i = 0; i < widget->nconns; i++) {
4164b96a6eceSZhao Edgar Liu - Sun Microsystems if (widget->output_path_next == i)
416588447a05SGarrett D'Amore continue;
416688447a05SGarrett D'Amore 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;
417088447a05SGarrett D'Amore widget->path_flags |= AUDIOHD_PATH_MON;
4171b96a6eceSZhao Edgar Liu - Sun Microsystems find = 1;
4172b96a6eceSZhao Edgar Liu - Sun Microsystems break;
417388447a05SGarrett D'Amore }
417488447a05SGarrett D'Amore }
4175b96a6eceSZhao Edgar Liu - Sun Microsystems break;
417688447a05SGarrett D'Amore default:
417788447a05SGarrett D'Amore break;
417888447a05SGarrett D'Amore }
417988447a05SGarrett D'Amore if (!find) {
418088447a05SGarrett D'Amore widget->path_flags |= AUDIOHD_PATH_NOMON;
4181c6e681c0SYang-Rong Jerry Zhou return (uint32_t)(DDI_FAILURE);
418288447a05SGarrett D'Amore }
418388447a05SGarrett D'Amore else
4184c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
418588447a05SGarrett D'Amore } /* audiohd_find_inpin_for_monitor */
418688447a05SGarrett D'Amore
418788447a05SGarrett D'Amore /*
418888447a05SGarrett D'Amore * audiohd_build_monitor_path()
418988447a05SGarrett D'Amore *
419088447a05SGarrett D'Amore * Description:
419188447a05SGarrett D'Amore * The functionality of mixer is to mix inputs, such as CD-IN, MIC,
419288447a05SGarrett D'Amore * Line-in, etc, with DAC outputs, so as to minitor what is being
419388447a05SGarrett D'Amore * recorded and implement "What you hear is what you get". However,
419488447a05SGarrett D'Amore * this functionality are really hardware-dependent: the inputs
419588447a05SGarrett D'Amore * must be directed to MIXER if they can be directed to ADC as
419688447a05SGarrett D'Amore * recording sources.
419788447a05SGarrett D'Amore */
419888447a05SGarrett D'Amore static void
audiohd_build_monitor_path(hda_codec_t * codec)419988447a05SGarrett D'Amore audiohd_build_monitor_path(hda_codec_t *codec)
420088447a05SGarrett D'Amore {
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;
420788447a05SGarrett D'Amore
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 }
422788447a05SGarrett D'Amore
422888447a05SGarrett D'Amore /*
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.
423288447a05SGarrett D'Amore */
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 }
427488447a05SGarrett D'Amore
427588447a05SGarrett D'Amore }
427688447a05SGarrett D'Amore
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++;
429188447a05SGarrett D'Amore }
429288447a05SGarrett D'Amore path->maxmixer[j] = l;
429388447a05SGarrett D'Amore }
429488447a05SGarrett D'Amore
429588447a05SGarrett D'Amore }
429688447a05SGarrett D'Amore 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;
430088447a05SGarrett D'Amore } /* audiohd_build_monitor_path */
430188447a05SGarrett D'Amore
430288447a05SGarrett D'Amore /*
430388447a05SGarrett D'Amore * audiohd_do_finish_monitor_path
430488447a05SGarrett D'Amore *
430588447a05SGarrett D'Amore * Description:
430688447a05SGarrett D'Amore * Enable the widgets on the monitor path
430788447a05SGarrett D'Amore */
430888447a05SGarrett D'Amore static void
audiohd_do_finish_monitor_path(hda_codec_t * codec,audiohd_widget_t * wgt)430988447a05SGarrett D'Amore audiohd_do_finish_monitor_path(hda_codec_t *codec, audiohd_widget_t *wgt)
431088447a05SGarrett D'Amore {
431188447a05SGarrett D'Amore uint_t caddr = codec->index;
431288447a05SGarrett D'Amore audiohd_widget_t *widget = wgt;
431388447a05SGarrett D'Amore audiohd_widget_t *w;
4314ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
431588447a05SGarrett D'Amore wid_t wid;
431688447a05SGarrett D'Amore int i;
431788447a05SGarrett D'Amore int share = 0;
431888447a05SGarrett D'Amore
431988447a05SGarrett D'Amore if (!widget || widget->finish)
432088447a05SGarrett D'Amore return;
432188447a05SGarrett D'Amore if (widget->path_flags & AUDIOHD_PATH_ADC)
432288447a05SGarrett D'Amore share = 1;
432388447a05SGarrett D'Amore if ((widget->outamp_cap) && !share)
432488447a05SGarrett D'Amore (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);
432788447a05SGarrett D'Amore if ((widget->inamp_cap) && !share) {
432888447a05SGarrett D'Amore for (i = 0; i < widget->used; i++) {
432988447a05SGarrett D'Amore (void) audioha_codec_4bit_verb_get(statep, caddr,
433088447a05SGarrett D'Amore 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));
433488447a05SGarrett D'Amore }
433588447a05SGarrett D'Amore }
433688447a05SGarrett D'Amore if ((widget->type == WTYPE_AUDIO_SEL) && (widget->nconns > 1) &&
433788447a05SGarrett D'Amore !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]);
434088447a05SGarrett D'Amore }
434188447a05SGarrett D'Amore widget->finish = 1;
434288447a05SGarrett D'Amore if (widget->used == 0)
434388447a05SGarrett D'Amore return;
434488447a05SGarrett D'Amore if (widget->used > 0) {
434588447a05SGarrett D'Amore for (i = 0; i < widget->used; i++) {
4346b96a6eceSZhao Edgar Liu - Sun Microsystems wid = widget->avail_conn[widget->monitor_path_next[i]];
434788447a05SGarrett D'Amore w = codec->widget[wid];
434888447a05SGarrett D'Amore audiohd_do_finish_monitor_path(codec, w);
434988447a05SGarrett D'Amore }
435088447a05SGarrett D'Amore }
435188447a05SGarrett D'Amore } /* audiohd_do_finish_monitor_path */
435288447a05SGarrett D'Amore
435388447a05SGarrett D'Amore /*
435488447a05SGarrett D'Amore * audiohd_finish_monitor_path
435588447a05SGarrett D'Amore *
435688447a05SGarrett D'Amore * Description:
435788447a05SGarrett D'Amore * Enable the monitor path for every ostream path
435888447a05SGarrett D'Amore */
435988447a05SGarrett D'Amore static void
audiohd_finish_monitor_path(hda_codec_t * codec)436088447a05SGarrett D'Amore audiohd_finish_monitor_path(hda_codec_t *codec)
436188447a05SGarrett D'Amore {
436288447a05SGarrett D'Amore audiohd_path_t *path;
436388447a05SGarrett D'Amore audiohd_widget_t *widget;
4364ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
436588447a05SGarrett D'Amore wid_t wid;
436688447a05SGarrett D'Amore int i, j, k;
436788447a05SGarrett D'Amore
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];
437588447a05SGarrett D'Amore if (wid == 0) {
437688447a05SGarrett D'Amore continue;
437788447a05SGarrett D'Amore }
437888447a05SGarrett D'Amore widget = codec->widget[wid];
437988447a05SGarrett D'Amore audiohd_do_finish_monitor_path(codec, widget);
438088447a05SGarrett D'Amore }
438188447a05SGarrett D'Amore }
438288447a05SGarrett D'Amore }
438388447a05SGarrett D'Amore } /* audiohd_finish_monitor_path */
438488447a05SGarrett D'Amore
438588447a05SGarrett D'Amore /*
438688447a05SGarrett D'Amore * audiohd_do_build_monit_amp()
438788447a05SGarrett D'Amore *
438888447a05SGarrett D'Amore * Description:
438988447a05SGarrett D'Amore * Search for the gain control widget for the monitor path
439088447a05SGarrett D'Amore */
439188447a05SGarrett D'Amore static void
audiohd_do_build_monitor_amp(hda_codec_t * codec,audiohd_pin_t * pin,audiohd_widget_t * widget)439288447a05SGarrett D'Amore audiohd_do_build_monitor_amp(hda_codec_t *codec, audiohd_pin_t *pin,
439388447a05SGarrett D'Amore audiohd_widget_t *widget)
439488447a05SGarrett D'Amore {
439588447a05SGarrett D'Amore audiohd_widget_t *w = widget;
439688447a05SGarrett D'Amore uint32_t gain;
439788447a05SGarrett D'Amore int i;
439888447a05SGarrett D'Amore wid_t wid;
439988447a05SGarrett D'Amore
440088447a05SGarrett D'Amore if (!w ||
440188447a05SGarrett D'Amore (w->type == WTYPE_PIN) ||
440288447a05SGarrett D'Amore !w->used ||
440388447a05SGarrett D'Amore (pin->num == AUDIOHD_MAX_CONN) ||
440488447a05SGarrett D'Amore (w->path_flags & AUDIOHD_PATH_ADC))
440588447a05SGarrett D'Amore return;
440688447a05SGarrett D'Amore if (!(w->path_flags & AUDIOHD_PATH_DAC)) {
440788447a05SGarrett D'Amore gain = w->outamp_cap & AUDIOHDC_AMP_CAP_STEP_NUMS;
440888447a05SGarrett D'Amore if (gain) {
440988447a05SGarrett D'Amore pin->mg_dir[pin->num] = AUDIOHDC_AMP_SET_OUTPUT;
441088447a05SGarrett D'Amore pin->mg_gain[pin->num] = gain;
441188447a05SGarrett D'Amore pin->mg_wid[pin->num] = w->wid_wid;
441288447a05SGarrett D'Amore pin->mg_gain[pin->num] >>= AUDIOHD_GAIN_OFF;
441388447a05SGarrett D'Amore pin->num++;
441488447a05SGarrett D'Amore return;
441588447a05SGarrett D'Amore }
441688447a05SGarrett D'Amore gain = w->inamp_cap & AUDIOHDC_AMP_CAP_STEP_NUMS;
441788447a05SGarrett D'Amore if (gain) {
441888447a05SGarrett D'Amore pin->mg_dir[pin->num] = AUDIOHDC_AMP_SET_INPUT;
441988447a05SGarrett D'Amore pin->mg_gain[pin->num] = gain;
442088447a05SGarrett D'Amore pin->mg_wid[pin->num] = w->wid_wid;
442188447a05SGarrett D'Amore pin->mg_gain[pin->num] >>= AUDIOHD_GAIN_OFF;
442288447a05SGarrett D'Amore pin->num++;
442388447a05SGarrett D'Amore return;
442488447a05SGarrett D'Amore }
442588447a05SGarrett D'Amore }
442688447a05SGarrett D'Amore for (i = 0; i < w->used; i++) {
4427b96a6eceSZhao Edgar Liu - Sun Microsystems wid = w->avail_conn[w->monitor_path_next[i]];
442888447a05SGarrett D'Amore audiohd_do_build_monitor_amp(codec, pin, codec->widget[wid]);
442988447a05SGarrett D'Amore }
443088447a05SGarrett D'Amore
443188447a05SGarrett D'Amore
443288447a05SGarrett D'Amore } /* audiohd_do_build_monitor_amp() */
443388447a05SGarrett D'Amore
443488447a05SGarrett D'Amore /*
443588447a05SGarrett D'Amore * audiohd_build_monitor_amp()
443688447a05SGarrett D'Amore *
443788447a05SGarrett D'Amore * Description:
443888447a05SGarrett D'Amore * Search gain control widget for every ostream monitor
443988447a05SGarrett D'Amore */
444088447a05SGarrett D'Amore static void
audiohd_build_monitor_amp(hda_codec_t * codec)444188447a05SGarrett D'Amore audiohd_build_monitor_amp(hda_codec_t *codec)
444288447a05SGarrett D'Amore {
444388447a05SGarrett D'Amore audiohd_path_t *path;
444488447a05SGarrett D'Amore audiohd_widget_t *widget, *w;
4445ea463888SZhao Edgar Liu - Sun Microsystems audiohd_state_t *statep = codec->statep;
444688447a05SGarrett D'Amore audiohd_pin_t *pin;
444788447a05SGarrett D'Amore wid_t wid, id;
444888447a05SGarrett D'Amore int i, j, k;
444988447a05SGarrett D'Amore
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];
445688447a05SGarrett D'Amore w = codec->widget[id];
445788447a05SGarrett D'Amore 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];
446088447a05SGarrett D'Amore if (!wid)
446188447a05SGarrett D'Amore continue;
446288447a05SGarrett D'Amore widget = codec->widget[wid];
446388447a05SGarrett D'Amore audiohd_do_build_monitor_amp(codec, pin,
446488447a05SGarrett D'Amore widget);
446588447a05SGarrett D'Amore }
446688447a05SGarrett D'Amore }
446788447a05SGarrett D'Amore }
446888447a05SGarrett D'Amore }
446988447a05SGarrett D'Amore
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);
476842c41cf8Slipeng sang - Sun Microsystems - Beijing China }
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
492288447a05SGarrett D'Amore /*
492388447a05SGarrett D'Amore * audiohd_build_path()
492488447a05SGarrett D'Amore *
492588447a05SGarrett D'Amore * Description:
492688447a05SGarrett D'Amore * Here we build the output, input, monitor path.
492788447a05SGarrett D'Amore * And also enable the path in default.
492888447a05SGarrett D'Amore * Search for the gain and mute control for the path
492988447a05SGarrett D'Amore */
493088447a05SGarrett D'Amore static void
audiohd_build_path(audiohd_state_t * statep)493188447a05SGarrett D'Amore audiohd_build_path(audiohd_state_t *statep)
493288447a05SGarrett D'Amore {
493388447a05SGarrett D'Amore int i;
493488447a05SGarrett D'Amore
493588447a05SGarrett D'Amore for (i = 0; i < AUDIOHD_CODEC_MAX; i++) {
493688447a05SGarrett D'Amore if (statep->codec[i]) {
493788447a05SGarrett D'Amore audiohd_build_output_path(statep->codec[i]);
493888447a05SGarrett D'Amore audiohd_build_output_amp(statep->codec[i]);
493988447a05SGarrett D'Amore audiohd_finish_output_path(statep->codec[i]);
494088447a05SGarrett D'Amore
494188447a05SGarrett D'Amore audiohd_build_input_path(statep->codec[i]);
494288447a05SGarrett D'Amore audiohd_build_input_amp(statep->codec[i]);
494388447a05SGarrett D'Amore audiohd_finish_input_path(statep->codec[i]);
494488447a05SGarrett D'Amore
494588447a05SGarrett D'Amore audiohd_build_monitor_path(statep->codec[i]);
494688447a05SGarrett D'Amore audiohd_build_monitor_amp(statep->codec[i]);
494788447a05SGarrett D'Amore 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]);
495488447a05SGarrett D'Amore }
495588447a05SGarrett D'Amore }
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");
5091c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
509288447a05SGarrett D'Amore }
5093c0e48486SYang-Rong Jerry Zhou }
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 }
520788447a05SGarrett D'Amore
520888447a05SGarrett D'Amore /*
52095ec2209cSZhao Edgar Liu - Sun Microsystems * audiohd_change_widget_power_state(audiohd_state_t *statep, int state)
521088447a05SGarrett D'Amore * 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.
521488447a05SGarrett D'Amore */
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)
521788447a05SGarrett D'Amore {
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;
522288447a05SGarrett D'Amore
522388447a05SGarrett D'Amore for (i = 0; i < AUDIOHD_CODEC_MAX; i++) {
522488447a05SGarrett D'Amore codec = statep->codec[i];
52255ec2209cSZhao Edgar Liu - Sun Microsystems if (codec == NULL)
522688447a05SGarrett D'Amore continue;
522788447a05SGarrett D'Amore for (wid = codec->first_wid; wid <= codec->last_wid;
522888447a05SGarrett D'Amore wid++) {
522988447a05SGarrett D'Amore widget = codec->widget[wid];
523088447a05SGarrett D'Amore if (widget->widget_cap &
523188447a05SGarrett D'Amore AUDIOHD_WIDCAP_PWRCTRL) {
523288447a05SGarrett D'Amore (void) audioha_codec_verb_get(statep,
523388447a05SGarrett D'Amore codec->index, wid,
523488447a05SGarrett D'Amore AUDIOHDC_VERB_SET_POWER_STATE,
52355ec2209cSZhao Edgar Liu - Sun Microsystems state);
523688447a05SGarrett D'Amore }
523788447a05SGarrett D'Amore }
523888447a05SGarrett D'Amore }
523988447a05SGarrett D'Amore }
524088447a05SGarrett D'Amore /*
524188447a05SGarrett D'Amore * audiohd_restore_path()
524288447a05SGarrett D'Amore * Description:
524388447a05SGarrett D'Amore * This routine is used to restore the path on the codec.
524488447a05SGarrett D'Amore */
524588447a05SGarrett D'Amore static void
audiohd_restore_path(audiohd_state_t * statep)524688447a05SGarrett D'Amore audiohd_restore_path(audiohd_state_t *statep)
524788447a05SGarrett D'Amore {
524888447a05SGarrett D'Amore int i;
524988447a05SGarrett D'Amore hda_codec_t *codec;
525088447a05SGarrett D'Amore
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]);
525988447a05SGarrett D'Amore }
526088447a05SGarrett D'Amore }
526188447a05SGarrett D'Amore
526288447a05SGarrett D'Amore /*
526388447a05SGarrett D'Amore * audiohd_reset_pins_ur_cap()
526488447a05SGarrett D'Amore * Description:
526588447a05SGarrett D'Amore * Enable the unsolicited response of the pins which have the unsolicited
526688447a05SGarrett D'Amore * response capability
526788447a05SGarrett D'Amore */
526888447a05SGarrett D'Amore static void
audiohd_reset_pins_ur_cap(audiohd_state_t * statep)526988447a05SGarrett D'Amore audiohd_reset_pins_ur_cap(audiohd_state_t *statep)
527088447a05SGarrett D'Amore {
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;
527688447a05SGarrett D'Amore
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 }
530288447a05SGarrett D'Amore }
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)
530688447a05SGarrett D'Amore {
530788447a05SGarrett D'Amore int i;
530888447a05SGarrett D'Amore wid_t wid;
530988447a05SGarrett D'Amore hda_codec_t *codec;
531088447a05SGarrett D'Amore
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;
531688447a05SGarrett D'Amore
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) {
532388447a05SGarrett D'Amore /*
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.
532788447a05SGarrett D'Amore */
532888447a05SGarrett D'Amore (void) audioha_codec_verb_get(statep, i, wid,
532988447a05SGarrett D'Amore AUDIOHDC_VERB_SET_GPIO_MASK, AUDIOHDC_GPIO_ENABLE);
533088447a05SGarrett D'Amore (void) audioha_codec_verb_get(statep, i, wid,
53319ba19c87SYang-Rong Jerry Zhou AUDIOHDC_VERB_SET_GPIO_DIREC, AUDIOHDC_GPIO_DIRECT);
533288447a05SGarrett D'Amore (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);
533588447a05SGarrett D'Amore (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 }
534188447a05SGarrett D'Amore /*
534288447a05SGarrett D'Amore * audiohd_resume()
534388447a05SGarrett D'Amore */
534488447a05SGarrett D'Amore static int
audiohd_resume(audiohd_state_t * statep)534588447a05SGarrett D'Amore audiohd_resume(audiohd_state_t *statep)
534688447a05SGarrett D'Amore {
534788447a05SGarrett D'Amore uint8_t rirbsts;
534888447a05SGarrett D'Amore
534988447a05SGarrett D'Amore 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");
535588447a05SGarrett D'Amore mutex_exit(&statep->hda_mutex);
53565ec2209cSZhao Edgar Liu - Sun Microsystems return (DDI_FAILURE);
535788447a05SGarrett D'Amore }
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);
536388447a05SGarrett D'Amore /* set widget power to D0 */
53645ec2209cSZhao Edgar Liu - Sun Microsystems audiohd_change_widget_power_state(statep, AUDIOHD_PW_D0);
536588447a05SGarrett D'Amore
536668c47f65SGarrett D'Amore audiohd_configure_output(statep);
536768c47f65SGarrett D'Amore audiohd_configure_input(statep);
536868c47f65SGarrett D'Amore mutex_exit(&statep->hda_mutex);
536968c47f65SGarrett D'Amore
537068c47f65SGarrett D'Amore audio_dev_resume(statep->adev);
537168c47f65SGarrett D'Amore
537288447a05SGarrett D'Amore return (DDI_SUCCESS);
537388447a05SGarrett D'Amore } /* audiohd_resume */
537488447a05SGarrett D'Amore
537588447a05SGarrett D'Amore /*
537688447a05SGarrett D'Amore * audiohd_suspend()
537788447a05SGarrett D'Amore */
537888447a05SGarrett D'Amore static int
audiohd_suspend(audiohd_state_t * statep)537988447a05SGarrett D'Amore audiohd_suspend(audiohd_state_t *statep)
538088447a05SGarrett D'Amore {
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;
538588447a05SGarrett D'Amore
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);
539288447a05SGarrett D'Amore
539388447a05SGarrett D'Amore return (DDI_SUCCESS);
539488447a05SGarrett D'Amore } /* audiohd_suspend */
539588447a05SGarrett D'Amore
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 }
541288447a05SGarrett D'Amore
541388447a05SGarrett D'Amore /*
541488447a05SGarrett D'Amore * audiohd_enable_pin()
541588447a05SGarrett D'Amore */
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)
543688447a05SGarrett D'Amore {
543788447a05SGarrett D'Amore audiohd_path_t *path;
543888447a05SGarrett D'Amore audiohd_widget_t *widget;
543988447a05SGarrett D'Amore audiohd_pin_t *pin;
544088447a05SGarrett D'Amore int i, j;
544188447a05SGarrett D'Amore wid_t wid;
544288447a05SGarrett D'Amore
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);
545688447a05SGarrett D'Amore }
545788447a05SGarrett D'Amore }
545888447a05SGarrett D'Amore
545988447a05SGarrett D'Amore } 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);
546888447a05SGarrett D'Amore }
546988447a05SGarrett D'Amore }
547088447a05SGarrett D'Amore }
547188447a05SGarrett D'Amore }
547288447a05SGarrett D'Amore }
547388447a05SGarrett D'Amore /*
547488447a05SGarrett D'Amore * audiohd_select_mic()
547588447a05SGarrett D'Amore *
547688447a05SGarrett D'Amore * 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.
548088447a05SGarrett D'Amore */
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)
548488447a05SGarrett D'Amore {
548588447a05SGarrett D'Amore 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;
549188447a05SGarrett D'Amore
549288447a05SGarrett D'Amore codec = statep->codec[index];
549388447a05SGarrett D'Amore 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
550288447a05SGarrett D'Amore for (j = 0; j < path->pin_nums; j++) {
550388447a05SGarrett D'Amore wid = path->pin_wid[j];
550488447a05SGarrett D'Amore widget = codec->widget[wid];
550588447a05SGarrett D'Amore 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;
554288447a05SGarrett D'Amore }
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);
556388447a05SGarrett D'Amore }
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);
557588447a05SGarrett D'Amore }
557688447a05SGarrett D'Amore }
5577aa5c9fd8SZhao Edgar Liu - Sun Microsystems }
5578aa5c9fd8SZhao Edgar Liu - Sun Microsystems }
5579aa5c9fd8SZhao Edgar Liu - Sun Microsystems }
5580aa5c9fd8SZhao Edgar Liu - Sun Microsystems
558188447a05SGarrett D'Amore /*
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.
558588447a05SGarrett D'Amore */
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;
561688447a05SGarrett D'Amore }
561788447a05SGarrett D'Amore }
561888447a05SGarrett D'Amore }
561988447a05SGarrett D'Amore }
562088447a05SGarrett D'Amore }
562188447a05SGarrett D'Amore /*
562288447a05SGarrett D'Amore * audiohd_pin_sense()
562388447a05SGarrett D'Amore *
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.
562988447a05SGarrett D'Amore */
563088447a05SGarrett D'Amore 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)
563288447a05SGarrett D'Amore {
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;
563888447a05SGarrett D'Amore hda_codec_t *codec;
563988447a05SGarrett D'Amore
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;
567288447a05SGarrett D'Amore }
567388447a05SGarrett D'Amore /* output pin is unplugged */
567488447a05SGarrett D'Amore audiohd_change_speaker_state(statep, AUDIOHD_SP_ON);
567588447a05SGarrett D'Amore }
567688447a05SGarrett D'Amore
567788447a05SGarrett D'Amore }
567888447a05SGarrett D'Amore
567988447a05SGarrett D'Amore /*
568088447a05SGarrett D'Amore * audiohd_disable_intr()
568188447a05SGarrett D'Amore *
568288447a05SGarrett D'Amore * Description:
568388447a05SGarrett D'Amore * Disable all possible interrupts.
568488447a05SGarrett D'Amore */
568588447a05SGarrett D'Amore static void
audiohd_disable_intr(audiohd_state_t * statep)568688447a05SGarrett D'Amore audiohd_disable_intr(audiohd_state_t *statep)
568788447a05SGarrett D'Amore {
568888447a05SGarrett D'Amore int i;
568988447a05SGarrett D'Amore uint32_t base;
569088447a05SGarrett D'Amore
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;
569788447a05SGarrett D'Amore }
569888447a05SGarrett D'Amore AUDIOHD_REG_SET32(AUDIOHD_REG_INTSTS, (uint32_t)(-1));
569988447a05SGarrett D'Amore
570088447a05SGarrett D'Amore } /* audiohd_disable_intr() */
570188447a05SGarrett D'Amore
570288447a05SGarrett D'Amore
570388447a05SGarrett D'Amore /*
570488447a05SGarrett D'Amore * audiohd_12bit_verb_to_codec()
570588447a05SGarrett D'Amore *
570688447a05SGarrett D'Amore * Description:
570788447a05SGarrett D'Amore *
570888447a05SGarrett D'Amore */
570988447a05SGarrett D'Amore static int
audiohd_12bit_verb_to_codec(audiohd_state_t * statep,uint8_t caddr,uint8_t wid,uint16_t cmd,uint8_t param)571088447a05SGarrett D'Amore audiohd_12bit_verb_to_codec(audiohd_state_t *statep, uint8_t caddr,
571188447a05SGarrett D'Amore uint8_t wid,
571288447a05SGarrett D'Amore uint16_t cmd, uint8_t param)
571388447a05SGarrett D'Amore {
571488447a05SGarrett D'Amore uint32_t verb;
571588447a05SGarrett D'Amore uint16_t wptr;
571688447a05SGarrett D'Amore uint16_t rptr;
571788447a05SGarrett D'Amore
571888447a05SGarrett D'Amore ASSERT((cmd & AUDIOHDC_12BIT_VERB_MASK) == 0);
571988447a05SGarrett D'Amore
572088447a05SGarrett D'Amore wptr = AUDIOHD_REG_GET16(AUDIOHD_REG_CORBWP) & AUDIOHD_CMDIO_ENT_MASK;
572188447a05SGarrett D'Amore rptr = AUDIOHD_REG_GET16(AUDIOHD_REG_CORBRP) & AUDIOHD_CMDIO_ENT_MASK;
572288447a05SGarrett D'Amore
572388447a05SGarrett D'Amore wptr++;
572488447a05SGarrett D'Amore wptr &= AUDIOHD_CMDIO_ENT_MASK;
572588447a05SGarrett D'Amore
572688447a05SGarrett D'Amore /* overflow */
572788447a05SGarrett D'Amore if (wptr == rptr) {
5728c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
572988447a05SGarrett D'Amore }
573088447a05SGarrett D'Amore
573188447a05SGarrett D'Amore verb = (caddr & 0x0f) << AUDIOHD_VERB_ADDR_OFF;
573288447a05SGarrett D'Amore verb |= wid << AUDIOHD_VERB_NID_OFF;
573388447a05SGarrett D'Amore verb |= cmd << AUDIOHD_VERB_CMD_OFF;
573488447a05SGarrett D'Amore verb |= param;
573588447a05SGarrett D'Amore
573688447a05SGarrett D'Amore *((uint32_t *)(statep->hda_dma_corb.ad_vaddr) + wptr) = verb;
573788447a05SGarrett D'Amore (void) ddi_dma_sync(statep->hda_dma_corb.ad_dmahdl, 0,
573888447a05SGarrett D'Amore sizeof (sd_bdle_t) * AUDIOHD_BDLE_NUMS, DDI_DMA_SYNC_FORDEV);
573988447a05SGarrett D'Amore AUDIOHD_REG_SET16(AUDIOHD_REG_CORBWP, wptr);
574088447a05SGarrett D'Amore
5741c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
574288447a05SGarrett D'Amore
574388447a05SGarrett D'Amore } /* audiohd_12bit_verb_to_codec() */
574488447a05SGarrett D'Amore
574588447a05SGarrett D'Amore /*
574688447a05SGarrett D'Amore * audiohd_4bit_verb_to_codec()
574788447a05SGarrett D'Amore *
574888447a05SGarrett D'Amore * Description:
574988447a05SGarrett D'Amore *
575088447a05SGarrett D'Amore */
575188447a05SGarrett D'Amore static int
audiohd_4bit_verb_to_codec(audiohd_state_t * statep,uint8_t caddr,uint8_t wid,uint32_t cmd,uint16_t param)575288447a05SGarrett D'Amore audiohd_4bit_verb_to_codec(audiohd_state_t *statep, uint8_t caddr,
575388447a05SGarrett D'Amore uint8_t wid,
575488447a05SGarrett D'Amore uint32_t cmd, uint16_t param)
575588447a05SGarrett D'Amore {
575688447a05SGarrett D'Amore uint32_t verb;
575788447a05SGarrett D'Amore uint16_t wptr;
575888447a05SGarrett D'Amore uint16_t rptr;
575988447a05SGarrett D'Amore
576088447a05SGarrett D'Amore ASSERT((cmd & AUDIOHDC_4BIT_VERB_MASK) == 0);
576188447a05SGarrett D'Amore
576288447a05SGarrett D'Amore wptr = AUDIOHD_REG_GET16(AUDIOHD_REG_CORBWP) & AUDIOHD_CMDIO_ENT_MASK;
576388447a05SGarrett D'Amore rptr = AUDIOHD_REG_GET16(AUDIOHD_REG_CORBRP) & AUDIOHD_CMDIO_ENT_MASK;
576488447a05SGarrett D'Amore
576588447a05SGarrett D'Amore wptr++;
576688447a05SGarrett D'Amore wptr &= AUDIOHD_CMDIO_ENT_MASK;
576788447a05SGarrett D'Amore
576888447a05SGarrett D'Amore /* overflow */
576988447a05SGarrett D'Amore if (wptr == rptr) {
5770c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
577188447a05SGarrett D'Amore }
577288447a05SGarrett D'Amore
577388447a05SGarrett D'Amore verb = (caddr & 0x0f) << AUDIOHD_VERB_ADDR_OFF;
577488447a05SGarrett D'Amore verb |= wid << AUDIOHD_VERB_NID_OFF;
577588447a05SGarrett D'Amore verb |= cmd << AUDIOHD_VERB_CMD16_OFF;
577688447a05SGarrett D'Amore verb |= param;
577788447a05SGarrett D'Amore
577888447a05SGarrett D'Amore *((uint32_t *)(statep->hda_dma_corb.ad_vaddr) + wptr) = verb;
577988447a05SGarrett D'Amore AUDIOHD_REG_SET16(AUDIOHD_REG_CORBWP, wptr);
578088447a05SGarrett D'Amore
5781c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
578288447a05SGarrett D'Amore
578388447a05SGarrett D'Amore } /* audiohd_4bit_verb_to_codec() */
578488447a05SGarrett D'Amore
578588447a05SGarrett D'Amore /*
578688447a05SGarrett D'Amore * audiohd_response_from_codec()
578788447a05SGarrett D'Amore *
578888447a05SGarrett D'Amore * Description:
578988447a05SGarrett D'Amore *
579088447a05SGarrett D'Amore */
579188447a05SGarrett D'Amore static int
audiohd_response_from_codec(audiohd_state_t * statep,uint32_t * resp,uint32_t * respex)579288447a05SGarrett D'Amore audiohd_response_from_codec(audiohd_state_t *statep, uint32_t *resp,
579388447a05SGarrett D'Amore uint32_t *respex)
579488447a05SGarrett D'Amore {
579588447a05SGarrett D'Amore uint16_t wptr;
579688447a05SGarrett D'Amore uint16_t rptr;
579788447a05SGarrett D'Amore uint32_t *lp;
579888447a05SGarrett D'Amore
579988447a05SGarrett D'Amore wptr = AUDIOHD_REG_GET16(AUDIOHD_REG_RIRBWP) & 0x00ff;
580088447a05SGarrett D'Amore rptr = statep->hda_rirb_rp;
580188447a05SGarrett D'Amore
580288447a05SGarrett D'Amore if (rptr == wptr) {
5803c6e681c0SYang-Rong Jerry Zhou return (DDI_FAILURE);
580488447a05SGarrett D'Amore }
580588447a05SGarrett D'Amore
580688447a05SGarrett D'Amore rptr++;
580788447a05SGarrett D'Amore rptr &= AUDIOHD_RING_MAX_SIZE;
580888447a05SGarrett D'Amore
580988447a05SGarrett D'Amore lp = (uint32_t *)(statep->hda_dma_rirb.ad_vaddr) + (rptr << 1);
581088447a05SGarrett D'Amore *resp = *(lp);
581188447a05SGarrett D'Amore *respex = *(lp + 1);
581288447a05SGarrett D'Amore
581388447a05SGarrett D'Amore statep->hda_rirb_rp = rptr;
581488447a05SGarrett D'Amore
5815c6e681c0SYang-Rong Jerry Zhou return (DDI_SUCCESS);
581688447a05SGarrett D'Amore
581788447a05SGarrett D'Amore } /* audiohd_response_from_codec() */
581888447a05SGarrett D'Amore
581988447a05SGarrett D'Amore
582088447a05SGarrett D'Amore /*
582188447a05SGarrett D'Amore * audioha_codec_verb_get()
582288447a05SGarrett D'Amore */
582388447a05SGarrett D'Amore static uint32_t
audioha_codec_verb_get(void * arg,uint8_t caddr,uint8_t wid,uint16_t verb,uint8_t param)582488447a05SGarrett D'Amore audioha_codec_verb_get(void *arg, uint8_t caddr, uint8_t wid,
582588447a05SGarrett D'Amore uint16_t verb,
582688447a05SGarrett D'Amore uint8_t param)
582788447a05SGarrett D'Amore {
582888447a05SGarrett D'Amore audiohd_state_t *statep = (audiohd_state_t *)arg;
582988447a05SGarrett D'Amore uint32_t resp;
583088447a05SGarrett D'Amore uint32_t respex;
583188447a05SGarrett D'Amore int ret;
583288447a05SGarrett D'Amore int i;
583388447a05SGarrett D'Amore
583488447a05SGarrett D'Amore ret = audiohd_12bit_verb_to_codec(statep, caddr, wid, verb, param);
5835c6e681c0SYang-Rong Jerry Zhou if (ret != DDI_SUCCESS) {
583688447a05SGarrett D'Amore return (uint32_t)(-1);
583788447a05SGarrett D'Amore }
583888447a05SGarrett D'Amore
583988447a05SGarrett D'Amore /*
584088447a05SGarrett D'Amore * Empirical testing times. 50 times is enough for audiohd spec 1.0.
584188447a05SGarrett D'Amore * But we need to make it work for audiohd spec 0.9, which is just a
584288447a05SGarrett D'Amore * draft version and requires more time to wait.
584388447a05SGarrett D'Amore */
584488447a05SGarrett D'Amore for (i = 0; i < 500; i++) {
584588447a05SGarrett D'Amore ret = audiohd_response_from_codec(statep, &resp, &respex);
584688447a05SGarrett D'Amore if (((respex & AUDIOHD_BDLE_RIRB_SDI) == caddr) &&
584788447a05SGarrett D'Amore ((respex & AUDIOHD_BDLE_RIRB_UNSOLICIT) == 0) &&
5848c6e681c0SYang-Rong Jerry Zhou (ret == DDI_SUCCESS))
584988447a05SGarrett D'Amore break;
585013084339SYang-Rong Jerry Zhou /* Empirical testing time, which works well */
585113084339SYang-Rong Jerry Zhou drv_usecwait(30);
585288447a05SGarrett D'Amore }
585388447a05SGarrett D'Amore
5854c6e681c0SYang-Rong Jerry Zhou if (ret == DDI_SUCCESS) {
585588447a05SGarrett D'Amore return (resp);
585688447a05SGarrett D'Amore }
585788447a05SGarrett D'Amore
58580c240c64SZhao Edgar Liu - Sun Microsystems if (wid != AUDIOHDC_NODE_ROOT && param != AUDIOHDC_PAR_VENDOR_ID) {
585988447a05SGarrett D'Amore audio_dev_warn(statep->adev, "timeout when get "
586088447a05SGarrett D'Amore "response from codec: wid=%d, verb=0x%04x, param=0x%04x",
586188447a05SGarrett D'Amore wid, verb, param);
58620c240c64SZhao Edgar Liu - Sun Microsystems }
586388447a05SGarrett D'Amore
586488447a05SGarrett D'Amore return ((uint32_t)(-1));
586588447a05SGarrett D'Amore
586688447a05SGarrett D'Amore } /* audioha_codec_verb_get() */
586788447a05SGarrett D'Amore
586888447a05SGarrett D'Amore
586988447a05SGarrett D'Amore /*
587088447a05SGarrett D'Amore * audioha_codec_4bit_verb_get()
587188447a05SGarrett D'Amore */
587288447a05SGarrett D'Amore static uint32_t
audioha_codec_4bit_verb_get(void * arg,uint8_t caddr,uint8_t wid,uint16_t verb,uint16_t param)587388447a05SGarrett D'Amore audioha_codec_4bit_verb_get(void *arg, uint8_t caddr, uint8_t wid,
587488447a05SGarrett D'Amore uint16_t verb, uint16_t param)
587588447a05SGarrett D'Amore {
587688447a05SGarrett D'Amore audiohd_state_t *statep = (audiohd_state_t *)arg;
587788447a05SGarrett D'Amore uint32_t resp;
587888447a05SGarrett D'Amore uint32_t respex;
587988447a05SGarrett D'Amore int ret;
588088447a05SGarrett D'Amore int i;
588188447a05SGarrett D'Amore
588288447a05SGarrett D'Amore ret = audiohd_4bit_verb_to_codec(statep, caddr, wid, verb, param);
5883c6e681c0SYang-Rong Jerry Zhou if (ret != DDI_SUCCESS) {
588488447a05SGarrett D'Amore return (uint32_t)(-1);
588588447a05SGarrett D'Amore }
588688447a05SGarrett D'Amore
588788447a05SGarrett D'Amore for (i = 0; i < 500; i++) {
588888447a05SGarrett D'Amore ret = audiohd_response_from_codec(statep, &resp, &respex);
588988447a05SGarrett D'Amore if (((respex & AUDIOHD_BDLE_RIRB_SDI) == caddr) &&
589088447a05SGarrett D'Amore ((respex & AUDIOHD_BDLE_RIRB_UNSOLICIT) == 0) &&
5891c6e681c0SYang-Rong Jerry Zhou (ret == DDI_SUCCESS))
589288447a05SGarrett D'Amore break;
589313084339SYang-Rong Jerry Zhou /* Empirical testing time, which works well */
589413084339SYang-Rong Jerry Zhou drv_usecwait(30);
589588447a05SGarrett D'Amore }
589688447a05SGarrett D'Amore
5897c6e681c0SYang-Rong Jerry Zhou if (ret == DDI_SUCCESS) {
589888447a05SGarrett D'Amore return (resp);
589988447a05SGarrett D'Amore }
590088447a05SGarrett D'Amore
590188447a05SGarrett D'Amore audio_dev_warn(statep->adev, "timeout when get "
590288447a05SGarrett D'Amore "response from codec: wid=%d, verb=0x%04x, param=0x%04x",
590388447a05SGarrett D'Amore wid, verb, param);
590488447a05SGarrett D'Amore
590588447a05SGarrett D'Amore return ((uint32_t)(-1));
590688447a05SGarrett D'Amore
590788447a05SGarrett D'Amore } /* audioha_codec_4bit_verb_get() */
5908