hdac.c revision 178155
1168404Spjd/*- 2168404Spjd * Copyright (c) 2006 Stephane E. Potvin <sepotvin@videotron.ca> 3168404Spjd * Copyright (c) 2006 Ariff Abdullah <ariff@FreeBSD.org> 4168404Spjd * All rights reserved. 5168404Spjd * 6168404Spjd * Redistribution and use in source and binary forms, with or without 7168404Spjd * modification, are permitted provided that the following conditions 8168404Spjd * are met: 9168404Spjd * 1. Redistributions of source code must retain the above copyright 10168404Spjd * notice, this list of conditions and the following disclaimer. 11168404Spjd * 2. Redistributions in binary form must reproduce the above copyright 12168404Spjd * notice, this list of conditions and the following disclaimer in the 13168404Spjd * documentation and/or other materials provided with the distribution. 14168404Spjd * 15168404Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16168404Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17168404Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18168404Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19168404Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20168404Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21168404Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22219089Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23277826Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24268123Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25260835Sdelphij * SUCH DAMAGE. 26268085Sdelphij */ 27168404Spjd 28168404Spjd/* 29168404Spjd * Intel High Definition Audio (Controller) driver for FreeBSD. Be advised 30168404Spjd * that this driver still in its early stage, and possible of rewrite are 31168404Spjd * pretty much guaranteed. There are supposedly several distinct parent/child 32168404Spjd * busses to make this "perfect", but as for now and for the sake of 33168404Spjd * simplicity, everything is gobble up within single source. 34168404Spjd * 35168404Spjd * List of subsys: 36168404Spjd * 1) HDA Controller support 37168404Spjd * 2) HDA Codecs support, which may include 38168404Spjd * - HDA 39168404Spjd * - Modem 40168404Spjd * - HDMI 41168404Spjd * 3) Widget parser - the real magic of why this driver works on so 42168404Spjd * many hardwares with minimal vendor specific quirk. The original 43168404Spjd * parser was written using Ruby and can be found at 44168404Spjd * http://people.freebsd.org/~ariff/HDA/parser.rb . This crude 45168404Spjd * ruby parser take the verbose dmesg dump as its input. Refer to 46168404Spjd * http://www.microsoft.com/whdc/device/audio/default.mspx for various 47168404Spjd * interesting documents, especially UAA (Universal Audio Architecture). 48168404Spjd * 4) Possible vendor specific support. 49168404Spjd * (snd_hda_intel, snd_hda_ati, etc..) 50168404Spjd * 51185029Spjd * Thanks to Ahmad Ubaidah Omar @ Defenxis Sdn. Bhd. for the 52185029Spjd * Compaq V3000 with Conexant HDA. 53168404Spjd * 54168404Spjd * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 55168404Spjd * * * 56168404Spjd * * This driver is a collaborative effort made by: * 57185029Spjd * * * 58168404Spjd * * Stephane E. Potvin <sepotvin@videotron.ca> * 59168404Spjd * * Andrea Bittau <a.bittau@cs.ucl.ac.uk> * 60168404Spjd * * Wesley Morgan <morganw@chemikals.org> * 61168404Spjd * * Daniel Eischen <deischen@FreeBSD.org> * 62251631Sdelphij * * Maxime Guillaud <bsd-ports@mguillaud.net> * 63168404Spjd * * Ariff Abdullah <ariff@FreeBSD.org> * 64168404Spjd * * * 65168404Spjd * * ....and various people from freebsd-multimedia@FreeBSD.org * 66251631Sdelphij * * * 67168404Spjd * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 68168404Spjd */ 69168404Spjd 70168404Spjd#include <dev/sound/pcm/sound.h> 71168404Spjd#include <dev/pci/pcireg.h> 72168404Spjd#include <dev/pci/pcivar.h> 73168404Spjd 74168404Spjd#include <sys/ctype.h> 75168404Spjd#include <sys/taskqueue.h> 76168404Spjd 77168404Spjd#include <dev/sound/pci/hda/hdac_private.h> 78168404Spjd#include <dev/sound/pci/hda/hdac_reg.h> 79185029Spjd#include <dev/sound/pci/hda/hda_reg.h> 80168404Spjd#include <dev/sound/pci/hda/hdac.h> 81251631Sdelphij 82168404Spjd#include "mixer_if.h" 83168404Spjd 84168404Spjd#define HDA_DRV_TEST_REV "20080412_0051" 85168404Spjd#define HDA_WIDGET_PARSER_REV 1 86168404Spjd 87168404SpjdSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/hda/hdac.c 178155 2008-04-12 15:07:32Z ariff $"); 88168404Spjd 89168404Spjd#define HDA_BOOTVERBOSE(stmt) do { \ 90168404Spjd if (bootverbose != 0 || snd_verbose > 3) { \ 91168404Spjd stmt \ 92168404Spjd } \ 93168404Spjd} while(0) 94168404Spjd 95168404Spjd#if 1 96168404Spjd#undef HDAC_INTR_EXTRA 97168404Spjd#define HDAC_INTR_EXTRA 1 98168404Spjd#endif 99168404Spjd 100168404Spjd#define hdac_lock(sc) snd_mtxlock((sc)->lock) 101168404Spjd#define hdac_unlock(sc) snd_mtxunlock((sc)->lock) 102168404Spjd#define hdac_lockassert(sc) snd_mtxassert((sc)->lock) 103168404Spjd#define hdac_lockowned(sc) mtx_owned((sc)->lock) 104168404Spjd 105168404Spjd#undef HDAC_MSI_ENABLED 106168404Spjd#if __FreeBSD_version >= 700026 || \ 107168404Spjd (__FreeBSD_version < 700000 && __FreeBSD_version >= 602106) 108268858Sdelphij#define HDAC_MSI_ENABLED 1 109168404Spjd#endif 110168404Spjd 111168404Spjd#define HDA_FLAG_MATCH(fl, v) (((fl) & (v)) == (v)) 112168404Spjd#define HDA_DEV_MATCH(fl, v) ((fl) == (v) || \ 113185029Spjd (fl) == 0xffffffff || \ 114286570Smav (((fl) & 0xffff0000) == 0xffff0000 && \ 115185029Spjd ((fl) & 0x0000ffff) == ((v) & 0x0000ffff)) || \ 116185029Spjd (((fl) & 0x0000ffff) == 0x0000ffff && \ 117185029Spjd ((fl) & 0xffff0000) == ((v) & 0xffff0000))) 118185029Spjd#define HDA_MATCH_ALL 0xffffffff 119185029Spjd#define HDAC_INVALID 0xffffffff 120185029Spjd 121168404Spjd/* Default controller / jack sense poll: 250ms */ 122168404Spjd#define HDAC_POLL_INTERVAL max(hz >> 2, 1) 123168404Spjd 124168404Spjd/* 125251478Sdelphij * Make room for possible 4096 playback/record channels, in 100 years to come. 126168404Spjd */ 127168404Spjd#define HDAC_TRIGGER_NONE 0x00000000 128168404Spjd#define HDAC_TRIGGER_PLAY 0x00000fff 129185029Spjd#define HDAC_TRIGGER_REC 0x00fff000 130219089Spjd#define HDAC_TRIGGER_UNSOL 0x80000000 131258632Savg 132168404Spjd#define HDA_MODEL_CONSTRUCT(vendor, model) \ 133168404Spjd (((uint32_t)(model) << 16) | ((vendor##_VENDORID) & 0xffff)) 134168404Spjd 135168404Spjd/* Controller models */ 136168404Spjd 137248572Ssmh/* Intel */ 138219089Spjd#define INTEL_VENDORID 0x8086 139168404Spjd#define HDA_INTEL_82801F HDA_MODEL_CONSTRUCT(INTEL, 0x2668) 140168404Spjd#define HDA_INTEL_63XXESB HDA_MODEL_CONSTRUCT(INTEL, 0x269a) 141191902Skmacy#define HDA_INTEL_82801G HDA_MODEL_CONSTRUCT(INTEL, 0x27d8) 142272483Ssmh#define HDA_INTEL_82801H HDA_MODEL_CONSTRUCT(INTEL, 0x284b) 143191902Skmacy#define HDA_INTEL_82801I HDA_MODEL_CONSTRUCT(INTEL, 0x293e) 144240133Smm#define HDA_INTEL_ALL HDA_MODEL_CONSTRUCT(INTEL, 0xffff) 145240133Smm 146240133Smm/* Nvidia */ 147240133Smm#define NVIDIA_VENDORID 0x10de 148240133Smm#define HDA_NVIDIA_MCP51 HDA_MODEL_CONSTRUCT(NVIDIA, 0x026c) 149240133Smm#define HDA_NVIDIA_MCP55 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0371) 150240133Smm#define HDA_NVIDIA_MCP61_1 HDA_MODEL_CONSTRUCT(NVIDIA, 0x03e4) 151240133Smm#define HDA_NVIDIA_MCP61_2 HDA_MODEL_CONSTRUCT(NVIDIA, 0x03f0) 152168404Spjd#define HDA_NVIDIA_MCP65_1 HDA_MODEL_CONSTRUCT(NVIDIA, 0x044a) 153168404Spjd#define HDA_NVIDIA_MCP65_2 HDA_MODEL_CONSTRUCT(NVIDIA, 0x044b) 154168404Spjd#define HDA_NVIDIA_MCP67_1 HDA_MODEL_CONSTRUCT(NVIDIA, 0x055c) 155168404Spjd#define HDA_NVIDIA_MCP67_2 HDA_MODEL_CONSTRUCT(NVIDIA, 0x055d) 156286625Smav#define HDA_NVIDIA_ALL HDA_MODEL_CONSTRUCT(NVIDIA, 0xffff) 157168404Spjd 158258632Savg/* ATI */ 159258632Savg#define ATI_VENDORID 0x1002 160258632Savg#define HDA_ATI_SB450 HDA_MODEL_CONSTRUCT(ATI, 0x437b) 161258632Savg#define HDA_ATI_SB600 HDA_MODEL_CONSTRUCT(ATI, 0x4383) 162258632Savg#define HDA_ATI_ALL HDA_MODEL_CONSTRUCT(ATI, 0xffff) 163258632Savg 164168404Spjd/* VIA */ 165168404Spjd#define VIA_VENDORID 0x1106 166168404Spjd#define HDA_VIA_VT82XX HDA_MODEL_CONSTRUCT(VIA, 0x3288) 167208373Smm#define HDA_VIA_ALL HDA_MODEL_CONSTRUCT(VIA, 0xffff) 168208373Smm 169208373Smm/* SiS */ 170208373Smm#define SIS_VENDORID 0x1039 171286625Smav#define HDA_SIS_966 HDA_MODEL_CONSTRUCT(SIS, 0x7502) 172208373Smm#define HDA_SIS_ALL HDA_MODEL_CONSTRUCT(SIS, 0xffff) 173168404Spjd 174286625Smav/* OEM/subvendors */ 175286625Smav 176286625Smav/* Intel */ 177286625Smav#define INTEL_D101GGC_SUBVENDOR HDA_MODEL_CONSTRUCT(INTEL, 0xd600) 178286625Smav 179286625Smav/* HP/Compaq */ 180286625Smav#define HP_VENDORID 0x103c 181286625Smav#define HP_V3000_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x30b5) 182286625Smav#define HP_NX7400_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x30a2) 183286625Smav#define HP_NX6310_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x30aa) 184286625Smav#define HP_NX6325_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x30b0) 185286625Smav#define HP_XW4300_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x3013) 186168404Spjd#define HP_3010_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x3010) 187168404Spjd#define HP_DV5000_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x30a5) 188168404Spjd#define HP_DC7700S_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x2801) 189168404Spjd#define HP_DC7700_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x2802) 190168404Spjd#define HP_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0xffff) 191258632Savg/* What is wrong with XN 2563 anyway? (Got the picture ?) */ 192258632Savg#define HP_NX6325_SUBVENDORX 0x103c30b0 193258632Savg 194258632Savg/* Dell */ 195258632Savg#define DELL_VENDORID 0x1028 196208373Smm#define DELL_D820_SUBVENDOR HDA_MODEL_CONSTRUCT(DELL, 0x01cc) 197194043Skmacy#define DELL_V1500_SUBVENDOR HDA_MODEL_CONSTRUCT(DELL, 0x0228) 198168404Spjd#define DELL_I1300_SUBVENDOR HDA_MODEL_CONSTRUCT(DELL, 0x01c9) 199168404Spjd#define DELL_XPSM1210_SUBVENDOR HDA_MODEL_CONSTRUCT(DELL, 0x01d7) 200185029Spjd#define DELL_OPLX745_SUBVENDOR HDA_MODEL_CONSTRUCT(DELL, 0x01da) 201185029Spjd#define DELL_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(DELL, 0xffff) 202185029Spjd 203185029Spjd/* Clevo */ 204185029Spjd#define CLEVO_VENDORID 0x1558 205185029Spjd#define CLEVO_D900T_SUBVENDOR HDA_MODEL_CONSTRUCT(CLEVO, 0x0900) 206185029Spjd#define CLEVO_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(CLEVO, 0xffff) 207275780Sdelphij 208208373Smm/* Acer */ 209208373Smm#define ACER_VENDORID 0x1025 210208373Smm#define ACER_A5050_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0x010f) 211242845Sdelphij#define ACER_A4520_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0x0127) 212269230Sdelphij#define ACER_A4710_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0x012f) 213272483Ssmh#define ACER_3681WXM_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0x0110) 214185029Spjd#define ACER_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0xffff) 215270759Ssmh 216275748Sdelphij/* Asus */ 217270759Ssmh#define ASUS_VENDORID 0x1043 218270759Ssmh#define ASUS_A8X_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1153) 219270759Ssmh#define ASUS_U5F_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1263) 220270759Ssmh#define ASUS_W6F_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1263) 221270759Ssmh#define ASUS_A7M_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1323) 222270759Ssmh#define ASUS_F3JC_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1338) 223272483Ssmh#define ASUS_G2K_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1339) 224270759Ssmh#define ASUS_A7T_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x13c2) 225270759Ssmh#define ASUS_W2J_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1971) 226270759Ssmh#define ASUS_M5200_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1993) 227270759Ssmh#define ASUS_P1AH2_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x81cb) 228185029Spjd#define ASUS_M2NPVMX_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x81cb) 229275780Sdelphij#define ASUS_M2V_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x81e7) 230273026Sdelphij#define ASUS_P5BWD_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x81ec) 231168473Spjd#define ASUS_M2N_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x8234) 232217367Smdf#define ASUS_A8NVMCSM_SUBVENDOR HDA_MODEL_CONSTRUCT(NVIDIA, 0xcb84) 233168473Spjd#define ASUS_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0xffff) 234217367Smdf 235168473Spjd/* IBM / Lenovo */ 236269230Sdelphij#define IBM_VENDORID 0x1014 237269230Sdelphij#define IBM_M52_SUBVENDOR HDA_MODEL_CONSTRUCT(IBM, 0x02f6) 238269230Sdelphij#define IBM_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(IBM, 0xffff) 239273026Sdelphij 240273026Sdelphij/* Lenovo */ 241273026Sdelphij#define LENOVO_VENDORID 0x17aa 242273026Sdelphij#define LENOVO_3KN100_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x2066) 243270759Ssmh#define LENOVO_TCA55_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x1015) 244270759Ssmh#define LENOVO_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0xffff) 245270759Ssmh 246270759Ssmh/* Samsung */ 247270759Ssmh#define SAMSUNG_VENDORID 0x144d 248270759Ssmh#define SAMSUNG_Q1_SUBVENDOR HDA_MODEL_CONSTRUCT(SAMSUNG, 0xc027) 249270759Ssmh#define SAMSUNG_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(SAMSUNG, 0xffff) 250270759Ssmh 251168404Spjd/* Medion ? */ 252270759Ssmh#define MEDION_VENDORID 0x161f 253270759Ssmh#define MEDION_MD95257_SUBVENDOR HDA_MODEL_CONSTRUCT(MEDION, 0x203d) 254270759Ssmh#define MEDION_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(MEDION, 0xffff) 255270759Ssmh 256270759Ssmh/* Apple Computer Inc. */ 257270759Ssmh#define APPLE_VENDORID 0x106b 258270759Ssmh#define APPLE_MB3_SUBVENDOR HDA_MODEL_CONSTRUCT(APPLE, 0x00a1) 259270759Ssmh 260270759Ssmh/* 261270759Ssmh * Apple Intel MacXXXX seems using Sigmatel codec/vendor id 262270759Ssmh * instead of their own, which is beyond my comprehension 263272483Ssmh * (see HDA_CODEC_STAC9221 below). 264270759Ssmh */ 265272483Ssmh#define APPLE_INTEL_MAC 0x76808384 266270759Ssmh 267270759Ssmh/* LG Electronics */ 268270759Ssmh#define LG_VENDORID 0x1854 269270759Ssmh#define LG_LW20_SUBVENDOR HDA_MODEL_CONSTRUCT(LG, 0x0018) 270270759Ssmh#define LG_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(LG, 0xffff) 271270759Ssmh 272275748Sdelphij/* Fujitsu Siemens */ 273275748Sdelphij#define FS_VENDORID 0x1734 274275748Sdelphij#define FS_PA1510_SUBVENDOR HDA_MODEL_CONSTRUCT(FS, 0x10b8) 275275748Sdelphij#define FS_SI1848_SUBVENDOR HDA_MODEL_CONSTRUCT(FS, 0x10cd) 276275748Sdelphij#define FS_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(FS, 0xffff) 277275748Sdelphij 278275748Sdelphij/* Fujitsu Limited */ 279275748Sdelphij#define FL_VENDORID 0x10cf 280275748Sdelphij#define FL_S7020D_SUBVENDOR HDA_MODEL_CONSTRUCT(FL, 0x1326) 281272483Ssmh#define FL_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(FL, 0xffff) 282270759Ssmh 283168404Spjd/* Toshiba */ 284185029Spjd#define TOSHIBA_VENDORID 0x1179 285168404Spjd#define TOSHIBA_U200_SUBVENDOR HDA_MODEL_CONSTRUCT(TOSHIBA, 0x0001) 286168404Spjd#define TOSHIBA_A135_SUBVENDOR HDA_MODEL_CONSTRUCT(TOSHIBA, 0xff01) 287168404Spjd#define TOSHIBA_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(TOSHIBA, 0xffff) 288168404Spjd 289168404Spjd/* Micro-Star International (MSI) */ 290185029Spjd#define MSI_VENDORID 0x1462 291185029Spjd#define MSI_MS1034_SUBVENDOR HDA_MODEL_CONSTRUCT(MSI, 0x0349) 292185029Spjd#define MSI_MS034A_SUBVENDOR HDA_MODEL_CONSTRUCT(MSI, 0x034a) 293185029Spjd#define MSI_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(MSI, 0xffff) 294185029Spjd 295185029Spjd/* Giga-Byte Technology */ 296185029Spjd#define GB_VENDORID 0x1458 297185029Spjd#define GB_G33S2H_SUBVENDOR HDA_MODEL_CONSTRUCT(GB, 0xa022) 298168404Spjd#define GP_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(GB, 0xffff) 299168404Spjd 300168404Spjd/* Uniwill ? */ 301168404Spjd#define UNIWILL_VENDORID 0x1584 302168404Spjd#define UNIWILL_9075_SUBVENDOR HDA_MODEL_CONSTRUCT(UNIWILL, 0x9075) 303168404Spjd#define UNIWILL_9080_SUBVENDOR HDA_MODEL_CONSTRUCT(UNIWILL, 0x9080) 304168404Spjd 305185029Spjd 306185029Spjd/* Misc constants.. */ 307185029Spjd#define HDA_AMP_MUTE_DEFAULT (0xffffffff) 308185029Spjd#define HDA_AMP_MUTE_NONE (0) 309185029Spjd#define HDA_AMP_MUTE_LEFT (1 << 0) 310185029Spjd#define HDA_AMP_MUTE_RIGHT (1 << 1) 311185029Spjd#define HDA_AMP_MUTE_ALL (HDA_AMP_MUTE_LEFT | HDA_AMP_MUTE_RIGHT) 312185029Spjd 313168404Spjd#define HDA_AMP_LEFT_MUTED(v) ((v) & (HDA_AMP_MUTE_LEFT)) 314168404Spjd#define HDA_AMP_RIGHT_MUTED(v) (((v) & HDA_AMP_MUTE_RIGHT) >> 1) 315205264Skmacy 316205231Skmacy#define HDA_DAC_PATH (1 << 0) 317205231Skmacy#define HDA_ADC_PATH (1 << 1) 318205231Skmacy#define HDA_ADC_RECSEL (1 << 2) 319205231Skmacy 320205231Skmacy#define HDA_DAC_LOCKED (1 << 3) 321205231Skmacy#define HDA_ADC_LOCKED (1 << 4) 322205231Skmacy 323205231Skmacy#define HDA_CTL_OUT (1 << 0) 324205231Skmacy#define HDA_CTL_IN (1 << 1) 325205231Skmacy#define HDA_CTL_BOTH (HDA_CTL_IN | HDA_CTL_OUT) 326205231Skmacy 327205231Skmacy#define HDA_GPIO_MAX 8 328205231Skmacy/* 0 - 7 = GPIO , 8 = Flush */ 329206796Spjd#define HDA_QUIRK_GPIO0 (1 << 0) 330205231Skmacy#define HDA_QUIRK_GPIO1 (1 << 1) 331168404Spjd#define HDA_QUIRK_GPIO2 (1 << 2) 332185029Spjd#define HDA_QUIRK_GPIO3 (1 << 3) 333185029Spjd#define HDA_QUIRK_GPIO4 (1 << 4) 334205231Skmacy#define HDA_QUIRK_GPIO5 (1 << 5) 335205264Skmacy#define HDA_QUIRK_GPIO6 (1 << 6) 336168404Spjd#define HDA_QUIRK_GPIO7 (1 << 7) 337168404Spjd#define HDA_QUIRK_GPIOFLUSH (1 << 8) 338206796Spjd 339205231Skmacy/* 9 - 25 = anything else */ 340185029Spjd#define HDA_QUIRK_SOFTPCMVOL (1 << 9) 341168404Spjd#define HDA_QUIRK_FIXEDRATE (1 << 10) 342168404Spjd#define HDA_QUIRK_FORCESTEREO (1 << 11) 343168404Spjd#define HDA_QUIRK_EAPDINV (1 << 12) 344168404Spjd#define HDA_QUIRK_DMAPOS (1 << 13) 345168404Spjd 346185029Spjd/* 26 - 31 = vrefs */ 347168404Spjd#define HDA_QUIRK_IVREF50 (1 << 26) 348168404Spjd#define HDA_QUIRK_IVREF80 (1 << 27) 349168404Spjd#define HDA_QUIRK_IVREF100 (1 << 28) 350168404Spjd#define HDA_QUIRK_OVREF50 (1 << 29) 351168404Spjd#define HDA_QUIRK_OVREF80 (1 << 30) 352168404Spjd#define HDA_QUIRK_OVREF100 (1 << 31) 353168404Spjd 354168404Spjd#define HDA_QUIRK_IVREF (HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF80 | \ 355168404Spjd HDA_QUIRK_IVREF100) 356168404Spjd#define HDA_QUIRK_OVREF (HDA_QUIRK_OVREF50 | HDA_QUIRK_OVREF80 | \ 357168404Spjd HDA_QUIRK_OVREF100) 358168404Spjd#define HDA_QUIRK_VREF (HDA_QUIRK_IVREF | HDA_QUIRK_OVREF) 359168404Spjd 360168404Spjd#define SOUND_MASK_SKIP (1 << 30) 361168404Spjd#define SOUND_MASK_DISABLE (1 << 31) 362168404Spjd 363205231Skmacy#if __FreeBSD_version < 600000 364168404Spjd#define taskqueue_drain(...) 365205231Skmacy#endif 366168404Spjd 367251629Sdelphijstatic const struct { 368251629Sdelphij char *key; 369251629Sdelphij uint32_t value; 370251629Sdelphij} hdac_quirks_tab[] = { 371251629Sdelphij { "gpio0", HDA_QUIRK_GPIO0 }, 372251629Sdelphij { "gpio1", HDA_QUIRK_GPIO1 }, 373168404Spjd { "gpio2", HDA_QUIRK_GPIO2 }, 374251629Sdelphij { "gpio3", HDA_QUIRK_GPIO3 }, 375251629Sdelphij { "gpio4", HDA_QUIRK_GPIO4 }, 376251629Sdelphij { "gpio5", HDA_QUIRK_GPIO5 }, 377251629Sdelphij { "gpio6", HDA_QUIRK_GPIO6 }, 378251629Sdelphij { "gpio7", HDA_QUIRK_GPIO7 }, 379168404Spjd { "gpioflush", HDA_QUIRK_GPIOFLUSH }, 380208373Smm { "softpcmvol", HDA_QUIRK_SOFTPCMVOL }, 381208373Smm { "fixedrate", HDA_QUIRK_FIXEDRATE }, 382208373Smm { "forcestereo", HDA_QUIRK_FORCESTEREO }, 383168404Spjd { "eapdinv", HDA_QUIRK_EAPDINV }, 384168404Spjd { "dmapos", HDA_QUIRK_DMAPOS }, 385168404Spjd { "ivref50", HDA_QUIRK_IVREF50 }, 386168404Spjd { "ivref80", HDA_QUIRK_IVREF80 }, 387168404Spjd { "ivref100", HDA_QUIRK_IVREF100 }, 388168404Spjd { "ovref50", HDA_QUIRK_OVREF50 }, 389168404Spjd { "ovref80", HDA_QUIRK_OVREF80 }, 390168404Spjd { "ovref100", HDA_QUIRK_OVREF100 }, 391168404Spjd { "ivref", HDA_QUIRK_IVREF }, 392168404Spjd { "ovref", HDA_QUIRK_OVREF }, 393286574Smav { "vref", HDA_QUIRK_VREF }, 394286574Smav}; 395286574Smav#define HDAC_QUIRKS_TAB_LEN \ 396286574Smav (sizeof(hdac_quirks_tab) / sizeof(hdac_quirks_tab[0])) 397286574Smav 398286574Smav#define HDA_BDL_MIN 2 399286574Smav#define HDA_BDL_MAX 256 400286574Smav#define HDA_BDL_DEFAULT HDA_BDL_MIN 401185029Spjd 402286574Smav#define HDA_BLK_MIN HDAC_DMA_ALIGNMENT 403286574Smav#define HDA_BLK_ALIGN (~(HDA_BLK_MIN - 1)) 404286574Smav 405286574Smav#define HDA_BUFSZ_MIN 4096 406286574Smav#define HDA_BUFSZ_MAX 65536 407208373Smm#define HDA_BUFSZ_DEFAULT 16384 408286574Smav 409286574Smav#define HDA_PARSE_MAXDEPTH 10 410286574Smav 411286574Smav#define HDAC_UNSOLTAG_EVENT_HP 0x00 412286574Smav#define HDAC_UNSOLTAG_EVENT_TEST 0x01 413286574Smav 414286574SmavMALLOC_DEFINE(M_HDAC, "hdac", "High Definition Audio Controller"); 415286574Smav 416286574Smavenum { 417286574Smav HDA_PARSE_MIXER, 418286574Smav HDA_PARSE_DIRECT 419286574Smav}; 420286574Smav 421286574Smav/* Default */ 422208373Smmstatic uint32_t hdac_fmt[] = { 423286574Smav AFMT_STEREO | AFMT_S16_LE, 424286574Smav 0 425286574Smav}; 426286574Smav 427286574Smavstatic struct pcmchan_caps hdac_caps = {48000, 48000, hdac_fmt, 0}; 428286574Smav 429286574Smavstatic const struct { 430286574Smav uint32_t model; 431286574Smav char *desc; 432286574Smav} hdac_devices[] = { 433286574Smav { HDA_INTEL_82801F, "Intel 82801F" }, 434286574Smav { HDA_INTEL_63XXESB, "Intel 631x/632xESB" }, 435286574Smav { HDA_INTEL_82801G, "Intel 82801G" }, 436286574Smav { HDA_INTEL_82801H, "Intel 82801H" }, 437286574Smav { HDA_INTEL_82801I, "Intel 82801I" }, 438286574Smav { HDA_NVIDIA_MCP51, "NVidia MCP51" }, 439286574Smav { HDA_NVIDIA_MCP55, "NVidia MCP55" }, 440286574Smav { HDA_NVIDIA_MCP61_1, "NVidia MCP61" }, 441286574Smav { HDA_NVIDIA_MCP61_2, "NVidia MCP61" }, 442286574Smav { HDA_NVIDIA_MCP65_1, "NVidia MCP65" }, 443286574Smav { HDA_NVIDIA_MCP65_2, "NVidia MCP65" }, 444286574Smav { HDA_NVIDIA_MCP67_1, "NVidia MCP67" }, 445286574Smav { HDA_NVIDIA_MCP67_2, "NVidia MCP67" }, 446286574Smav { HDA_ATI_SB450, "ATI SB450" }, 447286574Smav { HDA_ATI_SB600, "ATI SB600" }, 448286574Smav { HDA_VIA_VT82XX, "VIA VT8251/8237A" }, 449286574Smav { HDA_SIS_966, "SiS 966" }, 450286574Smav /* Unknown */ 451286574Smav { HDA_INTEL_ALL, "Intel (Unknown)" }, 452286574Smav { HDA_NVIDIA_ALL, "NVidia (Unknown)" }, 453286574Smav { HDA_ATI_ALL, "ATI (Unknown)" }, 454286574Smav { HDA_VIA_ALL, "VIA (Unknown)" }, 455286574Smav { HDA_SIS_ALL, "SiS (Unknown)" }, 456286574Smav}; 457286574Smav#define HDAC_DEVICES_LEN (sizeof(hdac_devices) / sizeof(hdac_devices[0])) 458286574Smav 459286574Smavstatic const struct { 460286574Smav uint16_t vendor; 461286574Smav uint8_t reg; 462286574Smav uint8_t mask; 463286574Smav uint8_t enable; 464286574Smav} hdac_pcie_snoop[] = { 465286574Smav { INTEL_VENDORID, 0x00, 0x00, 0x00 }, 466286574Smav { ATI_VENDORID, 0x42, 0xf8, 0x02 }, 467286574Smav { NVIDIA_VENDORID, 0x4e, 0xf0, 0x0f }, 468286574Smav}; 469286574Smav#define HDAC_PCIESNOOP_LEN \ 470286574Smav (sizeof(hdac_pcie_snoop) / sizeof(hdac_pcie_snoop[0])) 471286574Smav 472286574Smavstatic const struct { 473286574Smav uint32_t rate; 474286574Smav int valid; 475286574Smav uint16_t base; 476286574Smav uint16_t mul; 477286574Smav uint16_t div; 478286574Smav} hda_rate_tab[] = { 479286574Smav { 8000, 1, 0x0000, 0x0000, 0x0500 }, /* (48000 * 1) / 6 */ 480286574Smav { 9600, 0, 0x0000, 0x0000, 0x0400 }, /* (48000 * 1) / 5 */ 481286574Smav { 12000, 0, 0x0000, 0x0000, 0x0300 }, /* (48000 * 1) / 4 */ 482286574Smav { 16000, 1, 0x0000, 0x0000, 0x0200 }, /* (48000 * 1) / 3 */ 483286574Smav { 18000, 0, 0x0000, 0x1000, 0x0700 }, /* (48000 * 3) / 8 */ 484286574Smav { 19200, 0, 0x0000, 0x0800, 0x0400 }, /* (48000 * 2) / 5 */ 485286574Smav { 24000, 0, 0x0000, 0x0000, 0x0100 }, /* (48000 * 1) / 2 */ 486286574Smav { 28800, 0, 0x0000, 0x1000, 0x0400 }, /* (48000 * 3) / 5 */ 487286574Smav { 32000, 1, 0x0000, 0x0800, 0x0200 }, /* (48000 * 2) / 3 */ 488286574Smav { 36000, 0, 0x0000, 0x1000, 0x0300 }, /* (48000 * 3) / 4 */ 489286574Smav { 38400, 0, 0x0000, 0x1800, 0x0400 }, /* (48000 * 4) / 5 */ 490286574Smav { 48000, 1, 0x0000, 0x0000, 0x0000 }, /* (48000 * 1) / 1 */ 491286574Smav { 64000, 0, 0x0000, 0x1800, 0x0200 }, /* (48000 * 4) / 3 */ 492286574Smav { 72000, 0, 0x0000, 0x1000, 0x0100 }, /* (48000 * 3) / 2 */ 493286574Smav { 96000, 1, 0x0000, 0x0800, 0x0000 }, /* (48000 * 2) / 1 */ 494286574Smav { 144000, 0, 0x0000, 0x1000, 0x0000 }, /* (48000 * 3) / 1 */ 495286574Smav { 192000, 1, 0x0000, 0x1800, 0x0000 }, /* (48000 * 4) / 1 */ 496286574Smav { 8820, 0, 0x4000, 0x0000, 0x0400 }, /* (44100 * 1) / 5 */ 497286574Smav { 11025, 1, 0x4000, 0x0000, 0x0300 }, /* (44100 * 1) / 4 */ 498286574Smav { 12600, 0, 0x4000, 0x0800, 0x0600 }, /* (44100 * 2) / 7 */ 499286574Smav { 14700, 0, 0x4000, 0x0000, 0x0200 }, /* (44100 * 1) / 3 */ 500286574Smav { 17640, 0, 0x4000, 0x0800, 0x0400 }, /* (44100 * 2) / 5 */ 501286574Smav { 18900, 0, 0x4000, 0x1000, 0x0600 }, /* (44100 * 3) / 7 */ 502286574Smav { 22050, 1, 0x4000, 0x0000, 0x0100 }, /* (44100 * 1) / 2 */ 503286574Smav { 25200, 0, 0x4000, 0x1800, 0x0600 }, /* (44100 * 4) / 7 */ 504286574Smav { 26460, 0, 0x4000, 0x1000, 0x0400 }, /* (44100 * 3) / 5 */ 505286574Smav { 29400, 0, 0x4000, 0x0800, 0x0200 }, /* (44100 * 2) / 3 */ 506286574Smav { 33075, 0, 0x4000, 0x1000, 0x0300 }, /* (44100 * 3) / 4 */ 507286574Smav { 35280, 0, 0x4000, 0x1800, 0x0400 }, /* (44100 * 4) / 5 */ 508286574Smav { 44100, 1, 0x4000, 0x0000, 0x0000 }, /* (44100 * 1) / 1 */ 509286574Smav { 58800, 0, 0x4000, 0x1800, 0x0200 }, /* (44100 * 4) / 3 */ 510286574Smav { 66150, 0, 0x4000, 0x1000, 0x0100 }, /* (44100 * 3) / 2 */ 511286574Smav { 88200, 1, 0x4000, 0x0800, 0x0000 }, /* (44100 * 2) / 1 */ 512286574Smav { 132300, 0, 0x4000, 0x1000, 0x0000 }, /* (44100 * 3) / 1 */ 513286574Smav { 176400, 1, 0x4000, 0x1800, 0x0000 }, /* (44100 * 4) / 1 */ 514286574Smav}; 515286574Smav#define HDA_RATE_TAB_LEN (sizeof(hda_rate_tab) / sizeof(hda_rate_tab[0])) 516286574Smav 517286574Smav/* All codecs you can eat... */ 518286574Smav#define HDA_CODEC_CONSTRUCT(vendor, id) \ 519286574Smav (((uint32_t)(vendor##_VENDORID) << 16) | ((id) & 0xffff)) 520286574Smav 521286574Smav/* Realtek */ 522286574Smav#define REALTEK_VENDORID 0x10ec 523286574Smav#define HDA_CODEC_ALC260 HDA_CODEC_CONSTRUCT(REALTEK, 0x0260) 524185029Spjd#define HDA_CODEC_ALC262 HDA_CODEC_CONSTRUCT(REALTEK, 0x0262) 525185029Spjd#define HDA_CODEC_ALC268 HDA_CODEC_CONSTRUCT(REALTEK, 0x0268) 526185029Spjd#define HDA_CODEC_ALC660 HDA_CODEC_CONSTRUCT(REALTEK, 0x0660) 527185029Spjd#define HDA_CODEC_ALC861 HDA_CODEC_CONSTRUCT(REALTEK, 0x0861) 528208373Smm#define HDA_CODEC_ALC861VD HDA_CODEC_CONSTRUCT(REALTEK, 0x0862) 529208373Smm#define HDA_CODEC_ALC880 HDA_CODEC_CONSTRUCT(REALTEK, 0x0880) 530185029Spjd#define HDA_CODEC_ALC882 HDA_CODEC_CONSTRUCT(REALTEK, 0x0882) 531185029Spjd#define HDA_CODEC_ALC883 HDA_CODEC_CONSTRUCT(REALTEK, 0x0883) 532185029Spjd#define HDA_CODEC_ALC885 HDA_CODEC_CONSTRUCT(REALTEK, 0x0885) 533185029Spjd#define HDA_CODEC_ALC888 HDA_CODEC_CONSTRUCT(REALTEK, 0x0888) 534185029Spjd#define HDA_CODEC_ALCXXXX HDA_CODEC_CONSTRUCT(REALTEK, 0xffff) 535185029Spjd 536286570Smav/* Analog Devices */ 537185029Spjd#define ANALOGDEVICES_VENDORID 0x11d4 538274172Savg#define HDA_CODEC_AD1981HD HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1981) 539185029Spjd#define HDA_CODEC_AD1983 HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1983) 540185029Spjd#define HDA_CODEC_AD1984 HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1984) 541185029Spjd#define HDA_CODEC_AD1986A HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1986) 542185029Spjd#define HDA_CODEC_AD1988 HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1988) 543251478Sdelphij#define HDA_CODEC_AD1988B HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x198b) 544185029Spjd#define HDA_CODEC_ADXXXX HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0xffff) 545251478Sdelphij 546251478Sdelphij/* CMedia */ 547251478Sdelphij#define CMEDIA_VENDORID 0x434d 548205231Skmacy#define HDA_CODEC_CMI9880 HDA_CODEC_CONSTRUCT(CMEDIA, 0x4980) 549205231Skmacy#define HDA_CODEC_CMIXXXX HDA_CODEC_CONSTRUCT(CMEDIA, 0xffff) 550205231Skmacy 551206796Spjd/* Sigmatel */ 552205231Skmacy#define SIGMATEL_VENDORID 0x8384 553205231Skmacy#define HDA_CODEC_STAC9221 HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7680) 554205231Skmacy#define HDA_CODEC_STAC9221D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7683) 555205231Skmacy#define HDA_CODEC_STAC9220 HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7690) 556205231Skmacy#define HDA_CODEC_STAC922XD HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7681) 557205231Skmacy#define HDA_CODEC_STAC9227 HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7618) 558205231Skmacy#define HDA_CODEC_STAC9271D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7627) 559205231Skmacy#define HDA_CODEC_STAC9205 HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a0) 560242845Sdelphij#define HDA_CODEC_STACXXXX HDA_CODEC_CONSTRUCT(SIGMATEL, 0xffff) 561242845Sdelphij 562242845Sdelphij/* 563242845Sdelphij * Conexant 564275748Sdelphij * 565275748Sdelphij * Ok, the truth is, I don't have any idea at all whether 566275748Sdelphij * it is "Venice" or "Waikiki" or other unnamed CXyadayada. The only 567275780Sdelphij * place that tell me it is "Venice" is from its Windows driver INF. 568168404Spjd * 569168404Spjd * Venice - CX????? 570168404Spjd * Waikiki - CX20551-22 571168404Spjd */ 572168404Spjd#define CONEXANT_VENDORID 0x14f1 573168404Spjd#define HDA_CODEC_CXVENICE HDA_CODEC_CONSTRUCT(CONEXANT, 0x5045) 574168404Spjd#define HDA_CODEC_CXWAIKIKI HDA_CODEC_CONSTRUCT(CONEXANT, 0x5047) 575168404Spjd#define HDA_CODEC_CXXXXX HDA_CODEC_CONSTRUCT(CONEXANT, 0xffff) 576168404Spjd 577168404Spjd/* VIA */ 578168404Spjd#define HDA_CODEC_VT1708_8 HDA_CODEC_CONSTRUCT(VIA, 0x1708) 579168404Spjd#define HDA_CODEC_VT1708_9 HDA_CODEC_CONSTRUCT(VIA, 0x1709) 580168404Spjd#define HDA_CODEC_VT1708_A HDA_CODEC_CONSTRUCT(VIA, 0x170a) 581168404Spjd#define HDA_CODEC_VT1708_B HDA_CODEC_CONSTRUCT(VIA, 0x170b) 582168404Spjd#define HDA_CODEC_VT1709_0 HDA_CODEC_CONSTRUCT(VIA, 0xe710) 583168404Spjd#define HDA_CODEC_VT1709_1 HDA_CODEC_CONSTRUCT(VIA, 0xe711) 584168404Spjd#define HDA_CODEC_VT1709_2 HDA_CODEC_CONSTRUCT(VIA, 0xe712) 585205231Skmacy#define HDA_CODEC_VT1709_3 HDA_CODEC_CONSTRUCT(VIA, 0xe713) 586168404Spjd#define HDA_CODEC_VT1709_4 HDA_CODEC_CONSTRUCT(VIA, 0xe714) 587205231Skmacy#define HDA_CODEC_VT1709_5 HDA_CODEC_CONSTRUCT(VIA, 0xe715) 588168404Spjd#define HDA_CODEC_VT1709_6 HDA_CODEC_CONSTRUCT(VIA, 0xe716) 589168404Spjd#define HDA_CODEC_VT1709_7 HDA_CODEC_CONSTRUCT(VIA, 0xe717) 590168404Spjd#define HDA_CODEC_VTXXXX HDA_CODEC_CONSTRUCT(VIA, 0xffff) 591208373Smm 592208373Smm 593208373Smm/* Codecs */ 594168404Spjdstatic const struct { 595168404Spjd uint32_t id; 596168404Spjd char *name; 597168404Spjd} hdac_codecs[] = { 598168404Spjd { HDA_CODEC_ALC260, "Realtek ALC260" }, 599168404Spjd { HDA_CODEC_ALC262, "Realtek ALC262" }, 600168404Spjd { HDA_CODEC_ALC268, "Realtek ALC268" }, 601168404Spjd { HDA_CODEC_ALC660, "Realtek ALC660" }, 602168404Spjd { HDA_CODEC_ALC861, "Realtek ALC861" }, 603185029Spjd { HDA_CODEC_ALC861VD, "Realtek ALC861-VD" }, 604185029Spjd { HDA_CODEC_ALC880, "Realtek ALC880" }, 605208373Smm { HDA_CODEC_ALC882, "Realtek ALC882" }, 606286574Smav { HDA_CODEC_ALC883, "Realtek ALC883" }, 607208373Smm { HDA_CODEC_ALC885, "Realtek ALC885" }, 608286574Smav { HDA_CODEC_ALC888, "Realtek ALC888" }, 609286574Smav { HDA_CODEC_AD1981HD, "Analog Devices AD1981HD" }, 610286574Smav { HDA_CODEC_AD1983, "Analog Devices AD1983" }, 611286574Smav { HDA_CODEC_AD1984, "Analog Devices AD1984" }, 612286574Smav { HDA_CODEC_AD1986A, "Analog Devices AD1986A" }, 613286574Smav { HDA_CODEC_AD1988, "Analog Devices AD1988" }, 614286574Smav { HDA_CODEC_AD1988B, "Analog Devices AD1988B" }, 615286574Smav { HDA_CODEC_CMI9880, "CMedia CMI9880" }, 616286574Smav { HDA_CODEC_STAC9221, "Sigmatel STAC9221" }, 617286574Smav { HDA_CODEC_STAC9221D, "Sigmatel STAC9221D" }, 618286574Smav { HDA_CODEC_STAC9220, "Sigmatel STAC9220" }, 619286574Smav { HDA_CODEC_STAC922XD, "Sigmatel STAC9220D/9223D" }, 620286574Smav { HDA_CODEC_STAC9227, "Sigmatel STAC9227" }, 621286574Smav { HDA_CODEC_STAC9271D, "Sigmatel STAC9271D" }, 622286574Smav { HDA_CODEC_STAC9205, "Sigmatel STAC9205" }, 623185029Spjd { HDA_CODEC_CXVENICE, "Conexant Venice" }, 624185029Spjd { HDA_CODEC_CXWAIKIKI, "Conexant Waikiki" }, 625185029Spjd { HDA_CODEC_VT1708_8, "VIA VT1708_8" }, 626185029Spjd { HDA_CODEC_VT1708_9, "VIA VT1708_9" }, 627208373Smm { HDA_CODEC_VT1708_A, "VIA VT1708_A" }, 628208373Smm { HDA_CODEC_VT1708_B, "VIA VT1708_B" }, 629185029Spjd { HDA_CODEC_VT1709_0, "VIA VT1709_0" }, 630185029Spjd { HDA_CODEC_VT1709_1, "VIA VT1709_1" }, 631185029Spjd { HDA_CODEC_VT1709_2, "VIA VT1709_2" }, 632185029Spjd { HDA_CODEC_VT1709_3, "VIA VT1709_3" }, 633185029Spjd { HDA_CODEC_VT1709_4, "VIA VT1709_4" }, 634185029Spjd { HDA_CODEC_VT1709_5, "VIA VT1709_5" }, 635286570Smav { HDA_CODEC_VT1709_6, "VIA VT1709_6" }, 636185029Spjd { HDA_CODEC_VT1709_7, "VIA VT1709_7" }, 637274172Savg /* Unknown codec */ 638185029Spjd { HDA_CODEC_ALCXXXX, "Realtek (Unknown)" }, 639185029Spjd { HDA_CODEC_ADXXXX, "Analog Devices (Unknown)" }, 640185029Spjd { HDA_CODEC_CMIXXXX, "CMedia (Unknown)" }, 641185029Spjd { HDA_CODEC_STACXXXX, "Sigmatel (Unknown)" }, 642251478Sdelphij { HDA_CODEC_CXXXXX, "Conexant (Unknown)" }, 643185029Spjd { HDA_CODEC_VTXXXX, "VIA (Unknown)" }, 644251478Sdelphij}; 645251478Sdelphij#define HDAC_CODECS_LEN (sizeof(hdac_codecs) / sizeof(hdac_codecs[0])) 646251478Sdelphij 647206796Spjdenum { 648206796Spjd HDAC_HP_SWITCH_CTL, 649206796Spjd HDAC_HP_SWITCH_CTRL, 650206796Spjd HDAC_HP_SWITCH_DEBUG 651206796Spjd}; 652206796Spjd 653206796Spjdstatic const struct { 654206796Spjd uint32_t model; 655206796Spjd uint32_t id; 656206796Spjd int type; 657206796Spjd int inverted; 658242845Sdelphij int polling; 659242845Sdelphij int execsense; 660242845Sdelphij nid_t hpnid; 661242845Sdelphij nid_t spkrnid[8]; 662275748Sdelphij nid_t eapdnid; 663275748Sdelphij} hdac_hp_switch[] = { 664275748Sdelphij /* Specific OEM models */ 665275780Sdelphij { HP_V3000_SUBVENDOR, HDA_CODEC_CXVENICE, HDAC_HP_SWITCH_CTL, 666275780Sdelphij 0, 0, -1, 17, { 16, -1 }, 16 }, 667168404Spjd /* { HP_XW4300_SUBVENDOR, HDA_CODEC_ALC260, HDAC_HP_SWITCH_CTL, 668168404Spjd 0, 0, -1, 21, { 16, 17, -1 }, -1 } */ 669168404Spjd /* { HP_3010_SUBVENDOR, HDA_CODEC_ALC260, HDAC_HP_SWITCH_DEBUG, 670168404Spjd 0, 1, 0, 16, { 15, 18, 19, 20, 21, -1 }, -1 }, */ 671168404Spjd { HP_NX7400_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 672251631Sdelphij 0, 0, -1, 6, { 5, -1 }, 5 }, 673168404Spjd { HP_NX6310_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 674206796Spjd 0, 0, -1, 6, { 5, -1 }, 5 }, 675168404Spjd { HP_NX6325_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 676168404Spjd 0, 0, -1, 6, { 5, -1 }, 5 }, 677168404Spjd /* { HP_DC7700_SUBVENDOR, HDA_CODEC_ALC262, HDAC_HP_SWITCH_CTL, 678168404Spjd 0, 0, -1, 21, { 22, 27, -1 }, -1 }, */ 679168404Spjd { TOSHIBA_U200_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 680168404Spjd 0, 0, -1, 6, { 5, -1 }, -1 }, 681168404Spjd { TOSHIBA_A135_SUBVENDOR, HDA_CODEC_ALC861VD, HDAC_HP_SWITCH_CTL, 682168404Spjd 0, 0, -1, 27, { 20, -1 }, -1 }, 683168404Spjd { DELL_D820_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL, 684168404Spjd 0, 0, -1, 13, { 14, -1 }, -1 }, 685168404Spjd { DELL_I1300_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL, 686168404Spjd 0, 0, -1, 13, { 14, -1 }, -1 }, 687168404Spjd { DELL_OPLX745_SUBVENDOR, HDA_CODEC_AD1983, HDAC_HP_SWITCH_CTL, 688168404Spjd 0, 0, -1, 6, { 5, 7, -1 }, -1 }, 689168404Spjd { DELL_V1500_SUBVENDOR, HDA_CODEC_STAC9205, HDAC_HP_SWITCH_CTRL, 690168404Spjd 0, 0, -1, 10, { 13, -1 }, -1 }, 691168404Spjd { APPLE_MB3_SUBVENDOR, HDA_CODEC_ALC885, HDAC_HP_SWITCH_CTL, 692168404Spjd 0, 0, -1, 21, { 20, 22, -1 }, -1 }, 693168404Spjd { APPLE_INTEL_MAC, HDA_CODEC_STAC9221, HDAC_HP_SWITCH_CTRL, 694168404Spjd 0, 0, -1, 10, { 13, -1 }, -1 }, 695168404Spjd { LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A, HDAC_HP_SWITCH_CTL, 696168404Spjd 1, 0, -1, 26, { 27, -1 }, -1 }, 697168404Spjd /* { LENOVO_TCA55_SUBVENDOR, HDA_CODEC_AD1986A, HDAC_HP_SWITCH_CTL, 698168404Spjd 0, 0, -1, 26, { 27, 28, 29, 30, -1 }, -1 }, */ 699168404Spjd { LG_LW20_SUBVENDOR, HDA_CODEC_ALC880, HDAC_HP_SWITCH_CTL, 700168404Spjd 0, 0, -1, 27, { 20, -1 }, -1 }, 701168404Spjd { ACER_A5050_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, 702168404Spjd 0, 0, -1, 20, { 21, -1 }, -1 }, 703168404Spjd { ACER_3681WXM_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, 704168404Spjd 0, 0, -1, 20, { 21, -1 }, -1 }, 705168404Spjd { ACER_A4520_SUBVENDOR, HDA_CODEC_ALC268, HDAC_HP_SWITCH_CTL, 706168404Spjd 0, 0, -1, 20, { 21, -1 }, -1 }, 707168404Spjd { ACER_A4710_SUBVENDOR, HDA_CODEC_ALC268, HDAC_HP_SWITCH_CTL, 708206796Spjd 0, 0, -1, 20, { 21, -1 }, -1 }, 709168404Spjd { UNIWILL_9080_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, 710168404Spjd 0, 0, -1, 20, { 21, -1 }, -1 }, 711168404Spjd { MSI_MS1034_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, 712168404Spjd 0, 0, -1, 20, { 27, -1 }, -1 }, 713185029Spjd { MSI_MS034A_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, 714168404Spjd 0, 0, -1, 20, { 27, -1 }, -1 }, 715168404Spjd { FS_SI1848_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, 716168404Spjd 0, 0, -1, 20, { 21, -1 }, -1 }, 717168404Spjd { FL_S7020D_SUBVENDOR, HDA_CODEC_ALC260, HDAC_HP_SWITCH_CTL, 718168404Spjd 0, 0, -1, 20, { 16, -1 }, -1 }, 719168404Spjd /* 720168404Spjd * All models that at least come from the same vendor with 721168404Spjd * simmilar codec. 722168404Spjd */ 723168404Spjd { HP_ALL_SUBVENDOR, HDA_CODEC_CXVENICE, HDAC_HP_SWITCH_CTL, 724168404Spjd 0, 0, -1, 17, { 16, -1 }, 16 }, 725168404Spjd { HP_ALL_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 726168404Spjd 0, 0, -1, 6, { 5, -1 }, 5 }, 727168404Spjd { TOSHIBA_ALL_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 728275748Sdelphij 0, 0, -1, 6, { 5, -1 }, -1 }, 729275780Sdelphij { DELL_ALL_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL, 730275748Sdelphij 0, 0, -1, 13, { 14, -1 }, -1 }, 731275748Sdelphij#if 0 732168404Spjd { LENOVO_ALL_SUBVENDOR, HDA_CODEC_AD1986A, HDAC_HP_SWITCH_CTL, 733251478Sdelphij 1, 0, -1, 26, { 27, -1 }, -1 }, 734251478Sdelphij { ACER_ALL_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, 735251478Sdelphij 0, 0, -1, 20, { 21, -1 }, -1 }, 736168404Spjd#endif 737168404Spjd}; 738209962Smm#define HDAC_HP_SWITCH_LEN \ 739168404Spjd (sizeof(hdac_hp_switch) / sizeof(hdac_hp_switch[0])) 740168404Spjd 741168404Spjdstatic const struct { 742168404Spjd uint32_t model; 743168404Spjd uint32_t id; 744168404Spjd nid_t eapdnid; 745168404Spjd int hp_switch; 746168404Spjd} hdac_eapd_switch[] = { 747168404Spjd { HP_V3000_SUBVENDOR, HDA_CODEC_CXVENICE, 16, 1 }, 748168404Spjd { HP_NX7400_SUBVENDOR, HDA_CODEC_AD1981HD, 5, 1 }, 749168404Spjd { HP_NX6310_SUBVENDOR, HDA_CODEC_AD1981HD, 5, 1 }, 750168404Spjd}; 751168404Spjd#define HDAC_EAPD_SWITCH_LEN \ 752168404Spjd (sizeof(hdac_eapd_switch) / sizeof(hdac_eapd_switch[0])) 753168404Spjd 754168404Spjd/**************************************************************************** 755258632Savg * Function prototypes 756168404Spjd ****************************************************************************/ 757168404Spjdstatic void hdac_intr_handler(void *); 758168404Spjdstatic int hdac_reset(struct hdac_softc *); 759168404Spjdstatic int hdac_get_capabilities(struct hdac_softc *); 760286570Smavstatic void hdac_dma_cb(void *, bus_dma_segment_t *, int, int); 761286570Smavstatic int hdac_dma_alloc(struct hdac_softc *, 762286570Smav struct hdac_dma *, bus_size_t); 763286570Smavstatic void hdac_dma_free(struct hdac_softc *, struct hdac_dma *); 764286570Smavstatic int hdac_mem_alloc(struct hdac_softc *); 765286570Smavstatic void hdac_mem_free(struct hdac_softc *); 766286570Smavstatic int hdac_irq_alloc(struct hdac_softc *); 767286570Smavstatic void hdac_irq_free(struct hdac_softc *); 768286570Smavstatic void hdac_corb_init(struct hdac_softc *); 769286570Smavstatic void hdac_rirb_init(struct hdac_softc *); 770286570Smavstatic void hdac_corb_start(struct hdac_softc *); 771286570Smavstatic void hdac_rirb_start(struct hdac_softc *); 772286570Smavstatic void hdac_scan_codecs(struct hdac_softc *, int); 773286570Smavstatic int hdac_probe_codec(struct hdac_codec *); 774286570Smavstatic struct hdac_devinfo *hdac_probe_function(struct hdac_codec *, nid_t); 775286570Smavstatic void hdac_add_child(struct hdac_softc *, struct hdac_devinfo *); 776286570Smav 777286570Smavstatic void hdac_attach2(void *); 778286570Smav 779286570Smavstatic uint32_t hdac_command_sendone_internal(struct hdac_softc *, 780286570Smav uint32_t, int); 781286570Smavstatic void hdac_command_send_internal(struct hdac_softc *, 782286570Smav struct hdac_command_list *, int); 783286570Smav 784286570Smavstatic int hdac_probe(device_t); 785286570Smavstatic int hdac_attach(device_t); 786286570Smavstatic int hdac_detach(device_t); 787286570Smavstatic void hdac_widget_connection_select(struct hdac_widget *, uint8_t); 788286570Smavstatic void hdac_audio_ctl_amp_set(struct hdac_audio_ctl *, 789286570Smav uint32_t, int, int); 790286570Smavstatic struct hdac_audio_ctl *hdac_audio_ctl_amp_get(struct hdac_devinfo *, 791286570Smav nid_t, int, int); 792168404Spjdstatic void hdac_audio_ctl_amp_set_internal(struct hdac_softc *, 793286570Smav nid_t, nid_t, int, int, int, int, int, int); 794286570Smavstatic int hdac_audio_ctl_ossmixer_getnextdev(struct hdac_devinfo *); 795286570Smavstatic struct hdac_widget *hdac_widget_get(struct hdac_devinfo *, nid_t); 796286570Smav 797286570Smavstatic int hdac_rirb_flush(struct hdac_softc *sc); 798286570Smavstatic int hdac_unsolq_flush(struct hdac_softc *sc); 799219089Spjd 800286570Smav#define hdac_command(a1, a2, a3) \ 801168404Spjd hdac_command_sendone_internal(a1, a2, a3) 802168404Spjd 803168404Spjd#define hdac_codec_id(d) \ 804286570Smav ((uint32_t)((d == NULL) ? 0x00000000 : \ 805168404Spjd ((((uint32_t)(d)->vendor_id & 0x0000ffff) << 16) | \ 806168404Spjd ((uint32_t)(d)->device_id & 0x0000ffff)))) 807168404Spjd 808168404Spjdstatic char * 809168404Spjdhdac_codec_name(struct hdac_devinfo *devinfo) 810168404Spjd{ 811168404Spjd uint32_t id; 812168404Spjd int i; 813168404Spjd 814168404Spjd id = hdac_codec_id(devinfo); 815168404Spjd 816185029Spjd for (i = 0; i < HDAC_CODECS_LEN; i++) { 817286570Smav if (HDA_DEV_MATCH(hdac_codecs[i].id, id)) 818286570Smav return (hdac_codecs[i].name); 819286570Smav } 820286570Smav 821286570Smav return ((id == 0x00000000) ? "NULL Codec" : "Unknown Codec"); 822286570Smav} 823286570Smav 824286570Smavstatic char * 825286570Smavhdac_audio_ctl_ossmixer_mask2name(uint32_t devmask) 826286570Smav{ 827286570Smav static char *ossname[] = SOUND_DEVICE_NAMES; 828286570Smav static char *unknown = "???"; 829286570Smav int i; 830286570Smav 831185029Spjd for (i = SOUND_MIXER_NRDEVICES - 1; i >= 0; i--) { 832286570Smav if (devmask & (1 << i)) 833286570Smav return (ossname[i]); 834286570Smav } 835286570Smav return (unknown); 836286570Smav} 837286570Smav 838286570Smavstatic void 839286570Smavhdac_audio_ctl_ossmixer_mask2allname(uint32_t mask, char *buf, size_t len) 840286570Smav{ 841286570Smav static char *ossname[] = SOUND_DEVICE_NAMES; 842286570Smav int i, first = 1; 843286570Smav 844286570Smav bzero(buf, len); 845286570Smav for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 846286570Smav if (mask & (1 << i)) { 847286570Smav if (first == 0) 848286570Smav strlcat(buf, ", ", len); 849286570Smav strlcat(buf, ossname[i], len); 850286570Smav first = 0; 851286570Smav } 852286570Smav } 853286570Smav} 854286570Smav 855286570Smavstatic struct hdac_audio_ctl * 856286570Smavhdac_audio_ctl_each(struct hdac_devinfo *devinfo, int *index) 857168404Spjd{ 858168404Spjd if (devinfo == NULL || 859275748Sdelphij devinfo->node_type != HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO || 860275748Sdelphij index == NULL || devinfo->function.audio.ctl == NULL || 861275748Sdelphij devinfo->function.audio.ctlcnt < 1 || 862275748Sdelphij *index < 0 || *index >= devinfo->function.audio.ctlcnt) 863275748Sdelphij return (NULL); 864275748Sdelphij return (&devinfo->function.audio.ctl[(*index)++]); 865275748Sdelphij} 866275748Sdelphij 867275748Sdelphijstatic struct hdac_audio_ctl * 868275748Sdelphijhdac_audio_ctl_amp_get(struct hdac_devinfo *devinfo, nid_t nid, 869275748Sdelphij int index, int cnt) 870275748Sdelphij{ 871275748Sdelphij struct hdac_audio_ctl *ctl, *retctl = NULL; 872275748Sdelphij int i, at, atindex, found = 0; 873275748Sdelphij 874275748Sdelphij if (devinfo == NULL || devinfo->function.audio.ctl == NULL) 875275748Sdelphij return (NULL); 876275748Sdelphij 877275748Sdelphij at = cnt; 878275748Sdelphij if (at == 0) 879168404Spjd at = 1; 880168404Spjd else if (at < 0) 881168404Spjd at = -1; 882168404Spjd atindex = index; 883168404Spjd if (atindex < 0) 884185029Spjd atindex = -1; 885185029Spjd 886168404Spjd i = 0; 887275811Sdelphij while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 888275811Sdelphij if (ctl->enable == 0 || ctl->widget == NULL) 889275811Sdelphij continue; 890275811Sdelphij if (!(ctl->widget->nid == nid && (atindex == -1 || 891275811Sdelphij ctl->index == atindex))) 892275811Sdelphij continue; 893286570Smav found++; 894275811Sdelphij if (found == cnt) 895286570Smav return (ctl); 896275811Sdelphij retctl = ctl; 897286570Smav } 898286570Smav 899275811Sdelphij return ((at == -1) ? retctl : NULL); 900275811Sdelphij} 901275811Sdelphij 902168404Spjdstatic void 903286570Smavhdac_hp_switch_handler(struct hdac_devinfo *devinfo) 904286570Smav{ 905286570Smav struct hdac_softc *sc; 906286570Smav struct hdac_widget *w; 907286570Smav struct hdac_audio_ctl *ctl; 908286570Smav uint32_t val, id, res; 909286570Smav int i = 0, j, timeout, forcemute; 910286570Smav nid_t cad; 911286570Smav 912286570Smav if (devinfo == NULL || devinfo->codec == NULL || 913286570Smav devinfo->codec->sc == NULL) 914286570Smav return; 915286570Smav 916286570Smav sc = devinfo->codec->sc; 917286570Smav cad = devinfo->codec->cad; 918286570Smav id = hdac_codec_id(devinfo); 919168404Spjd for (i = 0; i < HDAC_HP_SWITCH_LEN; i++) { 920185029Spjd if (HDA_DEV_MATCH(hdac_hp_switch[i].model, 921185029Spjd sc->pci_subvendor) && 922185029Spjd hdac_hp_switch[i].id == id) 923286570Smav break; 924286570Smav } 925185029Spjd 926185029Spjd if (i >= HDAC_HP_SWITCH_LEN) 927168404Spjd return; 928168404Spjd 929168404Spjd forcemute = 0; 930205253Skmacy if (hdac_hp_switch[i].eapdnid != -1) { 931168404Spjd w = hdac_widget_get(devinfo, hdac_hp_switch[i].eapdnid); 932168404Spjd if (w != NULL && w->param.eapdbtl != HDAC_INVALID) 933168404Spjd forcemute = (w->param.eapdbtl & 934168404Spjd HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD) ? 0 : 1; 935168404Spjd } 936168404Spjd 937168404Spjd if (hdac_hp_switch[i].execsense != -1) 938168404Spjd hdac_command(sc, 939168404Spjd HDA_CMD_SET_PIN_SENSE(cad, hdac_hp_switch[i].hpnid, 940168404Spjd hdac_hp_switch[i].execsense), cad); 941168404Spjd 942168404Spjd timeout = 10000; 943205264Skmacy do { 944168404Spjd res = hdac_command(sc, 945168404Spjd HDA_CMD_GET_PIN_SENSE(cad, hdac_hp_switch[i].hpnid), 946168404Spjd cad); 947168404Spjd if (hdac_hp_switch[i].execsense == -1 || res != 0x7fffffff) 948168404Spjd break; 949168404Spjd DELAY(10); 950168404Spjd } while (--timeout != 0); 951168404Spjd 952219089Spjd HDA_BOOTVERBOSE( 953219089Spjd device_printf(sc->dev, 954168404Spjd "HDA_DEBUG: Pin sense: nid=%d timeout=%d res=0x%08x\n", 955168404Spjd hdac_hp_switch[i].hpnid, timeout, res); 956168404Spjd ); 957185029Spjd 958185029Spjd res = HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT(res); 959185029Spjd res ^= hdac_hp_switch[i].inverted; 960185029Spjd 961272707Savg switch (hdac_hp_switch[i].type) { 962251478Sdelphij case HDAC_HP_SWITCH_CTL: 963251478Sdelphij ctl = hdac_audio_ctl_amp_get(devinfo, 964251478Sdelphij hdac_hp_switch[i].hpnid, 0, 1); 965251478Sdelphij if (ctl != NULL) { 966251478Sdelphij val = (res != 0 && forcemute == 0) ? 967251478Sdelphij HDA_AMP_MUTE_NONE : HDA_AMP_MUTE_ALL; 968208373Smm if (val != ctl->muted) { 969208373Smm ctl->muted = val; 970185029Spjd hdac_audio_ctl_amp_set(ctl, 971286598Smav HDA_AMP_MUTE_DEFAULT, ctl->left, 972286598Smav ctl->right); 973286598Smav } 974286598Smav } 975286598Smav for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) { 976286598Smav ctl = hdac_audio_ctl_amp_get(devinfo, 977286598Smav hdac_hp_switch[i].spkrnid[j], 0, 1); 978286598Smav if (ctl == NULL) 979286598Smav continue; 980286598Smav val = (res != 0 || forcemute == 1) ? 981185029Spjd HDA_AMP_MUTE_ALL : HDA_AMP_MUTE_NONE; 982185029Spjd if (val == ctl->muted) 983185029Spjd continue; 984251631Sdelphij ctl->muted = val; 985185029Spjd hdac_audio_ctl_amp_set(ctl, HDA_AMP_MUTE_DEFAULT, 986185029Spjd ctl->left, ctl->right); 987185029Spjd } 988251478Sdelphij break; 989185029Spjd case HDAC_HP_SWITCH_CTRL: 990208373Smm if (res != 0) { 991219089Spjd /* HP in */ 992208373Smm w = hdac_widget_get(devinfo, hdac_hp_switch[i].hpnid); 993208373Smm if (w != NULL && w->type == 994185029Spjd HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) { 995217367Smdf if (forcemute == 0) 996205231Skmacy val = w->wclass.pin.ctrl | 997217367Smdf HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; 998205231Skmacy else 999217367Smdf val = w->wclass.pin.ctrl & 1000205231Skmacy ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; 1001217367Smdf if (val != w->wclass.pin.ctrl) { 1002205231Skmacy w->wclass.pin.ctrl = val; 1003217367Smdf hdac_command(sc, 1004208373Smm HDA_CMD_SET_PIN_WIDGET_CTRL(cad, 1005205231Skmacy w->nid, w->wclass.pin.ctrl), cad); 1006205231Skmacy } 1007205231Skmacy } 1008208373Smm for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) { 1009208373Smm w = hdac_widget_get(devinfo, 1010208373Smm hdac_hp_switch[i].spkrnid[j]); 1011208373Smm if (w == NULL || w->type != 1012205231Skmacy HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) 1013217367Smdf continue; 1014205231Skmacy val = w->wclass.pin.ctrl & 1015217367Smdf ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; 1016205231Skmacy if (val == w->wclass.pin.ctrl) 1017217367Smdf continue; 1018205231Skmacy w->wclass.pin.ctrl = val; 1019205231Skmacy hdac_command(sc, HDA_CMD_SET_PIN_WIDGET_CTRL( 1020217367Smdf cad, w->nid, w->wclass.pin.ctrl), cad); 1021205231Skmacy } 1022217367Smdf } else { 1023205231Skmacy /* HP out */ 1024217367Smdf w = hdac_widget_get(devinfo, hdac_hp_switch[i].hpnid); 1025205231Skmacy if (w != NULL && w->type == 1026205231Skmacy HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) { 1027217367Smdf val = w->wclass.pin.ctrl & 1028205231Skmacy ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; 1029217367Smdf if (val != w->wclass.pin.ctrl) { 1030205231Skmacy w->wclass.pin.ctrl = val; 1031205231Skmacy hdac_command(sc, 1032217367Smdf HDA_CMD_SET_PIN_WIDGET_CTRL(cad, 1033205231Skmacy w->nid, w->wclass.pin.ctrl), cad); 1034205231Skmacy } 1035205231Skmacy } 1036217367Smdf for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) { 1037205231Skmacy w = hdac_widget_get(devinfo, 1038217367Smdf hdac_hp_switch[i].spkrnid[j]); 1039205231Skmacy if (w == NULL || w->type != 1040217367Smdf HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) 1041205231Skmacy continue; 1042205231Skmacy if (forcemute == 0) 1043217367Smdf val = w->wclass.pin.ctrl | 1044205231Skmacy HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; 1045217367Smdf else 1046205231Skmacy val = w->wclass.pin.ctrl & 1047205231Skmacy ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; 1048217367Smdf if (val == w->wclass.pin.ctrl) 1049205231Skmacy continue; 1050205231Skmacy w->wclass.pin.ctrl = val; 1051205231Skmacy hdac_command(sc, HDA_CMD_SET_PIN_WIDGET_CTRL( 1052217367Smdf cad, w->nid, w->wclass.pin.ctrl), cad); 1053205231Skmacy } 1054205231Skmacy } 1055185029Spjd break; 1056185029Spjd case HDAC_HP_SWITCH_DEBUG: 1057185029Spjd if (hdac_hp_switch[i].execsense != -1) 1058286570Smav hdac_command(sc, 1059185029Spjd HDA_CMD_SET_PIN_SENSE(cad, hdac_hp_switch[i].hpnid, 1060185029Spjd hdac_hp_switch[i].execsense), cad); 1061185029Spjd res = hdac_command(sc, 1062185029Spjd HDA_CMD_GET_PIN_SENSE(cad, hdac_hp_switch[i].hpnid), cad); 1063185029Spjd device_printf(sc->dev, 1064185029Spjd "[ 0] HDA_DEBUG: Pin sense: nid=%d res=0x%08x\n", 1065208373Smm hdac_hp_switch[i].hpnid, res); 1066286570Smav for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) { 1067286570Smav w = hdac_widget_get(devinfo, 1068185029Spjd hdac_hp_switch[i].spkrnid[j]); 1069286598Smav if (w == NULL || w->type != 1070286570Smav HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) 1071185029Spjd continue; 1072185029Spjd if (hdac_hp_switch[i].execsense != -1) 1073185029Spjd hdac_command(sc, 1074185029Spjd HDA_CMD_SET_PIN_SENSE(cad, w->nid, 1075185029Spjd hdac_hp_switch[i].execsense), cad); 1076185029Spjd res = hdac_command(sc, 1077185029Spjd HDA_CMD_GET_PIN_SENSE(cad, w->nid), cad); 1078185029Spjd device_printf(sc->dev, 1079185029Spjd "[%2d] HDA_DEBUG: Pin sense: nid=%d res=0x%08x\n", 1080185029Spjd j + 1, w->nid, res); 1081185029Spjd } 1082251478Sdelphij break; 1083251478Sdelphij default: 1084251478Sdelphij break; 1085268123Sdelphij } 1086251478Sdelphij} 1087251478Sdelphij 1088185029Spjdstatic void 1089185029Spjdhdac_unsolicited_handler(struct hdac_codec *codec, uint32_t tag) 1090185029Spjd{ 1091185029Spjd struct hdac_softc *sc; 1092185029Spjd struct hdac_devinfo *devinfo = NULL; 1093185029Spjd device_t *devlist = NULL; 1094185029Spjd int devcount, i; 1095185029Spjd 1096185029Spjd if (codec == NULL || codec->sc == NULL) 1097185029Spjd return; 1098185029Spjd 1099185029Spjd sc = codec->sc; 1100185029Spjd 1101185029Spjd HDA_BOOTVERBOSE( 1102185029Spjd device_printf(sc->dev, "HDA_DEBUG: Unsol Tag: 0x%08x\n", tag); 1103185029Spjd ); 1104185029Spjd 1105185029Spjd device_get_children(sc->dev, &devlist, &devcount); 1106185029Spjd for (i = 0; devlist != NULL && i < devcount; i++) { 1107275811Sdelphij devinfo = (struct hdac_devinfo *)device_get_ivars(devlist[i]); 1108275811Sdelphij if (devinfo != NULL && devinfo->node_type == 1109275811Sdelphij HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO && 1110275811Sdelphij devinfo->codec != NULL && 1111275811Sdelphij devinfo->codec->cad == codec->cad) { 1112275811Sdelphij break; 1113286570Smav } else 1114286570Smav devinfo = NULL; 1115286570Smav } 1116275811Sdelphij if (devlist != NULL) 1117275811Sdelphij free(devlist, M_TEMP); 1118185029Spjd 1119286570Smav if (devinfo == NULL) 1120275811Sdelphij return; 1121275811Sdelphij 1122251478Sdelphij switch (tag) { 1123168404Spjd case HDAC_UNSOLTAG_EVENT_HP: 1124209962Smm hdac_hp_switch_handler(devinfo); 1125168404Spjd break; 1126168404Spjd case HDAC_UNSOLTAG_EVENT_TEST: 1127168404Spjd device_printf(sc->dev, "Unsol Test!\n"); 1128168404Spjd break; 1129168404Spjd default: 1130168404Spjd break; 1131168404Spjd } 1132168404Spjd} 1133168404Spjd 1134168404Spjdstatic int 1135209962Smmhdac_stream_intr(struct hdac_softc *sc, struct hdac_chan *ch) 1136168404Spjd{ 1137168404Spjd /* XXX to be removed */ 1138168404Spjd#ifdef HDAC_INTR_EXTRA 1139168404Spjd uint32_t res; 1140168404Spjd#endif 1141168404Spjd 1142286570Smav if (!(ch->flags & HDAC_CHN_RUNNING)) 1143168404Spjd return (0); 1144168404Spjd 1145168404Spjd /* XXX to be removed */ 1146168404Spjd#ifdef HDAC_INTR_EXTRA 1147168404Spjd res = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDSTS); 1148168404Spjd#endif 1149219089Spjd 1150219089Spjd /* XXX to be removed */ 1151219089Spjd#ifdef HDAC_INTR_EXTRA 1152219089Spjd HDA_BOOTVERBOSE( 1153219089Spjd if (res & (HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE)) 1154219089Spjd device_printf(sc->dev, 1155219089Spjd "PCMDIR_%s intr triggered beyond stream boundary:" 1156219089Spjd "%08x\n", 1157168404Spjd (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC", res); 1158268075Sdelphij ); 1159168404Spjd#endif 1160268075Sdelphij 1161268075Sdelphij HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDSTS, 1162168404Spjd HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE | HDAC_SDSTS_BCIS ); 1163168404Spjd 1164275811Sdelphij /* XXX to be removed */ 1165168404Spjd#ifdef HDAC_INTR_EXTRA 1166168404Spjd if (res & HDAC_SDSTS_BCIS) { 1167275811Sdelphij#endif 1168275811Sdelphij return (1); 1169275811Sdelphij /* XXX to be removed */ 1170168404Spjd#ifdef HDAC_INTR_EXTRA 1171275811Sdelphij } 1172168404Spjd#endif 1173168404Spjd 1174168404Spjd return (0); 1175168404Spjd} 1176168404Spjd 1177168404Spjd/**************************************************************************** 1178168404Spjd * void hdac_intr_handler(void *) 1179168404Spjd * 1180168404Spjd * Interrupt handler. Processes interrupts received from the hdac. 1181168404Spjd ****************************************************************************/ 1182168404Spjdstatic void 1183168404Spjdhdac_intr_handler(void *context) 1184286570Smav{ 1185168404Spjd struct hdac_softc *sc; 1186168404Spjd uint32_t intsts; 1187275811Sdelphij uint8_t rirbsts; 1188168404Spjd struct hdac_rirb *rirb_base; 1189275811Sdelphij uint32_t trigger; 1190168404Spjd 1191275811Sdelphij sc = (struct hdac_softc *)context; 1192168404Spjd 1193168404Spjd hdac_lock(sc); 1194275811Sdelphij if (sc->polling != 0) { 1195275811Sdelphij hdac_unlock(sc); 1196275811Sdelphij return; 1197286570Smav } 1198286570Smav 1199286570Smav /* Do we have anything to do? */ 1200286570Smav intsts = HDAC_READ_4(&sc->mem, HDAC_INTSTS); 1201286570Smav if (!HDA_FLAG_MATCH(intsts, HDAC_INTSTS_GIS)) { 1202286570Smav hdac_unlock(sc); 1203286570Smav return; 1204286570Smav } 1205275811Sdelphij 1206275811Sdelphij trigger = 0; 1207275811Sdelphij 1208275811Sdelphij /* Was this a controller interrupt? */ 1209168404Spjd if (HDA_FLAG_MATCH(intsts, HDAC_INTSTS_CIS)) { 1210168404Spjd rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr; 1211275811Sdelphij rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS); 1212275811Sdelphij /* Get as many responses that we can */ 1213275811Sdelphij while (HDA_FLAG_MATCH(rirbsts, HDAC_RIRBSTS_RINTFL)) { 1214168404Spjd HDAC_WRITE_1(&sc->mem, 1215168404Spjd HDAC_RIRBSTS, HDAC_RIRBSTS_RINTFL); 1216168404Spjd if (hdac_rirb_flush(sc) != 0) 1217168404Spjd trigger |= HDAC_TRIGGER_UNSOL; 1218168404Spjd rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS); 1219168404Spjd } 1220168404Spjd /* XXX to be removed */ 1221168404Spjd /* Clear interrupt and exit */ 1222168404Spjd#ifdef HDAC_INTR_EXTRA 1223168404Spjd HDAC_WRITE_4(&sc->mem, HDAC_INTSTS, HDAC_INTSTS_CIS); 1224168404Spjd#endif 1225168404Spjd } 1226168404Spjd 1227168404Spjd if (intsts & HDAC_INTSTS_SIS_MASK) { 1228168404Spjd if ((intsts & (1 << sc->num_iss)) && 1229168404Spjd hdac_stream_intr(sc, &sc->play) != 0) 1230168404Spjd trigger |= HDAC_TRIGGER_PLAY; 1231275811Sdelphij if ((intsts & (1 << 0)) && 1232168404Spjd hdac_stream_intr(sc, &sc->rec) != 0) 1233275811Sdelphij trigger |= HDAC_TRIGGER_REC; 1234275811Sdelphij /* XXX to be removed */ 1235168404Spjd#ifdef HDAC_INTR_EXTRA 1236168404Spjd HDAC_WRITE_4(&sc->mem, HDAC_INTSTS, intsts & 1237275811Sdelphij HDAC_INTSTS_SIS_MASK); 1238168404Spjd#endif 1239275811Sdelphij } 1240275811Sdelphij 1241275811Sdelphij hdac_unlock(sc); 1242275811Sdelphij 1243168404Spjd if (trigger & HDAC_TRIGGER_PLAY) 1244275811Sdelphij chn_intr(sc->play.c); 1245275811Sdelphij if (trigger & HDAC_TRIGGER_REC) 1246275811Sdelphij chn_intr(sc->rec.c); 1247168404Spjd if (trigger & HDAC_TRIGGER_UNSOL) 1248168404Spjd taskqueue_enqueue(taskqueue_thread, &sc->unsolq_task); 1249168404Spjd} 1250168404Spjd 1251168404Spjd/**************************************************************************** 1252168404Spjd * int hdac_reset(hdac_softc *) 1253168404Spjd * 1254168404Spjd * Reset the hdac to a quiescent and known state. 1255168404Spjd ****************************************************************************/ 1256168404Spjdstatic int 1257168404Spjdhdac_reset(struct hdac_softc *sc) 1258168404Spjd{ 1259286570Smav uint32_t gctl; 1260286570Smav int count, i; 1261168404Spjd 1262168404Spjd /* 1263168404Spjd * Stop all Streams DMA engine 1264168404Spjd */ 1265168404Spjd for (i = 0; i < sc->num_iss; i++) 1266168404Spjd HDAC_WRITE_4(&sc->mem, HDAC_ISDCTL(sc, i), 0x0); 1267168404Spjd for (i = 0; i < sc->num_oss; i++) 1268168404Spjd HDAC_WRITE_4(&sc->mem, HDAC_OSDCTL(sc, i), 0x0); 1269168404Spjd for (i = 0; i < sc->num_bss; i++) 1270168404Spjd HDAC_WRITE_4(&sc->mem, HDAC_BSDCTL(sc, i), 0x0); 1271168404Spjd 1272286570Smav /* 1273286570Smav * Stop Control DMA engines. 1274168404Spjd */ 1275168404Spjd HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, 0x0); 1276168404Spjd HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, 0x0); 1277168404Spjd 1278168404Spjd /* 1279168404Spjd * Reset DMA position buffer. 1280168404Spjd */ 1281168404Spjd HDAC_WRITE_4(&sc->mem, HDAC_DPIBLBASE, 0x0); 1282168404Spjd HDAC_WRITE_4(&sc->mem, HDAC_DPIBUBASE, 0x0); 1283286570Smav 1284168404Spjd /* 1285275811Sdelphij * Reset the controller. The reset must remain asserted for 1286168404Spjd * a minimum of 100us. 1287286570Smav */ 1288286570Smav gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL); 1289286570Smav HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl & ~HDAC_GCTL_CRST); 1290286570Smav count = 10000; 1291286570Smav do { 1292185029Spjd gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL); 1293168404Spjd if (!(gctl & HDAC_GCTL_CRST)) 1294168404Spjd break; 1295168404Spjd DELAY(10); 1296185029Spjd } while (--count); 1297185029Spjd if (gctl & HDAC_GCTL_CRST) { 1298286570Smav device_printf(sc->dev, "Unable to put hdac in reset\n"); 1299286570Smav return (ENXIO); 1300286570Smav } 1301286570Smav DELAY(100); 1302286570Smav gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL); 1303286570Smav HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl | HDAC_GCTL_CRST); 1304286570Smav count = 10000; 1305286570Smav do { 1306286570Smav gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL); 1307286570Smav if (gctl & HDAC_GCTL_CRST) 1308286570Smav break; 1309286570Smav DELAY(10); 1310185029Spjd } while (--count); 1311185029Spjd if (!(gctl & HDAC_GCTL_CRST)) { 1312185029Spjd device_printf(sc->dev, "Device stuck in reset\n"); 1313185029Spjd return (ENXIO); 1314185029Spjd } 1315219089Spjd 1316208373Smm /* 1317208373Smm * Wait for codecs to finish their own reset sequence. The delay here 1318185029Spjd * should be of 250us but for some reasons, on it's not enough on my 1319185029Spjd * computer. Let's use twice as much as necessary to make sure that 1320185029Spjd * it's reset properly. 1321168404Spjd */ 1322168404Spjd DELAY(1000); 1323168404Spjd 1324168404Spjd return (0); 1325168404Spjd} 1326168404Spjd 1327286570Smav 1328168404Spjd/**************************************************************************** 1329275811Sdelphij * int hdac_get_capabilities(struct hdac_softc *); 1330168404Spjd * 1331275811Sdelphij * Retreive the general capabilities of the hdac; 1332286570Smav * Number of Input Streams 1333286570Smav * Number of Output Streams 1334286570Smav * Number of bidirectional Streams 1335286570Smav * 64bit ready 1336168404Spjd * CORB and RIRB sizes 1337168404Spjd ****************************************************************************/ 1338185029Spjdstatic int 1339185029Spjdhdac_get_capabilities(struct hdac_softc *sc) 1340286570Smav{ 1341286570Smav uint16_t gcap; 1342286570Smav uint8_t corbsize, rirbsize; 1343286570Smav 1344286570Smav gcap = HDAC_READ_2(&sc->mem, HDAC_GCAP); 1345286570Smav sc->num_iss = HDAC_GCAP_ISS(gcap); 1346286570Smav sc->num_oss = HDAC_GCAP_OSS(gcap); 1347286570Smav sc->num_bss = HDAC_GCAP_BSS(gcap); 1348286570Smav 1349286570Smav sc->support_64bit = HDA_FLAG_MATCH(gcap, HDAC_GCAP_64OK); 1350185029Spjd 1351185029Spjd corbsize = HDAC_READ_1(&sc->mem, HDAC_CORBSIZE); 1352185029Spjd if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_256) == 1353185029Spjd HDAC_CORBSIZE_CORBSZCAP_256) 1354219089Spjd sc->corb_size = 256; 1355208373Smm else if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_16) == 1356185029Spjd HDAC_CORBSIZE_CORBSZCAP_16) 1357185029Spjd sc->corb_size = 16; 1358168404Spjd else if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_2) == 1359168404Spjd HDAC_CORBSIZE_CORBSZCAP_2) 1360168404Spjd sc->corb_size = 2; 1361168404Spjd else { 1362168404Spjd device_printf(sc->dev, "%s: Invalid corb size (%x)\n", 1363168404Spjd __func__, corbsize); 1364168404Spjd return (ENXIO); 1365168404Spjd } 1366168404Spjd 1367168404Spjd rirbsize = HDAC_READ_1(&sc->mem, HDAC_RIRBSIZE); 1368168404Spjd if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_256) == 1369168404Spjd HDAC_RIRBSIZE_RIRBSZCAP_256) 1370168404Spjd sc->rirb_size = 256; 1371168404Spjd else if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_16) == 1372168404Spjd HDAC_RIRBSIZE_RIRBSZCAP_16) 1373168404Spjd sc->rirb_size = 16; 1374168404Spjd else if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_2) == 1375168404Spjd HDAC_RIRBSIZE_RIRBSZCAP_2) 1376168404Spjd sc->rirb_size = 2; 1377168404Spjd else { 1378168404Spjd device_printf(sc->dev, "%s: Invalid rirb size (%x)\n", 1379168404Spjd __func__, rirbsize); 1380168404Spjd return (ENXIO); 1381168404Spjd } 1382168404Spjd 1383269230Sdelphij return (0); 1384269230Sdelphij} 1385269230Sdelphij 1386168404Spjd 1387269230Sdelphij/**************************************************************************** 1388168404Spjd * void hdac_dma_cb 1389168404Spjd * 1390168404Spjd * This function is called by bus_dmamap_load when the mapping has been 1391168404Spjd * established. We just record the physical address of the mapping into 1392168404Spjd * the struct hdac_dma passed in. 1393168404Spjd ****************************************************************************/ 1394168404Spjdstatic void 1395168404Spjdhdac_dma_cb(void *callback_arg, bus_dma_segment_t *segs, int nseg, int error) 1396168404Spjd{ 1397168404Spjd struct hdac_dma *dma; 1398168404Spjd 1399286570Smav if (error == 0) { 1400286570Smav dma = (struct hdac_dma *)callback_arg; 1401286570Smav dma->dma_paddr = segs[0].ds_addr; 1402286570Smav } 1403286570Smav} 1404168404Spjd 1405185029Spjd 1406168404Spjd/**************************************************************************** 1407168404Spjd * int hdac_dma_alloc 1408168404Spjd * 1409168404Spjd * This function allocate and setup a dma region (struct hdac_dma). 1410168404Spjd * It must be freed by a corresponding hdac_dma_free. 1411168404Spjd ****************************************************************************/ 1412168404Spjdstatic int 1413168404Spjdhdac_dma_alloc(struct hdac_softc *sc, struct hdac_dma *dma, bus_size_t size) 1414168404Spjd{ 1415168404Spjd bus_size_t roundsz; 1416168404Spjd int result; 1417286570Smav int lowaddr; 1418286570Smav 1419286570Smav roundsz = roundup2(size, HDAC_DMA_ALIGNMENT); 1420286570Smav lowaddr = (sc->support_64bit) ? BUS_SPACE_MAXADDR : 1421286570Smav BUS_SPACE_MAXADDR_32BIT; 1422286570Smav bzero(dma, sizeof(*dma)); 1423286570Smav 1424286570Smav /* 1425286570Smav * Create a DMA tag 1426286570Smav */ 1427286570Smav result = bus_dma_tag_create(NULL, /* parent */ 1428286570Smav HDAC_DMA_ALIGNMENT, /* alignment */ 1429286570Smav 0, /* boundary */ 1430286570Smav lowaddr, /* lowaddr */ 1431286570Smav BUS_SPACE_MAXADDR, /* highaddr */ 1432286570Smav NULL, /* filtfunc */ 1433286570Smav NULL, /* fistfuncarg */ 1434286570Smav roundsz, /* maxsize */ 1435286570Smav 1, /* nsegments */ 1436286570Smav roundsz, /* maxsegsz */ 1437286570Smav 0, /* flags */ 1438286570Smav NULL, /* lockfunc */ 1439286570Smav NULL, /* lockfuncarg */ 1440286570Smav &dma->dma_tag); /* dmat */ 1441286598Smav if (result != 0) { 1442286570Smav device_printf(sc->dev, "%s: bus_dma_tag_create failed (%x)\n", 1443286570Smav __func__, result); 1444286570Smav goto hdac_dma_alloc_fail; 1445286570Smav } 1446286570Smav 1447286570Smav /* 1448286570Smav * Allocate DMA memory 1449286570Smav */ 1450286570Smav result = bus_dmamem_alloc(dma->dma_tag, (void **)&dma->dma_vaddr, 1451286570Smav BUS_DMA_NOWAIT | BUS_DMA_ZERO | 1452286570Smav ((sc->flags & HDAC_F_DMA_NOCACHE) ? BUS_DMA_NOCACHE : 0), 1453286570Smav &dma->dma_map); 1454286570Smav if (result != 0) { 1455286570Smav device_printf(sc->dev, "%s: bus_dmamem_alloc failed (%x)\n", 1456286570Smav __func__, result); 1457286570Smav goto hdac_dma_alloc_fail; 1458286570Smav } 1459286570Smav 1460286570Smav dma->dma_size = roundsz; 1461286570Smav 1462286570Smav /* 1463286570Smav * Map the memory 1464286570Smav */ 1465286570Smav result = bus_dmamap_load(dma->dma_tag, dma->dma_map, 1466286570Smav (void *)dma->dma_vaddr, roundsz, hdac_dma_cb, (void *)dma, 0); 1467286570Smav if (result != 0 || dma->dma_paddr == 0) { 1468286570Smav if (result == 0) 1469286570Smav result = ENOMEM; 1470286570Smav device_printf(sc->dev, "%s: bus_dmamem_load failed (%x)\n", 1471286570Smav __func__, result); 1472286570Smav goto hdac_dma_alloc_fail; 1473286570Smav } 1474286570Smav 1475286570Smav HDA_BOOTVERBOSE( 1476286570Smav device_printf(sc->dev, "%s: size=%ju -> roundsz=%ju\n", 1477286570Smav __func__, (uintmax_t)size, (uintmax_t)roundsz); 1478286570Smav ); 1479286570Smav 1480286570Smav return (0); 1481286570Smav 1482286570Smavhdac_dma_alloc_fail: 1483286570Smav hdac_dma_free(sc, dma); 1484286570Smav 1485286598Smav return (result); 1486286598Smav} 1487286598Smav 1488286598Smav 1489286598Smav/**************************************************************************** 1490286598Smav * void hdac_dma_free(struct hdac_softc *, struct hdac_dma *) 1491286598Smav * 1492286598Smav * Free a struct dhac_dma that has been previously allocated via the 1493286598Smav * hdac_dma_alloc function. 1494286598Smav ****************************************************************************/ 1495286598Smavstatic void 1496286598Smavhdac_dma_free(struct hdac_softc *sc, struct hdac_dma *dma) 1497286598Smav{ 1498286598Smav if (dma->dma_map != NULL) { 1499286570Smav#if 0 1500286570Smav /* Flush caches */ 1501286570Smav bus_dmamap_sync(dma->dma_tag, dma->dma_map, 1502286570Smav BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1503286570Smav#endif 1504286570Smav bus_dmamap_unload(dma->dma_tag, dma->dma_map); 1505286570Smav } 1506286570Smav if (dma->dma_vaddr != NULL) { 1507168404Spjd bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map); 1508168404Spjd dma->dma_vaddr = NULL; 1509168404Spjd } 1510168404Spjd dma->dma_map = NULL; 1511168404Spjd if (dma->dma_tag != NULL) { 1512168404Spjd bus_dma_tag_destroy(dma->dma_tag); 1513168404Spjd dma->dma_tag = NULL; 1514168404Spjd } 1515168404Spjd dma->dma_size = 0; 1516168404Spjd} 1517286570Smav 1518286570Smav/**************************************************************************** 1519286570Smav * int hdac_mem_alloc(struct hdac_softc *) 1520168404Spjd * 1521168404Spjd * Allocate all the bus resources necessary to speak with the physical 1522168404Spjd * controller. 1523168404Spjd ****************************************************************************/ 1524168404Spjdstatic int 1525286570Smavhdac_mem_alloc(struct hdac_softc *sc) 1526168404Spjd{ 1527168404Spjd struct hdac_mem *mem; 1528185029Spjd 1529185029Spjd mem = &sc->mem; 1530185029Spjd mem->mem_rid = PCIR_BAR(0); 1531185029Spjd mem->mem_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1532185029Spjd &mem->mem_rid, RF_ACTIVE); 1533185029Spjd if (mem->mem_res == NULL) { 1534286570Smav device_printf(sc->dev, 1535185029Spjd "%s: Unable to allocate memory resource\n", __func__); 1536185029Spjd return (ENOMEM); 1537286570Smav } 1538185029Spjd mem->mem_tag = rman_get_bustag(mem->mem_res); 1539185029Spjd mem->mem_handle = rman_get_bushandle(mem->mem_res); 1540185029Spjd 1541185029Spjd return (0); 1542168404Spjd} 1543185029Spjd 1544168404Spjd/**************************************************************************** 1545185029Spjd * void hdac_mem_free(struct hdac_softc *) 1546168404Spjd * 1547168404Spjd * Free up resources previously allocated by hdac_mem_alloc. 1548286570Smav ****************************************************************************/ 1549168404Spjdstatic void 1550286570Smavhdac_mem_free(struct hdac_softc *sc) 1551168404Spjd{ 1552168404Spjd struct hdac_mem *mem; 1553168404Spjd 1554168404Spjd mem = &sc->mem; 1555168404Spjd if (mem->mem_res != NULL) 1556286570Smav bus_release_resource(sc->dev, SYS_RES_MEMORY, mem->mem_rid, 1557240133Smm mem->mem_res); 1558240133Smm mem->mem_res = NULL; 1559277300Ssmh} 1560168404Spjd 1561168404Spjd/**************************************************************************** 1562240133Smm * int hdac_irq_alloc(struct hdac_softc *) 1563240133Smm * 1564240133Smm * Allocate and setup the resources necessary for interrupt handling. 1565240133Smm ****************************************************************************/ 1566240133Smmstatic int 1567240133Smmhdac_irq_alloc(struct hdac_softc *sc) 1568240133Smm{ 1569240133Smm struct hdac_irq *irq; 1570240133Smm int result; 1571240133Smm 1572240133Smm irq = &sc->irq; 1573240133Smm irq->irq_rid = 0x0; 1574240133Smm 1575240133Smm#ifdef HDAC_MSI_ENABLED 1576240133Smm if ((sc->flags & HDAC_F_MSI) && 1577240133Smm (result = pci_msi_count(sc->dev)) == 1 && 1578240133Smm pci_alloc_msi(sc->dev, &result) == 0) 1579240133Smm irq->irq_rid = 0x1; 1580240133Smm else 1581240133Smm#endif 1582240133Smm sc->flags &= ~HDAC_F_MSI; 1583240133Smm 1584240133Smm irq->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, 1585240133Smm &irq->irq_rid, RF_SHAREABLE | RF_ACTIVE); 1586240133Smm if (irq->irq_res == NULL) { 1587240133Smm device_printf(sc->dev, "%s: Unable to allocate irq\n", 1588240133Smm __func__); 1589240133Smm goto hdac_irq_alloc_fail; 1590240133Smm } 1591240133Smm result = snd_setup_intr(sc->dev, irq->irq_res, INTR_MPSAFE, 1592240133Smm hdac_intr_handler, sc, &irq->irq_handle); 1593240133Smm if (result != 0) { 1594240133Smm device_printf(sc->dev, 1595240133Smm "%s: Unable to setup interrupt handler (%x)\n", 1596240133Smm __func__, result); 1597240133Smm goto hdac_irq_alloc_fail; 1598240133Smm } 1599240133Smm 1600240133Smm return (0); 1601240133Smm 1602240133Smmhdac_irq_alloc_fail: 1603240133Smm hdac_irq_free(sc); 1604240133Smm 1605240133Smm return (ENXIO); 1606240133Smm} 1607286570Smav 1608286570Smav/**************************************************************************** 1609286570Smav * void hdac_irq_free(struct hdac_softc *) 1610286570Smav * 1611286570Smav * Free up resources previously allocated by hdac_irq_alloc. 1612286570Smav ****************************************************************************/ 1613286570Smavstatic void 1614286570Smavhdac_irq_free(struct hdac_softc *sc) 1615286570Smav{ 1616286570Smav struct hdac_irq *irq; 1617286570Smav 1618286570Smav irq = &sc->irq; 1619286570Smav if (irq->irq_res != NULL && irq->irq_handle != NULL) 1620286570Smav bus_teardown_intr(sc->dev, irq->irq_res, irq->irq_handle); 1621286570Smav if (irq->irq_res != NULL) 1622286570Smav bus_release_resource(sc->dev, SYS_RES_IRQ, irq->irq_rid, 1623286570Smav irq->irq_res); 1624286570Smav#ifdef HDAC_MSI_ENABLED 1625286570Smav if ((sc->flags & HDAC_F_MSI) && irq->irq_rid == 0x1) 1626286570Smav pci_release_msi(sc->dev); 1627286570Smav#endif 1628286570Smav irq->irq_handle = NULL; 1629286570Smav irq->irq_res = NULL; 1630286570Smav irq->irq_rid = 0x0; 1631286570Smav} 1632286570Smav 1633168404Spjd/**************************************************************************** 1634168404Spjd * void hdac_corb_init(struct hdac_softc *) 1635168404Spjd * 1636185029Spjd * Initialize the corb registers for operations but do not start it up yet. 1637286570Smav * The CORB engine must not be running when this function is called. 1638185029Spjd ****************************************************************************/ 1639286570Smavstatic void 1640185029Spjdhdac_corb_init(struct hdac_softc *sc) 1641185029Spjd{ 1642185029Spjd uint8_t corbsize; 1643168404Spjd uint64_t corbpaddr; 1644286570Smav 1645168404Spjd /* Setup the CORB size. */ 1646168404Spjd switch (sc->corb_size) { 1647168404Spjd case 256: 1648168404Spjd corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_256); 1649219089Spjd break; 1650286570Smav case 16: 1651219089Spjd corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_16); 1652286570Smav break; 1653286570Smav case 2: 1654286570Smav corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_2); 1655219089Spjd break; 1656286570Smav default: 1657219089Spjd panic("%s: Invalid CORB size (%x)\n", __func__, sc->corb_size); 1658286570Smav } 1659240133Smm HDAC_WRITE_1(&sc->mem, HDAC_CORBSIZE, corbsize); 1660240133Smm 1661240133Smm /* Setup the CORB Address in the hdac */ 1662277300Ssmh corbpaddr = (uint64_t)sc->corb_dma.dma_paddr; 1663168404Spjd HDAC_WRITE_4(&sc->mem, HDAC_CORBLBASE, (uint32_t)corbpaddr); 1664168404Spjd HDAC_WRITE_4(&sc->mem, HDAC_CORBUBASE, (uint32_t)(corbpaddr >> 32)); 1665168404Spjd 1666168404Spjd /* Set the WP and RP */ 1667168404Spjd sc->corb_wp = 0; 1668219089Spjd HDAC_WRITE_2(&sc->mem, HDAC_CORBWP, sc->corb_wp); 1669219089Spjd HDAC_WRITE_2(&sc->mem, HDAC_CORBRP, HDAC_CORBRP_CORBRPRST); 1670168404Spjd /* 1671168404Spjd * The HDA specification indicates that the CORBRPRST bit will always 1672168404Spjd * read as zero. Unfortunately, it seems that at least the 82801G 1673219089Spjd * doesn't reset the bit to zero, which stalls the corb engine. 1674219089Spjd * manually reset the bit to zero before continuing. 1675219089Spjd */ 1676168404Spjd HDAC_WRITE_2(&sc->mem, HDAC_CORBRP, 0x0); 1677286570Smav 1678185029Spjd /* Enable CORB error reporting */ 1679219089Spjd#if 0 1680240133Smm HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, HDAC_CORBCTL_CMEIE); 1681168404Spjd#endif 1682168404Spjd} 1683168404Spjd 1684275811Sdelphij/**************************************************************************** 1685205231Skmacy * void hdac_rirb_init(struct hdac_softc *) 1686275811Sdelphij * 1687205231Skmacy * Initialize the rirb registers for operations but do not start it up yet. 1688286570Smav * The RIRB engine must not be running when this function is called. 1689206796Spjd ****************************************************************************/ 1690205231Skmacystatic void 1691206796Spjdhdac_rirb_init(struct hdac_softc *sc) 1692205231Skmacy{ 1693205231Skmacy uint8_t rirbsize; 1694205231Skmacy uint64_t rirbpaddr; 1695205231Skmacy 1696205231Skmacy /* Setup the RIRB size. */ 1697205231Skmacy switch (sc->rirb_size) { 1698205231Skmacy case 256: 1699205231Skmacy rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_256); 1700205231Skmacy break; 1701275811Sdelphij case 16: 1702168404Spjd rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_16); 1703286570Smav break; 1704168404Spjd case 2: 1705286570Smav rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_2); 1706168404Spjd break; 1707286570Smav default: 1708286570Smav panic("%s: Invalid RIRB size (%x)\n", __func__, sc->rirb_size); 1709286570Smav } 1710286570Smav HDAC_WRITE_1(&sc->mem, HDAC_RIRBSIZE, rirbsize); 1711286570Smav 1712286570Smav /* Setup the RIRB Address in the hdac */ 1713286570Smav rirbpaddr = (uint64_t)sc->rirb_dma.dma_paddr; 1714286570Smav HDAC_WRITE_4(&sc->mem, HDAC_RIRBLBASE, (uint32_t)rirbpaddr); 1715168404Spjd HDAC_WRITE_4(&sc->mem, HDAC_RIRBUBASE, (uint32_t)(rirbpaddr >> 32)); 1716286570Smav 1717286570Smav /* Setup the WP and RP */ 1718286570Smav sc->rirb_rp = 0; 1719286570Smav HDAC_WRITE_2(&sc->mem, HDAC_RIRBWP, HDAC_RIRBWP_RIRBWPRST); 1720286570Smav 1721286570Smav if (sc->polling == 0) { 1722286570Smav /* Setup the interrupt threshold */ 1723286570Smav HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT, sc->rirb_size / 2); 1724286570Smav 1725286570Smav /* Enable Overrun and response received reporting */ 1726286570Smav#if 0 1727286570Smav HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, 1728286570Smav HDAC_RIRBCTL_RIRBOIC | HDAC_RIRBCTL_RINTCTL); 1729286570Smav#else 1730168404Spjd HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, HDAC_RIRBCTL_RINTCTL); 1731185029Spjd#endif 1732286570Smav } 1733168404Spjd 1734168404Spjd#if 0 1735168404Spjd /* 1736168404Spjd * Make sure that the Host CPU cache doesn't contain any dirty 1737275811Sdelphij * cache lines that falls in the rirb. If I understood correctly, it 1738168404Spjd * should be sufficient to do this only once as the rirb is purely 1739168404Spjd * read-only from now on. 1740286570Smav */ 1741168404Spjd bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map, 1742286570Smav BUS_DMASYNC_PREREAD); 1743168404Spjd#endif 1744168404Spjd} 1745168404Spjd 1746286570Smav/**************************************************************************** 1747286570Smav * void hdac_corb_start(hdac_softc *) 1748286570Smav * 1749286570Smav * Startup the corb DMA engine 1750286570Smav ****************************************************************************/ 1751168404Spjdstatic void 1752286570Smavhdac_corb_start(struct hdac_softc *sc) 1753205231Skmacy{ 1754205231Skmacy uint32_t corbctl; 1755185029Spjd 1756275811Sdelphij corbctl = HDAC_READ_1(&sc->mem, HDAC_CORBCTL); 1757205231Skmacy corbctl |= HDAC_CORBCTL_CORBRUN; 1758205231Skmacy HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, corbctl); 1759286570Smav} 1760275811Sdelphij 1761286570Smav/**************************************************************************** 1762286570Smav * void hdac_rirb_start(hdac_softc *) 1763286570Smav * 1764206794Spjd * Startup the rirb DMA engine 1765168404Spjd ****************************************************************************/ 1766168404Spjdstatic void 1767168404Spjdhdac_rirb_start(struct hdac_softc *sc) 1768168404Spjd{ 1769168404Spjd uint32_t rirbctl; 1770168404Spjd 1771168404Spjd rirbctl = HDAC_READ_1(&sc->mem, HDAC_RIRBCTL); 1772168404Spjd rirbctl |= HDAC_RIRBCTL_RIRBDMAEN; 1773168404Spjd HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, rirbctl); 1774275811Sdelphij} 1775275811Sdelphij 1776168404Spjd 1777286570Smav/**************************************************************************** 1778286570Smav * void hdac_scan_codecs(struct hdac_softc *, int) 1779286570Smav * 1780168404Spjd * Scan the bus for available codecs, starting with num. 1781286570Smav ****************************************************************************/ 1782205231Skmacystatic void 1783205231Skmacyhdac_scan_codecs(struct hdac_softc *sc, int num) 1784168404Spjd{ 1785286570Smav struct hdac_codec *codec; 1786286570Smav int i; 1787286570Smav uint16_t statests; 1788286570Smav 1789286570Smav if (num < 0) 1790286570Smav num = 0; 1791286570Smav if (num >= HDAC_CODEC_MAX) 1792286570Smav num = HDAC_CODEC_MAX - 1; 1793286570Smav 1794286570Smav statests = HDAC_READ_2(&sc->mem, HDAC_STATESTS); 1795286570Smav for (i = num; i < HDAC_CODEC_MAX; i++) { 1796286570Smav if (HDAC_STATESTS_SDIWAKE(statests, i)) { 1797286570Smav /* We have found a codec. */ 1798286570Smav codec = (struct hdac_codec *)malloc(sizeof(*codec), 1799286570Smav M_HDAC, M_ZERO | M_NOWAIT); 1800286570Smav if (codec == NULL) { 1801286570Smav device_printf(sc->dev, 1802168404Spjd "Unable to allocate memory for codec\n"); 1803258632Savg continue; 1804286570Smav } 1805286570Smav codec->commands = NULL; 1806286570Smav codec->responses_received = 0; 1807168404Spjd codec->verbs_sent = 0; 1808286570Smav codec->sc = sc; 1809168404Spjd codec->cad = i; 1810168404Spjd sc->codecs[i] = codec; 1811168404Spjd if (hdac_probe_codec(codec) != 0) 1812168404Spjd break; 1813168404Spjd } 1814168404Spjd } 1815286570Smav /* All codecs have been probed, now try to attach drivers to them */ 1816205231Skmacy /* bus_generic_attach(sc->dev); */ 1817286570Smav} 1818168404Spjd 1819275811Sdelphij/**************************************************************************** 1820205231Skmacy * void hdac_probe_codec(struct hdac_softc *, int) 1821168404Spjd * 1822205231Skmacy * Probe a the given codec_id for available function groups. 1823168404Spjd ****************************************************************************/ 1824286570Smavstatic int 1825286570Smavhdac_probe_codec(struct hdac_codec *codec) 1826275811Sdelphij{ 1827168404Spjd struct hdac_softc *sc = codec->sc; 1828168404Spjd struct hdac_devinfo *devinfo; 1829168404Spjd uint32_t vendorid, revisionid, subnode; 1830219089Spjd int startnode; 1831168404Spjd int endnode; 1832286570Smav int i; 1833168404Spjd nid_t cad = codec->cad; 1834286570Smav 1835275811Sdelphij HDA_BOOTVERBOSE( 1836168404Spjd device_printf(sc->dev, "HDA_DEBUG: Probing codec: %d\n", cad); 1837185029Spjd ); 1838185029Spjd vendorid = hdac_command(sc, 1839168404Spjd HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_VENDOR_ID), 1840168404Spjd cad); 1841205231Skmacy revisionid = hdac_command(sc, 1842168404Spjd HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_REVISION_ID), 1843286570Smav cad); 1844206796Spjd subnode = hdac_command(sc, 1845286570Smav HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_SUB_NODE_COUNT), 1846168404Spjd cad); 1847286570Smav startnode = HDA_PARAM_SUB_NODE_COUNT_START(subnode); 1848286570Smav endnode = startnode + HDA_PARAM_SUB_NODE_COUNT_TOTAL(subnode); 1849286570Smav 1850286570Smav HDA_BOOTVERBOSE( 1851286570Smav device_printf(sc->dev, "HDA_DEBUG: \tstartnode=%d endnode=%d\n", 1852286570Smav startnode, endnode); 1853286570Smav ); 1854275811Sdelphij for (i = startnode; i < endnode; i++) { 1855205231Skmacy devinfo = hdac_probe_function(codec, i); 1856168404Spjd if (devinfo != NULL) { 1857205231Skmacy /* XXX Ignore other FG. */ 1858168404Spjd devinfo->vendor_id = 1859275811Sdelphij HDA_PARAM_VENDOR_ID_VENDOR_ID(vendorid); 1860168404Spjd devinfo->device_id = 1861168404Spjd HDA_PARAM_VENDOR_ID_DEVICE_ID(vendorid); 1862168404Spjd devinfo->revision_id = 1863286570Smav HDA_PARAM_REVISION_ID_REVISION_ID(revisionid); 1864286570Smav devinfo->stepping_id = 1865275811Sdelphij HDA_PARAM_REVISION_ID_STEPPING_ID(revisionid); 1866168404Spjd HDA_BOOTVERBOSE( 1867185029Spjd device_printf(sc->dev, 1868168404Spjd "HDA_DEBUG: \tFound AFG nid=%d " 1869168404Spjd "[startnode=%d endnode=%d]\n", 1870205231Skmacy devinfo->nid, startnode, endnode); 1871168404Spjd ); 1872168404Spjd return (1); 1873168404Spjd } 1874275811Sdelphij } 1875275811Sdelphij 1876275811Sdelphij HDA_BOOTVERBOSE( 1877168404Spjd device_printf(sc->dev, "HDA_DEBUG: \tAFG not found\n"); 1878286570Smav ); 1879286570Smav return (0); 1880168404Spjd} 1881286570Smav 1882168404Spjdstatic struct hdac_devinfo * 1883168404Spjdhdac_probe_function(struct hdac_codec *codec, nid_t nid) 1884168404Spjd{ 1885286570Smav struct hdac_softc *sc = codec->sc; 1886286570Smav struct hdac_devinfo *devinfo; 1887185029Spjd uint32_t fctgrptype; 1888286570Smav nid_t cad = codec->cad; 1889286570Smav 1890286570Smav fctgrptype = HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE(hdac_command(sc, 1891286570Smav HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_FCT_GRP_TYPE), cad)); 1892286576Smav 1893286570Smav /* XXX For now, ignore other FG. */ 1894286570Smav if (fctgrptype != HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) 1895286576Smav return (NULL); 1896168404Spjd 1897168404Spjd devinfo = (struct hdac_devinfo *)malloc(sizeof(*devinfo), M_HDAC, 1898185029Spjd M_NOWAIT | M_ZERO); 1899208373Smm if (devinfo == NULL) { 1900185029Spjd device_printf(sc->dev, "%s: Unable to allocate ivar\n", 1901208373Smm __func__); 1902208373Smm return (NULL); 1903208373Smm } 1904208373Smm 1905208373Smm devinfo->nid = nid; 1906208373Smm devinfo->node_type = fctgrptype; 1907286574Smav devinfo->codec = codec; 1908286574Smav 1909286574Smav hdac_add_child(sc, devinfo); 1910208373Smm 1911208373Smm return (devinfo); 1912208373Smm} 1913208373Smm 1914208373Smmstatic void 1915208373Smmhdac_add_child(struct hdac_softc *sc, struct hdac_devinfo *devinfo) 1916208373Smm{ 1917208373Smm devinfo->dev = device_add_child(sc->dev, NULL, -1); 1918208373Smm device_set_ivars(devinfo->dev, (void *)devinfo); 1919208373Smm /* XXX - Print more information when booting verbose??? */ 1920208373Smm} 1921286574Smav 1922286574Smavstatic void 1923286574Smavhdac_widget_connection_parse(struct hdac_widget *w) 1924185029Spjd{ 1925185029Spjd struct hdac_softc *sc = w->devinfo->codec->sc; 1926185029Spjd uint32_t res; 1927185029Spjd int i, j, max, ents, entnum; 1928208373Smm nid_t cad = w->devinfo->codec->cad; 1929185029Spjd nid_t nid = w->nid; 1930208373Smm nid_t cnid, addcnid, prevcnid; 1931208373Smm 1932208373Smm w->nconns = 0; 1933208373Smm 1934208373Smm res = hdac_command(sc, 1935208373Smm HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_CONN_LIST_LENGTH), cad); 1936286574Smav 1937286574Smav ents = HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH(res); 1938286574Smav 1939208373Smm if (ents < 1) 1940208373Smm return; 1941208373Smm 1942208373Smm entnum = HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM(res) ? 2 : 4; 1943208373Smm max = (sizeof(w->conns) / sizeof(w->conns[0])) - 1; 1944208373Smm prevcnid = 0; 1945208373Smm 1946208373Smm#define CONN_RMASK(e) (1 << ((32 / (e)) - 1)) 1947208373Smm#define CONN_NMASK(e) (CONN_RMASK(e) - 1) 1948208373Smm#define CONN_RESVAL(r, e, n) ((r) >> ((32 / (e)) * (n))) 1949208373Smm#define CONN_RANGE(r, e, n) (CONN_RESVAL(r, e, n) & CONN_RMASK(e)) 1950286574Smav#define CONN_CNID(r, e, n) (CONN_RESVAL(r, e, n) & CONN_NMASK(e)) 1951286574Smav 1952286574Smav for (i = 0; i < ents; i += entnum) { 1953286574Smav res = hdac_command(sc, 1954286574Smav HDA_CMD_GET_CONN_LIST_ENTRY(cad, nid, i), cad); 1955286574Smav for (j = 0; j < entnum; j++) { 1956286574Smav cnid = CONN_CNID(res, entnum, j); 1957185029Spjd if (cnid == 0) { 1958185029Spjd if (w->nconns < ents) 1959185029Spjd device_printf(sc->dev, 1960185029Spjd "%s: nid=%d WARNING: zero cnid " 1961168404Spjd "entnum=%d j=%d index=%d " 1962286570Smav "entries=%d found=%d res=0x%08x\n", 1963168404Spjd __func__, nid, entnum, j, i, 1964168404Spjd ents, w->nconns, res); 1965168404Spjd else 1966168404Spjd goto getconns_out; 1967168404Spjd } 1968286570Smav if (cnid < w->devinfo->startnode || 1969168404Spjd cnid >= w->devinfo->endnode) { 1970286570Smav HDA_BOOTVERBOSE( 1971168404Spjd device_printf(sc->dev, 1972228103Smm "%s: GHOST: nid=%d j=%d " 1973286570Smav "entnum=%d index=%d res=0x%08x\n", 1974185029Spjd __func__, nid, j, entnum, i, res); 1975168404Spjd ); 1976168404Spjd } 1977168404Spjd if (CONN_RANGE(res, entnum, j) == 0) 1978168404Spjd addcnid = cnid; 1979168404Spjd else if (prevcnid == 0 || prevcnid >= cnid) { 1980286570Smav device_printf(sc->dev, 1981286570Smav "%s: WARNING: Invalid child range " 1982286570Smav "nid=%d index=%d j=%d entnum=%d " 1983286570Smav "prevcnid=%d cnid=%d res=0x%08x\n", 1984286570Smav __func__, nid, i, j, entnum, prevcnid, 1985286570Smav cnid, res); 1986286570Smav addcnid = cnid; 1987286570Smav } else 1988286570Smav addcnid = prevcnid + 1; 1989168404Spjd while (addcnid <= cnid) { 1990286570Smav if (w->nconns > max) { 1991286570Smav device_printf(sc->dev, 1992168404Spjd "%s: nid=%d: Adding %d: " 1993168404Spjd "Max connection reached! max=%d\n", 1994168404Spjd __func__, nid, addcnid, max + 1); 1995168404Spjd goto getconns_out; 1996209962Smm } 1997209962Smm w->conns[w->nconns++] = addcnid++; 1998209962Smm } 1999209962Smm prevcnid = cnid; 2000209962Smm } 2001209962Smm } 2002209962Smm 2003209962Smmgetconns_out: 2004209962Smm HDA_BOOTVERBOSE( 2005209962Smm device_printf(sc->dev, 2006209962Smm "HDA_DEBUG: %s: nid=%d entries=%d found=%d\n", 2007209962Smm __func__, nid, ents, w->nconns); 2008209962Smm ); 2009209962Smm return; 2010209962Smm} 2011209962Smm 2012209962Smmstatic uint32_t 2013209962Smmhdac_widget_pin_getconfig(struct hdac_widget *w) 2014209962Smm{ 2015209962Smm struct hdac_softc *sc; 2016209962Smm uint32_t config, orig, id; 2017209962Smm nid_t cad, nid; 2018209962Smm 2019209962Smm sc = w->devinfo->codec->sc; 2020209962Smm cad = w->devinfo->codec->cad; 2021209962Smm nid = w->nid; 2022209962Smm id = hdac_codec_id(w->devinfo); 2023209962Smm 2024286570Smav config = hdac_command(sc, 2025286570Smav HDA_CMD_GET_CONFIGURATION_DEFAULT(cad, nid), 2026286570Smav cad); 2027209962Smm orig = config; 2028209962Smm 2029209962Smm /* 2030209962Smm * XXX REWRITE!!!! Don't argue! 2031219089Spjd */ 2032219089Spjd if (id == HDA_CODEC_ALC880 && sc->pci_subvendor == LG_LW20_SUBVENDOR) { 2033219089Spjd switch (nid) { 2034219089Spjd case 26: 2035286570Smav config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; 2036219089Spjd config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN; 2037219089Spjd break; 2038286570Smav case 27: 2039286570Smav config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; 2040286570Smav config |= HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT; 2041219089Spjd break; 2042219089Spjd default: 2043219089Spjd break; 2044219089Spjd } 2045219089Spjd } else if (id == HDA_CODEC_ALC880 && 2046219089Spjd (sc->pci_subvendor == CLEVO_D900T_SUBVENDOR || 2047168404Spjd sc->pci_subvendor == ASUS_M5200_SUBVENDOR)) { 2048168404Spjd /* 2049168404Spjd * Super broken BIOS 2050168404Spjd */ 2051168404Spjd switch (nid) { 2052168404Spjd case 20: 2053168404Spjd break; 2054286570Smav case 21: 2055286570Smav break; 2056219089Spjd case 22: 2057185029Spjd break; 2058168404Spjd case 23: 2059168404Spjd break; 2060168404Spjd case 24: /* MIC1 */ 2061168404Spjd config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; 2062286570Smav config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN; 2063286570Smav break; 2064168404Spjd case 25: /* XXX MIC2 */ 2065168404Spjd config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; 2066242845Sdelphij config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN; 2067242845Sdelphij break; 2068242845Sdelphij case 26: /* LINE1 */ 2069242845Sdelphij config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; 2070242845Sdelphij config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN; 2071242845Sdelphij break; 2072242845Sdelphij case 27: /* XXX LINE2 */ 2073286570Smav config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; 2074242845Sdelphij config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN; 2075242845Sdelphij break; 2076242845Sdelphij case 28: /* CD */ 2077286570Smav config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; 2078168404Spjd config |= HDA_CONFIG_DEFAULTCONF_DEVICE_CD; 2079168404Spjd break; 2080168404Spjd case 30: 2081168404Spjd break; 2082168404Spjd case 31: 2083168404Spjd break; 2084168404Spjd default: 2085168404Spjd break; 2086168404Spjd } 2087168404Spjd } else if (id == HDA_CODEC_ALC883 && 2088185029Spjd (sc->pci_subvendor == MSI_MS034A_SUBVENDOR || 2089185029Spjd HDA_DEV_MATCH(ACER_ALL_SUBVENDOR, sc->pci_subvendor))) { 2090185029Spjd switch (nid) { 2091168404Spjd case 25: 2092219089Spjd config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK | 2093185029Spjd HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK); 2094219089Spjd config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN | 2095168404Spjd HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED); 2096168404Spjd break; 2097219089Spjd case 28: 2098219089Spjd config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK | 2099185029Spjd HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK); 2100286570Smav config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD | 2101219089Spjd HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED); 2102219089Spjd break; 2103168404Spjd default: 2104286570Smav break; 2105286570Smav } 2106286570Smav } else if (id == HDA_CODEC_CXVENICE && sc->pci_subvendor == 2107168404Spjd HP_V3000_SUBVENDOR) { 2108208373Smm switch (nid) { 2109168404Spjd case 18: 2110168404Spjd config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK; 2111168404Spjd config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE; 2112286570Smav break; 2113286570Smav case 20: 2114168404Spjd config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK | 2115168404Spjd HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK); 2116168404Spjd config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN | 2117274172Savg HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED); 2118274172Savg break; 2119274172Savg case 21: 2120274172Savg config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK | 2121274172Savg HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK); 2122274172Savg config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD | 2123274172Savg HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED); 2124274172Savg break; 2125274172Savg default: 2126274172Savg break; 2127274172Savg } 2128274172Savg } else if (id == HDA_CODEC_CXWAIKIKI && sc->pci_subvendor == 2129274172Savg HP_DV5000_SUBVENDOR) { 2130274172Savg switch (nid) { 2131274172Savg case 20: 2132185029Spjd case 21: 2133185029Spjd config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK; 2134185029Spjd config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE; 2135185029Spjd break; 2136168404Spjd default: 2137240133Smm break; 2138185029Spjd } 2139240133Smm } else if (id == HDA_CODEC_ALC861 && sc->pci_subvendor == 2140240133Smm ASUS_W6F_SUBVENDOR) { 2141185029Spjd switch (nid) { 2142274172Savg case 11: 2143185029Spjd config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK | 2144185029Spjd HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK); 2145240133Smm config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT | 2146185029Spjd HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED); 2147185029Spjd break; 2148185029Spjd case 15: 2149268858Sdelphij config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK | 2150268858Sdelphij HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK); 2151268858Sdelphij config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT | 2152268858Sdelphij HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK); 2153185029Spjd break; 2154274172Savg default: 2155274172Savg break; 2156286570Smav } 2157286570Smav } else if (id == HDA_CODEC_ALC861 && sc->pci_subvendor == 2158274172Savg UNIWILL_9075_SUBVENDOR) { 2159286570Smav switch (nid) { 2160286570Smav case 15: 2161286570Smav config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK | 2162286570Smav HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK); 2163286570Smav config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT | 2164286570Smav HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK); 2165286570Smav break; 2166274172Savg default: 2167286570Smav break; 2168274172Savg } 2169274172Savg } else if (id == HDA_CODEC_AD1986A && 2170274172Savg (sc->pci_subvendor == ASUS_M2NPVMX_SUBVENDOR || 2171286570Smav sc->pci_subvendor == ASUS_A8NVMCSM_SUBVENDOR)) { 2172274172Savg switch (nid) { 2173286570Smav case 28: /* LINE */ 2174274172Savg config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; 2175286570Smav config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN; 2176274172Savg break; 2177274172Savg case 29: /* MIC */ 2178274172Savg config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; 2179268858Sdelphij config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN; 2180168404Spjd break; 2181168404Spjd default: 2182168404Spjd break; 2183168404Spjd } 2184286570Smav } else if (id == HDA_CODEC_ALC268 && 2185286570Smav HDA_DEV_MATCH(ACER_ALL_SUBVENDOR, sc->pci_subvendor)) { 2186168404Spjd switch (nid) { 2187286570Smav case 28: 2188168404Spjd config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK | 2189168404Spjd HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK); 2190240133Smm config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD | 2191240133Smm HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED); 2192277300Ssmh break; 2193219089Spjd default: 2194168404Spjd break; 2195168404Spjd } 2196240133Smm } 2197286574Smav 2198168404Spjd HDA_BOOTVERBOSE( 2199168404Spjd if (config != orig) 2200240133Smm device_printf(sc->dev, 2201286574Smav "HDA_DEBUG: Pin config nid=%u 0x%08x -> 0x%08x\n", 2202168404Spjd nid, orig, config); 2203168404Spjd ); 2204286570Smav 2205185029Spjd return (config); 2206185029Spjd} 2207286570Smav 2208286570Smavstatic uint32_t 2209286570Smavhdac_widget_pin_getcaps(struct hdac_widget *w) 2210185029Spjd{ 2211185029Spjd struct hdac_softc *sc; 2212185029Spjd uint32_t caps, orig, id; 2213168404Spjd nid_t cad, nid; 2214168404Spjd 2215168404Spjd sc = w->devinfo->codec->sc; 2216168404Spjd cad = w->devinfo->codec->cad; 2217242845Sdelphij nid = w->nid; 2218242845Sdelphij id = hdac_codec_id(w->devinfo); 2219242845Sdelphij 2220242845Sdelphij caps = hdac_command(sc, 2221242845Sdelphij HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_PIN_CAP), cad); 2222286570Smav orig = caps; 2223286570Smav 2224242845Sdelphij HDA_BOOTVERBOSE( 2225242845Sdelphij if (caps != orig) 2226242845Sdelphij device_printf(sc->dev, 2227286570Smav "HDA_DEBUG: Pin caps nid=%u 0x%08x -> 0x%08x\n", 2228286570Smav nid, orig, caps); 2229168404Spjd ); 2230168404Spjd 2231168404Spjd return (caps); 2232268858Sdelphij} 2233168404Spjd 2234168404Spjdstatic void 2235168404Spjdhdac_widget_pin_parse(struct hdac_widget *w) 2236286570Smav{ 2237286570Smav struct hdac_softc *sc = w->devinfo->codec->sc; 2238168404Spjd uint32_t config, pincap; 2239168404Spjd char *devstr, *connstr; 2240219089Spjd nid_t cad = w->devinfo->codec->cad; 2241168404Spjd nid_t nid = w->nid; 2242168404Spjd 2243168404Spjd config = hdac_widget_pin_getconfig(w); 2244168404Spjd w->wclass.pin.config = config; 2245168404Spjd 2246168404Spjd pincap = hdac_widget_pin_getcaps(w); 2247168404Spjd w->wclass.pin.cap = pincap; 2248168404Spjd 2249168404Spjd w->wclass.pin.ctrl = hdac_command(sc, 2250286598Smav HDA_CMD_GET_PIN_WIDGET_CTRL(cad, nid), cad) & 2251286598Smav ~(HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE | 2252286598Smav HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE | 2253286598Smav HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE | 2254286598Smav HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK); 2255286598Smav 2256286598Smav if (HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap)) 2257286598Smav w->wclass.pin.ctrl |= HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE; 2258286598Smav if (HDA_PARAM_PIN_CAP_OUTPUT_CAP(pincap)) 2259286598Smav w->wclass.pin.ctrl |= HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; 2260286598Smav if (HDA_PARAM_PIN_CAP_INPUT_CAP(pincap)) 2261286598Smav w->wclass.pin.ctrl |= HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE; 2262286598Smav if (HDA_PARAM_PIN_CAP_EAPD_CAP(pincap)) { 2263286598Smav w->param.eapdbtl = hdac_command(sc, 2264286598Smav HDA_CMD_GET_EAPD_BTL_ENABLE(cad, nid), cad); 2265286598Smav w->param.eapdbtl &= 0x7; 2266286598Smav w->param.eapdbtl |= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD; 2267286598Smav } else 2268286598Smav w->param.eapdbtl = HDAC_INVALID; 2269286598Smav 2270286598Smav switch (config & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) { 2271286598Smav case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT: 2272286598Smav devstr = "line out"; 2273286598Smav break; 2274286598Smav case HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER: 2275286598Smav devstr = "speaker"; 2276286598Smav break; 2277286598Smav case HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT: 2278286598Smav devstr = "headphones out"; 2279286598Smav break; 2280286598Smav case HDA_CONFIG_DEFAULTCONF_DEVICE_CD: 2281286598Smav devstr = "CD"; 2282286598Smav break; 2283286598Smav case HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_OUT: 2284286598Smav devstr = "SPDIF out"; 2285286598Smav break; 2286286598Smav case HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_OUT: 2287286598Smav devstr = "digital (other) out"; 2288286598Smav break; 2289286598Smav case HDA_CONFIG_DEFAULTCONF_DEVICE_MODEM_LINE: 2290286598Smav devstr = "modem, line side"; 2291286598Smav break; 2292286598Smav case HDA_CONFIG_DEFAULTCONF_DEVICE_MODEM_HANDSET: 2293286598Smav devstr = "modem, handset side"; 2294286598Smav break; 2295286598Smav case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN: 2296286598Smav devstr = "line in"; 2297286598Smav break; 2298286598Smav case HDA_CONFIG_DEFAULTCONF_DEVICE_AUX: 2299286598Smav devstr = "AUX"; 2300286598Smav break; 2301168404Spjd case HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN: 2302168404Spjd devstr = "Mic in"; 2303286570Smav break; 2304286570Smav case HDA_CONFIG_DEFAULTCONF_DEVICE_TELEPHONY: 2305286570Smav devstr = "telephony"; 2306286570Smav break; 2307286570Smav case HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_IN: 2308286570Smav devstr = "SPDIF in"; 2309168404Spjd break; 2310286570Smav case HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_IN: 2311168404Spjd devstr = "digital (other) in"; 2312286570Smav break; 2313286598Smav case HDA_CONFIG_DEFAULTCONF_DEVICE_OTHER: 2314286598Smav devstr = "other"; 2315286570Smav break; 2316286598Smav default: 2317286598Smav devstr = "unknown"; 2318219089Spjd break; 2319286570Smav } 2320286598Smav 2321286598Smav switch (config & HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) { 2322286598Smav case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK: 2323286598Smav connstr = "jack"; 2324286598Smav break; 2325286598Smav case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE: 2326286598Smav connstr = "none"; 2327286570Smav break; 2328286598Smav case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED: 2329286598Smav connstr = "fixed"; 2330286598Smav break; 2331286598Smav case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_BOTH: 2332286598Smav connstr = "jack / fixed"; 2333286570Smav break; 2334219089Spjd default: 2335286598Smav connstr = "unknown"; 2336185029Spjd break; 2337185029Spjd } 2338286570Smav 2339219089Spjd strlcat(w->name, ": ", sizeof(w->name)); 2340168404Spjd strlcat(w->name, devstr, sizeof(w->name)); 2341168404Spjd strlcat(w->name, " (", sizeof(w->name)); 2342168404Spjd strlcat(w->name, connstr, sizeof(w->name)); 2343168404Spjd strlcat(w->name, ")", sizeof(w->name)); 2344286570Smav} 2345286570Smav 2346286570Smavstatic void 2347286570Smavhdac_widget_parse(struct hdac_widget *w) 2348286570Smav{ 2349286570Smav struct hdac_softc *sc = w->devinfo->codec->sc; 2350286570Smav uint32_t wcap, cap; 2351286570Smav char *typestr; 2352286570Smav nid_t cad = w->devinfo->codec->cad; 2353286570Smav nid_t nid = w->nid; 2354286570Smav 2355286570Smav wcap = hdac_command(sc, 2356286570Smav HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_AUDIO_WIDGET_CAP), 2357286570Smav cad); 2358286570Smav w->param.widget_cap = wcap; 2359286570Smav w->type = HDA_PARAM_AUDIO_WIDGET_CAP_TYPE(wcap); 2360286570Smav 2361286570Smav switch (w->type) { 2362286570Smav case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT: 2363286570Smav typestr = "audio output"; 2364286570Smav break; 2365286570Smav case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT: 2366286570Smav typestr = "audio input"; 2367286570Smav break; 2368286570Smav case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER: 2369286570Smav typestr = "audio mixer"; 2370286570Smav break; 2371286570Smav case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR: 2372219089Spjd typestr = "audio selector"; 2373168404Spjd break; 2374168404Spjd case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX: 2375286570Smav typestr = "pin"; 2376286570Smav break; 2377286570Smav case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_POWER_WIDGET: 2378286570Smav typestr = "power widget"; 2379286570Smav break; 2380286570Smav case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VOLUME_WIDGET: 2381286570Smav typestr = "volume widget"; 2382168404Spjd break; 2383168404Spjd case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET: 2384168404Spjd typestr = "beep widget"; 2385168404Spjd break; 2386168404Spjd case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VENDOR_WIDGET: 2387168404Spjd typestr = "vendor widget"; 2388286570Smav break; 2389168404Spjd default: 2390168404Spjd typestr = "unknown type"; 2391168404Spjd break; 2392168404Spjd } 2393168404Spjd 2394168404Spjd strlcpy(w->name, typestr, sizeof(w->name)); 2395168404Spjd 2396168404Spjd if (HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL(wcap)) { 2397219089Spjd hdac_command(sc, 2398219089Spjd HDA_CMD_SET_POWER_STATE(cad, nid, HDA_CMD_POWER_STATE_D0), 2399219089Spjd cad); 2400168404Spjd DELAY(1000); 2401286570Smav } 2402168404Spjd 2403219089Spjd hdac_widget_connection_parse(w); 2404286570Smav 2405219089Spjd if (HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP(wcap)) { 2406275811Sdelphij if (HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR(wcap)) 2407219089Spjd w->param.outamp_cap = 2408168404Spjd hdac_command(sc, 2409168404Spjd HDA_CMD_GET_PARAMETER(cad, nid, 2410168404Spjd HDA_PARAM_OUTPUT_AMP_CAP), cad); 2411168404Spjd else 2412168404Spjd w->param.outamp_cap = 2413168404Spjd w->devinfo->function.audio.outamp_cap; 2414168404Spjd } else 2415168404Spjd w->param.outamp_cap = 0; 2416168404Spjd 2417168404Spjd if (HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP(wcap)) { 2418286570Smav if (HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR(wcap)) 2419168404Spjd w->param.inamp_cap = 2420168404Spjd hdac_command(sc, 2421168404Spjd HDA_CMD_GET_PARAMETER(cad, nid, 2422168404Spjd HDA_PARAM_INPUT_AMP_CAP), cad); 2423168404Spjd else 2424219089Spjd w->param.inamp_cap = 2425168404Spjd w->devinfo->function.audio.inamp_cap; 2426219089Spjd } else 2427168404Spjd w->param.inamp_cap = 0; 2428168404Spjd 2429168404Spjd if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT || 2430168404Spjd w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) { 2431248571Smm if (HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR(wcap)) { 2432168404Spjd cap = hdac_command(sc, 2433168404Spjd HDA_CMD_GET_PARAMETER(cad, nid, 2434168404Spjd HDA_PARAM_SUPP_STREAM_FORMATS), cad); 2435168404Spjd w->param.supp_stream_formats = (cap != 0) ? cap : 2436248571Smm w->devinfo->function.audio.supp_stream_formats; 2437168404Spjd cap = hdac_command(sc, 2438286570Smav HDA_CMD_GET_PARAMETER(cad, nid, 2439286570Smav HDA_PARAM_SUPP_PCM_SIZE_RATE), cad); 2440168404Spjd w->param.supp_pcm_size_rate = (cap != 0) ? cap : 2441168404Spjd w->devinfo->function.audio.supp_pcm_size_rate; 2442168404Spjd } else { 2443168404Spjd w->param.supp_stream_formats = 2444168404Spjd w->devinfo->function.audio.supp_stream_formats; 2445219089Spjd w->param.supp_pcm_size_rate = 2446286570Smav w->devinfo->function.audio.supp_pcm_size_rate; 2447219089Spjd } 2448286570Smav } else { 2449168404Spjd w->param.supp_stream_formats = 0; 2450168404Spjd w->param.supp_pcm_size_rate = 0; 2451168404Spjd } 2452286570Smav 2453168404Spjd if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) 2454168404Spjd hdac_widget_pin_parse(w); 2455168404Spjd} 2456286570Smav 2457219089Spjdstatic struct hdac_widget * 2458275811Sdelphijhdac_widget_get(struct hdac_devinfo *devinfo, nid_t nid) 2459168404Spjd{ 2460286570Smav if (devinfo == NULL || devinfo->widget == NULL || 2461286570Smav nid < devinfo->startnode || nid >= devinfo->endnode) 2462168404Spjd return (NULL); 2463168404Spjd return (&devinfo->widget[nid - devinfo->startnode]); 2464168404Spjd} 2465168404Spjd 2466286570Smavstatic __inline int 2467168404Spjdhda_poll_channel(struct hdac_chan *ch) 2468168404Spjd{ 2469168404Spjd uint32_t sz, delta; 2470168404Spjd volatile uint32_t ptr; 2471168404Spjd 2472168404Spjd if (!(ch->flags & HDAC_CHN_RUNNING)) 2473242845Sdelphij return (0); 2474242845Sdelphij 2475242845Sdelphij sz = ch->blksz * ch->blkcnt; 2476242845Sdelphij if (ch->dmapos != NULL) 2477242845Sdelphij ptr = *(ch->dmapos); 2478242845Sdelphij else 2479242845Sdelphij ptr = HDAC_READ_4(&ch->devinfo->codec->sc->mem, 2480242845Sdelphij ch->off + HDAC_SDLPIB); 2481242845Sdelphij ch->ptr = ptr; 2482242845Sdelphij ptr %= sz; 2483242845Sdelphij ptr &= ~(ch->blksz - 1); 2484242845Sdelphij delta = (sz + ptr - ch->prevptr) % sz; 2485242845Sdelphij 2486242845Sdelphij if (delta < ch->blksz) 2487242845Sdelphij return (0); 2488242845Sdelphij 2489242845Sdelphij ch->prevptr = ptr; 2490242845Sdelphij 2491242845Sdelphij return (1); 2492242845Sdelphij} 2493242845Sdelphij 2494242845Sdelphij#define hda_chan_active(sc) (((sc)->play.flags | (sc)->rec.flags) & \ 2495242845Sdelphij HDAC_CHN_RUNNING) 2496242845Sdelphij 2497242845Sdelphijstatic void 2498242845Sdelphijhda_poll_callback(void *arg) 2499242845Sdelphij{ 2500242845Sdelphij struct hdac_softc *sc = arg; 2501242845Sdelphij uint32_t trigger; 2502242845Sdelphij 2503242845Sdelphij if (sc == NULL) 2504242845Sdelphij return; 2505242845Sdelphij 2506242845Sdelphij hdac_lock(sc); 2507286570Smav if (sc->polling == 0 || hda_chan_active(sc) == 0) { 2508242845Sdelphij hdac_unlock(sc); 2509242845Sdelphij return; 2510242845Sdelphij } 2511242845Sdelphij 2512242845Sdelphij trigger = 0; 2513242845Sdelphij trigger |= (hda_poll_channel(&sc->play) != 0) ? HDAC_TRIGGER_PLAY : 0; 2514242845Sdelphij trigger |= (hda_poll_channel(&sc->rec)) != 0 ? HDAC_TRIGGER_REC : 0; 2515168404Spjd 2516168404Spjd /* XXX */ 2517168404Spjd callout_reset(&sc->poll_hda, 1/*sc->poll_ticks*/, 2518168404Spjd hda_poll_callback, sc); 2519168404Spjd 2520168404Spjd hdac_unlock(sc); 2521168404Spjd 2522185029Spjd if (trigger & HDAC_TRIGGER_PLAY) 2523185029Spjd chn_intr(sc->play.c); 2524185029Spjd if (trigger & HDAC_TRIGGER_REC) 2525185029Spjd chn_intr(sc->rec.c); 2526168404Spjd} 2527168404Spjd 2528209962Smmstatic int 2529168404Spjdhdac_rirb_flush(struct hdac_softc *sc) 2530168404Spjd{ 2531168404Spjd struct hdac_rirb *rirb_base, *rirb; 2532168404Spjd struct hdac_codec *codec; 2533205231Skmacy struct hdac_command_list *commands; 2534275811Sdelphij nid_t cad; 2535205231Skmacy uint32_t resp; 2536205231Skmacy uint8_t rirbwp; 2537168404Spjd int ret; 2538168404Spjd 2539168404Spjd rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr; 2540258632Savg rirbwp = HDAC_READ_1(&sc->mem, HDAC_RIRBWP); 2541258632Savg#if 0 2542205231Skmacy bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map, 2543258632Savg BUS_DMASYNC_POSTREAD); 2544168404Spjd#endif 2545168404Spjd 2546168404Spjd ret = 0; 2547168404Spjd 2548206796Spjd while (sc->rirb_rp != rirbwp) { 2549275780Sdelphij sc->rirb_rp++; 2550275780Sdelphij sc->rirb_rp %= sc->rirb_size; 2551275780Sdelphij rirb = &rirb_base[sc->rirb_rp]; 2552275780Sdelphij cad = HDAC_RIRB_RESPONSE_EX_SDATA_IN(rirb->response_ex); 2553275780Sdelphij if (cad < 0 || cad >= HDAC_CODEC_MAX || 2554275780Sdelphij sc->codecs[cad] == NULL) 2555275780Sdelphij continue; 2556275780Sdelphij resp = rirb->response; 2557275780Sdelphij codec = sc->codecs[cad]; 2558275780Sdelphij commands = codec->commands; 2559275780Sdelphij if (rirb->response_ex & HDAC_RIRB_RESPONSE_EX_UNSOLICITED) { 2560275780Sdelphij sc->unsolq[sc->unsolq_wp++] = (cad << 16) | 2561275780Sdelphij ((resp >> 26) & 0xffff); 2562275780Sdelphij sc->unsolq_wp %= HDAC_UNSOLQ_MAX; 2563275780Sdelphij } else if (commands != NULL && commands->num_commands > 0 && 2564275780Sdelphij codec->responses_received < commands->num_commands) 2565275780Sdelphij commands->responses[codec->responses_received++] = 2566275780Sdelphij resp; 2567286570Smav ret++; 2568286570Smav } 2569286570Smav 2570286570Smav return (ret); 2571286570Smav} 2572286570Smav 2573275780Sdelphijstatic int 2574286570Smavhdac_unsolq_flush(struct hdac_softc *sc) 2575275780Sdelphij{ 2576286570Smav nid_t cad; 2577275780Sdelphij uint32_t tag; 2578275780Sdelphij int ret = 0; 2579275780Sdelphij 2580275780Sdelphij if (sc->unsolq_st == HDAC_UNSOLQ_READY) { 2581275780Sdelphij sc->unsolq_st = HDAC_UNSOLQ_BUSY; 2582275780Sdelphij while (sc->unsolq_rp != sc->unsolq_wp) { 2583275780Sdelphij cad = sc->unsolq[sc->unsolq_rp] >> 16; 2584275780Sdelphij tag = sc->unsolq[sc->unsolq_rp++] & 0xffff; 2585275780Sdelphij sc->unsolq_rp %= HDAC_UNSOLQ_MAX; 2586275780Sdelphij hdac_unsolicited_handler(sc->codecs[cad], tag); 2587275780Sdelphij ret++; 2588275780Sdelphij } 2589275780Sdelphij sc->unsolq_st = HDAC_UNSOLQ_READY; 2590275780Sdelphij } 2591275780Sdelphij 2592275780Sdelphij return (ret); 2593205231Skmacy} 2594205231Skmacy 2595205231Skmacystatic void 2596205231Skmacyhdac_poll_callback(void *arg) 2597205231Skmacy{ 2598205231Skmacy struct hdac_softc *sc = arg; 2599205231Skmacy if (sc == NULL) 2600205231Skmacy return; 2601205231Skmacy 2602205231Skmacy hdac_lock(sc); 2603205231Skmacy if (sc->polling == 0 || sc->poll_ival == 0) { 2604205231Skmacy hdac_unlock(sc); 2605205231Skmacy return; 2606205231Skmacy } 2607258632Savg if (hdac_rirb_flush(sc) != 0) 2608206796Spjd hdac_unsolq_flush(sc); 2609205231Skmacy callout_reset(&sc->poll_hdac, sc->poll_ival, hdac_poll_callback, sc); 2610205231Skmacy hdac_unlock(sc); 2611205231Skmacy} 2612205231Skmacy 2613206796Spjdstatic void 2614168404Spjdhdac_stream_stop(struct hdac_chan *ch) 2615286570Smav{ 2616286570Smav struct hdac_softc *sc = ch->devinfo->codec->sc; 2617286570Smav uint32_t ctl; 2618286570Smav 2619286570Smav ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0); 2620286570Smav ctl &= ~(HDAC_SDCTL_IOCE | HDAC_SDCTL_FEIE | HDAC_SDCTL_DEIE | 2621286570Smav HDAC_SDCTL_RUN); 2622286570Smav HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl); 2623286570Smav 2624286570Smav ch->flags &= ~HDAC_CHN_RUNNING; 2625286570Smav 2626286570Smav if (sc->polling != 0) { 2627286570Smav int pollticks; 2628205231Skmacy 2629205231Skmacy if (hda_chan_active(sc) == 0) { 2630275811Sdelphij callout_stop(&sc->poll_hda); 2631275811Sdelphij sc->poll_ticks = 1; 2632286570Smav } else { 2633286570Smav if (sc->play.flags & HDAC_CHN_RUNNING) 2634286570Smav ch = &sc->play; 2635286570Smav else 2636168404Spjd ch = &sc->rec; 2637275811Sdelphij pollticks = ((uint64_t)hz * ch->blksz) / 2638275811Sdelphij ((uint64_t)sndbuf_getbps(ch->b) * 2639286570Smav sndbuf_getspd(ch->b)); 2640286570Smav pollticks >>= 2; 2641219089Spjd if (pollticks > hz) 2642168404Spjd pollticks = hz; 2643168404Spjd if (pollticks < 1) { 2644168404Spjd HDA_BOOTVERBOSE( 2645168404Spjd device_printf(sc->dev, 2646275811Sdelphij "%s: pollticks=%d < 1 !\n", 2647275811Sdelphij __func__, pollticks); 2648168404Spjd ); 2649258632Savg pollticks = 1; 2650258632Savg } 2651275811Sdelphij if (pollticks > sc->poll_ticks) { 2652258632Savg HDA_BOOTVERBOSE( 2653258632Savg device_printf(sc->dev, 2654258632Savg "%s: pollticks %d -> %d\n", 2655258632Savg __func__, sc->poll_ticks, 2656258632Savg pollticks); 2657258632Savg ); 2658258632Savg sc->poll_ticks = pollticks; 2659258632Savg callout_reset(&sc->poll_hda, 1, 2660258632Savg hda_poll_callback, sc); 2661258632Savg } 2662258632Savg } 2663258632Savg } else { 2664275811Sdelphij ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL); 2665286570Smav ctl &= ~(1 << (ch->off >> 5)); 2666258632Savg HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl); 2667258632Savg } 2668286570Smav} 2669258632Savg 2670275811Sdelphijstatic void 2671258632Savghdac_stream_start(struct hdac_chan *ch) 2672258632Savg{ 2673258632Savg struct hdac_softc *sc = ch->devinfo->codec->sc; 2674258632Savg uint32_t ctl; 2675258632Savg 2676275811Sdelphij if (sc->polling != 0) { 2677168404Spjd int pollticks; 2678168404Spjd 2679286570Smav pollticks = ((uint64_t)hz * ch->blksz) / 2680286570Smav ((uint64_t)sndbuf_getbps(ch->b) * sndbuf_getspd(ch->b)); 2681286570Smav pollticks >>= 2; 2682286570Smav if (pollticks > hz) 2683219089Spjd pollticks = hz; 2684185029Spjd if (pollticks < 1) { 2685185029Spjd HDA_BOOTVERBOSE( 2686185029Spjd device_printf(sc->dev, 2687286570Smav "%s: pollticks=%d < 1 !\n", 2688275811Sdelphij __func__, pollticks); 2689286570Smav ); 2690286570Smav pollticks = 1; 2691275811Sdelphij } 2692275811Sdelphij if (hda_chan_active(sc) == 0 || pollticks < sc->poll_ticks) { 2693168404Spjd HDA_BOOTVERBOSE( 2694168404Spjd if (hda_chan_active(sc) == 0) { 2695168404Spjd device_printf(sc->dev, 2696168404Spjd "%s: pollticks=%d\n", 2697286570Smav __func__, pollticks); 2698168404Spjd } else { 2699168404Spjd device_printf(sc->dev, 2700168404Spjd "%s: pollticks %d -> %d\n", 2701286570Smav __func__, sc->poll_ticks, 2702168404Spjd pollticks); 2703168404Spjd } 2704168404Spjd ); 2705168404Spjd sc->poll_ticks = pollticks; 2706219089Spjd callout_reset(&sc->poll_hda, 1, hda_poll_callback, 2707168404Spjd sc); 2708219089Spjd } 2709168404Spjd ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0); 2710168404Spjd ctl |= HDAC_SDCTL_RUN; 2711168404Spjd } else { 2712168404Spjd ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL); 2713208373Smm ctl |= 1 << (ch->off >> 5); 2714286570Smav HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl); 2715208373Smm ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0); 2716275811Sdelphij ctl |= HDAC_SDCTL_IOCE | HDAC_SDCTL_FEIE | HDAC_SDCTL_DEIE | 2717208373Smm HDAC_SDCTL_RUN; 2718275811Sdelphij } 2719208373Smm HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl); 2720275811Sdelphij 2721208373Smm ch->flags |= HDAC_CHN_RUNNING; 2722208373Smm} 2723208373Smm 2724275811Sdelphijstatic void 2725208373Smmhdac_stream_reset(struct hdac_chan *ch) 2726208373Smm{ 2727208373Smm struct hdac_softc *sc = ch->devinfo->codec->sc; 2728286570Smav int timeout = 1000; 2729275811Sdelphij int to = timeout; 2730275811Sdelphij uint32_t ctl; 2731275811Sdelphij 2732275811Sdelphij ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0); 2733275811Sdelphij ctl |= HDAC_SDCTL_SRST; 2734185029Spjd HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl); 2735168404Spjd do { 2736168404Spjd ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0); 2737168404Spjd if (ctl & HDAC_SDCTL_SRST) 2738168404Spjd break; 2739205231Skmacy DELAY(10); 2740205231Skmacy } while (--to); 2741205231Skmacy if (!(ctl & HDAC_SDCTL_SRST)) { 2742206796Spjd device_printf(sc->dev, "timeout in reset\n"); 2743258632Savg } 2744205231Skmacy ctl &= ~HDAC_SDCTL_SRST; 2745205231Skmacy HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl); 2746168404Spjd to = timeout; 2747168404Spjd do { 2748168404Spjd ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0); 2749168404Spjd if (!(ctl & HDAC_SDCTL_SRST)) 2750168404Spjd break; 2751286570Smav DELAY(10); 2752205231Skmacy } while (--to); 2753206796Spjd if (ctl & HDAC_SDCTL_SRST) 2754206796Spjd device_printf(sc->dev, "can't reset!\n"); 2755258632Savg} 2756168404Spjd 2757205231Skmacystatic void 2758258632Savghdac_stream_setid(struct hdac_chan *ch) 2759205231Skmacy{ 2760205231Skmacy struct hdac_softc *sc = ch->devinfo->codec->sc; 2761205231Skmacy uint32_t ctl; 2762205231Skmacy 2763205231Skmacy ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL2); 2764206796Spjd ctl &= ~HDAC_SDCTL2_STRM_MASK; 2765205231Skmacy ctl |= ch->sid << HDAC_SDCTL2_STRM_SHIFT; 2766205231Skmacy HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL2, ctl); 2767205231Skmacy} 2768206796Spjd 2769168404Spjdstatic void 2770168404Spjdhdac_bdl_setup(struct hdac_chan *ch) 2771168404Spjd{ 2772168404Spjd struct hdac_softc *sc = ch->devinfo->codec->sc; 2773168404Spjd struct hdac_bdle *bdle; 2774168404Spjd uint64_t addr; 2775185029Spjd uint32_t blksz, blkcnt; 2776258632Savg int i; 2777258632Savg 2778258632Savg addr = (uint64_t)sndbuf_getbufaddr(ch->b); 2779258632Savg bdle = (struct hdac_bdle *)ch->bdl_dma.dma_vaddr; 2780185029Spjd 2781185029Spjd if (sc->polling != 0) { 2782205231Skmacy blksz = ch->blksz * ch->blkcnt; 2783205231Skmacy blkcnt = 1; 2784168404Spjd } else { 2785168404Spjd blksz = ch->blksz; 2786168404Spjd blkcnt = ch->blkcnt; 2787168404Spjd } 2788168404Spjd 2789168404Spjd for (i = 0; i < blkcnt; i++, bdle++) { 2790168404Spjd bdle->addrl = (uint32_t)addr; 2791168404Spjd bdle->addrh = (uint32_t)(addr >> 32); 2792209962Smm bdle->len = blksz; 2793168404Spjd bdle->ioc = 1 ^ sc->polling; 2794275811Sdelphij addr += blksz; 2795219089Spjd } 2796205231Skmacy 2797205231Skmacy HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDCBL, blksz * blkcnt); 2798168404Spjd HDAC_WRITE_2(&sc->mem, ch->off + HDAC_SDLVI, blkcnt - 1); 2799168404Spjd addr = ch->bdl_dma.dma_paddr; 2800258632Savg HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDBDPL, (uint32_t)addr); 2801205231Skmacy HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDBDPU, (uint32_t)(addr >> 32)); 2802205231Skmacy if (ch->dmapos != NULL && 2803258632Savg !(HDAC_READ_4(&sc->mem, HDAC_DPIBLBASE) & 0x00000001)) { 2804168404Spjd addr = sc->pos_dma.dma_paddr; 2805168404Spjd HDAC_WRITE_4(&sc->mem, HDAC_DPIBLBASE, 2806205231Skmacy ((uint32_t)addr & HDAC_DPLBASE_DPLBASE_MASK) | 0x00000001); 2807205231Skmacy HDAC_WRITE_4(&sc->mem, HDAC_DPIBUBASE, (uint32_t)(addr >> 32)); 2808205231Skmacy } 2809205231Skmacy} 2810205231Skmacy 2811205231Skmacystatic int 2812205231Skmacyhdac_bdl_alloc(struct hdac_chan *ch) 2813206796Spjd{ 2814205231Skmacy struct hdac_softc *sc = ch->devinfo->codec->sc; 2815205231Skmacy int rc; 2816205231Skmacy 2817205231Skmacy rc = hdac_dma_alloc(sc, &ch->bdl_dma, 2818205231Skmacy sizeof(struct hdac_bdle) * HDA_BDL_MAX); 2819275811Sdelphij if (rc) { 2820275811Sdelphij device_printf(sc->dev, "can't alloc bdl\n"); 2821286570Smav return (rc); 2822275811Sdelphij } 2823275811Sdelphij 2824185029Spjd return (0); 2825219089Spjd} 2826219089Spjd 2827275811Sdelphijstatic void 2828219089Spjdhdac_audio_ctl_amp_set_internal(struct hdac_softc *sc, nid_t cad, nid_t nid, 2829219089Spjd int index, int lmute, int rmute, 2830275811Sdelphij int left, int right, int dir) 2831219089Spjd{ 2832219089Spjd uint16_t v = 0; 2833219089Spjd 2834258632Savg if (sc == NULL) 2835258632Savg return; 2836258632Savg 2837258632Savg if (left != right || lmute != rmute) { 2838258632Savg v = (1 << (15 - dir)) | (1 << 13) | (index << 8) | 2839258632Savg (lmute << 7) | left; 2840258632Savg hdac_command(sc, 2841258632Savg HDA_CMD_SET_AMP_GAIN_MUTE(cad, nid, v), cad); 2842275811Sdelphij v = (1 << (15 - dir)) | (1 << 12) | (index << 8) | 2843258632Savg (rmute << 7) | right; 2844258632Savg } else 2845258632Savg v = (1 << (15 - dir)) | (3 << 12) | (index << 8) | 2846275811Sdelphij (lmute << 7) | left; 2847258632Savg 2848258632Savg hdac_command(sc, 2849258632Savg HDA_CMD_SET_AMP_GAIN_MUTE(cad, nid, v), cad); 2850258632Savg} 2851168404Spjd 2852275811Sdelphijstatic void 2853286570Smavhdac_audio_ctl_amp_set(struct hdac_audio_ctl *ctl, uint32_t mute, 2854286570Smav int left, int right) 2855168404Spjd{ 2856275811Sdelphij struct hdac_softc *sc; 2857185029Spjd nid_t nid, cad; 2858286570Smav int lmute, rmute; 2859185029Spjd 2860185029Spjd if (ctl == NULL || ctl->widget == NULL || 2861185029Spjd ctl->widget->devinfo == NULL || 2862185029Spjd ctl->widget->devinfo->codec == NULL || 2863275811Sdelphij ctl->widget->devinfo->codec->sc == NULL) 2864286570Smav return; 2865286570Smav 2866286570Smav sc = ctl->widget->devinfo->codec->sc; 2867286570Smav cad = ctl->widget->devinfo->codec->cad; 2868286570Smav nid = ctl->widget->nid; 2869286570Smav 2870185029Spjd if (mute == HDA_AMP_MUTE_DEFAULT) { 2871185029Spjd lmute = HDA_AMP_LEFT_MUTED(ctl->muted); 2872275811Sdelphij rmute = HDA_AMP_RIGHT_MUTED(ctl->muted); 2873185029Spjd } else { 2874275811Sdelphij lmute = HDA_AMP_LEFT_MUTED(mute); 2875185029Spjd rmute = HDA_AMP_RIGHT_MUTED(mute); 2876185029Spjd } 2877275811Sdelphij 2878168404Spjd if (ctl->dir & HDA_CTL_OUT) 2879168404Spjd hdac_audio_ctl_amp_set_internal(sc, cad, nid, ctl->index, 2880219089Spjd lmute, rmute, left, right, 0); 2881219089Spjd if (ctl->dir & HDA_CTL_IN) 2882219089Spjd hdac_audio_ctl_amp_set_internal(sc, cad, nid, ctl->index, 2883219089Spjd lmute, rmute, left, right, 1); 2884219089Spjd ctl->left = left; 2885219089Spjd ctl->right = right; 2886275811Sdelphij} 2887219089Spjd 2888219089Spjdstatic void 2889219089Spjdhdac_widget_connection_select(struct hdac_widget *w, uint8_t index) 2890219089Spjd{ 2891275811Sdelphij if (w == NULL || w->nconns < 1 || index > (w->nconns - 1)) 2892219089Spjd return; 2893258632Savg hdac_command(w->devinfo->codec->sc, 2894168404Spjd HDA_CMD_SET_CONNECTION_SELECT_CONTROL(w->devinfo->codec->cad, 2895258632Savg w->nid, index), w->devinfo->codec->cad); 2896258632Savg w->selconn = index; 2897168404Spjd} 2898205231Skmacy 2899206796Spjd 2900258632Savg/**************************************************************************** 2901206796Spjd * uint32_t hdac_command_sendone_internal 2902258632Savg * 2903205231Skmacy * Wrapper function that sends only one command to a given codec 2904206796Spjd ****************************************************************************/ 2905205231Skmacystatic uint32_t 2906205231Skmacyhdac_command_sendone_internal(struct hdac_softc *sc, uint32_t verb, nid_t cad) 2907185029Spjd{ 2908205231Skmacy struct hdac_command_list cl; 2909205231Skmacy uint32_t response = HDAC_INVALID; 2910258632Savg 2911205231Skmacy if (!hdac_lockowned(sc)) 2912185029Spjd device_printf(sc->dev, "WARNING!!!! mtx not owned!!!!\n"); 2913185029Spjd cl.num_commands = 1; 2914168404Spjd cl.verbs = &verb; 2915168404Spjd cl.responses = &response; 2916168404Spjd 2917168404Spjd hdac_command_send_internal(sc, &cl, cad); 2918168404Spjd 2919168404Spjd return (response); 2920168404Spjd} 2921168404Spjd 2922168404Spjd/**************************************************************************** 2923168404Spjd * hdac_command_send_internal 2924168404Spjd * 2925168404Spjd * Send a command list to the codec via the corb. We queue as much verbs as 2926168404Spjd * we can and msleep on the codec. When the interrupt get the responses 2927208373Smm * back from the rirb, it will wake us up so we can queue the remaining verbs 2928168404Spjd * if any. 2929208373Smm ****************************************************************************/ 2930208373Smmstatic void 2931208373Smmhdac_command_send_internal(struct hdac_softc *sc, 2932168404Spjd struct hdac_command_list *commands, nid_t cad) 2933209275Smm{ 2934209275Smm struct hdac_codec *codec; 2935209275Smm int corbrp; 2936208373Smm uint32_t *corb; 2937208373Smm int timeout; 2938208373Smm int retry = 10; 2939209962Smm struct hdac_rirb *rirb_base; 2940208373Smm 2941168404Spjd if (sc == NULL || sc->codecs[cad] == NULL || commands == NULL || 2942168404Spjd commands->num_commands < 1) 2943208373Smm return; 2944208373Smm 2945209962Smm codec = sc->codecs[cad]; 2946185029Spjd codec->commands = commands; 2947185029Spjd codec->responses_received = 0; 2948185029Spjd codec->verbs_sent = 0; 2949208373Smm corb = (uint32_t *)sc->corb_dma.dma_vaddr; 2950208373Smm rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr; 2951208373Smm 2952168404Spjd do { 2953208373Smm if (codec->verbs_sent != commands->num_commands) { 2954208373Smm /* Queue as many verbs as possible */ 2955208373Smm corbrp = HDAC_READ_2(&sc->mem, HDAC_CORBRP); 2956208373Smm#if 0 2957209962Smm bus_dmamap_sync(sc->corb_dma.dma_tag, 2958208373Smm sc->corb_dma.dma_map, BUS_DMASYNC_PREWRITE); 2959168404Spjd#endif 2960168404Spjd while (codec->verbs_sent != commands->num_commands && 2961208373Smm ((sc->corb_wp + 1) % sc->corb_size) != corbrp) { 2962208373Smm sc->corb_wp++; 2963208373Smm sc->corb_wp %= sc->corb_size; 2964209962Smm corb[sc->corb_wp] = 2965208373Smm commands->verbs[codec->verbs_sent++]; 2966208373Smm } 2967168404Spjd 2968208373Smm /* Send the verbs to the codecs */ 2969208373Smm#if 0 2970208373Smm bus_dmamap_sync(sc->corb_dma.dma_tag, 2971168404Spjd sc->corb_dma.dma_map, BUS_DMASYNC_POSTWRITE); 2972208373Smm#endif 2973168404Spjd HDAC_WRITE_2(&sc->mem, HDAC_CORBWP, sc->corb_wp); 2974208373Smm } 2975208373Smm 2976209962Smm timeout = 1000; 2977208373Smm while (hdac_rirb_flush(sc) == 0 && --timeout) 2978185029Spjd DELAY(10); 2979208373Smm } while ((codec->verbs_sent != commands->num_commands || 2980208373Smm codec->responses_received != commands->num_commands) && --retry); 2981208373Smm 2982208373Smm if (retry == 0) 2983208373Smm device_printf(sc->dev, 2984209962Smm "%s: TIMEOUT numcmd=%d, sent=%d, received=%d\n", 2985168404Spjd __func__, commands->num_commands, codec->verbs_sent, 2986168404Spjd codec->responses_received); 2987168404Spjd 2988168404Spjd codec->commands = NULL; 2989168404Spjd codec->responses_received = 0; 2990168404Spjd codec->verbs_sent = 0; 2991191903Skmacy 2992191903Skmacy hdac_unsolq_flush(sc); 2993191903Skmacy} 2994191903Skmacy 2995191903Skmacy 2996206796Spjd/**************************************************************************** 2997168404Spjd * Device Methods 2998191903Skmacy ****************************************************************************/ 2999191903Skmacy 3000191903Skmacy/**************************************************************************** 3001191903Skmacy * int hdac_probe(device_t) 3002191903Skmacy * 3003191903Skmacy * Probe for the presence of an hdac. If none is found, check for a generic 3004191903Skmacy * match using the subclass of the device. 3005219089Spjd ****************************************************************************/ 3006168404Spjdstatic int 3007219089Spjdhdac_probe(device_t dev) 3008168404Spjd{ 3009168404Spjd int i, result; 3010268858Sdelphij uint32_t model; 3011168404Spjd uint16_t class, subclass; 3012168404Spjd char desc[64]; 3013168404Spjd 3014168404Spjd model = (uint32_t)pci_get_device(dev) << 16; 3015168404Spjd model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff; 3016191903Skmacy class = pci_get_class(dev); 3017191903Skmacy subclass = pci_get_subclass(dev); 3018191903Skmacy 3019168404Spjd bzero(desc, sizeof(desc)); 3020168404Spjd result = ENXIO; 3021168404Spjd for (i = 0; i < HDAC_DEVICES_LEN; i++) { 3022185029Spjd if (hdac_devices[i].model == model) { 3023168404Spjd strlcpy(desc, hdac_devices[i].desc, sizeof(desc)); 3024168404Spjd result = BUS_PROBE_DEFAULT; 3025168404Spjd break; 3026185029Spjd } 3027168404Spjd if (HDA_DEV_MATCH(hdac_devices[i].model, model) && 3028209962Smm class == PCIC_MULTIMEDIA && 3029209962Smm subclass == PCIS_MULTIMEDIA_HDA) { 3030286570Smav strlcpy(desc, hdac_devices[i].desc, sizeof(desc)); 3031228103Smm result = BUS_PROBE_GENERIC; 3032209962Smm break; 3033205231Skmacy } 3034209962Smm } 3035286570Smav if (result == ENXIO && class == PCIC_MULTIMEDIA && 3036185029Spjd subclass == PCIS_MULTIMEDIA_HDA) { 3037185029Spjd strlcpy(desc, "Generic", sizeof(desc)); 3038205231Skmacy result = BUS_PROBE_GENERIC; 3039209962Smm } 3040286570Smav if (result != ENXIO) { 3041185029Spjd strlcat(desc, " High Definition Audio Controller", 3042185029Spjd sizeof(desc)); 3043205231Skmacy device_set_desc_copy(dev, desc); 3044209962Smm } 3045286570Smav 3046185029Spjd return (result); 3047185029Spjd} 3048205231Skmacy 3049209962Smmstatic void * 3050286570Smavhdac_channel_init(kobj_t obj, void *data, struct snd_dbuf *b, 3051185029Spjd struct pcm_channel *c, int dir) 3052185029Spjd{ 3053168404Spjd struct hdac_devinfo *devinfo = data; 3054209962Smm struct hdac_softc *sc = devinfo->codec->sc; 3055209962Smm struct hdac_chan *ch; 3056168404Spjd 3057168404Spjd hdac_lock(sc); 3058168404Spjd if (dir == PCMDIR_PLAY) { 3059168404Spjd ch = &sc->play; 3060185029Spjd ch->off = (sc->num_iss + devinfo->function.audio.playcnt) << 5; 3061168404Spjd devinfo->function.audio.playcnt++; 3062168404Spjd } else { 3063168404Spjd ch = &sc->rec; 3064286625Smav ch->off = devinfo->function.audio.reccnt << 5; 3065168404Spjd devinfo->function.audio.reccnt++; 3066270759Ssmh } 3067168404Spjd if (devinfo->function.audio.quirks & HDA_QUIRK_FIXEDRATE) { 3068272483Ssmh ch->caps.minspeed = ch->caps.maxspeed = 48000; 3069272483Ssmh ch->pcmrates[0] = 48000; 3070168404Spjd ch->pcmrates[1] = 0; 3071168404Spjd } 3072168404Spjd if (sc->pos_dma.dma_vaddr != NULL) 3073168404Spjd ch->dmapos = (uint32_t *)(sc->pos_dma.dma_vaddr + 3074168404Spjd (sc->streamcnt * 8)); 3075168404Spjd else 3076168404Spjd ch->dmapos = NULL; 3077168404Spjd ch->sid = ++sc->streamcnt; 3078168404Spjd ch->dir = dir; 3079168404Spjd ch->b = b; 3080272483Ssmh ch->c = c; 3081272483Ssmh ch->devinfo = devinfo; 3082272483Ssmh ch->blksz = sc->chan_size / sc->chan_blkcnt; 3083272483Ssmh ch->blkcnt = sc->chan_blkcnt; 3084168404Spjd hdac_unlock(sc); 3085168404Spjd 3086168404Spjd if (hdac_bdl_alloc(ch) != 0) { 3087168404Spjd ch->blkcnt = 0; 3088270759Ssmh return (NULL); 3089270759Ssmh } 3090270759Ssmh 3091168404Spjd if (sndbuf_alloc(ch->b, sc->chan_dmat, 3092270759Ssmh (sc->flags & HDAC_F_DMA_NOCACHE) ? BUS_DMA_NOCACHE : 0, 3093168404Spjd sc->chan_size) != 0) 3094168404Spjd return (NULL); 3095286625Smav 3096168404Spjd return (ch); 3097286625Smav} 3098286625Smav 3099286625Smavstatic int 3100286625Smavhdac_channel_setformat(kobj_t obj, void *data, uint32_t format) 3101286625Smav{ 3102286625Smav struct hdac_chan *ch = data; 3103286625Smav int i; 3104286625Smav 3105286625Smav for (i = 0; ch->caps.fmtlist[i] != 0; i++) { 3106286625Smav if (format == ch->caps.fmtlist[i]) { 3107286625Smav ch->fmt = format; 3108286625Smav return (0); 3109286625Smav } 3110286625Smav } 3111286625Smav 3112286625Smav return (EINVAL); 3113286625Smav} 3114286625Smav 3115286625Smavstatic int 3116286625Smavhdac_channel_setspeed(kobj_t obj, void *data, uint32_t speed) 3117286625Smav{ 3118286625Smav struct hdac_chan *ch = data; 3119286625Smav uint32_t spd = 0, threshold; 3120286625Smav int i; 3121286625Smav 3122286625Smav for (i = 0; ch->pcmrates[i] != 0; i++) { 3123286625Smav spd = ch->pcmrates[i]; 3124286625Smav threshold = spd + ((ch->pcmrates[i + 1] != 0) ? 3125286625Smav ((ch->pcmrates[i + 1] - spd) >> 1) : 0); 3126286625Smav if (speed < threshold) 3127286625Smav break; 3128168404Spjd } 3129286625Smav 3130286625Smav if (spd == 0) /* impossible */ 3131286625Smav ch->spd = 48000; 3132168404Spjd else 3133168404Spjd ch->spd = spd; 3134286625Smav 3135286625Smav return (ch->spd); 3136286625Smav} 3137286625Smav 3138286625Smavstatic void 3139286625Smavhdac_stream_setup(struct hdac_chan *ch) 3140270759Ssmh{ 3141168404Spjd struct hdac_softc *sc = ch->devinfo->codec->sc; 3142191902Skmacy struct hdac_widget *w; 3143212780Savg int i, chn, totalchn; 3144212780Savg nid_t cad = ch->devinfo->codec->cad; 3145191902Skmacy uint16_t fmt; 3146286625Smav 3147286625Smav fmt = 0; 3148286625Smav if (ch->fmt & AFMT_S16_LE) 3149286625Smav fmt |= ch->bit16 << 4; 3150270759Ssmh else if (ch->fmt & AFMT_S32_LE) 3151191902Skmacy fmt |= ch->bit32 << 4; 3152277300Ssmh else 3153168404Spjd fmt |= 1 << 4; 3154185029Spjd 3155185029Spjd for (i = 0; i < HDA_RATE_TAB_LEN; i++) { 3156185029Spjd if (hda_rate_tab[i].valid && ch->spd == hda_rate_tab[i].rate) { 3157185029Spjd fmt |= hda_rate_tab[i].base; 3158185029Spjd fmt |= hda_rate_tab[i].mul; 3159185029Spjd fmt |= hda_rate_tab[i].div; 3160286625Smav break; 3161286625Smav } 3162286625Smav } 3163286625Smav 3164286625Smav if (ch->fmt & AFMT_STEREO) { 3165185029Spjd fmt |= 1; 3166185029Spjd totalchn = 2; 3167168404Spjd } else 3168185029Spjd totalchn = 1; 3169168404Spjd 3170168404Spjd HDAC_WRITE_2(&sc->mem, ch->off + HDAC_SDFMT, fmt); 3171168404Spjd 3172168404Spjd chn = 0; 3173286625Smav for (i = 0; ch->io[i] != -1; i++) { 3174286625Smav w = hdac_widget_get(ch->devinfo, ch->io[i]); 3175286625Smav if (w == NULL) 3176286625Smav continue; 3177286625Smav HDA_BOOTVERBOSE( 3178286625Smav device_printf(sc->dev, 3179168404Spjd "HDA_DEBUG: PCMDIR_%s: Stream setup nid=%d " 3180286625Smav "fmt=0x%08x\n", 3181168404Spjd (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC", 3182272483Ssmh ch->io[i], fmt); 3183272483Ssmh ); 3184272483Ssmh hdac_command(sc, 3185272483Ssmh HDA_CMD_SET_CONV_FMT(cad, ch->io[i], fmt), cad); 3186272483Ssmh if (ch->dir == PCMDIR_REC) 3187272483Ssmh hdac_command(sc, 3188286625Smav HDA_CMD_SET_CONV_STREAM_CHAN(cad, ch->io[i], 3189286625Smav (chn < totalchn) ? ((ch->sid << 4) | chn) : 0), 3190286625Smav cad); 3191286625Smav else 3192286625Smav hdac_command(sc, 3193286625Smav HDA_CMD_SET_CONV_STREAM_CHAN(cad, ch->io[i], 3194272483Ssmh ch->sid << 4), cad); 3195277300Ssmh chn += 3196272483Ssmh HDA_PARAM_AUDIO_WIDGET_CAP_STEREO(w->param.widget_cap) ? 3197272483Ssmh 2 : 1; 3198168404Spjd } 3199168404Spjd} 3200168404Spjd 3201168404Spjdstatic int 3202168404Spjdhdac_channel_setfragments(kobj_t obj, void *data, 3203168404Spjd uint32_t blksz, uint32_t blkcnt) 3204168404Spjd{ 3205185029Spjd struct hdac_chan *ch = data; 3206168404Spjd struct hdac_softc *sc = ch->devinfo->codec->sc; 3207168404Spjd 3208286625Smav blksz &= HDA_BLK_ALIGN; 3209286628Smav 3210286625Smav if (blksz > (sndbuf_getmaxsize(ch->b) / HDA_BDL_MIN)) 3211286625Smav blksz = sndbuf_getmaxsize(ch->b) / HDA_BDL_MIN; 3212286625Smav if (blksz < HDA_BLK_MIN) 3213270861Ssmh blksz = HDA_BLK_MIN; 3214281026Smav if (blkcnt > HDA_BDL_MAX) 3215281026Smav blkcnt = HDA_BDL_MAX; 3216281026Smav if (blkcnt < HDA_BDL_MIN) 3217270861Ssmh blkcnt = HDA_BDL_MIN; 3218281026Smav 3219272483Ssmh while ((blksz * blkcnt) > sndbuf_getmaxsize(ch->b)) { 3220272483Ssmh if ((blkcnt >> 1) >= HDA_BDL_MIN) 3221272483Ssmh blkcnt >>= 1; 3222272483Ssmh else if ((blksz >> 1) >= HDA_BLK_MIN) 3223272483Ssmh blksz >>= 1; 3224272483Ssmh else 3225272483Ssmh break; 3226272483Ssmh } 3227272483Ssmh 3228286625Smav if ((sndbuf_getblksz(ch->b) != blksz || 3229286625Smav sndbuf_getblkcnt(ch->b) != blkcnt) && 3230286625Smav sndbuf_resize(ch->b, blkcnt, blksz) != 0) 3231286625Smav device_printf(sc->dev, "%s: failed blksz=%u blkcnt=%u\n", 3232286625Smav __func__, blksz, blkcnt); 3233286625Smav 3234286625Smav ch->blksz = sndbuf_getblksz(ch->b); 3235286625Smav ch->blkcnt = sndbuf_getblkcnt(ch->b); 3236281026Smav 3237281026Smav return (1); 3238281026Smav} 3239281026Smav 3240281026Smavstatic int 3241286625Smavhdac_channel_setblocksize(kobj_t obj, void *data, uint32_t blksz) 3242286625Smav{ 3243286625Smav struct hdac_chan *ch = data; 3244286625Smav struct hdac_softc *sc = ch->devinfo->codec->sc; 3245286625Smav 3246286625Smav hdac_channel_setfragments(obj, data, blksz, sc->chan_blkcnt); 3247286625Smav 3248281109Smav return (ch->blksz); 3249281026Smav} 3250272483Ssmh 3251286625Smavstatic void 3252168404Spjdhdac_channel_stop(struct hdac_softc *sc, struct hdac_chan *ch) 3253286625Smav{ 3254272483Ssmh struct hdac_devinfo *devinfo = ch->devinfo; 3255270759Ssmh nid_t cad = devinfo->codec->cad; 3256286625Smav int i; 3257286625Smav 3258286625Smav hdac_stream_stop(ch); 3259286625Smav 3260168404Spjd for (i = 0; ch->io[i] != -1; i++) { 3261168404Spjd hdac_command(sc, 3262286625Smav HDA_CMD_SET_CONV_STREAM_CHAN(cad, ch->io[i], 3263286625Smav 0), cad); 3264286625Smav } 3265286625Smav} 3266286625Smav 3267286625Smavstatic void 3268286625Smavhdac_channel_start(struct hdac_softc *sc, struct hdac_chan *ch) 3269286625Smav{ 3270286625Smav ch->ptr = 0; 3271286625Smav ch->prevptr = 0; 3272286625Smav hdac_stream_stop(ch); 3273286625Smav hdac_stream_reset(ch); 3274208454Spjd hdac_bdl_setup(ch); 3275208454Spjd hdac_stream_setid(ch); 3276272527Sdelphij hdac_stream_setup(ch); 3277208454Spjd hdac_stream_start(ch); 3278278040Ssmh} 3279286625Smav 3280168404Spjdstatic int 3281168404Spjdhdac_channel_trigger(kobj_t obj, void *data, int go) 3282168404Spjd{ 3283168404Spjd struct hdac_chan *ch = data; 3284168404Spjd struct hdac_softc *sc = ch->devinfo->codec->sc; 3285272483Ssmh 3286168404Spjd if (!PCMTRIG_COMMON(go)) 3287185029Spjd return (0); 3288185029Spjd 3289185029Spjd hdac_lock(sc); 3290185029Spjd switch (go) { 3291185029Spjd case PCMTRIG_START: 3292185029Spjd hdac_channel_start(sc, ch); 3293185029Spjd break; 3294168404Spjd case PCMTRIG_STOP: 3295168404Spjd case PCMTRIG_ABORT: 3296168404Spjd hdac_channel_stop(sc, ch); 3297168404Spjd break; 3298168404Spjd default: 3299168404Spjd break; 3300168404Spjd } 3301168404Spjd hdac_unlock(sc); 3302168404Spjd 3303168404Spjd return (0); 3304168404Spjd} 3305168404Spjd 3306168404Spjdstatic int 3307168404Spjdhdac_channel_getptr(kobj_t obj, void *data) 3308168404Spjd{ 3309168404Spjd struct hdac_chan *ch = data; 3310168404Spjd struct hdac_softc *sc = ch->devinfo->codec->sc; 3311168404Spjd uint32_t ptr; 3312168404Spjd 3313286570Smav hdac_lock(sc); 3314286570Smav if (sc->polling != 0) 3315272506Sdelphij ptr = ch->ptr; 3316272483Ssmh else if (ch->dmapos != NULL) 3317277300Ssmh ptr = *(ch->dmapos); 3318286625Smav else 3319286625Smav ptr = HDAC_READ_4(&sc->mem, ch->off + HDAC_SDLPIB); 3320286625Smav hdac_unlock(sc); 3321286625Smav 3322286625Smav /* 3323272483Ssmh * Round to available space and force 128 bytes aligment. 3324286625Smav */ 3325272483Ssmh ptr %= ch->blksz * ch->blkcnt; 3326272483Ssmh ptr &= HDA_BLK_ALIGN; 3327168404Spjd 3328168404Spjd return (ptr); 3329168404Spjd} 3330168404Spjd 3331168404Spjdstatic struct pcmchan_caps * 3332168404Spjdhdac_channel_getcaps(kobj_t obj, void *data) 3333168404Spjd{ 3334168404Spjd return (&((struct hdac_chan *)data)->caps); 3335168404Spjd} 3336168404Spjd 3337168404Spjdstatic kobj_method_t hdac_channel_methods[] = { 3338168404Spjd KOBJMETHOD(channel_init, hdac_channel_init), 3339286625Smav KOBJMETHOD(channel_setformat, hdac_channel_setformat), 3340286625Smav KOBJMETHOD(channel_setspeed, hdac_channel_setspeed), 3341168404Spjd KOBJMETHOD(channel_setblocksize, hdac_channel_setblocksize), 3342286625Smav KOBJMETHOD(channel_setfragments, hdac_channel_setfragments), 3343286625Smav KOBJMETHOD(channel_trigger, hdac_channel_trigger), 3344168404Spjd KOBJMETHOD(channel_getptr, hdac_channel_getptr), 3345286625Smav KOBJMETHOD(channel_getcaps, hdac_channel_getcaps), 3346286625Smav { 0, 0 } 3347286625Smav}; 3348286625SmavCHANNEL_DECLARE(hdac_channel); 3349219089Spjd 3350168404Spjdstatic void 3351286625Smavhdac_jack_poll_callback(void *arg) 3352286625Smav{ 3353286625Smav struct hdac_devinfo *devinfo = arg; 3354286625Smav struct hdac_softc *sc; 3355286625Smav 3356286625Smav if (devinfo == NULL || devinfo->codec == NULL || 3357286625Smav devinfo->codec->sc == NULL) 3358286625Smav return; 3359286625Smav sc = devinfo->codec->sc; 3360286625Smav hdac_lock(sc); 3361286625Smav if (sc->poll_ival == 0) { 3362286625Smav hdac_unlock(sc); 3363286625Smav return; 3364286625Smav } 3365286625Smav hdac_hp_switch_handler(devinfo); 3366168404Spjd callout_reset(&sc->poll_jack, sc->poll_ival, 3367286625Smav hdac_jack_poll_callback, devinfo); 3368286625Smav hdac_unlock(sc); 3369286625Smav} 3370286625Smav 3371168404Spjdstatic int 3372168404Spjdhdac_audio_ctl_ossmixer_init(struct snd_mixer *m) 3373209275Smm{ 3374168404Spjd struct hdac_devinfo *devinfo = mix_getdevinfo(m); 3375168404Spjd struct hdac_softc *sc = devinfo->codec->sc; 3376168404Spjd struct hdac_widget *w, *cw; 3377168404Spjd struct hdac_audio_ctl *ctl; 3378211762Savg uint32_t mask, recmask, id; 3379211762Savg int i, j, softpcmvol; 3380185029Spjd nid_t cad; 3381185029Spjd 3382211762Savg hdac_lock(sc); 3383168404Spjd 3384168404Spjd mask = 0; 3385286574Smav recmask = 0; 3386286574Smav 3387286574Smav id = hdac_codec_id(devinfo); 3388286574Smav cad = devinfo->codec->cad; 3389286574Smav for (i = 0; i < HDAC_HP_SWITCH_LEN; i++) { 3390286574Smav if (!(HDA_DEV_MATCH(hdac_hp_switch[i].model, 3391286574Smav sc->pci_subvendor) && hdac_hp_switch[i].id == id)) 3392286574Smav continue; 3393286574Smav w = hdac_widget_get(devinfo, hdac_hp_switch[i].hpnid); 3394286574Smav if (w == NULL || w->enable == 0 || w->type != 3395286574Smav HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) 3396286574Smav continue; 3397286574Smav if (hdac_hp_switch[i].polling != 0) 3398286574Smav callout_reset(&sc->poll_jack, 1, 3399168404Spjd hdac_jack_poll_callback, devinfo); 3400168404Spjd else if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap)) 3401168404Spjd hdac_command(sc, 3402168404Spjd HDA_CMD_SET_UNSOLICITED_RESPONSE(cad, w->nid, 3403168404Spjd HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE | 3404168404Spjd HDAC_UNSOLTAG_EVENT_HP), cad); 3405168404Spjd else 3406168404Spjd continue; 3407168404Spjd hdac_hp_switch_handler(devinfo); 3408168404Spjd HDA_BOOTVERBOSE( 3409168404Spjd device_printf(sc->dev, 3410168404Spjd "HDA_DEBUG: Enabling headphone/speaker " 3411168404Spjd "audio routing switching:\n"); 3412168404Spjd device_printf(sc->dev, 3413168404Spjd "HDA_DEBUG: \tindex=%d nid=%d " 3414168404Spjd "pci_subvendor=0x%08x " 3415168404Spjd "codec=0x%08x [%s]\n", 3416168404Spjd i, w->nid, sc->pci_subvendor, id, 3417168404Spjd (hdac_hp_switch[i].polling != 0) ? "POLL" : 3418168404Spjd "UNSOL"); 3419168404Spjd ); 3420168404Spjd break; 3421208373Smm } 3422168404Spjd for (i = 0; i < HDAC_EAPD_SWITCH_LEN; i++) { 3423185029Spjd if (!(HDA_DEV_MATCH(hdac_eapd_switch[i].model, 3424185029Spjd sc->pci_subvendor) && 3425185029Spjd hdac_eapd_switch[i].id == id)) 3426168404Spjd continue; 3427168404Spjd w = hdac_widget_get(devinfo, hdac_eapd_switch[i].eapdnid); 3428168404Spjd if (w == NULL || w->enable == 0) 3429168404Spjd break; 3430168404Spjd if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX || 3431168404Spjd w->param.eapdbtl == HDAC_INVALID) 3432168404Spjd break; 3433168404Spjd mask |= SOUND_MASK_OGAIN; 3434168404Spjd break; 3435168404Spjd } 3436168404Spjd 3437168404Spjd for (i = devinfo->startnode; i < devinfo->endnode; i++) { 3438209275Smm w = hdac_widget_get(devinfo, i); 3439168404Spjd if (w == NULL || w->enable == 0) 3440208373Smm continue; 3441168404Spjd mask |= w->ctlflags; 3442208373Smm if (!(w->pflags & HDA_ADC_RECSEL)) 3443208373Smm continue; 3444168404Spjd for (j = 0; j < w->nconns; j++) { 3445168404Spjd cw = hdac_widget_get(devinfo, w->conns[j]); 3446209275Smm if (cw == NULL || cw->enable == 0) 3447168404Spjd continue; 3448208373Smm recmask |= cw->ctlflags; 3449208373Smm } 3450168404Spjd } 3451168404Spjd 3452168404Spjd if (!(mask & SOUND_MASK_PCM)) { 3453168404Spjd softpcmvol = 1; 3454168404Spjd mask |= SOUND_MASK_PCM; 3455168404Spjd } else 3456168404Spjd softpcmvol = (devinfo->function.audio.quirks & 3457168404Spjd HDA_QUIRK_SOFTPCMVOL) ? 1 : 0; 3458168404Spjd 3459168404Spjd i = 0; 3460168404Spjd ctl = NULL; 3461168404Spjd while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 3462168404Spjd if (ctl->widget == NULL || ctl->enable == 0) 3463168404Spjd continue; 3464168404Spjd if (!(ctl->ossmask & SOUND_MASK_PCM)) 3465168404Spjd continue; 3466168404Spjd if (ctl->step > 0) 3467168404Spjd break; 3468168404Spjd } 3469272483Ssmh 3470168404Spjd if (softpcmvol == 1 || ctl == NULL) { 3471168404Spjd pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL); 3472168404Spjd HDA_BOOTVERBOSE( 3473168404Spjd device_printf(sc->dev, 3474168404Spjd "HDA_DEBUG: %s Soft PCM volume\n", 3475168404Spjd (softpcmvol == 1) ? 3476168404Spjd "Forcing" : "Enabling"); 3477168404Spjd ); 3478168404Spjd i = 0; 3479168404Spjd /* 3480168404Spjd * XXX Temporary quirk for STAC9220, until the parser 3481168404Spjd * become smarter. 3482168404Spjd */ 3483168404Spjd if (id == HDA_CODEC_STAC9220) { 3484168404Spjd mask |= SOUND_MASK_VOLUME; 3485168404Spjd while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != 3486185029Spjd NULL) { 3487168404Spjd if (ctl->widget == NULL || ctl->enable == 0) 3488185029Spjd continue; 3489185029Spjd if (ctl->widget->nid == 11 && ctl->index == 0) { 3490185029Spjd ctl->ossmask = SOUND_MASK_VOLUME; 3491168404Spjd ctl->ossval = 100 | (100 << 8); 3492168404Spjd } else 3493168404Spjd ctl->ossmask &= ~SOUND_MASK_VOLUME; 3494168404Spjd } 3495168404Spjd } else if (id == HDA_CODEC_STAC9221) { 3496168404Spjd mask |= SOUND_MASK_VOLUME; 3497168404Spjd while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != 3498168404Spjd NULL) { 3499168404Spjd if (ctl->widget == NULL) 3500168404Spjd continue; 3501168404Spjd if (ctl->widget->type == 3502168404Spjd HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT && 3503168404Spjd ctl->index == 0 && (ctl->widget->nid == 2 || 3504168404Spjd ctl->widget->enable != 0)) { 3505168404Spjd ctl->enable = 1; 3506168404Spjd ctl->ossmask = SOUND_MASK_VOLUME; 3507168404Spjd ctl->ossval = 100 | (100 << 8); 3508168404Spjd } else if (ctl->enable == 0) 3509168404Spjd continue; 3510168404Spjd else 3511168404Spjd ctl->ossmask &= ~SOUND_MASK_VOLUME; 3512168404Spjd } 3513168404Spjd } else { 3514168404Spjd mix_setparentchild(m, SOUND_MIXER_VOLUME, 3515168404Spjd SOUND_MASK_PCM); 3516168404Spjd if (!(mask & SOUND_MASK_VOLUME)) 3517168404Spjd mix_setrealdev(m, SOUND_MIXER_VOLUME, 3518168404Spjd SOUND_MIXER_NONE); 3519168404Spjd while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != 3520168404Spjd NULL) { 3521168404Spjd if (ctl->widget == NULL || ctl->enable == 0) 3522168404Spjd continue; 3523286570Smav if (!HDA_FLAG_MATCH(ctl->ossmask, 3524168404Spjd SOUND_MASK_VOLUME | SOUND_MASK_PCM)) 3525286570Smav continue; 3526168404Spjd if (!(ctl->mute == 1 && ctl->step == 0)) 3527168404Spjd ctl->enable = 0; 3528168404Spjd } 3529168404Spjd } 3530168404Spjd } 3531168404Spjd 3532168404Spjd recmask &= ~(SOUND_MASK_PCM | SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER | 3533185029Spjd SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_IGAIN | 3534168404Spjd SOUND_MASK_OGAIN); 3535168404Spjd recmask &= (1 << SOUND_MIXER_NRDEVICES) - 1; 3536286574Smav mask &= (1 << SOUND_MIXER_NRDEVICES) - 1; 3537168404Spjd 3538168404Spjd mix_setrecdevs(m, recmask); 3539168404Spjd mix_setdevs(m, mask); 3540286574Smav 3541168404Spjd hdac_unlock(sc); 3542168404Spjd 3543168404Spjd return (0); 3544168404Spjd} 3545168404Spjd 3546168404Spjdstatic int 3547168404Spjdhdac_audio_ctl_ossmixer_set(struct snd_mixer *m, unsigned dev, 3548168404Spjd unsigned left, unsigned right) 3549168404Spjd{ 3550286570Smav struct hdac_devinfo *devinfo = mix_getdevinfo(m); 3551168404Spjd struct hdac_softc *sc = devinfo->codec->sc; 3552168404Spjd struct hdac_widget *w; 3553168404Spjd struct hdac_audio_ctl *ctl; 3554168404Spjd uint32_t id, mute; 3555168404Spjd int lvol, rvol, mlvol, mrvol; 3556208373Smm int i = 0; 3557185029Spjd 3558168404Spjd hdac_lock(sc); 3559168404Spjd if (dev == SOUND_MIXER_OGAIN) { 3560168404Spjd uint32_t orig; 3561208373Smm /*if (left != right || !(left == 0 || left == 1)) { 3562185029Spjd hdac_unlock(sc); 3563168404Spjd return (-1); 3564209962Smm }*/ 3565168404Spjd id = hdac_codec_id(devinfo); 3566168404Spjd for (i = 0; i < HDAC_EAPD_SWITCH_LEN; i++) { 3567286574Smav if (HDA_DEV_MATCH(hdac_eapd_switch[i].model, 3568168404Spjd sc->pci_subvendor) && 3569168404Spjd hdac_eapd_switch[i].id == id) 3570168404Spjd break; 3571286574Smav } 3572168404Spjd if (i >= HDAC_EAPD_SWITCH_LEN) { 3573168404Spjd hdac_unlock(sc); 3574168404Spjd return (-1); 3575168404Spjd } 3576168404Spjd w = hdac_widget_get(devinfo, hdac_eapd_switch[i].eapdnid); 3577168404Spjd if (w == NULL || 3578168404Spjd w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX || 3579168404Spjd w->param.eapdbtl == HDAC_INVALID) { 3580168404Spjd hdac_unlock(sc); 3581286570Smav return (-1); 3582168404Spjd } 3583168404Spjd orig = w->param.eapdbtl; 3584286570Smav if (left == 0) 3585286570Smav w->param.eapdbtl &= ~HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD; 3586286570Smav else 3587286570Smav w->param.eapdbtl |= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD; 3588286570Smav if (orig != w->param.eapdbtl) { 3589168404Spjd uint32_t val; 3590168404Spjd 3591168404Spjd if (hdac_eapd_switch[i].hp_switch != 0) 3592168404Spjd hdac_hp_switch_handler(devinfo); 3593168404Spjd val = w->param.eapdbtl; 3594286570Smav if (devinfo->function.audio.quirks & HDA_QUIRK_EAPDINV) 3595168404Spjd val ^= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD; 3596168404Spjd hdac_command(sc, 3597168404Spjd HDA_CMD_SET_EAPD_BTL_ENABLE(devinfo->codec->cad, 3598205231Skmacy w->nid, val), devinfo->codec->cad); 3599168404Spjd } 3600168404Spjd hdac_unlock(sc); 3601168404Spjd return (left | (left << 8)); 3602168404Spjd } 3603168404Spjd if (dev == SOUND_MIXER_VOLUME) 3604168404Spjd devinfo->function.audio.mvol = left | (right << 8); 3605168404Spjd 3606275811Sdelphij mlvol = devinfo->function.audio.mvol & 0x7f; 3607168404Spjd mrvol = (devinfo->function.audio.mvol >> 8) & 0x7f; 3608219089Spjd lvol = 0; 3609219089Spjd rvol = 0; 3610168404Spjd 3611286570Smav i = 0; 3612168404Spjd while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 3613286570Smav if (ctl->widget == NULL || ctl->enable == 0 || 3614168404Spjd !(ctl->ossmask & (1 << dev))) 3615168404Spjd continue; 3616168404Spjd switch (dev) { 3617168404Spjd case SOUND_MIXER_VOLUME: 3618168404Spjd lvol = ((ctl->ossval & 0x7f) * left) / 100; 3619168404Spjd lvol = (lvol * ctl->step) / 100; 3620286570Smav rvol = (((ctl->ossval >> 8) & 0x7f) * right) / 100; 3621286570Smav rvol = (rvol * ctl->step) / 100; 3622275811Sdelphij break; 3623275811Sdelphij default: 3624168404Spjd if (ctl->ossmask & SOUND_MASK_VOLUME) { 3625286570Smav lvol = (left * mlvol) / 100; 3626219089Spjd lvol = (lvol * ctl->step) / 100; 3627219089Spjd rvol = (right * mrvol) / 100; 3628168404Spjd rvol = (rvol * ctl->step) / 100; 3629168404Spjd } else { 3630168404Spjd lvol = (left * ctl->step) / 100; 3631168404Spjd rvol = (right * ctl->step) / 100; 3632168404Spjd } 3633168404Spjd ctl->ossval = left | (right << 8); 3634168404Spjd break; 3635168404Spjd } 3636286570Smav mute = 0; 3637286570Smav if (ctl->step < 1) { 3638286570Smav mute |= (left == 0) ? HDA_AMP_MUTE_LEFT : 3639286570Smav (ctl->muted & HDA_AMP_MUTE_LEFT); 3640168404Spjd mute |= (right == 0) ? HDA_AMP_MUTE_RIGHT : 3641275811Sdelphij (ctl->muted & HDA_AMP_MUTE_RIGHT); 3642168404Spjd } else { 3643168404Spjd mute |= (lvol == 0) ? HDA_AMP_MUTE_LEFT : 3644286570Smav (ctl->muted & HDA_AMP_MUTE_LEFT); 3645168404Spjd mute |= (rvol == 0) ? HDA_AMP_MUTE_RIGHT : 3646168404Spjd (ctl->muted & HDA_AMP_MUTE_RIGHT); 3647168404Spjd } 3648168404Spjd hdac_audio_ctl_amp_set(ctl, mute, lvol, rvol); 3649168404Spjd } 3650168404Spjd hdac_unlock(sc); 3651168404Spjd 3652168404Spjd return (left | (right << 8)); 3653286570Smav} 3654168404Spjd 3655168404Spjdstatic int 3656168404Spjdhdac_audio_ctl_ossmixer_setrecsrc(struct snd_mixer *m, uint32_t src) 3657168404Spjd{ 3658168404Spjd struct hdac_devinfo *devinfo = mix_getdevinfo(m); 3659286570Smav struct hdac_widget *w, *cw; 3660275811Sdelphij struct hdac_softc *sc = devinfo->codec->sc; 3661275811Sdelphij uint32_t ret = src, target; 3662168404Spjd int i, j; 3663168404Spjd 3664286570Smav target = 0; 3665168404Spjd for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 3666168404Spjd if (src & (1 << i)) { 3667168404Spjd target = 1 << i; 3668168404Spjd break; 3669168404Spjd } 3670168404Spjd } 3671168404Spjd 3672286570Smav hdac_lock(sc); 3673168404Spjd 3674286570Smav for (i = devinfo->startnode; i < devinfo->endnode; i++) { 3675275811Sdelphij w = hdac_widget_get(devinfo, i); 3676275811Sdelphij if (w == NULL || w->enable == 0) 3677168404Spjd continue; 3678168404Spjd if (!(w->pflags & HDA_ADC_RECSEL)) 3679275811Sdelphij continue; 3680168404Spjd for (j = 0; j < w->nconns; j++) { 3681168404Spjd cw = hdac_widget_get(devinfo, w->conns[j]); 3682286570Smav if (cw == NULL || cw->enable == 0) 3683275811Sdelphij continue; 3684168404Spjd if ((target == SOUND_MASK_VOLUME && 3685168404Spjd cw->type != 3686286570Smav HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) || 3687168404Spjd (target != SOUND_MASK_VOLUME && 3688168404Spjd cw->type == 3689168404Spjd HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)) 3690168404Spjd continue; 3691168404Spjd if (cw->ctlflags & target) { 3692168404Spjd if (!(w->pflags & HDA_ADC_LOCKED)) 3693168404Spjd hdac_widget_connection_select(w, j); 3694168404Spjd ret = target; 3695168404Spjd j += w->nconns; 3696286570Smav } 3697286570Smav } 3698286570Smav } 3699168404Spjd 3700168404Spjd hdac_unlock(sc); 3701286570Smav 3702286570Smav return (ret); 3703168404Spjd} 3704168404Spjd 3705168404Spjdstatic kobj_method_t hdac_audio_ctl_ossmixer_methods[] = { 3706168404Spjd KOBJMETHOD(mixer_init, hdac_audio_ctl_ossmixer_init), 3707168404Spjd KOBJMETHOD(mixer_set, hdac_audio_ctl_ossmixer_set), 3708168404Spjd KOBJMETHOD(mixer_setrecsrc, hdac_audio_ctl_ossmixer_setrecsrc), 3709168404Spjd { 0, 0 } 3710286570Smav}; 3711168404SpjdMIXER_DECLARE(hdac_audio_ctl_ossmixer); 3712168404Spjd 3713168404Spjdstatic void 3714168404Spjdhdac_unsolq_task(void *context, int pending) 3715286570Smav{ 3716168404Spjd struct hdac_softc *sc; 3717168404Spjd 3718168404Spjd sc = (struct hdac_softc *)context; 3719286570Smav 3720275811Sdelphij hdac_lock(sc); 3721275811Sdelphij hdac_unsolq_flush(sc); 3722168404Spjd hdac_unlock(sc); 3723168404Spjd} 3724286570Smav 3725185029Spjd/**************************************************************************** 3726185029Spjd * int hdac_attach(device_t) 3727185029Spjd * 3728185029Spjd * Attach the device into the kernel. Interrupts usually won't be enabled 3729286570Smav * when this function is called. Setup everything that doesn't require 3730275811Sdelphij * interrupts and defer probing of codecs until interrupts are enabled. 3731275811Sdelphij ****************************************************************************/ 3732168404Spjdstatic int 3733168404Spjdhdac_attach(device_t dev) 3734168404Spjd{ 3735168404Spjd struct hdac_softc *sc; 3736168404Spjd int result; 3737168404Spjd int i; 3738168404Spjd uint16_t vendor; 3739168404Spjd uint8_t v; 3740168404Spjd 3741168404Spjd sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 3742219089Spjd sc->lock = snd_mtxcreate(device_get_nameunit(dev), HDAC_MTX_NAME); 3743219089Spjd sc->dev = dev; 3744248571Smm sc->pci_subvendor = (uint32_t)pci_get_subdevice(sc->dev) << 16; 3745168404Spjd sc->pci_subvendor |= (uint32_t)pci_get_subvendor(sc->dev) & 0x0000ffff; 3746168404Spjd vendor = pci_get_vendor(dev); 3747185029Spjd 3748168404Spjd if (sc->pci_subvendor == HP_NX6325_SUBVENDORX) { 3749168404Spjd /* Screw nx6325 - subdevice/subvendor swapped */ 3750168404Spjd sc->pci_subvendor = HP_NX6325_SUBVENDOR; 3751168404Spjd } 3752168404Spjd 3753248571Smm callout_init(&sc->poll_hda, CALLOUT_MPSAFE); 3754168404Spjd callout_init(&sc->poll_hdac, CALLOUT_MPSAFE); 3755168404Spjd callout_init(&sc->poll_jack, CALLOUT_MPSAFE); 3756168404Spjd 3757219089Spjd TASK_INIT(&sc->unsolq_task, 0, hdac_unsolq_task, sc); 3758168404Spjd 3759168404Spjd sc->poll_ticks = 1; 3760168404Spjd sc->poll_ival = HDAC_POLL_INTERVAL; 3761168404Spjd if (resource_int_value(device_get_name(dev), 3762168404Spjd device_get_unit(dev), "polling", &i) == 0 && i != 0) 3763168404Spjd sc->polling = 1; 3764268075Sdelphij else 3765168404Spjd sc->polling = 0; 3766168404Spjd 3767268075Sdelphij sc->chan_size = pcm_getbuffersize(dev, 3768168404Spjd HDA_BUFSZ_MIN, HDA_BUFSZ_DEFAULT, HDA_BUFSZ_MAX); 3769168404Spjd 3770168404Spjd if (resource_int_value(device_get_name(dev), 3771168404Spjd device_get_unit(dev), "blocksize", &i) == 0 && i > 0) { 3772168404Spjd i &= HDA_BLK_ALIGN; 3773168404Spjd if (i < HDA_BLK_MIN) 3774168404Spjd i = HDA_BLK_MIN; 3775168404Spjd sc->chan_blkcnt = sc->chan_size / i; 3776168404Spjd i = 0; 3777168404Spjd while (sc->chan_blkcnt >> i) 3778168404Spjd i++; 3779168404Spjd sc->chan_blkcnt = 1 << (i - 1); 3780168404Spjd if (sc->chan_blkcnt < HDA_BDL_MIN) 3781168404Spjd sc->chan_blkcnt = HDA_BDL_MIN; 3782268075Sdelphij else if (sc->chan_blkcnt > HDA_BDL_MAX) 3783268075Sdelphij sc->chan_blkcnt = HDA_BDL_MAX; 3784268075Sdelphij } else 3785268075Sdelphij sc->chan_blkcnt = HDA_BDL_DEFAULT; 3786268075Sdelphij 3787268075Sdelphij result = bus_dma_tag_create(NULL, /* parent */ 3788168404Spjd HDAC_DMA_ALIGNMENT, /* alignment */ 3789268075Sdelphij 0, /* boundary */ 3790268075Sdelphij BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 3791168404Spjd BUS_SPACE_MAXADDR, /* highaddr */ 3792268075Sdelphij NULL, /* filtfunc */ 3793268075Sdelphij NULL, /* fistfuncarg */ 3794268075Sdelphij sc->chan_size, /* maxsize */ 3795268075Sdelphij 1, /* nsegments */ 3796268075Sdelphij sc->chan_size, /* maxsegsz */ 3797268075Sdelphij 0, /* flags */ 3798268075Sdelphij NULL, /* lockfunc */ 3799275811Sdelphij NULL, /* lockfuncarg */ 3800286570Smav &sc->chan_dmat); /* dmat */ 3801275811Sdelphij if (result != 0) { 3802206796Spjd device_printf(dev, "%s: bus_dma_tag_create failed (%x)\n", 3803168404Spjd __func__, result); 3804286570Smav snd_mtxfree(sc->lock); 3805168404Spjd free(sc, M_DEVBUF); 3806209101Smm return (ENXIO); 3807236884Smm } 3808236884Smm 3809185029Spjd 3810185029Spjd sc->hdabus = NULL; 3811236884Smm for (i = 0; i < HDAC_CODEC_MAX; i++) 3812185029Spjd sc->codecs[i] = NULL; 3813185029Spjd 3814168404Spjd pci_enable_busmaster(dev); 3815185029Spjd 3816240133Smm if (vendor == INTEL_VENDORID) { 3817240133Smm /* TCSEL -> TC0 */ 3818277300Ssmh v = pci_read_config(dev, 0x44, 1); 3819168404Spjd pci_write_config(dev, 0x44, v & 0xf8, 1); 3820286570Smav HDA_BOOTVERBOSE( 3821286570Smav device_printf(dev, "TCSEL: 0x%02d -> 0x%02d\n", v, 3822219089Spjd pci_read_config(dev, 0x44, 1)); 3823219089Spjd ); 3824219089Spjd } 3825219089Spjd 3826219089Spjd#ifdef HDAC_MSI_ENABLED 3827219089Spjd if (resource_int_value(device_get_name(dev), 3828219089Spjd device_get_unit(dev), "msi", &i) == 0 && i != 0 && 3829219089Spjd pci_msi_count(dev) == 1) 3830219089Spjd sc->flags |= HDAC_F_MSI; 3831168404Spjd else 3832168404Spjd#endif 3833168404Spjd sc->flags &= ~HDAC_F_MSI; 3834168404Spjd 3835242845Sdelphij#if defined(__i386__) || defined(__amd64__) 3836242845Sdelphij sc->flags |= HDAC_F_DMA_NOCACHE; 3837168404Spjd 3838242845Sdelphij if (resource_int_value(device_get_name(dev), 3839168404Spjd device_get_unit(dev), "snoop", &i) == 0 && i != 0) { 3840168404Spjd#else 3841168404Spjd sc->flags &= ~HDAC_F_DMA_NOCACHE; 3842168404Spjd#endif 3843286570Smav /* 3844275811Sdelphij * Try to enable PCIe snoop to avoid messing around with 3845168404Spjd * uncacheable DMA attribute. Since PCIe snoop register 3846219089Spjd * config is pretty much vendor specific, there are no 3847219089Spjd * general solutions on how to enable it, forcing us (even 3848286570Smav * Microsoft) to enable uncacheable or write combined DMA 3849275811Sdelphij * by default. 3850219089Spjd * 3851168404Spjd * http://msdn2.microsoft.com/en-us/library/ms790324.aspx 3852286570Smav */ 3853286570Smav for (i = 0; i < HDAC_PCIESNOOP_LEN; i++) { 3854168404Spjd if (hdac_pcie_snoop[i].vendor != vendor) 3855168404Spjd continue; 3856275811Sdelphij sc->flags &= ~HDAC_F_DMA_NOCACHE; 3857286570Smav if (hdac_pcie_snoop[i].reg == 0x00) 3858168404Spjd break; 3859168404Spjd v = pci_read_config(dev, hdac_pcie_snoop[i].reg, 1); 3860168404Spjd if ((v & hdac_pcie_snoop[i].enable) == 3861286570Smav hdac_pcie_snoop[i].enable) 3862168404Spjd break; 3863168404Spjd v &= hdac_pcie_snoop[i].mask; 3864168404Spjd v |= hdac_pcie_snoop[i].enable; 3865168404Spjd pci_write_config(dev, hdac_pcie_snoop[i].reg, v, 1); 3866168404Spjd v = pci_read_config(dev, hdac_pcie_snoop[i].reg, 1); 3867168404Spjd if ((v & hdac_pcie_snoop[i].enable) != 3868168404Spjd hdac_pcie_snoop[i].enable) { 3869286570Smav HDA_BOOTVERBOSE( 3870168404Spjd device_printf(dev, 3871286570Smav "WARNING: Failed to enable PCIe " 3872168404Spjd "snoop!\n"); 3873168404Spjd ); 3874168404Spjd#if defined(__i386__) || defined(__amd64__) 3875168404Spjd sc->flags |= HDAC_F_DMA_NOCACHE; 3876168404Spjd#endif 3877168404Spjd } 3878168404Spjd break; 3879168404Spjd } 3880286570Smav#if defined(__i386__) || defined(__amd64__) 3881286570Smav } 3882168404Spjd#endif 3883168404Spjd 3884168404Spjd HDA_BOOTVERBOSE( 3885168404Spjd device_printf(dev, "DMA Coherency: %s / vendor=0x%04x\n", 3886168404Spjd (sc->flags & HDAC_F_DMA_NOCACHE) ? 3887168404Spjd "Uncacheable" : "PCIe snoop", vendor); 3888168404Spjd ); 3889168404Spjd 3890168404Spjd /* Allocate resources */ 3891168404Spjd result = hdac_mem_alloc(sc); 3892168404Spjd if (result != 0) 3893168404Spjd goto hdac_attach_fail; 3894168404Spjd result = hdac_irq_alloc(sc); 3895168404Spjd if (result != 0) 3896168404Spjd goto hdac_attach_fail; 3897168404Spjd 3898168404Spjd /* Get Capabilities */ 3899168404Spjd result = hdac_get_capabilities(sc); 3900168404Spjd if (result != 0) 3901168404Spjd goto hdac_attach_fail; 3902168404Spjd 3903168404Spjd /* Allocate CORB and RIRB dma memory */ 3904168404Spjd result = hdac_dma_alloc(sc, &sc->corb_dma, 3905168404Spjd sc->corb_size * sizeof(uint32_t)); 3906168404Spjd if (result != 0) 3907168404Spjd goto hdac_attach_fail; 3908168404Spjd result = hdac_dma_alloc(sc, &sc->rirb_dma, 3909168404Spjd sc->rirb_size * sizeof(struct hdac_rirb)); 3910168404Spjd if (result != 0) 3911168404Spjd goto hdac_attach_fail; 3912168404Spjd 3913168404Spjd /* Quiesce everything */ 3914168404Spjd hdac_reset(sc); 3915168404Spjd 3916168404Spjd /* Initialize the CORB and RIRB */ 3917168404Spjd hdac_corb_init(sc); 3918168404Spjd hdac_rirb_init(sc); 3919168404Spjd 3920168404Spjd /* Defer remaining of initialization until interrupts are enabled */ 3921246666Smm sc->intrhook.ich_func = hdac_attach2; 3922275811Sdelphij sc->intrhook.ich_arg = (void *)sc; 3923275811Sdelphij if (cold == 0 || config_intrhook_establish(&sc->intrhook) != 0) { 3924168404Spjd sc->intrhook.ich_func = NULL; 3925268075Sdelphij hdac_attach2((void *)sc); 3926247187Smm } 3927268075Sdelphij 3928185029Spjd return (0); 3929228103Smm 3930168404Spjdhdac_attach_fail: 3931268075Sdelphij hdac_irq_free(sc); 3932268075Sdelphij hdac_dma_free(sc, &sc->rirb_dma); 3933268075Sdelphij hdac_dma_free(sc, &sc->corb_dma); 3934168404Spjd hdac_mem_free(sc); 3935268075Sdelphij snd_mtxfree(sc->lock); 3936268075Sdelphij free(sc, M_DEVBUF); 3937268075Sdelphij 3938268075Sdelphij return (ENXIO); 3939268075Sdelphij} 3940268075Sdelphij 3941268075Sdelphijstatic void 3942168404Spjdhdac_audio_parse(struct hdac_devinfo *devinfo) 3943286570Smav{ 3944268075Sdelphij struct hdac_softc *sc = devinfo->codec->sc; 3945275811Sdelphij struct hdac_widget *w; 3946168404Spjd uint32_t res; 3947168404Spjd int i; 3948168404Spjd nid_t cad, nid; 3949275811Sdelphij 3950286570Smav cad = devinfo->codec->cad; 3951168404Spjd nid = devinfo->nid; 3952168404Spjd 3953168404Spjd hdac_command(sc, 3954275811Sdelphij HDA_CMD_SET_POWER_STATE(cad, nid, HDA_CMD_POWER_STATE_D0), cad); 3955168404Spjd 3956168404Spjd DELAY(100); 3957168404Spjd 3958168404Spjd res = hdac_command(sc, 3959168404Spjd HDA_CMD_GET_PARAMETER(cad , nid, HDA_PARAM_SUB_NODE_COUNT), cad); 3960168404Spjd 3961168404Spjd devinfo->nodecnt = HDA_PARAM_SUB_NODE_COUNT_TOTAL(res); 3962168404Spjd devinfo->startnode = HDA_PARAM_SUB_NODE_COUNT_START(res); 3963168404Spjd devinfo->endnode = devinfo->startnode + devinfo->nodecnt; 3964168404Spjd 3965209962Smm res = hdac_command(sc, 3966168404Spjd HDA_CMD_GET_PARAMETER(cad , nid, HDA_PARAM_GPIO_COUNT), cad); 3967168404Spjd devinfo->function.audio.gpio = res; 3968286570Smav 3969286570Smav HDA_BOOTVERBOSE( 3970168404Spjd device_printf(sc->dev, " Vendor: 0x%08x\n", 3971168404Spjd devinfo->vendor_id); 3972168404Spjd device_printf(sc->dev, " Device: 0x%08x\n", 3973168404Spjd devinfo->device_id); 3974168404Spjd device_printf(sc->dev, " Revision: 0x%08x\n", 3975168404Spjd devinfo->revision_id); 3976168404Spjd device_printf(sc->dev, " Stepping: 0x%08x\n", 3977168404Spjd devinfo->stepping_id); 3978286570Smav device_printf(sc->dev, "PCI Subvendor: 0x%08x\n", 3979286570Smav sc->pci_subvendor); 3980168404Spjd device_printf(sc->dev, " Nodes: start=%d " 3981168404Spjd "endnode=%d total=%d\n", 3982168404Spjd devinfo->startnode, devinfo->endnode, devinfo->nodecnt); 3983168404Spjd device_printf(sc->dev, " CORB size: %d\n", sc->corb_size); 3984168404Spjd device_printf(sc->dev, " RIRB size: %d\n", sc->rirb_size); 3985168404Spjd device_printf(sc->dev, " Streams: ISS=%d OSS=%d BSS=%d\n", 3986168404Spjd sc->num_iss, sc->num_oss, sc->num_bss); 3987168404Spjd device_printf(sc->dev, " GPIO: 0x%08x\n", 3988286570Smav devinfo->function.audio.gpio); 3989168404Spjd device_printf(sc->dev, " NumGPIO=%d NumGPO=%d " 3990168404Spjd "NumGPI=%d GPIWake=%d GPIUnsol=%d\n", 3991168404Spjd HDA_PARAM_GPIO_COUNT_NUM_GPIO(devinfo->function.audio.gpio), 3992168404Spjd HDA_PARAM_GPIO_COUNT_NUM_GPO(devinfo->function.audio.gpio), 3993275811Sdelphij HDA_PARAM_GPIO_COUNT_NUM_GPI(devinfo->function.audio.gpio), 3994168404Spjd HDA_PARAM_GPIO_COUNT_GPI_WAKE(devinfo->function.audio.gpio), 3995168404Spjd HDA_PARAM_GPIO_COUNT_GPI_UNSOL(devinfo->function.audio.gpio)); 3996168404Spjd ); 3997219089Spjd 3998275811Sdelphij res = hdac_command(sc, 3999286570Smav HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_SUPP_STREAM_FORMATS), 4000275811Sdelphij cad); 4001168404Spjd devinfo->function.audio.supp_stream_formats = res; 4002168404Spjd 4003168404Spjd res = hdac_command(sc, 4004275811Sdelphij HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_SUPP_PCM_SIZE_RATE), 4005275811Sdelphij cad); 4006275811Sdelphij devinfo->function.audio.supp_pcm_size_rate = res; 4007275811Sdelphij 4008168404Spjd res = hdac_command(sc, 4009168404Spjd HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_OUTPUT_AMP_CAP), 4010286570Smav cad); 4011286570Smav devinfo->function.audio.outamp_cap = res; 4012168404Spjd 4013168404Spjd res = hdac_command(sc, 4014168404Spjd HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_INPUT_AMP_CAP), 4015168404Spjd cad); 4016168404Spjd devinfo->function.audio.inamp_cap = res; 4017168404Spjd 4018268075Sdelphij if (devinfo->nodecnt > 0) 4019185029Spjd devinfo->widget = (struct hdac_widget *)malloc( 4020247187Smm sizeof(*(devinfo->widget)) * devinfo->nodecnt, M_HDAC, 4021208373Smm M_NOWAIT | M_ZERO); 4022258389Savg else 4023286570Smav devinfo->widget = NULL; 4024168404Spjd 4025168404Spjd if (devinfo->widget == NULL) { 4026168404Spjd device_printf(sc->dev, "unable to allocate widgets!\n"); 4027268075Sdelphij devinfo->endnode = devinfo->startnode; 4028168404Spjd devinfo->nodecnt = 0; 4029168404Spjd return; 4030168404Spjd } 4031268075Sdelphij 4032268075Sdelphij for (i = devinfo->startnode; i < devinfo->endnode; i++) { 4033268075Sdelphij w = hdac_widget_get(devinfo, i); 4034268075Sdelphij if (w == NULL) 4035268075Sdelphij device_printf(sc->dev, "Ghost widget! nid=%d!\n", i); 4036268075Sdelphij else { 4037168404Spjd w->devinfo = devinfo; 4038168404Spjd w->nid = i; 4039219089Spjd w->enable = 1; 4040168404Spjd w->selconn = -1; 4041168404Spjd w->pflags = 0; 4042168404Spjd w->ctlflags = 0; 4043275811Sdelphij w->param.eapdbtl = HDAC_INVALID; 4044168404Spjd hdac_widget_parse(w); 4045275811Sdelphij } 4046168404Spjd } 4047168404Spjd} 4048275811Sdelphij 4049168404Spjdstatic void 4050275811Sdelphijhdac_audio_ctl_parse(struct hdac_devinfo *devinfo) 4051275811Sdelphij{ 4052275811Sdelphij struct hdac_softc *sc = devinfo->codec->sc; 4053275811Sdelphij struct hdac_audio_ctl *ctls; 4054168404Spjd struct hdac_widget *w, *cw; 4055275811Sdelphij int i, j, cnt, max, ocap, icap; 4056168404Spjd int mute, offset, step, size; 4057286570Smav 4058286570Smav /* XXX This is redundant */ 4059286570Smav max = 0; 4060286570Smav for (i = devinfo->startnode; i < devinfo->endnode; i++) { 4061286570Smav w = hdac_widget_get(devinfo, i); 4062286570Smav if (w == NULL || w->enable == 0) 4063286570Smav continue; 4064286570Smav if (w->param.outamp_cap != 0) 4065286570Smav max++; 4066286570Smav if (w->param.inamp_cap != 0) { 4067286570Smav switch (w->type) { 4068168404Spjd case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR: 4069286570Smav case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER: 4070286570Smav for (j = 0; j < w->nconns; j++) { 4071168404Spjd cw = hdac_widget_get(devinfo, 4072168404Spjd w->conns[j]); 4073275811Sdelphij if (cw == NULL || cw->enable == 0) 4074275811Sdelphij continue; 4075168404Spjd max++; 4076168404Spjd } 4077275811Sdelphij break; 4078275811Sdelphij default: 4079275811Sdelphij max++; 4080275811Sdelphij break; 4081185029Spjd } 4082168404Spjd } 4083168404Spjd } 4084168404Spjd 4085168404Spjd devinfo->function.audio.ctlcnt = max; 4086168404Spjd 4087286570Smav if (max < 1) 4088286570Smav return; 4089286570Smav 4090219089Spjd ctls = (struct hdac_audio_ctl *)malloc( 4091219089Spjd sizeof(*ctls) * max, M_HDAC, M_ZERO | M_NOWAIT); 4092168404Spjd 4093168404Spjd if (ctls == NULL) { 4094286570Smav /* Blekh! */ 4095219089Spjd device_printf(sc->dev, "unable to allocate ctls!\n"); 4096168404Spjd devinfo->function.audio.ctlcnt = 0; 4097168404Spjd return; 4098168404Spjd } 4099168404Spjd 4100286570Smav cnt = 0; 4101286570Smav for (i = devinfo->startnode; cnt < max && i < devinfo->endnode; i++) { 4102275811Sdelphij if (cnt >= max) { 4103168404Spjd device_printf(sc->dev, "%s: Ctl overflow!\n", 4104286570Smav __func__); 4105286570Smav break; 4106286570Smav } 4107286570Smav w = hdac_widget_get(devinfo, i); 4108286570Smav if (w == NULL || w->enable == 0) 4109286570Smav continue; 4110185029Spjd ocap = w->param.outamp_cap; 4111185029Spjd icap = w->param.inamp_cap; 4112185029Spjd if (ocap != 0) { 4113185029Spjd mute = HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(ocap); 4114185029Spjd step = HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(ocap); 4115185029Spjd size = HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(ocap); 4116185029Spjd offset = HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(ocap); 4117185029Spjd /*if (offset > step) { 4118268075Sdelphij HDA_BOOTVERBOSE( 4119268075Sdelphij device_printf(sc->dev, 4120168404Spjd "HDA_DEBUG: BUGGY outamp: nid=%d " 4121251629Sdelphij "[offset=%d > step=%d]\n", 4122251629Sdelphij w->nid, offset, step); 4123251629Sdelphij ); 4124251629Sdelphij offset = step; 4125168404Spjd }*/ 4126219089Spjd ctls[cnt].enable = 1; 4127268123Sdelphij ctls[cnt].widget = w; 4128168404Spjd ctls[cnt].mute = mute; 4129286570Smav ctls[cnt].step = step; 4130286570Smav ctls[cnt].size = size; 4131168404Spjd ctls[cnt].offset = offset; 4132228392Spjd ctls[cnt].left = offset; 4133228392Spjd ctls[cnt].right = offset; 4134228392Spjd ctls[cnt++].dir = HDA_CTL_OUT; 4135168404Spjd } 4136208373Smm 4137185029Spjd if (icap != 0) { 4138185029Spjd mute = HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(icap); 4139185029Spjd step = HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(icap); 4140185029Spjd size = HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(icap); 4141185029Spjd offset = HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(icap); 4142185029Spjd /*if (offset > step) { 4143185029Spjd HDA_BOOTVERBOSE( 4144208373Smm device_printf(sc->dev, 4145185029Spjd "HDA_DEBUG: BUGGY inamp: nid=%d " 4146286570Smav "[offset=%d > step=%d]\n", 4147208373Smm w->nid, offset, step); 4148208373Smm ); 4149185029Spjd offset = step; 4150185029Spjd }*/ 4151185029Spjd switch (w->type) { 4152185029Spjd case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR: 4153185029Spjd case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER: 4154185029Spjd for (j = 0; j < w->nconns; j++) { 4155185029Spjd if (cnt >= max) { 4156185029Spjd device_printf(sc->dev, 4157185029Spjd "%s: Ctl overflow!\n", 4158185029Spjd __func__); 4159185029Spjd break; 4160185029Spjd } 4161258389Savg cw = hdac_widget_get(devinfo, 4162185029Spjd w->conns[j]); 4163247187Smm if (cw == NULL || cw->enable == 0) 4164247187Smm continue; 4165247187Smm ctls[cnt].enable = 1; 4166247187Smm ctls[cnt].widget = w; 4167185029Spjd ctls[cnt].childwidget = cw; 4168185029Spjd ctls[cnt].index = j; 4169185029Spjd ctls[cnt].mute = mute; 4170251478Sdelphij ctls[cnt].step = step; 4171251478Sdelphij ctls[cnt].size = size; 4172185029Spjd ctls[cnt].offset = offset; 4173258389Savg ctls[cnt].left = offset; 4174251478Sdelphij ctls[cnt].right = offset; 4175251478Sdelphij ctls[cnt++].dir = HDA_CTL_IN; 4176251478Sdelphij } 4177251478Sdelphij break; 4178251478Sdelphij default: 4179251478Sdelphij if (cnt >= max) { 4180251478Sdelphij device_printf(sc->dev, 4181251478Sdelphij "%s: Ctl overflow!\n", 4182258389Savg __func__); 4183258389Savg break; 4184251478Sdelphij } 4185251478Sdelphij ctls[cnt].enable = 1; 4186251478Sdelphij ctls[cnt].widget = w; 4187251478Sdelphij ctls[cnt].mute = mute; 4188251478Sdelphij ctls[cnt].step = step; 4189251478Sdelphij ctls[cnt].size = size; 4190185029Spjd ctls[cnt].offset = offset; 4191185029Spjd ctls[cnt].left = offset; 4192258389Savg ctls[cnt].right = offset; 4193185029Spjd ctls[cnt++].dir = HDA_CTL_IN; 4194275811Sdelphij break; 4195185029Spjd } 4196185029Spjd } 4197185029Spjd } 4198185029Spjd 4199275811Sdelphij devinfo->function.audio.ctl = ctls; 4200185029Spjd} 4201185029Spjd 4202185029Spjdstatic const struct { 4203185029Spjd uint32_t model; 4204185029Spjd uint32_t id; 4205185029Spjd uint32_t set, unset; 4206185029Spjd} hdac_quirks[] = { 4207185029Spjd /* 4208185029Spjd * XXX Force stereo quirk. Monoural recording / playback 4209185029Spjd * on few codecs (especially ALC880) seems broken or 4210185029Spjd * perhaps unsupported. 4211185029Spjd */ 4212208373Smm { HDA_MATCH_ALL, HDA_MATCH_ALL, 4213208373Smm HDA_QUIRK_FORCESTEREO | HDA_QUIRK_IVREF, 0 }, 4214208373Smm { ACER_ALL_SUBVENDOR, HDA_MATCH_ALL, 4215208373Smm HDA_QUIRK_GPIO0, 0 }, 4216208373Smm { ASUS_G2K_SUBVENDOR, HDA_CODEC_ALC660, 4217208373Smm HDA_QUIRK_GPIO0, 0 }, 4218208373Smm { ASUS_M5200_SUBVENDOR, HDA_CODEC_ALC880, 4219208373Smm HDA_QUIRK_GPIO0, 0 }, 4220185029Spjd { ASUS_A7M_SUBVENDOR, HDA_CODEC_ALC880, 4221185029Spjd HDA_QUIRK_GPIO0, 0 }, 4222168404Spjd { ASUS_A7T_SUBVENDOR, HDA_CODEC_ALC882, 4223185029Spjd HDA_QUIRK_GPIO0, 0 }, 4224168404Spjd { ASUS_W2J_SUBVENDOR, HDA_CODEC_ALC882, 4225275811Sdelphij HDA_QUIRK_GPIO0, 0 }, 4226168404Spjd { ASUS_U5F_SUBVENDOR, HDA_CODEC_AD1986A, 4227168404Spjd HDA_QUIRK_EAPDINV, 0 }, 4228275811Sdelphij { ASUS_A8X_SUBVENDOR, HDA_CODEC_AD1986A, 4229168404Spjd HDA_QUIRK_EAPDINV, 0 }, 4230168404Spjd { ASUS_F3JC_SUBVENDOR, HDA_CODEC_ALC861, 4231168404Spjd HDA_QUIRK_OVREF, 0 }, 4232168404Spjd { ASUS_W6F_SUBVENDOR, HDA_CODEC_ALC861, 4233168404Spjd HDA_QUIRK_OVREF, 0 }, 4234168404Spjd { UNIWILL_9075_SUBVENDOR, HDA_CODEC_ALC861, 4235168404Spjd HDA_QUIRK_OVREF, 0 }, 4236168404Spjd /*{ ASUS_M2N_SUBVENDOR, HDA_CODEC_AD1988, 4237168404Spjd HDA_QUIRK_IVREF80, HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF100 },*/ 4238286570Smav { MEDION_MD95257_SUBVENDOR, HDA_CODEC_ALC880, 4239286570Smav HDA_QUIRK_GPIO1, 0 }, 4240286570Smav { LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A, 4241219089Spjd HDA_QUIRK_EAPDINV, 0 }, 4242219089Spjd { SAMSUNG_Q1_SUBVENDOR, HDA_CODEC_AD1986A, 4243219089Spjd HDA_QUIRK_EAPDINV, 0 }, 4244168404Spjd { APPLE_MB3_SUBVENDOR, HDA_CODEC_ALC885, 4245168404Spjd HDA_QUIRK_GPIO0 | HDA_QUIRK_OVREF50, 0}, 4246168404Spjd { APPLE_INTEL_MAC, HDA_CODEC_STAC9221, 4247168404Spjd HDA_QUIRK_GPIO0 | HDA_QUIRK_GPIO1, 0 }, 4248168404Spjd { DELL_V1500_SUBVENDOR, HDA_CODEC_STAC9205, 4249251520Sdelphij HDA_QUIRK_GPIO0, 0 }, 4250251520Sdelphij { HDA_MATCH_ALL, HDA_CODEC_AD1988, 4251251520Sdelphij HDA_QUIRK_IVREF80, HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF100 }, 4252251520Sdelphij { HDA_MATCH_ALL, HDA_CODEC_AD1988B, 4253251520Sdelphij HDA_QUIRK_IVREF80, HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF100 }, 4254251520Sdelphij { HDA_MATCH_ALL, HDA_CODEC_CXVENICE, 4255251520Sdelphij 0, HDA_QUIRK_FORCESTEREO }, 4256251520Sdelphij { HDA_MATCH_ALL, HDA_CODEC_STACXXXX, 4257251520Sdelphij HDA_QUIRK_SOFTPCMVOL, 0 } 4258268075Sdelphij}; 4259268075Sdelphij#define HDAC_QUIRKS_LEN (sizeof(hdac_quirks) / sizeof(hdac_quirks[0])) 4260268075Sdelphij 4261251520Sdelphijstatic void 4262251520Sdelphijhdac_vendor_patch_parse(struct hdac_devinfo *devinfo) 4263251520Sdelphij{ 4264286570Smav struct hdac_widget *w; 4265251520Sdelphij struct hdac_audio_ctl *ctl; 4266275811Sdelphij uint32_t id, subvendor; 4267251520Sdelphij int i; 4268251520Sdelphij 4269251520Sdelphij id = hdac_codec_id(devinfo); 4270251520Sdelphij subvendor = devinfo->codec->sc->pci_subvendor; 4271251520Sdelphij 4272251520Sdelphij /* 4273251520Sdelphij * Quirks 4274251520Sdelphij */ 4275251520Sdelphij for (i = 0; i < HDAC_QUIRKS_LEN; i++) { 4276251520Sdelphij if (!(HDA_DEV_MATCH(hdac_quirks[i].model, subvendor) && 4277251520Sdelphij HDA_DEV_MATCH(hdac_quirks[i].id, id))) 4278268858Sdelphij continue; 4279268858Sdelphij if (hdac_quirks[i].set != 0) 4280268858Sdelphij devinfo->function.audio.quirks |= 4281268858Sdelphij hdac_quirks[i].set; 4282268858Sdelphij if (hdac_quirks[i].unset != 0) 4283268858Sdelphij devinfo->function.audio.quirks &= 4284268858Sdelphij ~(hdac_quirks[i].unset); 4285268858Sdelphij } 4286268858Sdelphij 4287268858Sdelphij switch (id) { 4288268858Sdelphij case HDA_CODEC_ALC260: 4289168404Spjd for (i = devinfo->startnode; i < devinfo->endnode; i++) { 4290268858Sdelphij w = hdac_widget_get(devinfo, i); 4291268858Sdelphij if (w == NULL || w->enable == 0) 4292168404Spjd continue; 4293168404Spjd if (w->type != 4294168404Spjd HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) 4295268858Sdelphij continue; 4296268858Sdelphij if (w->nid != 5) 4297205231Skmacy w->enable = 0; 4298205231Skmacy } 4299206796Spjd if (subvendor == HP_XW4300_SUBVENDOR) { 4300219089Spjd ctl = hdac_audio_ctl_amp_get(devinfo, 16, 0, 1); 4301168404Spjd if (ctl != NULL && ctl->widget != NULL) { 4302168404Spjd ctl->ossmask = SOUND_MASK_SPEAKER; 4303168404Spjd ctl->widget->ctlflags |= SOUND_MASK_SPEAKER; 4304168404Spjd } 4305168404Spjd ctl = hdac_audio_ctl_amp_get(devinfo, 17, 0, 1); 4306168404Spjd if (ctl != NULL && ctl->widget != NULL) { 4307219089Spjd ctl->ossmask = SOUND_MASK_SPEAKER; 4308268858Sdelphij ctl->widget->ctlflags |= SOUND_MASK_SPEAKER; 4309185029Spjd } 4310185029Spjd } else if (subvendor == HP_3010_SUBVENDOR) { 4311185029Spjd ctl = hdac_audio_ctl_amp_get(devinfo, 17, 0, 1); 4312185029Spjd if (ctl != NULL && ctl->widget != NULL) { 4313185029Spjd ctl->ossmask = SOUND_MASK_SPEAKER; 4314185029Spjd ctl->widget->ctlflags |= SOUND_MASK_SPEAKER; 4315219089Spjd } 4316268858Sdelphij ctl = hdac_audio_ctl_amp_get(devinfo, 21, 0, 1); 4317268858Sdelphij if (ctl != NULL && ctl->widget != NULL) { 4318168404Spjd ctl->ossmask = SOUND_MASK_SPEAKER; 4319168404Spjd ctl->widget->ctlflags |= SOUND_MASK_SPEAKER; 4320168404Spjd } 4321219089Spjd } 4322219089Spjd break; 4323168404Spjd case HDA_CODEC_ALC262: 4324286570Smav if (subvendor == HP_DC7700S_SUBVENDOR) { 4325286570Smav ctl = hdac_audio_ctl_amp_get(devinfo, 21, 0, 1); 4326286570Smav if (ctl != NULL && ctl->widget != NULL) { 4327286570Smav ctl->ossmask = SOUND_MASK_PHONEOUT; 4328168404Spjd ctl->widget->ctlflags |= SOUND_MASK_PHONEOUT; 4329268858Sdelphij } 4330268858Sdelphij ctl = hdac_audio_ctl_amp_get(devinfo, 22, 0, 1); 4331168404Spjd if (ctl != NULL && ctl->widget != NULL) { 4332286570Smav ctl->ossmask = SOUND_MASK_SPEAKER; 4333268858Sdelphij ctl->widget->ctlflags |= SOUND_MASK_SPEAKER; 4334268858Sdelphij } 4335268858Sdelphij } else if (subvendor == HP_DC7700_SUBVENDOR) { 4336286570Smav ctl = hdac_audio_ctl_amp_get(devinfo, 22, 0, 1); 4337275811Sdelphij if (ctl != NULL && ctl->widget != NULL) { 4338268858Sdelphij ctl->ossmask = SOUND_MASK_SPEAKER; 4339268858Sdelphij ctl->widget->ctlflags |= SOUND_MASK_SPEAKER; 4340168404Spjd } 4341168404Spjd ctl = hdac_audio_ctl_amp_get(devinfo, 27, 0, 1); 4342268858Sdelphij if (ctl != NULL && ctl->widget != NULL) { 4343268858Sdelphij ctl->ossmask = SOUND_MASK_SPEAKER; 4344168404Spjd ctl->widget->ctlflags |= SOUND_MASK_SPEAKER; 4345168404Spjd } 4346168404Spjd } 4347251629Sdelphij break; 4348251629Sdelphij case HDA_CODEC_ALC268: 4349168404Spjd if (HDA_DEV_MATCH(ACER_ALL_SUBVENDOR, subvendor)) { 4350185029Spjd w = hdac_widget_get(devinfo, 29); 4351168404Spjd if (w != NULL) { 4352168404Spjd w->enable = 1; 4353168404Spjd w->type = 4354168404Spjd HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET; 4355286570Smav w->param.widget_cap &= 4356168404Spjd ~HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK; 4357219089Spjd w->param.widget_cap |= 4358219089Spjd HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET << 4359219089Spjd HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT; 4360219089Spjd strlcpy(w->name, "beep widget", sizeof(w->name)); 4361219089Spjd } 4362219089Spjd } 4363219089Spjd break; 4364286570Smav case HDA_CODEC_ALC861: 4365286570Smav ctl = hdac_audio_ctl_amp_get(devinfo, 21, 2, 1); 4366286570Smav if (ctl != NULL) 4367286570Smav ctl->muted = HDA_AMP_MUTE_ALL; 4368286570Smav break; 4369286570Smav case HDA_CODEC_ALC880: 4370286570Smav for (i = devinfo->startnode; i < devinfo->endnode; i++) { 4371286570Smav w = hdac_widget_get(devinfo, i); 4372286570Smav if (w == NULL || w->enable == 0) 4373286570Smav continue; 4374286570Smav if (w->type == 4375286570Smav HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT && 4376286570Smav w->nid != 9 && w->nid != 29) { 4377286570Smav w->enable = 0; 4378185029Spjd } else if (w->type != 4379286570Smav HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET && 4380286570Smav w->nid == 29) { 4381168404Spjd w->type = 4382286570Smav HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET; 4383286570Smav w->param.widget_cap &= 4384286570Smav ~HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK; 4385286570Smav w->param.widget_cap |= 4386168404Spjd HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET << 4387168404Spjd HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT; 4388286570Smav strlcpy(w->name, "beep widget", sizeof(w->name)); 4389286570Smav } 4390286570Smav } 4391286570Smav break; 4392286570Smav case HDA_CODEC_ALC883: 4393286570Smav /* 4394286570Smav * nid: 24/25 = External (jack) or Internal (fixed) Mic. 4395286570Smav * Clear vref cap for jack connectivity. 4396286570Smav */ 4397286570Smav w = hdac_widget_get(devinfo, 24); 4398286570Smav if (w != NULL && w->enable != 0 && w->type == 4399286570Smav HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX && 4400286570Smav (w->wclass.pin.config & 4401286570Smav HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) == 4402286570Smav HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK) 4403286570Smav w->wclass.pin.cap &= ~( 4404286570Smav HDA_PARAM_PIN_CAP_VREF_CTRL_100_MASK | 4405286570Smav HDA_PARAM_PIN_CAP_VREF_CTRL_80_MASK | 4406286570Smav HDA_PARAM_PIN_CAP_VREF_CTRL_50_MASK); 4407286598Smav w = hdac_widget_get(devinfo, 25); 4408286598Smav if (w != NULL && w->enable != 0 && w->type == 4409286598Smav HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX && 4410286598Smav (w->wclass.pin.config & 4411286598Smav HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) == 4412286598Smav HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK) 4413286570Smav w->wclass.pin.cap &= ~( 4414286598Smav HDA_PARAM_PIN_CAP_VREF_CTRL_100_MASK | 4415286598Smav HDA_PARAM_PIN_CAP_VREF_CTRL_80_MASK | 4416286598Smav HDA_PARAM_PIN_CAP_VREF_CTRL_50_MASK); 4417286598Smav /* 4418286598Smav * nid: 26 = Line-in, leave it alone. 4419286570Smav */ 4420286570Smav break; 4421185029Spjd case HDA_CODEC_AD1981HD: 4422185029Spjd w = hdac_widget_get(devinfo, 11); 4423168404Spjd if (w != NULL && w->enable != 0 && w->nconns > 3) 4424168404Spjd w->selconn = 3; 4425168404Spjd if (subvendor == IBM_M52_SUBVENDOR) { 4426286570Smav ctl = hdac_audio_ctl_amp_get(devinfo, 7, 0, 1); 4427168404Spjd if (ctl != NULL) 4428168404Spjd ctl->ossmask = SOUND_MASK_SPEAKER; 4429168404Spjd } 4430209962Smm break; 4431286570Smav case HDA_CODEC_AD1986A: 4432185029Spjd for (i = devinfo->startnode; i < devinfo->endnode; i++) { 4433168404Spjd w = hdac_widget_get(devinfo, i); 4434286570Smav if (w == NULL || w->enable == 0) 4435168404Spjd continue; 4436219089Spjd if (w->type != 4437219089Spjd HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT) 4438168404Spjd continue; 4439168404Spjd if (w->nid != 3) 4440286570Smav w->enable = 0; 4441168404Spjd } 4442168404Spjd if (subvendor == ASUS_M2NPVMX_SUBVENDOR || 4443219089Spjd subvendor == ASUS_A8NVMCSM_SUBVENDOR) { 4444168404Spjd /* nid 28 is mic, nid 29 is line-in */ 4445168404Spjd w = hdac_widget_get(devinfo, 15); 4446286570Smav if (w != NULL) 4447286570Smav w->selconn = 2; 4448286570Smav w = hdac_widget_get(devinfo, 16); 4449286570Smav if (w != NULL) 4450286570Smav w->selconn = 1; 4451286570Smav } else if (subvendor == ASUS_A8X_SUBVENDOR) { 4452185029Spjd /* 4453185029Spjd * This is just plain ridiculous.. There 4454168404Spjd * are several A8 series that share the same 4455242845Sdelphij * pci id but works differently (EAPD). 4456242845Sdelphij */ 4457242845Sdelphij w = hdac_widget_get(devinfo, 26); 4458242845Sdelphij if (w != NULL && w->type == 4459242845Sdelphij HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX && 4460286570Smav (w->wclass.pin.config & 4461242845Sdelphij HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) != 4462242845Sdelphij HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE) 4463242845Sdelphij devinfo->function.audio.quirks &= 4464242845Sdelphij ~HDA_QUIRK_EAPDINV; 4465286570Smav } 4466168404Spjd break; 4467240133Smm case HDA_CODEC_AD1988: 4468240133Smm case HDA_CODEC_AD1988B: 4469277300Ssmh /*w = hdac_widget_get(devinfo, 12); 4470168404Spjd if (w != NULL) { 4471168404Spjd w->selconn = 1; 4472168404Spjd w->pflags |= HDA_ADC_LOCKED; 4473286570Smav } 4474168404Spjd w = hdac_widget_get(devinfo, 13); 4475168404Spjd if (w != NULL) { 4476286570Smav w->selconn = 4; 4477275811Sdelphij w->pflags |= HDA_ADC_LOCKED; 4478286570Smav } 4479286570Smav w = hdac_widget_get(devinfo, 14); 4480286570Smav if (w != NULL) { 4481286570Smav w->selconn = 2; 4482286570Smav w->pflags |= HDA_ADC_LOCKED; 4483286570Smav }*/ 4484286570Smav ctl = hdac_audio_ctl_amp_get(devinfo, 57, 0, 1); 4485168404Spjd if (ctl != NULL) { 4486286570Smav ctl->ossmask = SOUND_MASK_IGAIN; 4487286570Smav ctl->widget->ctlflags |= SOUND_MASK_IGAIN; 4488168404Spjd } 4489219089Spjd ctl = hdac_audio_ctl_amp_get(devinfo, 58, 0, 1); 4490168404Spjd if (ctl != NULL) { 4491168404Spjd ctl->ossmask = SOUND_MASK_IGAIN; 4492219089Spjd ctl->widget->ctlflags |= SOUND_MASK_IGAIN; 4493286570Smav } 4494286570Smav ctl = hdac_audio_ctl_amp_get(devinfo, 60, 0, 1); 4495286570Smav if (ctl != NULL) { 4496168404Spjd ctl->ossmask = SOUND_MASK_IGAIN; 4497286570Smav ctl->widget->ctlflags |= SOUND_MASK_IGAIN; 4498286570Smav } 4499286570Smav ctl = hdac_audio_ctl_amp_get(devinfo, 32, 0, 1); 4500185029Spjd if (ctl != NULL) { 4501219089Spjd ctl->ossmask = SOUND_MASK_MIC | SOUND_MASK_VOLUME; 4502168404Spjd ctl->widget->ctlflags |= SOUND_MASK_MIC; 4503168404Spjd } 4504168404Spjd ctl = hdac_audio_ctl_amp_get(devinfo, 32, 4, 1); 4505168404Spjd if (ctl != NULL) { 4506168404Spjd ctl->ossmask = SOUND_MASK_MIC | SOUND_MASK_VOLUME; 4507168404Spjd ctl->widget->ctlflags |= SOUND_MASK_MIC; 4508168404Spjd } 4509168404Spjd ctl = hdac_audio_ctl_amp_get(devinfo, 32, 1, 1); 4510168404Spjd if (ctl != NULL) { 4511185029Spjd ctl->ossmask = SOUND_MASK_LINE | SOUND_MASK_VOLUME; 4512185029Spjd ctl->widget->ctlflags |= SOUND_MASK_LINE; 4513219089Spjd } 4514286570Smav ctl = hdac_audio_ctl_amp_get(devinfo, 32, 7, 1); 4515286570Smav if (ctl != NULL) { 4516219089Spjd ctl->ossmask = SOUND_MASK_SPEAKER | SOUND_MASK_VOLUME; 4517185029Spjd ctl->widget->ctlflags |= SOUND_MASK_SPEAKER; 4518168404Spjd } 4519168404Spjd break; 4520168404Spjd case HDA_CODEC_STAC9205: 4521168404Spjd if (subvendor == DELL_V1500_SUBVENDOR) { 4522168404Spjd w = hdac_widget_get(devinfo, 29); 4523168404Spjd if (w != NULL) 4524185029Spjd w->selconn = 1; 4525185029Spjd w = hdac_widget_get(devinfo, 30); 4526219089Spjd if (w != NULL) 4527286570Smav w->selconn = 1; 4528219089Spjd } 4529185029Spjd break; 4530168404Spjd case HDA_CODEC_STAC9221: 4531168404Spjd /* 4532168404Spjd * Dell XPS M1210 need all DACs for each output jacks 4533168404Spjd */ 4534168404Spjd if (subvendor == DELL_XPSM1210_SUBVENDOR) 4535168404Spjd break; 4536168404Spjd for (i = devinfo->startnode; i < devinfo->endnode; i++) { 4537168404Spjd w = hdac_widget_get(devinfo, i); 4538185029Spjd if (w == NULL || w->enable == 0) 4539168404Spjd continue; 4540286570Smav if (w->type != 4541286570Smav HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT) 4542286570Smav continue; 4543185029Spjd if (w->nid != 2) 4544185029Spjd w->enable = 0; 4545185029Spjd } 4546185029Spjd break; 4547185029Spjd case HDA_CODEC_STAC9221D: 4548185029Spjd for (i = devinfo->startnode; i < devinfo->endnode; i++) { 4549185029Spjd w = hdac_widget_get(devinfo, i); 4550185029Spjd if (w == NULL || w->enable == 0) 4551185029Spjd continue; 4552286570Smav if (w->type == 4553185029Spjd HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT && 4554185029Spjd w->nid != 6) 4555185029Spjd w->enable = 0; 4556185029Spjd 4557286570Smav } 4558168404Spjd break; 4559185029Spjd case HDA_CODEC_STAC9227: 4560275811Sdelphij w = hdac_widget_get(devinfo, 8); 4561168404Spjd if (w != NULL) 4562168404Spjd w->enable = 0; 4563258632Savg w = hdac_widget_get(devinfo, 9); 4564258632Savg if (w != NULL) 4565258632Savg w->enable = 0; 4566258632Savg break; 4567168404Spjd case HDA_CODEC_CXWAIKIKI: 4568258632Savg if (subvendor == HP_DV5000_SUBVENDOR) { 4569258632Savg w = hdac_widget_get(devinfo, 27); 4570258632Savg if (w != NULL) 4571258632Savg w->enable = 0; 4572258632Savg } 4573258632Savg ctl = hdac_audio_ctl_amp_get(devinfo, 16, 0, 1); 4574258632Savg if (ctl != NULL) 4575258632Savg ctl->ossmask = SOUND_MASK_SKIP; 4576168404Spjd ctl = hdac_audio_ctl_amp_get(devinfo, 25, 0, 1); 4577168404Spjd if (ctl != NULL && ctl->childwidget != NULL && 4578168404Spjd ctl->childwidget->enable != 0) { 4579168404Spjd ctl->ossmask = SOUND_MASK_PCM | SOUND_MASK_VOLUME; 4580168404Spjd ctl->childwidget->ctlflags |= SOUND_MASK_PCM; 4581168404Spjd } 4582286570Smav ctl = hdac_audio_ctl_amp_get(devinfo, 25, 1, 1); 4583168404Spjd if (ctl != NULL && ctl->childwidget != NULL && 4584219089Spjd ctl->childwidget->enable != 0) { 4585268075Sdelphij ctl->ossmask = SOUND_MASK_LINE | SOUND_MASK_VOLUME; 4586260150Sdelphij ctl->childwidget->ctlflags |= SOUND_MASK_LINE; 4587260150Sdelphij } 4588260150Sdelphij ctl = hdac_audio_ctl_amp_get(devinfo, 25, 2, 1); 4589260150Sdelphij if (ctl != NULL && ctl->childwidget != NULL && 4590260150Sdelphij ctl->childwidget->enable != 0) { 4591219089Spjd ctl->ossmask = SOUND_MASK_MIC | SOUND_MASK_VOLUME; 4592219089Spjd ctl->childwidget->ctlflags |= SOUND_MASK_MIC; 4593219089Spjd } 4594219089Spjd ctl = hdac_audio_ctl_amp_get(devinfo, 26, 0, 1); 4595168404Spjd if (ctl != NULL) { 4596268075Sdelphij ctl->ossmask = SOUND_MASK_SKIP; 4597268075Sdelphij /* XXX mixer \=rec mic broken.. why?!? */ 4598268075Sdelphij /* ctl->widget->ctlflags |= SOUND_MASK_MIC; */ 4599268075Sdelphij } 4600168404Spjd break; 4601168404Spjd default: 4602168404Spjd break; 4603168404Spjd } 4604168404Spjd} 4605219089Spjd 4606219089Spjdstatic int 4607168404Spjdhdac_audio_ctl_ossmixer_getnextdev(struct hdac_devinfo *devinfo) 4608168404Spjd{ 4609168404Spjd int *dev = &devinfo->function.audio.ossidx; 4610286570Smav 4611168404Spjd while (*dev < SOUND_MIXER_NRDEVICES) { 4612168404Spjd switch (*dev) { 4613168404Spjd case SOUND_MIXER_VOLUME: 4614168404Spjd case SOUND_MIXER_BASS: 4615168404Spjd case SOUND_MIXER_TREBLE: 4616219089Spjd case SOUND_MIXER_PCM: 4617219089Spjd case SOUND_MIXER_SPEAKER: 4618219089Spjd case SOUND_MIXER_LINE: 4619219089Spjd case SOUND_MIXER_MIC: 4620286570Smav case SOUND_MIXER_CD: 4621286570Smav case SOUND_MIXER_RECLEV: 4622219089Spjd case SOUND_MIXER_IGAIN: 4623219089Spjd case SOUND_MIXER_OGAIN: /* reserved for EAPD switch */ 4624219089Spjd (*dev)++; 4625219089Spjd break; 4626219089Spjd default: 4627243524Smm return (*dev)++; 4628243524Smm break; 4629243524Smm } 4630243524Smm } 4631243524Smm 4632243524Smm return (-1); 4633219089Spjd} 4634219089Spjd 4635286570Smavstatic int 4636286570Smavhdac_widget_find_dac_path(struct hdac_devinfo *devinfo, nid_t nid, int depth) 4637219089Spjd{ 4638219089Spjd struct hdac_widget *w; 4639219089Spjd int i, ret = 0; 4640168404Spjd 4641275811Sdelphij if (depth > HDA_PARSE_MAXDEPTH) 4642185029Spjd return (0); 4643286570Smav w = hdac_widget_get(devinfo, nid); 4644185029Spjd if (w == NULL || w->enable == 0) 4645168404Spjd return (0); 4646168404Spjd switch (w->type) { 4647275811Sdelphij case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT: 4648168404Spjd w->pflags |= HDA_DAC_PATH; 4649168404Spjd ret = 1; 4650286570Smav break; 4651219089Spjd case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER: 4652168404Spjd case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR: 4653168404Spjd for (i = 0; i < w->nconns; i++) { 4654168404Spjd if (hdac_widget_find_dac_path(devinfo, 4655168404Spjd w->conns[i], depth + 1) != 0) { 4656168404Spjd if (w->selconn == -1) 4657219089Spjd w->selconn = i; 4658251478Sdelphij ret = 1; 4659258632Savg w->pflags |= HDA_DAC_PATH; 4660258632Savg } 4661268123Sdelphij } 4662168404Spjd break; 4663168404Spjd default: 4664168404Spjd break; 4665185029Spjd } 4666168404Spjd return (ret); 4667185029Spjd} 4668219089Spjd 4669168404Spjdstatic int 4670286570Smavhdac_widget_find_adc_path(struct hdac_devinfo *devinfo, nid_t nid, int depth) 4671286570Smav{ 4672286570Smav struct hdac_widget *w; 4673185029Spjd int i, conndev, ret = 0; 4674275811Sdelphij 4675251478Sdelphij if (depth > HDA_PARSE_MAXDEPTH) 4676275811Sdelphij return (0); 4677168404Spjd w = hdac_widget_get(devinfo, nid); 4678168404Spjd if (w == NULL || w->enable == 0) 4679258632Savg return (0); 4680168404Spjd switch (w->type) { 4681168404Spjd case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT: 4682168404Spjd case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR: 4683168404Spjd case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER: 4684219089Spjd for (i = 0; i < w->nconns; i++) { 4685258632Savg if (hdac_widget_find_adc_path(devinfo, w->conns[i], 4686258632Savg depth + 1) != 0) { 4687185029Spjd if (w->selconn == -1) 4688168404Spjd w->selconn = i; 4689168404Spjd w->pflags |= HDA_ADC_PATH; 4690168404Spjd ret = 1; 4691185029Spjd } 4692258632Savg } 4693185029Spjd break; 4694185029Spjd case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX: 4695272483Ssmh conndev = w->wclass.pin.config & 4696185029Spjd HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; 4697185029Spjd if (HDA_PARAM_PIN_CAP_INPUT_CAP(w->wclass.pin.cap) && 4698185029Spjd (conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_CD || 4699272483Ssmh conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN || 4700185029Spjd conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN)) { 4701272483Ssmh w->pflags |= HDA_ADC_PATH; 4702185029Spjd ret = 1; 4703258632Savg } 4704272483Ssmh break; 4705185029Spjd /*case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER: 4706185029Spjd if (w->pflags & HDA_DAC_PATH) { 4707185029Spjd w->pflags |= HDA_ADC_PATH; 4708185029Spjd ret = 1; 4709185029Spjd } 4710185029Spjd break;*/ 4711185029Spjd default: 4712185029Spjd break; 4713185029Spjd } 4714185029Spjd return (ret); 4715185029Spjd} 4716185029Spjd 4717272483Ssmhstatic uint32_t 4718249195Smmhdac_audio_ctl_outamp_build(struct hdac_devinfo *devinfo, 4719185029Spjd nid_t nid, nid_t pnid, int index, int depth) 4720185029Spjd{ 4721185029Spjd struct hdac_widget *w, *pw; 4722185029Spjd struct hdac_audio_ctl *ctl; 4723185029Spjd uint32_t fl = 0; 4724185029Spjd int i, ossdev, conndev, strategy; 4725249195Smm 4726185029Spjd if (depth > HDA_PARSE_MAXDEPTH) 4727185029Spjd return (0); 4728185029Spjd 4729185029Spjd w = hdac_widget_get(devinfo, nid); 4730185029Spjd if (w == NULL || w->enable == 0) 4731185029Spjd return (0); 4732168404Spjd 4733185029Spjd pw = hdac_widget_get(devinfo, pnid); 4734168404Spjd strategy = devinfo->function.audio.parsing_strategy; 4735185029Spjd 4736168404Spjd if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER 4737168404Spjd || w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR) { 4738168404Spjd for (i = 0; i < w->nconns; i++) { 4739168404Spjd fl |= hdac_audio_ctl_outamp_build(devinfo, w->conns[i], 4740185029Spjd w->nid, i, depth + 1); 4741168404Spjd } 4742185029Spjd w->ctlflags |= fl; 4743209962Smm return (fl); 4744185029Spjd } else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT && 4745272483Ssmh (w->pflags & HDA_DAC_PATH)) { 4746185029Spjd i = 0; 4747272483Ssmh while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 4748272483Ssmh if (ctl->enable == 0 || ctl->widget == NULL) 4749185029Spjd continue; 4750249195Smm /* XXX This should be compressed! */ 4751168404Spjd if (((ctl->widget->nid == w->nid) || 4752168404Spjd (ctl->widget->nid == pnid && ctl->index == index && 4753209962Smm (ctl->dir & HDA_CTL_IN)) || 4754209962Smm (ctl->widget->nid == pnid && pw != NULL && 4755209962Smm pw->type == 4756209962Smm HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR && 4757209962Smm (pw->nconns < 2 || pw->selconn == index || 4758209962Smm pw->selconn == -1) && 4759209962Smm (ctl->dir & HDA_CTL_OUT)) || 4760185029Spjd (strategy == HDA_PARSE_DIRECT && 4761251631Sdelphij ctl->widget->nid == w->nid)) && 4762185029Spjd !(ctl->ossmask & ~SOUND_MASK_VOLUME)) { 4763185029Spjd /*if (pw != NULL && pw->selconn == -1) 4764258632Savg pw->selconn = index; 4765258632Savg fl |= SOUND_MASK_VOLUME; 4766185029Spjd fl |= SOUND_MASK_PCM; 4767185029Spjd ctl->ossmask |= SOUND_MASK_VOLUME; 4768185029Spjd ctl->ossmask |= SOUND_MASK_PCM; 4769168404Spjd ctl->ossdev = SOUND_MIXER_PCM;*/ 4770168404Spjd if (!(w->ctlflags & SOUND_MASK_PCM) || 4771168404Spjd (pw != NULL && 4772168404Spjd !(pw->ctlflags & SOUND_MASK_PCM))) { 4773168404Spjd fl |= SOUND_MASK_VOLUME; 4774168404Spjd fl |= SOUND_MASK_PCM; 4775209962Smm ctl->ossmask |= SOUND_MASK_VOLUME; 4776209962Smm ctl->ossmask |= SOUND_MASK_PCM; 4777209962Smm ctl->ossdev = SOUND_MIXER_PCM; 4778185029Spjd w->ctlflags |= SOUND_MASK_VOLUME; 4779185029Spjd w->ctlflags |= SOUND_MASK_PCM; 4780185029Spjd if (pw != NULL) { 4781185029Spjd if (pw->selconn == -1) 4782185029Spjd pw->selconn = index; 4783185029Spjd pw->ctlflags |= 4784249195Smm SOUND_MASK_VOLUME; 4785168404Spjd pw->ctlflags |= 4786185029Spjd SOUND_MASK_PCM; 4787168404Spjd } 4788168404Spjd } 4789168404Spjd } 4790286626Smav } 4791286626Smav w->ctlflags |= fl; 4792286626Smav return (fl); 4793286626Smav } else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX && 4794286626Smav HDA_PARAM_PIN_CAP_INPUT_CAP(w->wclass.pin.cap) && 4795286626Smav (w->pflags & HDA_ADC_PATH)) { 4796286626Smav conndev = w->wclass.pin.config & 4797286626Smav HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; 4798286626Smav i = 0; 4799286626Smav while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 4800286626Smav if (ctl->enable == 0 || ctl->widget == NULL) 4801286626Smav continue; 4802286626Smav /* XXX This should be compressed! */ 4803286626Smav if (((ctl->widget->nid == pnid && ctl->index == index && 4804286626Smav (ctl->dir & HDA_CTL_IN)) || 4805286626Smav (ctl->widget->nid == pnid && pw != NULL && 4806286626Smav pw->type == 4807286626Smav HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR && 4808286626Smav (pw->nconns < 2 || pw->selconn == index || 4809286626Smav pw->selconn == -1) && 4810286626Smav (ctl->dir & HDA_CTL_OUT)) || 4811286626Smav (strategy == HDA_PARSE_DIRECT && 4812286626Smav ctl->widget->nid == w->nid)) && 4813286626Smav !(ctl->ossmask & ~SOUND_MASK_VOLUME)) { 4814286626Smav if (pw != NULL && pw->selconn == -1) 4815286626Smav pw->selconn = index; 4816286626Smav ossdev = 0; 4817286626Smav switch (conndev) { 4818286626Smav case HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN: 4819286626Smav ossdev = SOUND_MIXER_MIC; 4820286626Smav break; 4821286626Smav case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN: 4822286626Smav ossdev = SOUND_MIXER_LINE; 4823286626Smav break; 4824286626Smav case HDA_CONFIG_DEFAULTCONF_DEVICE_CD: 4825286626Smav ossdev = SOUND_MIXER_CD; 4826286626Smav break; 4827286626Smav default: 4828286626Smav ossdev = 4829286626Smav hdac_audio_ctl_ossmixer_getnextdev( 4830286626Smav devinfo); 4831286626Smav if (ossdev < 0) 4832168404Spjd ossdev = 0; 4833168566Spjd break; 4834168404Spjd } 4835168404Spjd if (strategy == HDA_PARSE_MIXER) { 4836168566Spjd fl |= SOUND_MASK_VOLUME; 4837168404Spjd ctl->ossmask |= SOUND_MASK_VOLUME; 4838168404Spjd } 4839219089Spjd fl |= 1 << ossdev; 4840286625Smav ctl->ossmask |= 1 << ossdev; 4841286625Smav ctl->ossdev = ossdev; 4842272483Ssmh } 4843168404Spjd } 4844241773Savg w->ctlflags |= fl; 4845241773Savg return (fl); 4846241773Savg } else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET) { 4847241773Savg i = 0; 4848241773Savg while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 4849241773Savg if (ctl->enable == 0 || ctl->widget == NULL) 4850286623Smav continue; 4851286623Smav /* XXX This should be compressed! */ 4852219089Spjd if (((ctl->widget->nid == pnid && ctl->index == index && 4853168404Spjd (ctl->dir & HDA_CTL_IN)) || 4854168404Spjd (ctl->widget->nid == pnid && pw != NULL && 4855168404Spjd pw->type == 4856168404Spjd HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR && 4857168404Spjd (pw->nconns < 2 || pw->selconn == index || 4858168404Spjd pw->selconn == -1) && 4859219089Spjd (ctl->dir & HDA_CTL_OUT)) || 4860205231Skmacy (strategy == HDA_PARSE_DIRECT && 4861168404Spjd ctl->widget->nid == w->nid)) && 4862168404Spjd !(ctl->ossmask & ~SOUND_MASK_VOLUME)) { 4863168404Spjd if (pw != NULL && pw->selconn == -1) 4864168404Spjd pw->selconn = index; 4865168404Spjd fl |= SOUND_MASK_VOLUME; 4866168404Spjd fl |= SOUND_MASK_SPEAKER; 4867168404Spjd ctl->ossmask |= SOUND_MASK_VOLUME; 4868168566Spjd ctl->ossmask |= SOUND_MASK_SPEAKER; 4869219089Spjd ctl->ossdev = SOUND_MIXER_SPEAKER; 4870277300Ssmh } 4871192360Skmacy } 4872192360Skmacy w->ctlflags |= fl; 4873192360Skmacy return (fl); 4874192360Skmacy } 4875192360Skmacy return (0); 4876192360Skmacy} 4877192360Skmacy 4878192360Skmacystatic uint32_t 4879277300Ssmhhdac_audio_ctl_inamp_build(struct hdac_devinfo *devinfo, nid_t nid, int depth) 4880168566Spjd{ 4881280822Smav struct hdac_widget *w, *cw; 4882168566Spjd struct hdac_audio_ctl *ctl; 4883280822Smav uint32_t fl; 4884280822Smav int i; 4885168404Spjd 4886168404Spjd if (depth > HDA_PARSE_MAXDEPTH) 4887175633Spjd return (0); 4888219089Spjd 4889168481Spjd w = hdac_widget_get(devinfo, nid); 4890168404Spjd if (w == NULL || w->enable == 0) 4891168404Spjd return (0); 4892168566Spjd /*if (!(w->pflags & HDA_ADC_PATH)) 4893168404Spjd return (0); 4894280822Smav if (!(w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT || 4895168404Spjd w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR)) 4896280822Smav return (0);*/ 4897168404Spjd i = 0; 4898168481Spjd while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 4899219089Spjd if (ctl->enable == 0 || ctl->widget == NULL) 4900168404Spjd continue; 4901168404Spjd if (ctl->widget->nid == nid) { 4902168404Spjd ctl->ossmask |= SOUND_MASK_RECLEV; 4903185029Spjd w->ctlflags |= SOUND_MASK_RECLEV; 4904185029Spjd return (SOUND_MASK_RECLEV); 4905185029Spjd } 4906185029Spjd } 4907185029Spjd for (i = 0; i < w->nconns; i++) { 4908185029Spjd cw = hdac_widget_get(devinfo, w->conns[i]); 4909185029Spjd if (cw == NULL || cw->enable == 0) 4910185029Spjd continue; 4911185029Spjd if (cw->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR) 4912185029Spjd continue; 4913275780Sdelphij fl = hdac_audio_ctl_inamp_build(devinfo, cw->nid, depth + 1); 4914275780Sdelphij if (fl != 0) { 4915275780Sdelphij cw->ctlflags |= fl; 4916275780Sdelphij w->ctlflags |= fl; 4917275780Sdelphij return (fl); 4918275780Sdelphij } 4919208373Smm } 4920208373Smm return (0); 4921208373Smm} 4922208373Smm 4923208373Smmstatic int 4924208373Smmhdac_audio_ctl_recsel_build(struct hdac_devinfo *devinfo, nid_t nid, int depth) 4925286625Smav{ 4926286625Smav struct hdac_widget *w, *cw; 4927286625Smav int i, child = 0; 4928286625Smav 4929286625Smav if (depth > HDA_PARSE_MAXDEPTH) 4930286625Smav return (0); 4931208373Smm 4932208373Smm w = hdac_widget_get(devinfo, nid); 4933208373Smm if (w == NULL || w->enable == 0) 4934168404Spjd return (0); 4935168404Spjd /*if (!(w->pflags & HDA_ADC_PATH)) 4936168404Spjd return (0); 4937168404Spjd if (!(w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT || 4938168404Spjd w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR)) 4939168404Spjd return (0);*/ 4940168473Spjd /* XXX weak! */ 4941168473Spjd for (i = 0; i < w->nconns; i++) { 4942168473Spjd cw = hdac_widget_get(devinfo, w->conns[i]); 4943168404Spjd if (cw == NULL) 4944168404Spjd continue; 4945168404Spjd if (++child > 1) { 4946168404Spjd w->pflags |= HDA_ADC_RECSEL; 4947168404Spjd return (1); 4948185029Spjd } 4949168404Spjd } 4950168404Spjd for (i = 0; i < w->nconns; i++) { 4951205231Skmacy if (hdac_audio_ctl_recsel_build(devinfo, 4952205231Skmacy w->conns[i], depth + 1) != 0) 4953205231Skmacy return (1); 4954205231Skmacy } 4955205231Skmacy return (0); 4956205231Skmacy} 4957205231Skmacy 4958205231Skmacystatic int 4959205231Skmacyhdac_audio_build_tree_strategy(struct hdac_devinfo *devinfo) 4960205231Skmacy{ 4961205231Skmacy struct hdac_widget *w, *cw; 4962205231Skmacy int i, j, conndev, found_dac = 0; 4963205231Skmacy int strategy; 4964206796Spjd 4965205231Skmacy strategy = devinfo->function.audio.parsing_strategy; 4966286570Smav 4967286570Smav for (i = devinfo->startnode; i < devinfo->endnode; i++) { 4968205231Skmacy w = hdac_widget_get(devinfo, i); 4969286570Smav if (w == NULL || w->enable == 0) 4970286570Smav continue; 4971205231Skmacy if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) 4972286570Smav continue; 4973286570Smav if (!HDA_PARAM_PIN_CAP_OUTPUT_CAP(w->wclass.pin.cap)) 4974205231Skmacy continue; 4975286570Smav conndev = w->wclass.pin.config & 4976286570Smav HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; 4977205231Skmacy if (!(conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT || 4978286570Smav conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER || 4979286570Smav conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT)) 4980205231Skmacy continue; 4981286570Smav for (j = 0; j < w->nconns; j++) { 4982286570Smav cw = hdac_widget_get(devinfo, w->conns[j]); 4983205231Skmacy if (cw == NULL || cw->enable == 0) 4984168404Spjd continue; 4985168404Spjd if (strategy == HDA_PARSE_MIXER && !(cw->type == 4986168404Spjd HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER || 4987168404Spjd cw->type == 4988168404Spjd HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR)) 4989168404Spjd continue; 4990168404Spjd if (hdac_widget_find_dac_path(devinfo, cw->nid, 0) 4991168404Spjd != 0) { 4992168404Spjd if (w->selconn == -1) 4993168404Spjd w->selconn = j; 4994168404Spjd w->pflags |= HDA_DAC_PATH; 4995168404Spjd found_dac++; 4996168404Spjd } 4997286574Smav } 4998168404Spjd } 4999168404Spjd 5000168404Spjd return (found_dac); 5001168404Spjd} 5002168404Spjd 5003168404Spjdstatic void 5004168404Spjdhdac_audio_build_tree(struct hdac_devinfo *devinfo) 5005168566Spjd{ 5006168404Spjd struct hdac_widget *w; 5007168404Spjd struct hdac_audio_ctl *ctl; 5008168404Spjd int i, j, dacs, strategy; 5009168404Spjd 5010185029Spjd /* Construct DAC path */ 5011168566Spjd strategy = HDA_PARSE_MIXER; 5012258632Savg devinfo->function.audio.parsing_strategy = strategy; 5013258632Savg HDA_BOOTVERBOSE( 5014258632Savg device_printf(devinfo->codec->sc->dev, 5015258632Savg "HDA_DEBUG: HWiP: HDA Widget Parser - Revision %d\n", 5016258632Savg HDA_WIDGET_PARSER_REV); 5017258632Savg ); 5018258632Savg dacs = hdac_audio_build_tree_strategy(devinfo); 5019258632Savg if (dacs == 0) { 5020258632Savg HDA_BOOTVERBOSE( 5021258632Savg device_printf(devinfo->codec->sc->dev, 5022258632Savg "HDA_DEBUG: HWiP: 0 DAC path found! " 5023258632Savg "Retrying parser " 5024258632Savg "using HDA_PARSE_DIRECT strategy.\n"); 5025258632Savg ); 5026185029Spjd strategy = HDA_PARSE_DIRECT; 5027168566Spjd devinfo->function.audio.parsing_strategy = strategy; 5028194043Skmacy dacs = hdac_audio_build_tree_strategy(devinfo); 5029193953Skmacy } 5030206796Spjd 5031193878Skmacy HDA_BOOTVERBOSE( 5032193953Skmacy device_printf(devinfo->codec->sc->dev, 5033196863Strasz "HDA_DEBUG: HWiP: Found %d DAC path using HDA_PARSE_%s " 5034196863Strasz "strategy.\n", 5035196863Strasz dacs, (strategy == HDA_PARSE_MIXER) ? "MIXER" : "DIRECT"); 5036196863Strasz ); 5037219089Spjd 5038193878Skmacy /* Construct ADC path */ 5039206796Spjd for (i = devinfo->startnode; i < devinfo->endnode; i++) { 5040193878Skmacy w = hdac_widget_get(devinfo, i); 5041193953Skmacy if (w == NULL || w->enable == 0) 5042196863Strasz continue; 5043196941Strasz if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) 5044196863Strasz continue; 5045196863Strasz (void)hdac_widget_find_adc_path(devinfo, w->nid, 0); 5046219089Spjd } 5047193878Skmacy 5048206796Spjd /* Output mixers */ 5049175633Spjd for (i = devinfo->startnode; i < devinfo->endnode; i++) { 5050168696Spjd w = hdac_widget_get(devinfo, i); 5051168987Sbmah if (w == NULL || w->enable == 0) 5052168987Sbmah continue; 5053175633Spjd if ((strategy == HDA_PARSE_MIXER && 5054175633Spjd (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER || 5055173419Spjd w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR) 5056168987Sbmah && (w->pflags & HDA_DAC_PATH)) || 5057185029Spjd (strategy == HDA_PARSE_DIRECT && (w->pflags & 5058173419Spjd (HDA_DAC_PATH | HDA_ADC_PATH)))) { 5059185029Spjd w->ctlflags |= hdac_audio_ctl_outamp_build(devinfo, 5060168566Spjd w->nid, devinfo->startnode - 1, 0, 0); 5061168566Spjd } else if (w->type == 5062168404Spjd HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET) { 5063168404Spjd j = 0; 5064168404Spjd while ((ctl = hdac_audio_ctl_each(devinfo, &j)) != 5065168404Spjd NULL) { 5066168404Spjd if (ctl->enable == 0 || ctl->widget == NULL) 5067205231Skmacy continue; 5068206796Spjd if (ctl->widget->nid != w->nid) 5069168404Spjd continue; 5070168404Spjd ctl->ossmask |= SOUND_MASK_VOLUME; 5071168404Spjd ctl->ossmask |= SOUND_MASK_SPEAKER; 5072168404Spjd ctl->ossdev = SOUND_MIXER_SPEAKER; 5073168404Spjd w->ctlflags |= SOUND_MASK_VOLUME; 5074168404Spjd w->ctlflags |= SOUND_MASK_SPEAKER; 5075168404Spjd } 5076185029Spjd } 5077168404Spjd } 5078168404Spjd 5079168404Spjd /* Input mixers (rec) */ 5080168404Spjd for (i = devinfo->startnode; i < devinfo->endnode; i++) { 5081168404Spjd w = hdac_widget_get(devinfo, i); 5082168404Spjd if (w == NULL || w->enable == 0) 5083168404Spjd continue; 5084168404Spjd if (!(w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT && 5085168404Spjd w->pflags & HDA_ADC_PATH)) 5086168404Spjd continue; 5087168404Spjd hdac_audio_ctl_inamp_build(devinfo, w->nid, 0); 5088168404Spjd hdac_audio_ctl_recsel_build(devinfo, w->nid, 0); 5089205231Skmacy } 5090205231Skmacy} 5091205231Skmacy 5092205231Skmacy#define HDA_COMMIT_CONN (1 << 0) 5093205231Skmacy#define HDA_COMMIT_CTRL (1 << 1) 5094206795Spjd#define HDA_COMMIT_EAPD (1 << 2) 5095168404Spjd#define HDA_COMMIT_GPIO (1 << 3) 5096205231Skmacy#define HDA_COMMIT_MISC (1 << 4) 5097205231Skmacy#define HDA_COMMIT_ALL (HDA_COMMIT_CONN | HDA_COMMIT_CTRL | \ 5098205231Skmacy HDA_COMMIT_EAPD | HDA_COMMIT_GPIO | HDA_COMMIT_MISC) 5099205231Skmacy 5100205231Skmacystatic void 5101206795Spjdhdac_audio_commit(struct hdac_devinfo *devinfo, uint32_t cfl) 5102205231Skmacy{ 5103206796Spjd struct hdac_softc *sc = devinfo->codec->sc; 5104168404Spjd struct hdac_widget *w; 5105168404Spjd nid_t cad; 5106286570Smav int i; 5107209962Smm 5108168404Spjd if (!(cfl & HDA_COMMIT_ALL)) 5109168566Spjd return; 5110168566Spjd 5111168404Spjd cad = devinfo->codec->cad; 5112168404Spjd 5113185029Spjd if ((cfl & HDA_COMMIT_MISC)) { 5114185029Spjd if (sc->pci_subvendor == APPLE_INTEL_MAC) 5115185029Spjd hdac_command(sc, HDA_CMD_12BIT(cad, devinfo->nid, 5116185029Spjd 0x7e7, 0), cad); 5117185029Spjd } 5118185029Spjd 5119185029Spjd if (cfl & HDA_COMMIT_GPIO) { 5120185029Spjd uint32_t gdata, gmask, gdir; 5121185029Spjd int commitgpio, numgpio; 5122185029Spjd 5123185029Spjd gdata = 0; 5124185029Spjd gmask = 0; 5125185029Spjd gdir = 0; 5126185029Spjd commitgpio = 0; 5127185029Spjd 5128185029Spjd numgpio = HDA_PARAM_GPIO_COUNT_NUM_GPIO( 5129185029Spjd devinfo->function.audio.gpio); 5130185029Spjd 5131185029Spjd if (devinfo->function.audio.quirks & HDA_QUIRK_GPIOFLUSH) 5132185029Spjd commitgpio = (numgpio > 0) ? 1 : 0; 5133185029Spjd else { 5134185029Spjd for (i = 0; i < numgpio && i < HDA_GPIO_MAX; i++) { 5135185029Spjd if (!(devinfo->function.audio.quirks & 5136185029Spjd (1 << i))) 5137185029Spjd continue; 5138185029Spjd if (commitgpio == 0) { 5139185029Spjd commitgpio = 1; 5140185029Spjd HDA_BOOTVERBOSE( 5141185029Spjd gdata = hdac_command(sc, 5142185029Spjd HDA_CMD_GET_GPIO_DATA(cad, 5143185029Spjd devinfo->nid), cad); 5144185029Spjd gmask = hdac_command(sc, 5145185029Spjd HDA_CMD_GET_GPIO_ENABLE_MASK(cad, 5146185029Spjd devinfo->nid), cad); 5147185029Spjd gdir = hdac_command(sc, 5148185029Spjd HDA_CMD_GET_GPIO_DIRECTION(cad, 5149185029Spjd devinfo->nid), cad); 5150185029Spjd device_printf(sc->dev, 5151185029Spjd "GPIO init: data=0x%08x " 5152185029Spjd "mask=0x%08x dir=0x%08x\n", 5153185029Spjd gdata, gmask, gdir); 5154185029Spjd gdata = 0; 5155185029Spjd gmask = 0; 5156185029Spjd gdir = 0; 5157185029Spjd ); 5158185029Spjd } 5159185029Spjd gdata |= 1 << i; 5160185029Spjd gmask |= 1 << i; 5161185029Spjd gdir |= 1 << i; 5162185029Spjd } 5163185029Spjd } 5164185029Spjd 5165185029Spjd if (commitgpio != 0) { 5166185029Spjd HDA_BOOTVERBOSE( 5167185029Spjd device_printf(sc->dev, 5168185029Spjd "GPIO commit: data=0x%08x mask=0x%08x " 5169251478Sdelphij "dir=0x%08x\n", 5170251478Sdelphij gdata, gmask, gdir); 5171251478Sdelphij ); 5172251478Sdelphij hdac_command(sc, 5173251478Sdelphij HDA_CMD_SET_GPIO_ENABLE_MASK(cad, devinfo->nid, 5174251478Sdelphij gmask), cad); 5175185029Spjd hdac_command(sc, 5176185029Spjd HDA_CMD_SET_GPIO_DIRECTION(cad, devinfo->nid, 5177185029Spjd gdir), cad); 5178185029Spjd hdac_command(sc, 5179185029Spjd HDA_CMD_SET_GPIO_DATA(cad, devinfo->nid, 5180185029Spjd gdata), cad); 5181185029Spjd } 5182185029Spjd } 5183185029Spjd 5184185029Spjd for (i = 0; i < devinfo->nodecnt; i++) { 5185185029Spjd w = &devinfo->widget[i]; 5186185029Spjd if (w == NULL || w->enable == 0) 5187185029Spjd continue; 5188185029Spjd if (cfl & HDA_COMMIT_CONN) { 5189185029Spjd if (w->selconn == -1) 5190185029Spjd w->selconn = 0; 5191185029Spjd if (w->nconns > 0) 5192185029Spjd hdac_widget_connection_select(w, w->selconn); 5193185029Spjd } 5194185029Spjd if ((cfl & HDA_COMMIT_CTRL) && 5195185029Spjd w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) { 5196185029Spjd uint32_t pincap; 5197185029Spjd 5198185029Spjd pincap = w->wclass.pin.cap; 5199185029Spjd 5200185029Spjd if ((w->pflags & (HDA_DAC_PATH | HDA_ADC_PATH)) == 5201185029Spjd (HDA_DAC_PATH | HDA_ADC_PATH)) 5202185029Spjd device_printf(sc->dev, "WARNING: node %d " 5203185029Spjd "participate both for DAC/ADC!\n", w->nid); 5204185029Spjd if (w->pflags & HDA_DAC_PATH) { 5205185029Spjd w->wclass.pin.ctrl &= 5206185029Spjd ~HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE; 5207185029Spjd if ((w->wclass.pin.config & 5208185029Spjd HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) != 5209185029Spjd HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT) 5210185029Spjd w->wclass.pin.ctrl &= 5211185029Spjd ~HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE; 5212185029Spjd if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF100) && 5213185029Spjd HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap)) 5214185029Spjd w->wclass.pin.ctrl |= 5215185029Spjd HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE( 5216185029Spjd HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100); 5217185029Spjd else if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF80) && 5218185029Spjd HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap)) 5219185029Spjd w->wclass.pin.ctrl |= 5220185029Spjd HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE( 5221185029Spjd HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80); 5222185029Spjd else if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF50) && 5223185029Spjd HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap)) 5224185029Spjd w->wclass.pin.ctrl |= 5225185029Spjd HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE( 5226185029Spjd HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50); 5227185029Spjd } else if (w->pflags & HDA_ADC_PATH) { 5228185029Spjd w->wclass.pin.ctrl &= 5229185029Spjd ~(HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE | 5230185029Spjd HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE); 5231185029Spjd if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF100) && 5232185029Spjd HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap)) 5233185029Spjd w->wclass.pin.ctrl |= 5234185029Spjd HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE( 5235185029Spjd HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100); 5236185029Spjd else if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF80) && 5237185029Spjd HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap)) 5238185029Spjd w->wclass.pin.ctrl |= 5239251478Sdelphij HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE( 5240251478Sdelphij HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80); 5241251478Sdelphij else if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF50) && 5242251478Sdelphij HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap)) 5243251478Sdelphij w->wclass.pin.ctrl |= 5244185029Spjd HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE( 5245185029Spjd HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50); 5246185029Spjd } else 5247185029Spjd w->wclass.pin.ctrl &= ~( 5248208373Smm HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE | 5249208373Smm HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE | 5250208373Smm HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE | 5251208373Smm HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK); 5252208373Smm hdac_command(sc, 5253208373Smm HDA_CMD_SET_PIN_WIDGET_CTRL(cad, w->nid, 5254208373Smm w->wclass.pin.ctrl), cad); 5255208373Smm } 5256208373Smm if ((cfl & HDA_COMMIT_EAPD) && 5257185029Spjd w->param.eapdbtl != HDAC_INVALID) { 5258185029Spjd uint32_t val; 5259208373Smm 5260275811Sdelphij val = w->param.eapdbtl; 5261208373Smm if (devinfo->function.audio.quirks & 5262208373Smm HDA_QUIRK_EAPDINV) 5263208373Smm val ^= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD; 5264208373Smm hdac_command(sc, 5265208373Smm HDA_CMD_SET_EAPD_BTL_ENABLE(cad, w->nid, 5266208373Smm val), cad); 5267208373Smm 5268208373Smm } 5269275811Sdelphij DELAY(1000); 5270208373Smm } 5271208373Smm} 5272208373Smm 5273286570Smavstatic void 5274208373Smmhdac_audio_ctl_commit(struct hdac_devinfo *devinfo) 5275208373Smm{ 5276208373Smm struct hdac_softc *sc = devinfo->codec->sc; 5277275811Sdelphij struct hdac_audio_ctl *ctl; 5278208373Smm int i; 5279208373Smm 5280208373Smm devinfo->function.audio.mvol = 100 | (100 << 8); 5281275811Sdelphij i = 0; 5282208373Smm while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 5283208373Smm if (ctl->enable == 0 || ctl->widget == NULL) { 5284208373Smm HDA_BOOTVERBOSE( 5285208373Smm device_printf(sc->dev, "[%2d] Ctl nid=%d", 5286208373Smm i, (ctl->widget != NULL) ? 5287208373Smm ctl->widget->nid : -1); 5288208373Smm if (ctl->childwidget != NULL) 5289208373Smm printf(" childnid=%d", 5290251478Sdelphij ctl->childwidget->nid); 5291208373Smm if (ctl->widget == NULL) 5292208373Smm printf(" NULL WIDGET!"); 5293208373Smm printf(" DISABLED\n"); 5294251478Sdelphij ); 5295251478Sdelphij continue; 5296251478Sdelphij } 5297251478Sdelphij HDA_BOOTVERBOSE( 5298251478Sdelphij if (ctl->ossmask == 0) { 5299251478Sdelphij device_printf(sc->dev, "[%2d] Ctl nid=%d", 5300251478Sdelphij i, ctl->widget->nid); 5301251478Sdelphij if (ctl->childwidget != NULL) 5302251478Sdelphij printf(" childnid=%d", 5303251478Sdelphij ctl->childwidget->nid); 5304251478Sdelphij printf(" Bind to NONE\n"); 5305208373Smm } 5306208373Smm ); 5307251478Sdelphij if (ctl->step > 0) { 5308208373Smm ctl->ossval = (ctl->left * 100) / ctl->step; 5309208373Smm ctl->ossval |= ((ctl->right * 100) / ctl->step) << 8; 5310208373Smm } else 5311208373Smm ctl->ossval = 0; 5312208373Smm hdac_audio_ctl_amp_set(ctl, HDA_AMP_MUTE_DEFAULT, 5313208373Smm ctl->left, ctl->right); 5314208373Smm } 5315208373Smm} 5316219089Spjd 5317208373Smmstatic int 5318208373Smmhdac_pcmchannel_setup(struct hdac_devinfo *devinfo, int dir) 5319208373Smm{ 5320208373Smm struct hdac_chan *ch; 5321208373Smm struct hdac_widget *w; 5322208373Smm uint32_t cap, fmtcap, pcmcap, path; 5323208373Smm int i, type, ret, max; 5324208373Smm 5325208373Smm if (dir == PCMDIR_PLAY) { 5326208373Smm type = HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT; 5327208373Smm ch = &devinfo->codec->sc->play; 5328208373Smm path = HDA_DAC_PATH; 5329219089Spjd } else { 5330219089Spjd type = HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT; 5331208373Smm ch = &devinfo->codec->sc->rec; 5332208373Smm path = HDA_ADC_PATH; 5333208373Smm } 5334208373Smm 5335185029Spjd ch->caps = hdac_caps; 5336185029Spjd ch->caps.fmtlist = ch->fmtlist; 5337185029Spjd ch->bit16 = 1; 5338185029Spjd ch->bit32 = 0; 5339185029Spjd ch->pcmrates[0] = 48000; 5340185029Spjd ch->pcmrates[1] = 0; 5341185029Spjd 5342185029Spjd ret = 0; 5343185029Spjd fmtcap = devinfo->function.audio.supp_stream_formats; 5344185029Spjd pcmcap = devinfo->function.audio.supp_pcm_size_rate; 5345185029Spjd max = (sizeof(ch->io) / sizeof(ch->io[0])) - 1; 5346185029Spjd 5347185029Spjd for (i = devinfo->startnode; i < devinfo->endnode && ret < max; i++) { 5348185029Spjd w = hdac_widget_get(devinfo, i); 5349185029Spjd if (w == NULL || w->enable == 0 || w->type != type || 5350185029Spjd !(w->pflags & path)) 5351185029Spjd continue; 5352185029Spjd cap = w->param.widget_cap; 5353185029Spjd /*if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(cap)) 5354185029Spjd continue;*/ 5355185029Spjd if (!HDA_PARAM_AUDIO_WIDGET_CAP_STEREO(cap)) 5356185029Spjd continue; 5357185029Spjd cap = w->param.supp_stream_formats; 5358185029Spjd /*if (HDA_PARAM_SUPP_STREAM_FORMATS_AC3(cap)) { 5359185029Spjd } 5360185029Spjd if (HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32(cap)) { 5361185029Spjd }*/ 5362185029Spjd if (!HDA_PARAM_SUPP_STREAM_FORMATS_PCM(cap)) 5363185029Spjd continue; 5364185029Spjd if (ret == 0) { 5365185029Spjd fmtcap = w->param.supp_stream_formats; 5366185029Spjd pcmcap = w->param.supp_pcm_size_rate; 5367185029Spjd } else { 5368185029Spjd fmtcap &= w->param.supp_stream_formats; 5369185029Spjd pcmcap &= w->param.supp_pcm_size_rate; 5370185029Spjd } 5371185029Spjd ch->io[ret++] = i; 5372185029Spjd } 5373185029Spjd ch->io[ret] = -1; 5374185029Spjd 5375185029Spjd ch->supp_stream_formats = fmtcap; 5376185029Spjd ch->supp_pcm_size_rate = pcmcap; 5377185029Spjd 5378185029Spjd /* 5379185029Spjd * 8bit = 0 5380185029Spjd * 16bit = 1 5381185029Spjd * 20bit = 2 5382185029Spjd * 24bit = 3 5383185029Spjd * 32bit = 4 5384185029Spjd */ 5385185029Spjd if (ret > 0) { 5386185029Spjd cap = pcmcap; 5387185029Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(cap)) 5388185029Spjd ch->bit16 = 1; 5389185029Spjd else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(cap)) 5390185029Spjd ch->bit16 = 0; 5391185029Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(cap)) 5392185029Spjd ch->bit32 = 4; 5393185029Spjd else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT(cap)) 5394185029Spjd ch->bit32 = 3; 5395185029Spjd else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT(cap)) 5396185029Spjd ch->bit32 = 2; 5397185029Spjd i = 0; 5398185029Spjd if (!(devinfo->function.audio.quirks & HDA_QUIRK_FORCESTEREO)) 5399185029Spjd ch->fmtlist[i++] = AFMT_S16_LE; 5400185029Spjd ch->fmtlist[i++] = AFMT_S16_LE | AFMT_STEREO; 5401185029Spjd if (ch->bit32 > 0) { 5402185029Spjd if (!(devinfo->function.audio.quirks & 5403185029Spjd HDA_QUIRK_FORCESTEREO)) 5404185029Spjd ch->fmtlist[i++] = AFMT_S32_LE; 5405185029Spjd ch->fmtlist[i++] = AFMT_S32_LE | AFMT_STEREO; 5406185029Spjd } 5407185029Spjd ch->fmtlist[i] = 0; 5408185029Spjd i = 0; 5409185029Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(cap)) 5410185029Spjd ch->pcmrates[i++] = 8000; 5411185029Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(cap)) 5412185029Spjd ch->pcmrates[i++] = 11025; 5413185029Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ(cap)) 5414185029Spjd ch->pcmrates[i++] = 16000; 5415185029Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ(cap)) 5416185029Spjd ch->pcmrates[i++] = 22050; 5417185029Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ(cap)) 5418185029Spjd ch->pcmrates[i++] = 32000; 5419185029Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ(cap)) 5420185029Spjd ch->pcmrates[i++] = 44100; 5421185029Spjd /* if (HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ(cap)) */ 5422185029Spjd ch->pcmrates[i++] = 48000; 5423185029Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ(cap)) 5424185029Spjd ch->pcmrates[i++] = 88200; 5425185029Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ(cap)) 5426185029Spjd ch->pcmrates[i++] = 96000; 5427185029Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ(cap)) 5428185029Spjd ch->pcmrates[i++] = 176400; 5429185029Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ(cap)) 5430275811Sdelphij ch->pcmrates[i++] = 192000; 5431185029Spjd /* if (HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ(cap)) */ 5432268085Sdelphij ch->pcmrates[i] = 0; 5433185029Spjd if (i > 0) { 5434185029Spjd ch->caps.minspeed = ch->pcmrates[0]; 5435185029Spjd ch->caps.maxspeed = ch->pcmrates[i - 1]; 5436185029Spjd } 5437185029Spjd } 5438185029Spjd 5439185029Spjd return (ret); 5440286570Smav} 5441185029Spjd 5442185029Spjdstatic void 5443185029Spjdhdac_dump_ctls(struct hdac_devinfo *devinfo, const char *banner, uint32_t flag) 5444185029Spjd{ 5445185029Spjd struct hdac_audio_ctl *ctl; 5446185029Spjd struct hdac_softc *sc = devinfo->codec->sc; 5447185029Spjd int i; 5448286570Smav uint32_t fl = 0; 5449185029Spjd 5450185029Spjd 5451185029Spjd if (flag == 0) { 5452185029Spjd fl = SOUND_MASK_VOLUME | SOUND_MASK_PCM | 5453275811Sdelphij SOUND_MASK_CD | SOUND_MASK_LINE | SOUND_MASK_RECLEV | 5454275811Sdelphij SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_OGAIN; 5455185029Spjd } 5456275811Sdelphij 5457185029Spjd i = 0; 5458185029Spjd while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 5459185029Spjd if (ctl->enable == 0 || ctl->widget == NULL || 5460286570Smav ctl->widget->enable == 0 || (ctl->ossmask & 5461185029Spjd (SOUND_MASK_SKIP | SOUND_MASK_DISABLE))) 5462185029Spjd continue; 5463185029Spjd if ((flag == 0 && (ctl->ossmask & ~fl)) || 5464185029Spjd (flag != 0 && (ctl->ossmask & flag))) { 5465185029Spjd if (banner != NULL) { 5466185029Spjd device_printf(sc->dev, "\n"); 5467286570Smav device_printf(sc->dev, "%s\n", banner); 5468286570Smav } 5469286570Smav goto hdac_ctl_dump_it_all; 5470286570Smav } 5471286570Smav } 5472286570Smav 5473286570Smav return; 5474286570Smav 5475286570Smavhdac_ctl_dump_it_all: 5476286570Smav i = 0; 5477185029Spjd while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 5478185029Spjd if (ctl->enable == 0 || ctl->widget == NULL || 5479185029Spjd ctl->widget->enable == 0) 5480185029Spjd continue; 5481286570Smav if (!((flag == 0 && (ctl->ossmask & ~fl)) || 5482286570Smav (flag != 0 && (ctl->ossmask & flag)))) 5483286570Smav continue; 5484286570Smav if (flag == 0) { 5485286570Smav device_printf(sc->dev, "\n"); 5486275811Sdelphij device_printf(sc->dev, "Unknown Ctl (OSS: %s)\n", 5487286598Smav hdac_audio_ctl_ossmixer_mask2name(ctl->ossmask)); 5488286598Smav } 5489286598Smav device_printf(sc->dev, " |\n"); 5490286598Smav device_printf(sc->dev, " +- nid: %2d index: %2d ", 5491185029Spjd ctl->widget->nid, ctl->index); 5492185029Spjd if (ctl->childwidget != NULL) 5493185029Spjd printf("(nid: %2d) ", ctl->childwidget->nid); 5494185029Spjd else 5495185029Spjd printf(" "); 5496275811Sdelphij printf("mute: %d step: %3d size: %3d off: %3d dir=0x%x ossmask=0x%08x\n", 5497185029Spjd ctl->mute, ctl->step, ctl->size, ctl->offset, ctl->dir, 5498185029Spjd ctl->ossmask); 5499185029Spjd } 5500185029Spjd} 5501185029Spjd 5502185029Spjdstatic void 5503286570Smavhdac_dump_audio_formats(struct hdac_softc *sc, uint32_t fcap, uint32_t pcmcap) 5504286570Smav{ 5505286570Smav uint32_t cap; 5506185029Spjd 5507268085Sdelphij cap = fcap; 5508268085Sdelphij if (cap != 0) { 5509185029Spjd device_printf(sc->dev, " Stream cap: 0x%08x\n", cap); 5510185029Spjd device_printf(sc->dev, " Format:"); 5511185029Spjd if (HDA_PARAM_SUPP_STREAM_FORMATS_AC3(cap)) 5512185029Spjd printf(" AC3"); 5513185029Spjd if (HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32(cap)) 5514185029Spjd printf(" FLOAT32"); 5515185029Spjd if (HDA_PARAM_SUPP_STREAM_FORMATS_PCM(cap)) 5516185029Spjd printf(" PCM"); 5517185029Spjd printf("\n"); 5518185029Spjd } 5519185029Spjd cap = pcmcap; 5520185029Spjd if (cap != 0) { 5521185029Spjd device_printf(sc->dev, " PCM cap: 0x%08x\n", cap); 5522185029Spjd device_printf(sc->dev, " PCM size:"); 5523185029Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(cap)) 5524185029Spjd printf(" 8"); 5525185029Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(cap)) 5526185029Spjd printf(" 16"); 5527185029Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT(cap)) 5528185029Spjd printf(" 20"); 5529185029Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT(cap)) 5530185029Spjd printf(" 24"); 5531185029Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(cap)) 5532185029Spjd printf(" 32"); 5533185029Spjd printf("\n"); 5534185029Spjd device_printf(sc->dev, " PCM rate:"); 5535185029Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(cap)) 5536185029Spjd printf(" 8"); 5537219089Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(cap)) 5538185029Spjd printf(" 11"); 5539219089Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ(cap)) 5540219089Spjd printf(" 16"); 5541185029Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ(cap)) 5542185029Spjd printf(" 22"); 5543251478Sdelphij if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ(cap)) 5544251478Sdelphij printf(" 32"); 5545251478Sdelphij if (HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ(cap)) 5546251478Sdelphij printf(" 44"); 5547251478Sdelphij printf(" 48"); 5548251478Sdelphij if (HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ(cap)) 5549251478Sdelphij printf(" 88"); 5550185029Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ(cap)) 5551185029Spjd printf(" 96"); 5552185029Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ(cap)) 5553185029Spjd printf(" 176"); 5554185029Spjd if (HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ(cap)) 5555185029Spjd printf(" 192"); 5556185029Spjd printf("\n"); 5557185029Spjd } 5558185029Spjd} 5559185029Spjd 5560185029Spjdstatic void 5561185029Spjdhdac_dump_pin(struct hdac_softc *sc, struct hdac_widget *w) 5562185029Spjd{ 5563185029Spjd uint32_t pincap, wcap; 5564185029Spjd 5565185029Spjd pincap = w->wclass.pin.cap; 5566185029Spjd wcap = w->param.widget_cap; 5567185029Spjd 5568249195Smm device_printf(sc->dev, " Pin cap: 0x%08x\n", pincap); 5569185029Spjd device_printf(sc->dev, " "); 5570185029Spjd if (HDA_PARAM_PIN_CAP_IMP_SENSE_CAP(pincap)) 5571185029Spjd printf(" ISC"); 5572185029Spjd if (HDA_PARAM_PIN_CAP_TRIGGER_REQD(pincap)) 5573185029Spjd printf(" TRQD"); 5574185029Spjd if (HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(pincap)) 5575185029Spjd printf(" PDC"); 5576185029Spjd if (HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap)) 5577185029Spjd printf(" HP"); 5578209962Smm if (HDA_PARAM_PIN_CAP_OUTPUT_CAP(pincap)) 5579209962Smm printf(" OUT"); 5580209962Smm if (HDA_PARAM_PIN_CAP_INPUT_CAP(pincap)) 5581209962Smm printf(" IN"); 5582209962Smm if (HDA_PARAM_PIN_CAP_BALANCED_IO_PINS(pincap)) 5583209962Smm printf(" BAL"); 5584185029Spjd if (HDA_PARAM_PIN_CAP_VREF_CTRL(pincap)) { 5585185029Spjd printf(" VREF["); 5586209962Smm if (HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap)) 5587185029Spjd printf(" 50"); 5588185029Spjd if (HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap)) 5589185029Spjd printf(" 80"); 5590185029Spjd if (HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap)) 5591185029Spjd printf(" 100"); 5592185029Spjd if (HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND(pincap)) 5593185029Spjd printf(" GROUND"); 5594185029Spjd if (HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ(pincap)) 5595185029Spjd printf(" HIZ"); 5596185029Spjd printf(" ]"); 5597185029Spjd } 5598185029Spjd if (HDA_PARAM_PIN_CAP_EAPD_CAP(pincap)) 5599185029Spjd printf(" EAPD"); 5600185029Spjd if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(wcap)) 5601185029Spjd printf(" : UNSOL"); 5602185029Spjd printf("\n"); 5603185029Spjd device_printf(sc->dev, " Pin config: 0x%08x\n", 5604185029Spjd w->wclass.pin.config); 5605247187Smm device_printf(sc->dev, " Pin control: 0x%08x", w->wclass.pin.ctrl); 5606205231Skmacy if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE) 5607185029Spjd printf(" HP"); 5608206796Spjd if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE) 5609206796Spjd printf(" IN"); 5610205231Skmacy if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE) 5611205231Skmacy printf(" OUT"); 5612205231Skmacy printf("\n"); 5613205231Skmacy} 5614206796Spjd 5615205231Skmacystatic void 5616205231Skmacyhdac_dump_amp(struct hdac_softc *sc, uint32_t cap, char *banner) 5617205231Skmacy{ 5618206796Spjd device_printf(sc->dev, " %s amp: 0x%08x\n", banner, cap); 5619205231Skmacy device_printf(sc->dev, " " 5620205231Skmacy "mute=%d step=%d size=%d offset=%d\n", 5621205231Skmacy HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(cap), 5622205231Skmacy HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(cap), 5623205231Skmacy HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(cap), 5624205231Skmacy HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(cap)); 5625205231Skmacy} 5626205231Skmacy 5627185029Spjdstatic void 5628185029Spjdhdac_dump_nodes(struct hdac_devinfo *devinfo) 5629185029Spjd{ 5630185029Spjd struct hdac_softc *sc = devinfo->codec->sc; 5631185029Spjd struct hdac_widget *w, *cw; 5632185029Spjd int i, j; 5633185029Spjd 5634185029Spjd device_printf(sc->dev, "\n"); 5635185029Spjd device_printf(sc->dev, "Default Parameter\n"); 5636185029Spjd device_printf(sc->dev, "-----------------\n"); 5637185029Spjd hdac_dump_audio_formats(sc, 5638185029Spjd devinfo->function.audio.supp_stream_formats, 5639185029Spjd devinfo->function.audio.supp_pcm_size_rate); 5640185029Spjd device_printf(sc->dev, " IN amp: 0x%08x\n", 5641185029Spjd devinfo->function.audio.inamp_cap); 5642185029Spjd device_printf(sc->dev, " OUT amp: 0x%08x\n", 5643185029Spjd devinfo->function.audio.outamp_cap); 5644275811Sdelphij for (i = devinfo->startnode; i < devinfo->endnode; i++) { 5645185029Spjd w = hdac_widget_get(devinfo, i); 5646185029Spjd if (w == NULL) { 5647185029Spjd device_printf(sc->dev, "Ghost widget nid=%d\n", i); 5648286570Smav continue; 5649185029Spjd } 5650185029Spjd device_printf(sc->dev, "\n"); 5651185029Spjd device_printf(sc->dev, " nid: %d [%s]%s\n", w->nid, 5652185029Spjd HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap) ? 5653185029Spjd "DIGITAL" : "ANALOG", 5654185029Spjd (w->enable == 0) ? " [DISABLED]" : ""); 5655185029Spjd device_printf(sc->dev, " name: %s\n", w->name); 5656185029Spjd device_printf(sc->dev, " widget_cap: 0x%08x\n", 5657185029Spjd w->param.widget_cap); 5658185029Spjd device_printf(sc->dev, " Parse flags: 0x%08x\n", 5659185029Spjd w->pflags); 5660185029Spjd device_printf(sc->dev, " Ctl flags: 0x%08x\n", 5661185029Spjd w->ctlflags); 5662185029Spjd if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT || 5663185029Spjd w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) { 5664185029Spjd hdac_dump_audio_formats(sc, 5665185029Spjd w->param.supp_stream_formats, 5666185029Spjd w->param.supp_pcm_size_rate); 5667185029Spjd } else if (w->type == 5668185029Spjd HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) 5669185029Spjd hdac_dump_pin(sc, w); 5670185029Spjd if (w->param.eapdbtl != HDAC_INVALID) 5671286570Smav device_printf(sc->dev, " EAPD: 0x%08x\n", 5672275811Sdelphij w->param.eapdbtl); 5673275811Sdelphij if (HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP(w->param.widget_cap) && 5674185029Spjd w->param.outamp_cap != 0) 5675275811Sdelphij hdac_dump_amp(sc, w->param.outamp_cap, "Output"); 5676185029Spjd if (HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP(w->param.widget_cap) && 5677185029Spjd w->param.inamp_cap != 0) 5678185029Spjd hdac_dump_amp(sc, w->param.inamp_cap, " Input"); 5679185029Spjd device_printf(sc->dev, " connections: %d\n", w->nconns); 5680185029Spjd for (j = 0; j < w->nconns; j++) { 5681286570Smav cw = hdac_widget_get(devinfo, w->conns[j]); 5682185029Spjd device_printf(sc->dev, " |\n"); 5683185029Spjd device_printf(sc->dev, " + <- nid=%d [%s]", 5684185029Spjd w->conns[j], (cw == NULL) ? "GHOST!" : cw->name); 5685185029Spjd if (cw == NULL) 5686185029Spjd printf(" [UNKNOWN]"); 5687275811Sdelphij else if (cw->enable == 0) 5688185029Spjd printf(" [DISABLED]"); 5689185029Spjd if (w->nconns > 1 && w->selconn == j && w->type != 5690185029Spjd HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) 5691185029Spjd printf(" (selected)"); 5692275811Sdelphij printf("\n"); 5693185029Spjd } 5694185029Spjd } 5695185029Spjd 5696185029Spjd} 5697286570Smav 5698286570Smavstatic int 5699286570Smavhdac_dump_dac_internal(struct hdac_devinfo *devinfo, nid_t nid, int depth) 5700185029Spjd{ 5701185029Spjd struct hdac_widget *w, *cw; 5702185029Spjd struct hdac_softc *sc = devinfo->codec->sc; 5703185029Spjd int i; 5704185029Spjd 5705185029Spjd if (depth > HDA_PARSE_MAXDEPTH) 5706185029Spjd return (0); 5707185029Spjd 5708286570Smav w = hdac_widget_get(devinfo, nid); 5709286570Smav if (w == NULL || w->enable == 0 || !(w->pflags & HDA_DAC_PATH)) 5710275811Sdelphij return (0); 5711185029Spjd 5712185029Spjd if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) { 5713185029Spjd device_printf(sc->dev, "\n"); 5714185029Spjd device_printf(sc->dev, " nid=%d [%s]\n", w->nid, w->name); 5715185029Spjd device_printf(sc->dev, " ^\n"); 5716275811Sdelphij device_printf(sc->dev, " |\n"); 5717275811Sdelphij device_printf(sc->dev, " +-----<------+\n"); 5718185029Spjd } else { 5719286570Smav device_printf(sc->dev, " ^\n"); 5720286570Smav device_printf(sc->dev, " |\n"); 5721185029Spjd device_printf(sc->dev, " "); 5722185029Spjd printf(" nid=%d [%s]\n", w->nid, w->name); 5723185029Spjd } 5724185029Spjd 5725185029Spjd if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT) { 5726275811Sdelphij return (1); 5727185029Spjd } else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) { 5728275811Sdelphij for (i = 0; i < w->nconns; i++) { 5729185029Spjd cw = hdac_widget_get(devinfo, w->conns[i]); 5730185029Spjd if (cw == NULL || cw->enable == 0 || cw->type == 5731286598Smav HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) 5732185029Spjd continue; 5733185029Spjd if (hdac_dump_dac_internal(devinfo, cw->nid, 5734185029Spjd depth + 1) != 0) 5735286570Smav return (1); 5736185029Spjd } 5737185029Spjd } else if ((w->type == 5738185029Spjd HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR || 5739185029Spjd w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) && 5740185029Spjd w->selconn > -1 && w->selconn < w->nconns) { 5741275811Sdelphij if (hdac_dump_dac_internal(devinfo, w->conns[w->selconn], 5742185029Spjd depth + 1) != 0) 5743251478Sdelphij return (1); 5744251478Sdelphij } 5745251478Sdelphij 5746251478Sdelphij return (0); 5747251478Sdelphij} 5748185029Spjd 5749208373Smmstatic void 5750251478Sdelphijhdac_dump_dac(struct hdac_devinfo *devinfo) 5751251478Sdelphij{ 5752185029Spjd struct hdac_widget *w; 5753275811Sdelphij struct hdac_softc *sc = devinfo->codec->sc; 5754185029Spjd int i, printed = 0; 5755251478Sdelphij 5756251478Sdelphij for (i = devinfo->startnode; i < devinfo->endnode; i++) { 5757185029Spjd w = hdac_widget_get(devinfo, i); 5758251478Sdelphij if (w == NULL || w->enable == 0) 5759251478Sdelphij continue; 5760185029Spjd if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX || 5761185029Spjd !(w->pflags & HDA_DAC_PATH)) 5762228103Smm continue; 5763251478Sdelphij if (printed == 0) { 5764185029Spjd printed = 1; 5765185029Spjd device_printf(sc->dev, "\n"); 5766185029Spjd device_printf(sc->dev, "Playback path:\n"); 5767185029Spjd } 5768251478Sdelphij hdac_dump_dac_internal(devinfo, w->nid, 0); 5769251478Sdelphij } 5770251478Sdelphij} 5771185029Spjd 5772251478Sdelphijstatic void 5773185029Spjdhdac_dump_adc(struct hdac_devinfo *devinfo) 5774286570Smav{ 5775275811Sdelphij struct hdac_widget *w, *cw; 5776286570Smav struct hdac_softc *sc = devinfo->codec->sc; 5777185029Spjd int i, j; 5778205231Skmacy int printed = 0; 5779185029Spjd char ossdevs[256]; 5780251478Sdelphij 5781251478Sdelphij for (i = devinfo->startnode; i < devinfo->endnode; i++) { 5782251478Sdelphij w = hdac_widget_get(devinfo, i); 5783251478Sdelphij if (w == NULL || w->enable == 0) 5784251478Sdelphij continue; 5785251478Sdelphij if (!(w->pflags & HDA_ADC_RECSEL)) 5786185029Spjd continue; 5787185029Spjd if (printed == 0) { 5788286570Smav printed = 1; 5789206796Spjd device_printf(sc->dev, "\n"); 5790251478Sdelphij device_printf(sc->dev, "Recording sources:\n"); 5791251478Sdelphij } 5792185029Spjd device_printf(sc->dev, "\n"); 5793205231Skmacy device_printf(sc->dev, " nid=%d [%s]\n", w->nid, w->name); 5794185029Spjd for (j = 0; j < w->nconns; j++) { 5795185029Spjd cw = hdac_widget_get(devinfo, w->conns[j]); 5796185029Spjd if (cw == NULL || cw->enable == 0) 5797185029Spjd continue; 5798185029Spjd hdac_audio_ctl_ossmixer_mask2allname(cw->ctlflags, 5799185029Spjd ossdevs, sizeof(ossdevs)); 5800185029Spjd device_printf(sc->dev, " |\n"); 5801185029Spjd device_printf(sc->dev, " + <- nid=%d [%s]", 5802275811Sdelphij cw->nid, cw->name); 5803185029Spjd if (strlen(ossdevs) > 0) { 5804275811Sdelphij printf(" [recsrc: %s]", ossdevs); 5805275811Sdelphij } 5806205231Skmacy printf("\n"); 5807185029Spjd } 5808272708Savg } 5809251478Sdelphij} 5810251478Sdelphij 5811251478Sdelphijstatic void 5812275811Sdelphijhdac_dump_pcmchannels(struct hdac_softc *sc, int pcnt, int rcnt) 5813251478Sdelphij{ 5814251478Sdelphij nid_t *nids; 5815251478Sdelphij 5816185029Spjd if (pcnt > 0) { 5817275811Sdelphij device_printf(sc->dev, "\n"); 5818185029Spjd device_printf(sc->dev, " PCM Playback: %d\n", pcnt); 5819275811Sdelphij hdac_dump_audio_formats(sc, sc->play.supp_stream_formats, 5820275811Sdelphij sc->play.supp_pcm_size_rate); 5821206796Spjd device_printf(sc->dev, " DAC:"); 5822275811Sdelphij for (nids = sc->play.io; *nids != -1; nids++) 5823251478Sdelphij printf(" %d", *nids); 5824205231Skmacy printf("\n"); 5825185029Spjd } 5826185029Spjd 5827185029Spjd if (rcnt > 0) { 5828185029Spjd device_printf(sc->dev, "\n"); 5829185029Spjd device_printf(sc->dev, " PCM Record: %d\n", rcnt); 5830185029Spjd hdac_dump_audio_formats(sc, sc->play.supp_stream_formats, 5831275811Sdelphij sc->rec.supp_pcm_size_rate); 5832185029Spjd device_printf(sc->dev, " ADC:"); 5833185029Spjd for (nids = sc->rec.io; *nids != -1; nids++) 5834185029Spjd printf(" %d", *nids); 5835185029Spjd printf("\n"); 5836185029Spjd } 5837205231Skmacy} 5838185029Spjd 5839185029Spjdstatic void 5840185029Spjdhdac_release_resources(struct hdac_softc *sc) 5841275811Sdelphij{ 5842185029Spjd struct hdac_devinfo *devinfo = NULL; 5843185029Spjd device_t *devlist = NULL; 5844185029Spjd int i, devcount; 5845185029Spjd 5846275811Sdelphij if (sc == NULL) 5847185029Spjd return; 5848185029Spjd 5849205231Skmacy hdac_lock(sc); 5850185029Spjd sc->polling = 0; 5851185029Spjd sc->poll_ival = 0; 5852185029Spjd callout_stop(&sc->poll_hda); 5853185029Spjd callout_stop(&sc->poll_hdac); 5854185029Spjd callout_stop(&sc->poll_jack); 5855185029Spjd hdac_reset(sc); 5856185029Spjd hdac_unlock(sc); 5857185029Spjd taskqueue_drain(taskqueue_thread, &sc->unsolq_task); 5858185029Spjd callout_drain(&sc->poll_hda); 5859286570Smav callout_drain(&sc->poll_hdac); 5860185029Spjd callout_drain(&sc->poll_jack); 5861185029Spjd 5862185029Spjd hdac_irq_free(sc); 5863185029Spjd 5864185029Spjd device_get_children(sc->dev, &devlist, &devcount); 5865185029Spjd for (i = 0; devlist != NULL && i < devcount; i++) { 5866185029Spjd devinfo = (struct hdac_devinfo *)device_get_ivars(devlist[i]); 5867205231Skmacy if (devinfo == NULL) 5868185029Spjd continue; 5869185029Spjd if (devinfo->widget != NULL) 5870185029Spjd free(devinfo->widget, M_HDAC); 5871185029Spjd if (devinfo->node_type == 5872185029Spjd HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO && 5873286570Smav devinfo->function.audio.ctl != NULL) 5874275811Sdelphij free(devinfo->function.audio.ctl, M_HDAC); 5875251478Sdelphij free(devinfo, M_HDAC); 5876251478Sdelphij device_delete_child(sc->dev, devlist[i]); 5877251478Sdelphij } 5878286570Smav if (devlist != NULL) 5879251478Sdelphij free(devlist, M_TEMP); 5880251478Sdelphij 5881251478Sdelphij for (i = 0; i < HDAC_CODEC_MAX; i++) { 5882251478Sdelphij if (sc->codecs[i] != NULL) 5883286570Smav free(sc->codecs[i], M_HDAC); 5884286570Smav sc->codecs[i] = NULL; 5885286570Smav } 5886251478Sdelphij 5887286598Smav hdac_dma_free(sc, &sc->pos_dma); 5888286598Smav hdac_dma_free(sc, &sc->rirb_dma); 5889286598Smav hdac_dma_free(sc, &sc->corb_dma); 5890286598Smav if (sc->play.blkcnt > 0) 5891286598Smav hdac_dma_free(sc, &sc->play.bdl_dma); 5892286598Smav if (sc->rec.blkcnt > 0) 5893286598Smav hdac_dma_free(sc, &sc->rec.bdl_dma); 5894286598Smav if (sc->chan_dmat != NULL) { 5895286598Smav bus_dma_tag_destroy(sc->chan_dmat); 5896286598Smav sc->chan_dmat = NULL; 5897286598Smav } 5898286598Smav hdac_mem_free(sc); 5899286598Smav snd_mtxfree(sc->lock); 5900286598Smav free(sc, M_DEVBUF); 5901286598Smav} 5902286598Smav 5903286598Smav/* This function surely going to make its way into upper level someday. */ 5904286598Smavstatic void 5905286598Smavhdac_config_fetch(struct hdac_softc *sc, uint32_t *on, uint32_t *off) 5906286598Smav{ 5907286598Smav const char *res = NULL; 5908286598Smav int i = 0, j, k, len, inv; 5909286598Smav 5910275811Sdelphij if (on != NULL) 5911286570Smav *on = 0; 5912185029Spjd if (off != NULL) 5913286570Smav *off = 0; 5914251478Sdelphij if (sc == NULL) 5915185029Spjd return; 5916185029Spjd if (resource_string_value(device_get_name(sc->dev), 5917185029Spjd device_get_unit(sc->dev), "config", &res) != 0) 5918185029Spjd return; 5919286570Smav if (!(res != NULL && strlen(res) > 0)) 5920286570Smav return; 5921185029Spjd HDA_BOOTVERBOSE( 5922185029Spjd device_printf(sc->dev, "HDA_DEBUG: HDA Config:"); 5923185029Spjd ); 5924251478Sdelphij for (;;) { 5925251478Sdelphij while (res[i] != '\0' && 5926251478Sdelphij (res[i] == ',' || isspace(res[i]) != 0)) 5927251478Sdelphij i++; 5928251478Sdelphij if (res[i] == '\0') { 5929251478Sdelphij HDA_BOOTVERBOSE( 5930251478Sdelphij printf("\n"); 5931251478Sdelphij ); 5932251478Sdelphij return; 5933251478Sdelphij } 5934251478Sdelphij j = i; 5935251478Sdelphij while (res[j] != '\0' && 5936286570Smav !(res[j] == ',' || isspace(res[j]) != 0)) 5937286570Smav j++; 5938286570Smav len = j - i; 5939251478Sdelphij if (len > 2 && strncmp(res + i, "no", 2) == 0) 5940251478Sdelphij inv = 2; 5941251478Sdelphij else 5942251478Sdelphij inv = 0; 5943251478Sdelphij for (k = 0; len > inv && k < HDAC_QUIRKS_TAB_LEN; k++) { 5944251478Sdelphij if (strncmp(res + i + inv, 5945251478Sdelphij hdac_quirks_tab[k].key, len - inv) != 0) 5946251478Sdelphij continue; 5947286570Smav if (len - inv != strlen(hdac_quirks_tab[k].key)) 5948286570Smav break; 5949251478Sdelphij HDA_BOOTVERBOSE( 5950251478Sdelphij printf(" %s%s", (inv != 0) ? "no" : "", 5951251478Sdelphij hdac_quirks_tab[k].key); 5952251478Sdelphij ); 5953275811Sdelphij if (inv == 0 && on != NULL) 5954275811Sdelphij *on |= hdac_quirks_tab[k].value; 5955286570Smav else if (inv != 0 && off != NULL) 5956275811Sdelphij *off |= hdac_quirks_tab[k].value; 5957251478Sdelphij break; 5958286570Smav } 5959251478Sdelphij i = j; 5960286570Smav } 5961286570Smav} 5962286570Smav 5963251478Sdelphij#ifdef SND_DYNSYSCTL 5964251478Sdelphijstatic int 5965251478Sdelphijsysctl_hdac_polling(SYSCTL_HANDLER_ARGS) 5966251478Sdelphij{ 5967251478Sdelphij struct hdac_softc *sc; 5968251478Sdelphij struct hdac_devinfo *devinfo; 5969251478Sdelphij device_t dev; 5970251478Sdelphij uint32_t ctl; 5971251478Sdelphij int err, val; 5972251478Sdelphij 5973251478Sdelphij dev = oidp->oid_arg1; 5974251478Sdelphij devinfo = pcm_getdevinfo(dev); 5975286570Smav if (devinfo == NULL || devinfo->codec == NULL || 5976286570Smav devinfo->codec->sc == NULL) 5977251478Sdelphij return (EINVAL); 5978274172Savg sc = devinfo->codec->sc; 5979274172Savg hdac_lock(sc); 5980274172Savg val = sc->polling; 5981274172Savg hdac_unlock(sc); 5982274172Savg err = sysctl_handle_int(oidp, &val, 0, req); 5983286570Smav 5984286570Smav if (err != 0 || req->newptr == NULL) 5985274172Savg return (err); 5986286598Smav if (val < 0 || val > 1) 5987286598Smav return (EINVAL); 5988286598Smav 5989286598Smav hdac_lock(sc); 5990286598Smav if (val != sc->polling) { 5991286598Smav if (hda_chan_active(sc) != 0) 5992286598Smav err = EBUSY; 5993251478Sdelphij else if (val == 0) { 5994251478Sdelphij callout_stop(&sc->poll_hdac); 5995251478Sdelphij hdac_unlock(sc); 5996251478Sdelphij callout_drain(&sc->poll_hdac); 5997185029Spjd hdac_lock(sc); 5998185029Spjd HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT, 5999185029Spjd sc->rirb_size / 2); 6000185029Spjd ctl = HDAC_READ_1(&sc->mem, HDAC_RIRBCTL); 6001185029Spjd ctl |= HDAC_RIRBCTL_RINTCTL; 6002185029Spjd HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, ctl); 6003185029Spjd HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, 6004185029Spjd HDAC_INTCTL_CIE | HDAC_INTCTL_GIE); 6005185029Spjd sc->polling = 0; 6006251478Sdelphij DELAY(1000); 6007286598Smav } else { 6008185029Spjd HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, 0); 6009185029Spjd HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT, 0); 6010185029Spjd ctl = HDAC_READ_1(&sc->mem, HDAC_RIRBCTL); 6011251478Sdelphij ctl &= ~HDAC_RIRBCTL_RINTCTL; 6012251478Sdelphij HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, ctl); 6013251478Sdelphij hdac_unlock(sc); 6014185029Spjd taskqueue_drain(taskqueue_thread, &sc->unsolq_task); 6015251478Sdelphij hdac_lock(sc); 6016185029Spjd callout_reset(&sc->poll_hdac, 1, hdac_poll_callback, 6017286570Smav sc); 6018185029Spjd sc->polling = 1; 6019251478Sdelphij DELAY(1000); 6020185029Spjd } 6021251478Sdelphij } 6022185029Spjd hdac_unlock(sc); 6023251478Sdelphij 6024275096Sdelphij return (err); 6025185029Spjd} 6026185029Spjd 6027185029Spjdstatic int 6028185029Spjdsysctl_hdac_polling_interval(SYSCTL_HANDLER_ARGS) 6029185029Spjd{ 6030185029Spjd struct hdac_softc *sc; 6031185029Spjd struct hdac_devinfo *devinfo; 6032185029Spjd device_t dev; 6033185029Spjd int err, val; 6034185029Spjd 6035208373Smm dev = oidp->oid_arg1; 6036185029Spjd devinfo = pcm_getdevinfo(dev); 6037208373Smm if (devinfo == NULL || devinfo->codec == NULL || 6038208373Smm devinfo->codec->sc == NULL) 6039251478Sdelphij return (EINVAL); 6040185029Spjd sc = devinfo->codec->sc; 6041185029Spjd hdac_lock(sc); 6042185029Spjd val = ((uint64_t)sc->poll_ival * 1000) / hz; 6043251478Sdelphij hdac_unlock(sc); 6044286570Smav err = sysctl_handle_int(oidp, &val, 0, req); 6045251478Sdelphij 6046251478Sdelphij if (err != 0 || req->newptr == NULL) 6047251478Sdelphij return (err); 6048251478Sdelphij 6049251478Sdelphij if (val < 1) 6050251478Sdelphij val = 1; 6051251478Sdelphij if (val > 5000) 6052251478Sdelphij val = 5000; 6053251478Sdelphij val = ((uint64_t)val * hz) / 1000; 6054251478Sdelphij if (val < 1) 6055251478Sdelphij val = 1; 6056251478Sdelphij if (val > (hz * 5)) 6057251478Sdelphij val = hz * 5; 6058251478Sdelphij 6059251478Sdelphij hdac_lock(sc); 6060251478Sdelphij sc->poll_ival = val; 6061251478Sdelphij hdac_unlock(sc); 6062286570Smav 6063251478Sdelphij return (err); 6064251478Sdelphij} 6065268075Sdelphij 6066286570Smav#ifdef SND_DEBUG 6067286570Smavstatic int 6068251478Sdelphijsysctl_hdac_pindump(SYSCTL_HANDLER_ARGS) 6069286570Smav{ 6070286570Smav struct hdac_softc *sc; 6071286570Smav struct hdac_devinfo *devinfo; 6072251478Sdelphij struct hdac_widget *w; 6073251478Sdelphij device_t dev; 6074251478Sdelphij uint32_t res, pincap, timeout; 6075286570Smav int i, err, val; 6076286570Smav nid_t cad; 6077269086Sdelphij 6078251478Sdelphij dev = oidp->oid_arg1; 6079251478Sdelphij devinfo = pcm_getdevinfo(dev); 6080251478Sdelphij if (devinfo == NULL || devinfo->codec == NULL || 6081251478Sdelphij devinfo->codec->sc == NULL) 6082286570Smav return (EINVAL); 6083251478Sdelphij val = 0; 6084286570Smav err = sysctl_handle_int(oidp, &val, 0, req); 6085251478Sdelphij if (err != 0 || req->newptr == NULL || val == 0) 6086251478Sdelphij return (err); 6087274628Savg sc = devinfo->codec->sc; 6088274628Savg cad = devinfo->codec->cad; 6089274628Savg hdac_lock(sc); 6090274628Savg device_printf(dev, "HDAC Dump AFG [nid=%d]:\n", devinfo->nid); 6091274628Savg for (i = devinfo->startnode; i < devinfo->endnode; i++) { 6092251478Sdelphij w = hdac_widget_get(devinfo, i); 6093251478Sdelphij if (w == NULL || w->type != 6094251478Sdelphij HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) 6095251478Sdelphij continue; 6096274628Savg pincap = w->wclass.pin.cap; 6097274628Savg if ((HDA_PARAM_PIN_CAP_IMP_SENSE_CAP(pincap) || 6098274628Savg HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(pincap)) && 6099274628Savg HDA_PARAM_PIN_CAP_TRIGGER_REQD(pincap)) { 6100286570Smav timeout = 10000; 6101251478Sdelphij hdac_command(sc, 6102286570Smav HDA_CMD_SET_PIN_SENSE(cad, w->nid, 0), cad); 6103251478Sdelphij do { 6104251478Sdelphij res = hdac_command(sc, 6105251478Sdelphij HDA_CMD_GET_PIN_SENSE(cad, w->nid), cad); 6106251478Sdelphij if (res != 0x7fffffff) 6107251478Sdelphij break; 6108251478Sdelphij DELAY(10); 6109251478Sdelphij } while (--timeout != 0); 6110251478Sdelphij } else { 6111251478Sdelphij timeout = -1; 6112251478Sdelphij res = hdac_command(sc, HDA_CMD_GET_PIN_SENSE(cad, 6113251478Sdelphij w->nid), cad); 6114251478Sdelphij } 6115251478Sdelphij device_printf(dev, 6116251478Sdelphij "PIN_SENSE: nid=%-3d timeout=%d res=0x%08x [%s]\n", 6117251478Sdelphij w->nid, timeout, res, 6118251478Sdelphij (w->enable == 0) ? "DISABLED" : "ENABLED"); 6119251478Sdelphij } 6120251478Sdelphij device_printf(dev, 6121251478Sdelphij "NumGPIO=%d NumGPO=%d NumGPI=%d GPIWake=%d GPIUnsol=%d\n", 6122251478Sdelphij HDA_PARAM_GPIO_COUNT_NUM_GPIO(devinfo->function.audio.gpio), 6123251478Sdelphij HDA_PARAM_GPIO_COUNT_NUM_GPO(devinfo->function.audio.gpio), 6124251478Sdelphij HDA_PARAM_GPIO_COUNT_NUM_GPI(devinfo->function.audio.gpio), 6125251478Sdelphij HDA_PARAM_GPIO_COUNT_GPI_WAKE(devinfo->function.audio.gpio), 6126251478Sdelphij HDA_PARAM_GPIO_COUNT_GPI_UNSOL(devinfo->function.audio.gpio)); 6127251478Sdelphij if (HDA_PARAM_GPIO_COUNT_NUM_GPI(devinfo->function.audio.gpio) > 0) { 6128251478Sdelphij device_printf(dev, " GPI:"); 6129251478Sdelphij res = hdac_command(sc, 6130251478Sdelphij HDA_CMD_GET_GPI_DATA(cad, devinfo->nid), cad); 6131251478Sdelphij printf(" data=0x%08x", res); 6132251478Sdelphij res = hdac_command(sc, 6133251478Sdelphij HDA_CMD_GET_GPI_WAKE_ENABLE_MASK(cad, devinfo->nid), 6134251478Sdelphij cad); 6135251478Sdelphij printf(" wake=0x%08x", res); 6136251478Sdelphij res = hdac_command(sc, 6137251478Sdelphij HDA_CMD_GET_GPI_UNSOLICITED_ENABLE_MASK(cad, devinfo->nid), 6138251478Sdelphij cad); 6139251478Sdelphij printf(" unsol=0x%08x", res); 6140251478Sdelphij res = hdac_command(sc, 6141251478Sdelphij HDA_CMD_GET_GPI_STICKY_MASK(cad, devinfo->nid), cad); 6142251478Sdelphij printf(" sticky=0x%08x\n", res); 6143251478Sdelphij } 6144251478Sdelphij if (HDA_PARAM_GPIO_COUNT_NUM_GPO(devinfo->function.audio.gpio) > 0) { 6145251478Sdelphij device_printf(dev, " GPO:"); 6146251478Sdelphij res = hdac_command(sc, 6147286570Smav HDA_CMD_GET_GPO_DATA(cad, devinfo->nid), cad); 6148286570Smav printf(" data=0x%08x\n", res); 6149286570Smav } 6150251478Sdelphij if (HDA_PARAM_GPIO_COUNT_NUM_GPIO(devinfo->function.audio.gpio) > 0) { 6151251478Sdelphij device_printf(dev, "GPI0:"); 6152251478Sdelphij res = hdac_command(sc, 6153251478Sdelphij HDA_CMD_GET_GPIO_DATA(cad, devinfo->nid), cad); 6154251478Sdelphij printf(" data=0x%08x", res); 6155251478Sdelphij res = hdac_command(sc, 6156251478Sdelphij HDA_CMD_GET_GPIO_ENABLE_MASK(cad, devinfo->nid), cad); 6157251478Sdelphij printf(" enable=0x%08x", res); 6158251478Sdelphij res = hdac_command(sc, 6159251478Sdelphij HDA_CMD_GET_GPIO_DIRECTION(cad, devinfo->nid), cad); 6160251478Sdelphij printf(" direction=0x%08x\n", res); 6161251478Sdelphij res = hdac_command(sc, 6162251478Sdelphij HDA_CMD_GET_GPIO_WAKE_ENABLE_MASK(cad, devinfo->nid), cad); 6163251478Sdelphij device_printf(dev, " wake=0x%08x", res); 6164251478Sdelphij res = hdac_command(sc, 6165251478Sdelphij HDA_CMD_GET_GPIO_UNSOLICITED_ENABLE_MASK(cad, devinfo->nid), 6166251478Sdelphij cad); 6167251478Sdelphij printf(" unsol=0x%08x", res); 6168251478Sdelphij res = hdac_command(sc, 6169251478Sdelphij HDA_CMD_GET_GPIO_STICKY_MASK(cad, devinfo->nid), cad); 6170251478Sdelphij printf(" sticky=0x%08x\n", res); 6171251478Sdelphij } 6172251478Sdelphij hdac_unlock(sc); 6173251478Sdelphij return (0); 6174251478Sdelphij} 6175251478Sdelphij#endif 6176251478Sdelphij#endif 6177251478Sdelphij 6178251478Sdelphijstatic void 6179251478Sdelphijhdac_attach2(void *arg) 6180251478Sdelphij{ 6181251478Sdelphij struct hdac_softc *sc; 6182251478Sdelphij struct hdac_widget *w; 6183251478Sdelphij struct hdac_audio_ctl *ctl; 6184251478Sdelphij uint32_t quirks_on, quirks_off; 6185275811Sdelphij int pcnt, rcnt, codec_index; 6186251478Sdelphij int i; 6187286570Smav char status[SND_STATUSLEN]; 6188286570Smav device_t *devlist = NULL; 6189251478Sdelphij int devcount; 6190251478Sdelphij struct hdac_devinfo *devinfo = NULL; 6191251478Sdelphij 6192251478Sdelphij sc = (struct hdac_softc *)arg; 6193286570Smav 6194286570Smav hdac_config_fetch(sc, &quirks_on, &quirks_off); 6195286570Smav 6196286570Smav HDA_BOOTVERBOSE( 6197274172Savg device_printf(sc->dev, "HDA_DEBUG: HDA Config: on=0x%08x off=0x%08x\n", 6198286570Smav quirks_on, quirks_off); 6199251478Sdelphij ); 6200251478Sdelphij 6201251478Sdelphij if (resource_int_value(device_get_name(sc->dev), 6202251478Sdelphij device_get_unit(sc->dev), "codec_index", &codec_index) != 0) { 6203185029Spjd switch (sc->pci_subvendor) { 6204185029Spjd case GB_G33S2H_SUBVENDOR: 6205185029Spjd codec_index = 2; 6206185029Spjd break; 6207185029Spjd default: 6208185029Spjd codec_index = 0; 6209185029Spjd break; 6210185029Spjd } 6211185029Spjd } 6212208373Smm 6213219089Spjd hdac_lock(sc); 6214251478Sdelphij 6215185029Spjd /* Remove ourselves from the config hooks */ 6216185029Spjd if (sc->intrhook.ich_func != NULL) { 6217185029Spjd config_intrhook_disestablish(&sc->intrhook); 6218185029Spjd sc->intrhook.ich_func = NULL; 6219185029Spjd } 6220185029Spjd 6221185029Spjd /* Start the corb and rirb engines */ 6222185029Spjd HDA_BOOTVERBOSE( 6223219089Spjd device_printf(sc->dev, "HDA_DEBUG: Starting CORB Engine...\n"); 6224185029Spjd ); 6225219089Spjd hdac_corb_start(sc); 6226185029Spjd HDA_BOOTVERBOSE( 6227185029Spjd device_printf(sc->dev, "HDA_DEBUG: Starting RIRB Engine...\n"); 6228185029Spjd ); 6229185029Spjd hdac_rirb_start(sc); 6230185029Spjd 6231185029Spjd HDA_BOOTVERBOSE( 6232185029Spjd device_printf(sc->dev, 6233185029Spjd "HDA_DEBUG: Enabling controller interrupt...\n"); 6234185029Spjd ); 6235185029Spjd if (sc->polling == 0) 6236219089Spjd HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, 6237185029Spjd HDAC_INTCTL_CIE | HDAC_INTCTL_GIE); 6238185029Spjd HDAC_WRITE_4(&sc->mem, HDAC_GCTL, HDAC_READ_4(&sc->mem, HDAC_GCTL) | 6239185029Spjd HDAC_GCTL_UNSOL); 6240185029Spjd 6241185029Spjd DELAY(1000); 6242185029Spjd 6243185029Spjd HDA_BOOTVERBOSE( 6244185029Spjd device_printf(sc->dev, 6245185029Spjd "HDA_DEBUG: Scanning HDA codecs [start index=%d] ...\n", 6246185029Spjd codec_index); 6247185029Spjd ); 6248185029Spjd hdac_scan_codecs(sc, codec_index); 6249185029Spjd 6250185029Spjd device_get_children(sc->dev, &devlist, &devcount); 6251185029Spjd for (i = 0; devlist != NULL && i < devcount; i++) { 6252185029Spjd devinfo = (struct hdac_devinfo *)device_get_ivars(devlist[i]); 6253185029Spjd if (devinfo != NULL && devinfo->node_type == 6254185029Spjd HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) { 6255219089Spjd break; 6256219089Spjd } else 6257219089Spjd devinfo = NULL; 6258219089Spjd } 6259219089Spjd if (devlist != NULL) 6260219089Spjd free(devlist, M_TEMP); 6261219089Spjd 6262219089Spjd if (devinfo == NULL) { 6263219089Spjd hdac_unlock(sc); 6264219089Spjd device_printf(sc->dev, "Audio Function Group not found!\n"); 6265185029Spjd hdac_release_resources(sc); 6266185029Spjd return; 6267185029Spjd } 6268185029Spjd 6269185029Spjd HDA_BOOTVERBOSE( 6270185029Spjd device_printf(sc->dev, 6271185029Spjd "HDA_DEBUG: Parsing AFG nid=%d cad=%d\n", 6272185029Spjd devinfo->nid, devinfo->codec->cad); 6273185029Spjd ); 6274185029Spjd hdac_audio_parse(devinfo); 6275251478Sdelphij HDA_BOOTVERBOSE( 6276185029Spjd device_printf(sc->dev, "HDA_DEBUG: Parsing Ctls...\n"); 6277185029Spjd ); 6278185029Spjd hdac_audio_ctl_parse(devinfo); 6279185029Spjd HDA_BOOTVERBOSE( 6280185029Spjd device_printf(sc->dev, "HDA_DEBUG: Parsing vendor patch...\n"); 6281185029Spjd ); 6282185029Spjd hdac_vendor_patch_parse(devinfo); 6283185029Spjd if (quirks_on != 0) 6284185029Spjd devinfo->function.audio.quirks |= quirks_on; 6285251478Sdelphij if (quirks_off != 0) 6286208373Smm devinfo->function.audio.quirks &= ~quirks_off; 6287208373Smm 6288208373Smm /* XXX Disable all DIGITAL path. */ 6289208373Smm for (i = devinfo->startnode; i < devinfo->endnode; i++) { 6290208373Smm w = hdac_widget_get(devinfo, i); 6291185029Spjd if (w == NULL) 6292185029Spjd continue; 6293185029Spjd if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) { 6294185029Spjd w->enable = 0; 6295185029Spjd continue; 6296185029Spjd } 6297185029Spjd /* XXX Disable useless pin ? */ 6298185029Spjd if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX && 6299185029Spjd (w->wclass.pin.config & 6300185029Spjd HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) == 6301185029Spjd HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE) 6302185029Spjd w->enable = 0; 6303185029Spjd } 6304185029Spjd i = 0; 6305185029Spjd while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 6306185029Spjd if (ctl->widget == NULL) 6307185029Spjd continue; 6308185029Spjd if (ctl->ossmask & SOUND_MASK_DISABLE) 6309185029Spjd ctl->enable = 0; 6310185029Spjd w = ctl->widget; 6311185029Spjd if (w->enable == 0 || 6312185029Spjd HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) 6313185029Spjd ctl->enable = 0; 6314185029Spjd w = ctl->childwidget; 6315185029Spjd if (w == NULL) 6316185029Spjd continue; 6317185029Spjd if (w->enable == 0 || 6318185029Spjd HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) 6319185029Spjd ctl->enable = 0; 6320185029Spjd } 6321219089Spjd 6322185029Spjd HDA_BOOTVERBOSE( 6323185029Spjd device_printf(sc->dev, "HDA_DEBUG: Building AFG tree...\n"); 6324185029Spjd ); 6325185029Spjd hdac_audio_build_tree(devinfo); 6326185029Spjd 6327255753Sgibbs i = 0; 6328255753Sgibbs while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 6329185029Spjd if (ctl->ossmask & (SOUND_MASK_SKIP | SOUND_MASK_DISABLE)) 6330185029Spjd ctl->ossmask = 0; 6331185029Spjd } 6332185029Spjd HDA_BOOTVERBOSE( 6333185029Spjd device_printf(sc->dev, "HDA_DEBUG: AFG commit...\n"); 6334185029Spjd ); 6335219089Spjd hdac_audio_commit(devinfo, HDA_COMMIT_ALL); 6336219089Spjd HDA_BOOTVERBOSE( 6337185029Spjd device_printf(sc->dev, "HDA_DEBUG: Ctls commit...\n"); 6338185029Spjd ); 6339208373Smm hdac_audio_ctl_commit(devinfo); 6340185029Spjd 6341286570Smav HDA_BOOTVERBOSE( 6342185029Spjd device_printf(sc->dev, "HDA_DEBUG: PCMDIR_PLAY setup...\n"); 6343185029Spjd ); 6344185029Spjd pcnt = hdac_pcmchannel_setup(devinfo, PCMDIR_PLAY); 6345185029Spjd HDA_BOOTVERBOSE( 6346286570Smav device_printf(sc->dev, "HDA_DEBUG: PCMDIR_REC setup...\n"); 6347286570Smav ); 6348185029Spjd rcnt = hdac_pcmchannel_setup(devinfo, PCMDIR_REC); 6349219089Spjd 6350286598Smav hdac_unlock(sc); 6351185029Spjd HDA_BOOTVERBOSE( 6352185029Spjd device_printf(sc->dev, 6353185029Spjd "HDA_DEBUG: OSS mixer initialization...\n"); 6354185029Spjd ); 6355185029Spjd 6356185029Spjd /* 6357185029Spjd * There is no point of return after this. If the driver failed, 6358185029Spjd * so be it. Let the detach procedure do all the cleanup. 6359185029Spjd */ 6360185029Spjd if (mixer_init(sc->dev, &hdac_audio_ctl_ossmixer_class, devinfo) != 0) 6361185029Spjd device_printf(sc->dev, "Can't register mixer\n"); 6362185029Spjd 6363185029Spjd if (pcnt > 0) 6364185029Spjd pcnt = 1; 6365185029Spjd if (rcnt > 0) 6366185029Spjd rcnt = 1; 6367185029Spjd 6368185029Spjd HDA_BOOTVERBOSE( 6369185029Spjd device_printf(sc->dev, 6370185029Spjd "HDA_DEBUG: Registering PCM channels...\n"); 6371185029Spjd ); 6372185029Spjd if (pcm_register(sc->dev, devinfo, pcnt, rcnt) != 0) 6373185029Spjd device_printf(sc->dev, "Can't register PCM\n"); 6374185029Spjd 6375185029Spjd sc->registered++; 6376185029Spjd 6377185029Spjd if ((devinfo->function.audio.quirks & HDA_QUIRK_DMAPOS) && 6378185029Spjd hdac_dma_alloc(sc, &sc->pos_dma, 6379185029Spjd (sc->num_iss + sc->num_oss + sc->num_bss) * 8) != 0) { 6380185029Spjd HDA_BOOTVERBOSE( 6381185029Spjd device_printf(sc->dev, 6382185029Spjd "Failed to allocate DMA pos buffer (non-fatal)\n"); 6383185029Spjd ); 6384185029Spjd } 6385185029Spjd 6386185029Spjd for (i = 0; i < pcnt; i++) 6387185029Spjd pcm_addchan(sc->dev, PCMDIR_PLAY, &hdac_channel_class, devinfo); 6388185029Spjd for (i = 0; i < rcnt; i++) 6389185029Spjd pcm_addchan(sc->dev, PCMDIR_REC, &hdac_channel_class, devinfo); 6390185029Spjd 6391185029Spjd#ifdef SND_DYNSYSCTL 6392185029Spjd SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev), 6393185029Spjd SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO, 6394286570Smav "polling", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev), 6395286570Smav sysctl_hdac_polling, "I", "Enable polling mode"); 6396286598Smav SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev), 6397185029Spjd SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO, 6398185029Spjd "polling_interval", CTLTYPE_INT | CTLFLAG_RW, sc->dev, 6399185029Spjd sizeof(sc->dev), sysctl_hdac_polling_interval, "I", 6400185029Spjd "Controller/Jack Sense polling interval (1-1000 ms)"); 6401185029Spjd#ifdef SND_DEBUG 6402185029Spjd SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev), 6403185029Spjd SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO, 6404185029Spjd "pindump", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev), 6405185029Spjd sysctl_hdac_pindump, "I", "Dump pin states/data"); 6406185029Spjd#endif 6407185029Spjd#endif 6408185029Spjd 6409185029Spjd snprintf(status, SND_STATUSLEN, "at memory 0x%lx irq %ld %s [%s]", 6410185029Spjd rman_get_start(sc->mem.mem_res), rman_get_start(sc->irq.irq_res), 6411185029Spjd PCM_KLDSTRING(snd_hda), HDA_DRV_TEST_REV); 6412185029Spjd pcm_setstatus(sc->dev, status); 6413185029Spjd device_printf(sc->dev, "<HDA Codec: %s>\n", hdac_codec_name(devinfo)); 6414185029Spjd HDA_BOOTVERBOSE( 6415185029Spjd device_printf(sc->dev, "<HDA Codec ID: 0x%08x>\n", 6416185029Spjd hdac_codec_id(devinfo)); 6417185029Spjd ); 6418185029Spjd device_printf(sc->dev, "<HDA Driver Revision: %s>\n", 6419185029Spjd HDA_DRV_TEST_REV); 6420185029Spjd 6421185029Spjd HDA_BOOTVERBOSE( 6422185029Spjd if (devinfo->function.audio.quirks != 0) { 6423185029Spjd device_printf(sc->dev, "\n"); 6424185029Spjd device_printf(sc->dev, "HDA config/quirks:"); 6425185029Spjd for (i = 0; i < HDAC_QUIRKS_TAB_LEN; i++) { 6426185029Spjd if ((devinfo->function.audio.quirks & 6427185029Spjd hdac_quirks_tab[i].value) == 6428185029Spjd hdac_quirks_tab[i].value) 6429185029Spjd printf(" %s", hdac_quirks_tab[i].key); 6430185029Spjd } 6431185029Spjd printf("\n"); 6432185029Spjd } 6433185029Spjd device_printf(sc->dev, "\n"); 6434185029Spjd device_printf(sc->dev, "+-------------------+\n"); 6435185029Spjd device_printf(sc->dev, "| DUMPING HDA NODES |\n"); 6436185029Spjd device_printf(sc->dev, "+-------------------+\n"); 6437185029Spjd hdac_dump_nodes(devinfo); 6438185029Spjd device_printf(sc->dev, "\n"); 6439185029Spjd device_printf(sc->dev, "+------------------------+\n"); 6440185029Spjd device_printf(sc->dev, "| DUMPING HDA AMPLIFIERS |\n"); 6441185029Spjd device_printf(sc->dev, "+------------------------+\n"); 6442185029Spjd device_printf(sc->dev, "\n"); 6443185029Spjd i = 0; 6444209962Smm while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 6445185029Spjd device_printf(sc->dev, "%3d: nid=%d", i, 6446185029Spjd (ctl->widget != NULL) ? ctl->widget->nid : -1); 6447185029Spjd if (ctl->childwidget != NULL) 6448185029Spjd printf(" cnid=%d", ctl->childwidget->nid); 6449185029Spjd printf(" dir=0x%x index=%d " 6450185029Spjd "ossmask=0x%08x ossdev=%d%s\n", 6451185029Spjd ctl->dir, ctl->index, 6452185029Spjd ctl->ossmask, ctl->ossdev, 6453185029Spjd (ctl->enable == 0) ? " [DISABLED]" : ""); 6454209962Smm } 6455185029Spjd device_printf(sc->dev, "\n"); 6456185029Spjd device_printf(sc->dev, "+-----------------------------------+\n"); 6457185029Spjd device_printf(sc->dev, "| DUMPING HDA AUDIO/VOLUME CONTROLS |\n"); 6458185029Spjd device_printf(sc->dev, "+-----------------------------------+\n"); 6459185029Spjd hdac_dump_ctls(devinfo, "Master Volume (OSS: vol)", SOUND_MASK_VOLUME); 6460185029Spjd hdac_dump_ctls(devinfo, "PCM Volume (OSS: pcm)", SOUND_MASK_PCM); 6461185029Spjd hdac_dump_ctls(devinfo, "CD Volume (OSS: cd)", SOUND_MASK_CD); 6462185029Spjd hdac_dump_ctls(devinfo, "Microphone Volume (OSS: mic)", SOUND_MASK_MIC); 6463185029Spjd hdac_dump_ctls(devinfo, "Line-in Volume (OSS: line)", SOUND_MASK_LINE); 6464 hdac_dump_ctls(devinfo, "Recording Level (OSS: rec)", SOUND_MASK_RECLEV); 6465 hdac_dump_ctls(devinfo, "Speaker/Beep (OSS: speaker)", SOUND_MASK_SPEAKER); 6466 hdac_dump_ctls(devinfo, NULL, 0); 6467 hdac_dump_dac(devinfo); 6468 hdac_dump_adc(devinfo); 6469 device_printf(sc->dev, "\n"); 6470 device_printf(sc->dev, "+--------------------------------------+\n"); 6471 device_printf(sc->dev, "| DUMPING PCM Playback/Record Channels |\n"); 6472 device_printf(sc->dev, "+--------------------------------------+\n"); 6473 hdac_dump_pcmchannels(sc, pcnt, rcnt); 6474 ); 6475 6476 if (sc->polling != 0) { 6477 hdac_lock(sc); 6478 callout_reset(&sc->poll_hdac, 1, hdac_poll_callback, sc); 6479 hdac_unlock(sc); 6480 } 6481} 6482 6483/**************************************************************************** 6484 * int hdac_detach(device_t) 6485 * 6486 * Detach and free up resources utilized by the hdac device. 6487 ****************************************************************************/ 6488static int 6489hdac_detach(device_t dev) 6490{ 6491 struct hdac_softc *sc = NULL; 6492 struct hdac_devinfo *devinfo = NULL; 6493 int err; 6494 6495 devinfo = (struct hdac_devinfo *)pcm_getdevinfo(dev); 6496 if (devinfo != NULL && devinfo->codec != NULL) 6497 sc = devinfo->codec->sc; 6498 if (sc == NULL) 6499 return (0); 6500 6501 if (sc->registered > 0) { 6502 err = pcm_unregister(dev); 6503 if (err != 0) 6504 return (err); 6505 } 6506 6507 hdac_release_resources(sc); 6508 6509 return (0); 6510} 6511 6512static device_method_t hdac_methods[] = { 6513 /* device interface */ 6514 DEVMETHOD(device_probe, hdac_probe), 6515 DEVMETHOD(device_attach, hdac_attach), 6516 DEVMETHOD(device_detach, hdac_detach), 6517 { 0, 0 } 6518}; 6519 6520static driver_t hdac_driver = { 6521 "pcm", 6522 hdac_methods, 6523 PCM_SOFTC_SIZE, 6524}; 6525 6526DRIVER_MODULE(snd_hda, pci, hdac_driver, pcm_devclass, 0, 0); 6527MODULE_DEPEND(snd_hda, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 6528MODULE_VERSION(snd_hda, 1); 6529