hdac.c revision 167702
1162922Sariff/*- 2162922Sariff * Copyright (c) 2006 Stephane E. Potvin <sepotvin@videotron.ca> 3162922Sariff * Copyright (c) 2006 Ariff Abdullah <ariff@FreeBSD.org> 4162922Sariff * All rights reserved. 5162922Sariff * 6162922Sariff * Redistribution and use in source and binary forms, with or without 7162922Sariff * modification, are permitted provided that the following conditions 8162922Sariff * are met: 9162922Sariff * 1. Redistributions of source code must retain the above copyright 10162922Sariff * notice, this list of conditions and the following disclaimer. 11162922Sariff * 2. Redistributions in binary form must reproduce the above copyright 12162922Sariff * notice, this list of conditions and the following disclaimer in the 13162922Sariff * documentation and/or other materials provided with the distribution. 14162922Sariff * 15162922Sariff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16162922Sariff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17162922Sariff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18162922Sariff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19162922Sariff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20162922Sariff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21162922Sariff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22162922Sariff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23162922Sariff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24162922Sariff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25162922Sariff * SUCH DAMAGE. 26162922Sariff */ 27162922Sariff 28162922Sariff/* 29162922Sariff * Intel High Definition Audio (Controller) driver for FreeBSD. Be advised 30162922Sariff * that this driver still in its early stage, and possible of rewrite are 31162922Sariff * pretty much guaranteed. There are supposedly several distinct parent/child 32162922Sariff * busses to make this "perfect", but as for now and for the sake of 33162922Sariff * simplicity, everything is gobble up within single source. 34162922Sariff * 35162922Sariff * List of subsys: 36162922Sariff * 1) HDA Controller support 37162922Sariff * 2) HDA Codecs support, which may include 38162922Sariff * - HDA 39162922Sariff * - Modem 40162922Sariff * - HDMI 41162922Sariff * 3) Widget parser - the real magic of why this driver works on so 42162922Sariff * many hardwares with minimal vendor specific quirk. The original 43162922Sariff * parser was written using Ruby and can be found at 44162922Sariff * http://people.freebsd.org/~ariff/HDA/parser.rb . This crude 45162922Sariff * ruby parser take the verbose dmesg dump as its input. Refer to 46162922Sariff * http://www.microsoft.com/whdc/device/audio/default.mspx for various 47164614Sariff * interesting documents, especially UAA (Universal Audio Architecture). 48162922Sariff * 4) Possible vendor specific support. 49162922Sariff * (snd_hda_intel, snd_hda_ati, etc..) 50162922Sariff * 51162922Sariff * Thanks to Ahmad Ubaidah Omar @ Defenxis Sdn. Bhd. for the 52162922Sariff * Compaq V3000 with Conexant HDA. 53162922Sariff * 54162922Sariff * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 55162922Sariff * * * 56162922Sariff * * This driver is a collaborative effort made by: * 57162922Sariff * * * 58162922Sariff * * Stephane E. Potvin <sepotvin@videotron.ca> * 59162922Sariff * * Andrea Bittau <a.bittau@cs.ucl.ac.uk> * 60162922Sariff * * Wesley Morgan <morganw@chemikals.org> * 61162922Sariff * * Daniel Eischen <deischen@FreeBSD.org> * 62162922Sariff * * Maxime Guillaud <bsd-ports@mguillaud.net> * 63162922Sariff * * Ariff Abdullah <ariff@FreeBSD.org> * 64162922Sariff * * * 65162922Sariff * * ....and various people from freebsd-multimedia@FreeBSD.org * 66162922Sariff * * * 67162922Sariff * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 68162922Sariff */ 69162922Sariff 70163057Sariff#include <sys/ctype.h> 71163057Sariff 72162922Sariff#include <dev/sound/pcm/sound.h> 73162922Sariff#include <dev/pci/pcireg.h> 74162922Sariff#include <dev/pci/pcivar.h> 75162922Sariff 76162922Sariff#include <dev/sound/pci/hda/hdac_private.h> 77162922Sariff#include <dev/sound/pci/hda/hdac_reg.h> 78162922Sariff#include <dev/sound/pci/hda/hda_reg.h> 79162922Sariff#include <dev/sound/pci/hda/hdac.h> 80162922Sariff 81162922Sariff#include "mixer_if.h" 82162922Sariff 83167648Sariff#define HDA_DRV_TEST_REV "20070317_0042" 84162922Sariff#define HDA_WIDGET_PARSER_REV 1 85162922Sariff 86162922SariffSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/hda/hdac.c 167702 2007-03-19 16:06:26Z ariff $"); 87162922Sariff 88162922Sariff#undef HDA_DEBUG_ENABLED 89162922Sariff#define HDA_DEBUG_ENABLED 1 90162922Sariff 91162922Sariff#ifdef HDA_DEBUG_ENABLED 92163057Sariff#define HDA_DEBUG(stmt) do { \ 93163057Sariff stmt \ 94162922Sariff} while(0) 95162922Sariff#else 96163057Sariff#define HDA_DEBUG(stmt) 97162922Sariff#endif 98162922Sariff 99163057Sariff#define HDA_BOOTVERBOSE(stmt) do { \ 100162922Sariff if (bootverbose) { \ 101162922Sariff stmt \ 102162922Sariff } \ 103162922Sariff} while(0) 104162922Sariff 105162965Sariff#if 1 106162922Sariff#undef HDAC_INTR_EXTRA 107162922Sariff#define HDAC_INTR_EXTRA 1 108162922Sariff#endif 109162922Sariff 110162965Sariff#define hdac_lock(sc) snd_mtxlock((sc)->lock) 111162965Sariff#define hdac_unlock(sc) snd_mtxunlock((sc)->lock) 112163057Sariff#define hdac_lockassert(sc) snd_mtxassert((sc)->lock) 113163057Sariff#define hdac_lockowned(sc) mtx_owned((sc)->lock) 114162922Sariff 115162965Sariff#define HDA_FLAG_MATCH(fl, v) (((fl) & (v)) == (v)) 116163257Sariff#define HDA_DEV_MATCH(fl, v) ((fl) == (v) || \ 117163257Sariff (fl) == 0xffffffff || \ 118163257Sariff (((fl) & 0xffff0000) == 0xffff0000 && \ 119163257Sariff ((fl) & 0x0000ffff) == ((v) & 0x0000ffff)) || \ 120163257Sariff (((fl) & 0x0000ffff) == 0x0000ffff && \ 121163257Sariff ((fl) & 0xffff0000) == ((v) & 0xffff0000))) 122162965Sariff#define HDA_MATCH_ALL 0xffffffff 123162965Sariff#define HDAC_INVALID 0xffffffff 124162965Sariff 125162922Sariff#define HDA_MODEL_CONSTRUCT(vendor, model) \ 126162922Sariff (((uint32_t)(model) << 16) | ((vendor##_VENDORID) & 0xffff)) 127162922Sariff 128162922Sariff/* Controller models */ 129162922Sariff 130162922Sariff/* Intel */ 131162922Sariff#define INTEL_VENDORID 0x8086 132162922Sariff#define HDA_INTEL_82801F HDA_MODEL_CONSTRUCT(INTEL, 0x2668) 133162922Sariff#define HDA_INTEL_82801G HDA_MODEL_CONSTRUCT(INTEL, 0x27d8) 134163136Sariff#define HDA_INTEL_82801H HDA_MODEL_CONSTRUCT(INTEL, 0x284b) 135163136Sariff#define HDA_INTEL_63XXESB HDA_MODEL_CONSTRUCT(INTEL, 0x269a) 136162922Sariff#define HDA_INTEL_ALL HDA_MODEL_CONSTRUCT(INTEL, 0xffff) 137162922Sariff 138162922Sariff/* Nvidia */ 139162922Sariff#define NVIDIA_VENDORID 0x10de 140162922Sariff#define HDA_NVIDIA_MCP51 HDA_MODEL_CONSTRUCT(NVIDIA, 0x026c) 141162922Sariff#define HDA_NVIDIA_MCP55 HDA_MODEL_CONSTRUCT(NVIDIA, 0x0371) 142163136Sariff#define HDA_NVIDIA_MCP61A HDA_MODEL_CONSTRUCT(NVIDIA, 0x03e4) 143163136Sariff#define HDA_NVIDIA_MCP61B HDA_MODEL_CONSTRUCT(NVIDIA, 0x03f0) 144163136Sariff#define HDA_NVIDIA_MCP65A HDA_MODEL_CONSTRUCT(NVIDIA, 0x044a) 145163136Sariff#define HDA_NVIDIA_MCP65B HDA_MODEL_CONSTRUCT(NVIDIA, 0x044b) 146162922Sariff#define HDA_NVIDIA_ALL HDA_MODEL_CONSTRUCT(NVIDIA, 0xffff) 147162922Sariff 148162922Sariff/* ATI */ 149162922Sariff#define ATI_VENDORID 0x1002 150162922Sariff#define HDA_ATI_SB450 HDA_MODEL_CONSTRUCT(ATI, 0x437b) 151163136Sariff#define HDA_ATI_SB600 HDA_MODEL_CONSTRUCT(ATI, 0x4383) 152162922Sariff#define HDA_ATI_ALL HDA_MODEL_CONSTRUCT(ATI, 0xffff) 153162922Sariff 154163136Sariff/* VIA */ 155163136Sariff#define VIA_VENDORID 0x1106 156163136Sariff#define HDA_VIA_VT82XX HDA_MODEL_CONSTRUCT(VIA, 0x3288) 157163136Sariff#define HDA_VIA_ALL HDA_MODEL_CONSTRUCT(VIA, 0xffff) 158163136Sariff 159163136Sariff/* SiS */ 160163136Sariff#define SIS_VENDORID 0x1039 161163136Sariff#define HDA_SIS_966 HDA_MODEL_CONSTRUCT(SIS, 0x7502) 162163136Sariff#define HDA_SIS_ALL HDA_MODEL_CONSTRUCT(SIS, 0xffff) 163163136Sariff 164162922Sariff/* OEM/subvendors */ 165162922Sariff 166165466Sariff/* Intel */ 167165466Sariff#define INTEL_D101GGC_SUBVENDOR HDA_MODEL_CONSTRUCT(INTEL, 0xd600) 168165466Sariff 169162922Sariff/* HP/Compaq */ 170162922Sariff#define HP_VENDORID 0x103c 171162922Sariff#define HP_V3000_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x30b5) 172162922Sariff#define HP_NX7400_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x30a2) 173162922Sariff#define HP_NX6310_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x30aa) 174165281Sariff#define HP_NX6325_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x30b0) 175166294Sariff#define HP_XW4300_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x3013) 176162922Sariff#define HP_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0xffff) 177165281Sariff/* What is wrong with XN 2563 anyway? (Got the picture ?) */ 178165281Sariff#define HP_NX6325_SUBVENDORX 0x103c30b0 179162922Sariff 180162922Sariff/* Dell */ 181162922Sariff#define DELL_VENDORID 0x1028 182162922Sariff#define DELL_D820_SUBVENDOR HDA_MODEL_CONSTRUCT(DELL, 0x01cc) 183162922Sariff#define DELL_I1300_SUBVENDOR HDA_MODEL_CONSTRUCT(DELL, 0x01c9) 184162922Sariff#define DELL_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(DELL, 0xffff) 185162922Sariff 186162922Sariff/* Clevo */ 187162922Sariff#define CLEVO_VENDORID 0x1558 188162922Sariff#define CLEVO_D900T_SUBVENDOR HDA_MODEL_CONSTRUCT(CLEVO, 0x0900) 189162922Sariff#define CLEVO_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(CLEVO, 0xffff) 190162922Sariff 191162922Sariff/* Acer */ 192162922Sariff#define ACER_VENDORID 0x1025 193165992Sariff#define ACER_A5050_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0x010f) 194162922Sariff#define ACER_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0xffff) 195162922Sariff 196162965Sariff/* Asus */ 197162965Sariff#define ASUS_VENDORID 0x1043 198162965Sariff#define ASUS_M5200_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1993) 199163276Sariff#define ASUS_U5F_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1263) 200163432Sariff#define ASUS_A8JC_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1153) 201165103Sariff#define ASUS_P1AH2_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x81cb) 202165281Sariff#define ASUS_A7M_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1323) 203167623Sariff#define ASUS_A7T_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x13c2) 204167648Sariff#define ASUS_W6F_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1263) 205162965Sariff#define ASUS_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0xffff) 206162922Sariff 207163257Sariff/* IBM / Lenovo */ 208163257Sariff#define IBM_VENDORID 0x1014 209163257Sariff#define IBM_M52_SUBVENDOR HDA_MODEL_CONSTRUCT(IBM, 0x02f6) 210163257Sariff#define IBM_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(IBM, 0xffff) 211162965Sariff 212164614Sariff/* Lenovo */ 213164657Sariff#define LENOVO_VENDORID 0x17aa 214164657Sariff#define LENOVO_3KN100_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x2066) 215164657Sariff#define LENOVO_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0xffff) 216163257Sariff 217164657Sariff/* Samsung */ 218164657Sariff#define SAMSUNG_VENDORID 0x144d 219164657Sariff#define SAMSUNG_Q1_SUBVENDOR HDA_MODEL_CONSTRUCT(SAMSUNG, 0xc027) 220164657Sariff#define SAMSUNG_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(SAMSUNG, 0xffff) 221164614Sariff 222164750Sariff/* Medion ? */ 223164750Sariff#define MEDION_VENDORID 0x161f 224164750Sariff#define MEDION_MD95257_SUBVENDOR HDA_MODEL_CONSTRUCT(MEDION, 0x203d) 225164750Sariff#define MEDION_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(MEDION, 0xffff) 226164750Sariff 227164828Sariff/* 228164828Sariff * Apple Intel MacXXXX seems using Sigmatel codec/vendor id 229164828Sariff * instead of their own, which is beyond my comprehension 230164828Sariff * (see HDA_CODEC_STAC9221 below). 231164828Sariff */ 232164828Sariff#define APPLE_INTEL_MAC 0x76808384 233164828Sariff 234165281Sariff/* LG Electronics */ 235165281Sariff#define LG_VENDORID 0x1854 236165281Sariff#define LG_LW20_SUBVENDOR HDA_MODEL_CONSTRUCT(LG, 0x0018) 237165281Sariff#define LG_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(LG, 0xffff) 238165281Sariff 239165351Sariff/* Fujitsu Siemens */ 240165351Sariff#define FS_VENDORID 0x1734 241165351Sariff#define FS_PA1510_SUBVENDOR HDA_MODEL_CONSTRUCT(FS, 0x10b8) 242165351Sariff#define FS_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(FS, 0xffff) 243165351Sariff 244165770Sariff/* Toshiba */ 245165770Sariff#define TOSHIBA_VENDORID 0x1179 246165770Sariff#define TOSHIBA_U200_SUBVENDOR HDA_MODEL_CONSTRUCT(TOSHIBA, 0x0001) 247165770Sariff#define TOSHIBA_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(TOSHIBA, 0xffff) 248165770Sariff 249165992Sariff/* Micro-Star International (MSI) */ 250165992Sariff#define MSI_VENDORID 0x1462 251165992Sariff#define MSI_MS1034_SUBVENDOR HDA_MODEL_CONSTRUCT(MSI, 0x0349) 252165992Sariff#define MSI_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(MSI, 0xffff) 253165992Sariff 254162922Sariff/* Misc constants.. */ 255162922Sariff#define HDA_AMP_MUTE_DEFAULT (0xffffffff) 256162922Sariff#define HDA_AMP_MUTE_NONE (0) 257162922Sariff#define HDA_AMP_MUTE_LEFT (1 << 0) 258162922Sariff#define HDA_AMP_MUTE_RIGHT (1 << 1) 259162922Sariff#define HDA_AMP_MUTE_ALL (HDA_AMP_MUTE_LEFT | HDA_AMP_MUTE_RIGHT) 260162922Sariff 261162922Sariff#define HDA_AMP_LEFT_MUTED(v) ((v) & (HDA_AMP_MUTE_LEFT)) 262162922Sariff#define HDA_AMP_RIGHT_MUTED(v) (((v) & HDA_AMP_MUTE_RIGHT) >> 1) 263162922Sariff 264162922Sariff#define HDA_DAC_PATH (1 << 0) 265162922Sariff#define HDA_ADC_PATH (1 << 1) 266162922Sariff#define HDA_ADC_RECSEL (1 << 2) 267162922Sariff 268163057Sariff#define HDA_CTL_OUT (1 << 0) 269163057Sariff#define HDA_CTL_IN (1 << 1) 270162922Sariff#define HDA_CTL_BOTH (HDA_CTL_IN | HDA_CTL_OUT) 271162922Sariff 272163057Sariff#define HDA_GPIO_MAX 15 273163057Sariff/* 0 - 14 = GPIO */ 274163057Sariff#define HDA_QUIRK_GPIO0 (1 << 0) 275163057Sariff#define HDA_QUIRK_GPIO1 (1 << 1) 276163057Sariff#define HDA_QUIRK_GPIO2 (1 << 2) 277165039Sariff#define HDA_QUIRK_GPIOFLUSH (1 << 15) 278165039Sariff#define HDA_QUIRK_SOFTPCMVOL (1 << 16) 279165039Sariff#define HDA_QUIRK_FIXEDRATE (1 << 17) 280165039Sariff#define HDA_QUIRK_FORCESTEREO (1 << 18) 281165039Sariff#define HDA_QUIRK_EAPDINV (1 << 19) 282165069Sariff#define HDA_QUIRK_VREF (1 << 20) 283162922Sariff 284163057Sariffstatic const struct { 285163057Sariff char *key; 286163057Sariff uint32_t value; 287163057Sariff} hdac_quirks_tab[] = { 288163057Sariff { "gpio0", HDA_QUIRK_GPIO0 }, 289163057Sariff { "gpio1", HDA_QUIRK_GPIO1 }, 290163057Sariff { "gpio2", HDA_QUIRK_GPIO2 }, 291165039Sariff { "gpioflush", HDA_QUIRK_GPIOFLUSH }, 292163057Sariff { "softpcmvol", HDA_QUIRK_SOFTPCMVOL }, 293163057Sariff { "fixedrate", HDA_QUIRK_FIXEDRATE }, 294163136Sariff { "forcestereo", HDA_QUIRK_FORCESTEREO }, 295163276Sariff { "eapdinv", HDA_QUIRK_EAPDINV }, 296165069Sariff { "vref", HDA_QUIRK_VREF }, 297163057Sariff}; 298163057Sariff#define HDAC_QUIRKS_TAB_LEN \ 299163057Sariff (sizeof(hdac_quirks_tab) / sizeof(hdac_quirks_tab[0])) 300163057Sariff 301162922Sariff#define HDA_BDL_MIN 2 302162922Sariff#define HDA_BDL_MAX 256 303162922Sariff#define HDA_BDL_DEFAULT HDA_BDL_MIN 304162922Sariff 305167648Sariff#define HDA_BLK_MIN 128 306167648Sariff#define HDA_BLK_ALIGN (~(HDA_BLK_MIN - 1)) 307167648Sariff 308162922Sariff#define HDA_BUFSZ_MIN 4096 309162922Sariff#define HDA_BUFSZ_MAX 65536 310162922Sariff#define HDA_BUFSZ_DEFAULT 16384 311162922Sariff 312162922Sariff#define HDA_PARSE_MAXDEPTH 10 313162922Sariff 314162922Sariff#define HDAC_UNSOLTAG_EVENT_HP 0x00 315162922Sariff 316165239SariffMALLOC_DEFINE(M_HDAC, "hdac", "High Definition Audio Controller"); 317162922Sariff 318162922Sariffenum { 319162922Sariff HDA_PARSE_MIXER, 320162922Sariff HDA_PARSE_DIRECT 321162922Sariff}; 322162922Sariff 323162922Sariff/* Default */ 324162922Sariffstatic uint32_t hdac_fmt[] = { 325162922Sariff AFMT_STEREO | AFMT_S16_LE, 326162922Sariff 0 327162922Sariff}; 328162922Sariff 329162922Sariffstatic struct pcmchan_caps hdac_caps = {48000, 48000, hdac_fmt, 0}; 330162922Sariff 331162922Sariffstatic const struct { 332162922Sariff uint32_t model; 333162922Sariff char *desc; 334162922Sariff} hdac_devices[] = { 335162922Sariff { HDA_INTEL_82801F, "Intel 82801F" }, 336162922Sariff { HDA_INTEL_82801G, "Intel 82801G" }, 337163136Sariff { HDA_INTEL_82801H, "Intel 82801H" }, 338163136Sariff { HDA_INTEL_63XXESB, "Intel 631x/632xESB" }, 339162922Sariff { HDA_NVIDIA_MCP51, "NVidia MCP51" }, 340162922Sariff { HDA_NVIDIA_MCP55, "NVidia MCP55" }, 341163136Sariff { HDA_NVIDIA_MCP61A, "NVidia MCP61A" }, 342163136Sariff { HDA_NVIDIA_MCP61B, "NVidia MCP61B" }, 343163136Sariff { HDA_NVIDIA_MCP65A, "NVidia MCP65A" }, 344163136Sariff { HDA_NVIDIA_MCP65B, "NVidia MCP65B" }, 345162922Sariff { HDA_ATI_SB450, "ATI SB450" }, 346163136Sariff { HDA_ATI_SB600, "ATI SB600" }, 347163136Sariff { HDA_VIA_VT82XX, "VIA VT8251/8237A" }, 348163136Sariff { HDA_SIS_966, "SiS 966" }, 349162922Sariff /* Unknown */ 350162922Sariff { HDA_INTEL_ALL, "Intel (Unknown)" }, 351162922Sariff { HDA_NVIDIA_ALL, "NVidia (Unknown)" }, 352162922Sariff { HDA_ATI_ALL, "ATI (Unknown)" }, 353163136Sariff { HDA_VIA_ALL, "VIA (Unknown)" }, 354163136Sariff { HDA_SIS_ALL, "SiS (Unknown)" }, 355162922Sariff}; 356162922Sariff#define HDAC_DEVICES_LEN (sizeof(hdac_devices) / sizeof(hdac_devices[0])) 357162922Sariff 358162922Sariffstatic const struct { 359162922Sariff uint32_t rate; 360162922Sariff int valid; 361162922Sariff uint16_t base; 362162922Sariff uint16_t mul; 363162922Sariff uint16_t div; 364162922Sariff} hda_rate_tab[] = { 365162922Sariff { 8000, 1, 0x0000, 0x0000, 0x0500 }, /* (48000 * 1) / 6 */ 366162922Sariff { 9600, 0, 0x0000, 0x0000, 0x0400 }, /* (48000 * 1) / 5 */ 367162922Sariff { 12000, 0, 0x0000, 0x0000, 0x0300 }, /* (48000 * 1) / 4 */ 368162922Sariff { 16000, 1, 0x0000, 0x0000, 0x0200 }, /* (48000 * 1) / 3 */ 369162922Sariff { 18000, 0, 0x0000, 0x1000, 0x0700 }, /* (48000 * 3) / 8 */ 370162922Sariff { 19200, 0, 0x0000, 0x0800, 0x0400 }, /* (48000 * 2) / 5 */ 371162922Sariff { 24000, 0, 0x0000, 0x0000, 0x0100 }, /* (48000 * 1) / 2 */ 372162922Sariff { 28800, 0, 0x0000, 0x1000, 0x0400 }, /* (48000 * 3) / 5 */ 373162922Sariff { 32000, 1, 0x0000, 0x0800, 0x0200 }, /* (48000 * 2) / 3 */ 374162922Sariff { 36000, 0, 0x0000, 0x1000, 0x0300 }, /* (48000 * 3) / 4 */ 375162922Sariff { 38400, 0, 0x0000, 0x1800, 0x0400 }, /* (48000 * 4) / 5 */ 376162922Sariff { 48000, 1, 0x0000, 0x0000, 0x0000 }, /* (48000 * 1) / 1 */ 377162922Sariff { 64000, 0, 0x0000, 0x1800, 0x0200 }, /* (48000 * 4) / 3 */ 378162922Sariff { 72000, 0, 0x0000, 0x1000, 0x0100 }, /* (48000 * 3) / 2 */ 379162922Sariff { 96000, 1, 0x0000, 0x0800, 0x0000 }, /* (48000 * 2) / 1 */ 380162922Sariff { 144000, 0, 0x0000, 0x1000, 0x0000 }, /* (48000 * 3) / 1 */ 381162922Sariff { 192000, 1, 0x0000, 0x1800, 0x0000 }, /* (48000 * 4) / 1 */ 382162922Sariff { 8820, 0, 0x4000, 0x0000, 0x0400 }, /* (44100 * 1) / 5 */ 383162922Sariff { 11025, 1, 0x4000, 0x0000, 0x0300 }, /* (44100 * 1) / 4 */ 384162922Sariff { 12600, 0, 0x4000, 0x0800, 0x0600 }, /* (44100 * 2) / 7 */ 385162922Sariff { 14700, 0, 0x4000, 0x0000, 0x0200 }, /* (44100 * 1) / 3 */ 386162922Sariff { 17640, 0, 0x4000, 0x0800, 0x0400 }, /* (44100 * 2) / 5 */ 387162922Sariff { 18900, 0, 0x4000, 0x1000, 0x0600 }, /* (44100 * 3) / 7 */ 388162922Sariff { 22050, 1, 0x4000, 0x0000, 0x0100 }, /* (44100 * 1) / 2 */ 389162922Sariff { 25200, 0, 0x4000, 0x1800, 0x0600 }, /* (44100 * 4) / 7 */ 390162922Sariff { 26460, 0, 0x4000, 0x1000, 0x0400 }, /* (44100 * 3) / 5 */ 391162922Sariff { 29400, 0, 0x4000, 0x0800, 0x0200 }, /* (44100 * 2) / 3 */ 392162922Sariff { 33075, 0, 0x4000, 0x1000, 0x0300 }, /* (44100 * 3) / 4 */ 393162922Sariff { 35280, 0, 0x4000, 0x1800, 0x0400 }, /* (44100 * 4) / 5 */ 394162922Sariff { 44100, 1, 0x4000, 0x0000, 0x0000 }, /* (44100 * 1) / 1 */ 395162922Sariff { 58800, 0, 0x4000, 0x1800, 0x0200 }, /* (44100 * 4) / 3 */ 396162922Sariff { 66150, 0, 0x4000, 0x1000, 0x0100 }, /* (44100 * 3) / 2 */ 397162922Sariff { 88200, 1, 0x4000, 0x0800, 0x0000 }, /* (44100 * 2) / 1 */ 398162922Sariff { 132300, 0, 0x4000, 0x1000, 0x0000 }, /* (44100 * 3) / 1 */ 399162922Sariff { 176400, 1, 0x4000, 0x1800, 0x0000 }, /* (44100 * 4) / 1 */ 400162922Sariff}; 401162922Sariff#define HDA_RATE_TAB_LEN (sizeof(hda_rate_tab) / sizeof(hda_rate_tab[0])) 402162922Sariff 403162922Sariff/* All codecs you can eat... */ 404162922Sariff#define HDA_CODEC_CONSTRUCT(vendor, id) \ 405162922Sariff (((uint32_t)(vendor##_VENDORID) << 16) | ((id) & 0xffff)) 406162922Sariff 407162922Sariff/* Realtek */ 408162922Sariff#define REALTEK_VENDORID 0x10ec 409162922Sariff#define HDA_CODEC_ALC260 HDA_CODEC_CONSTRUCT(REALTEK, 0x0260) 410162922Sariff#define HDA_CODEC_ALC861 HDA_CODEC_CONSTRUCT(REALTEK, 0x0861) 411162922Sariff#define HDA_CODEC_ALC880 HDA_CODEC_CONSTRUCT(REALTEK, 0x0880) 412163057Sariff#define HDA_CODEC_ALC882 HDA_CODEC_CONSTRUCT(REALTEK, 0x0882) 413163057Sariff#define HDA_CODEC_ALC883 HDA_CODEC_CONSTRUCT(REALTEK, 0x0883) 414165305Sariff#define HDA_CODEC_ALC888 HDA_CODEC_CONSTRUCT(REALTEK, 0x0888) 415162922Sariff#define HDA_CODEC_ALCXXXX HDA_CODEC_CONSTRUCT(REALTEK, 0xffff) 416162922Sariff 417162922Sariff/* Analog Device */ 418162922Sariff#define ANALOGDEVICE_VENDORID 0x11d4 419162922Sariff#define HDA_CODEC_AD1981HD HDA_CODEC_CONSTRUCT(ANALOGDEVICE, 0x1981) 420162922Sariff#define HDA_CODEC_AD1983 HDA_CODEC_CONSTRUCT(ANALOGDEVICE, 0x1983) 421162922Sariff#define HDA_CODEC_AD1986A HDA_CODEC_CONSTRUCT(ANALOGDEVICE, 0x1986) 422162922Sariff#define HDA_CODEC_ADXXXX HDA_CODEC_CONSTRUCT(ANALOGDEVICE, 0xffff) 423162922Sariff 424162922Sariff/* CMedia */ 425162922Sariff#define CMEDIA_VENDORID 0x434d 426162922Sariff#define HDA_CODEC_CMI9880 HDA_CODEC_CONSTRUCT(CMEDIA, 0x4980) 427162922Sariff#define HDA_CODEC_CMIXXXX HDA_CODEC_CONSTRUCT(CMEDIA, 0xffff) 428162922Sariff 429162922Sariff/* Sigmatel */ 430162922Sariff#define SIGMATEL_VENDORID 0x8384 431162922Sariff#define HDA_CODEC_STAC9221 HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7680) 432162922Sariff#define HDA_CODEC_STAC9221D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7683) 433162922Sariff#define HDA_CODEC_STAC9220 HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7690) 434162922Sariff#define HDA_CODEC_STAC922XD HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7681) 435165305Sariff#define HDA_CODEC_STAC9227 HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7618) 436166796Sariff#define HDA_CODEC_STAC9271D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7627) 437162922Sariff#define HDA_CODEC_STACXXXX HDA_CODEC_CONSTRUCT(SIGMATEL, 0xffff) 438162922Sariff 439162922Sariff/* 440162922Sariff * Conexant 441162922Sariff * 442162922Sariff * Ok, the truth is, I don't have any idea at all whether 443162922Sariff * it is "Venice" or "Waikiki" or other unnamed CXyadayada. The only 444162922Sariff * place that tell me it is "Venice" is from its Windows driver INF. 445163057Sariff * 446163057Sariff * Venice - CX????? 447163057Sariff * Waikiki - CX20551-22 448162922Sariff */ 449162922Sariff#define CONEXANT_VENDORID 0x14f1 450162922Sariff#define HDA_CODEC_CXVENICE HDA_CODEC_CONSTRUCT(CONEXANT, 0x5045) 451163057Sariff#define HDA_CODEC_CXWAIKIKI HDA_CODEC_CONSTRUCT(CONEXANT, 0x5047) 452162922Sariff#define HDA_CODEC_CXXXXX HDA_CODEC_CONSTRUCT(CONEXANT, 0xffff) 453162922Sariff 454162922Sariff 455162922Sariff/* Codecs */ 456162922Sariffstatic const struct { 457162922Sariff uint32_t id; 458162922Sariff char *name; 459162922Sariff} hdac_codecs[] = { 460162922Sariff { HDA_CODEC_ALC260, "Realtek ALC260" }, 461162922Sariff { HDA_CODEC_ALC861, "Realtek ALC861" }, 462162922Sariff { HDA_CODEC_ALC880, "Realtek ALC880" }, 463162922Sariff { HDA_CODEC_ALC882, "Realtek ALC882" }, 464163057Sariff { HDA_CODEC_ALC883, "Realtek ALC883" }, 465165305Sariff { HDA_CODEC_ALC888, "Realtek ALC888" }, 466162922Sariff { HDA_CODEC_AD1981HD, "Analog Device AD1981HD" }, 467162922Sariff { HDA_CODEC_AD1983, "Analog Device AD1983" }, 468162922Sariff { HDA_CODEC_AD1986A, "Analog Device AD1986A" }, 469162922Sariff { HDA_CODEC_CMI9880, "CMedia CMI9880" }, 470162922Sariff { HDA_CODEC_STAC9221, "Sigmatel STAC9221" }, 471162922Sariff { HDA_CODEC_STAC9221D, "Sigmatel STAC9221D" }, 472162922Sariff { HDA_CODEC_STAC9220, "Sigmatel STAC9220" }, 473162922Sariff { HDA_CODEC_STAC922XD, "Sigmatel STAC9220D/9223D" }, 474165305Sariff { HDA_CODEC_STAC9227, "Sigmatel STAC9227" }, 475166796Sariff { HDA_CODEC_STAC9271D, "Sigmatel STAC9271D" }, 476162922Sariff { HDA_CODEC_CXVENICE, "Conexant Venice" }, 477163057Sariff { HDA_CODEC_CXWAIKIKI, "Conexant Waikiki" }, 478162922Sariff /* Unknown codec */ 479162922Sariff { HDA_CODEC_ALCXXXX, "Realtek (Unknown)" }, 480162922Sariff { HDA_CODEC_ADXXXX, "Analog Device (Unknown)" }, 481162922Sariff { HDA_CODEC_CMIXXXX, "CMedia (Unknown)" }, 482162922Sariff { HDA_CODEC_STACXXXX, "Sigmatel (Unknown)" }, 483162922Sariff { HDA_CODEC_CXXXXX, "Conexant (Unknown)" }, 484162922Sariff}; 485162922Sariff#define HDAC_CODECS_LEN (sizeof(hdac_codecs) / sizeof(hdac_codecs[0])) 486162922Sariff 487162922Sariffenum { 488162922Sariff HDAC_HP_SWITCH_CTL, 489162922Sariff HDAC_HP_SWITCH_CTRL 490162922Sariff}; 491162922Sariff 492162922Sariffstatic const struct { 493162965Sariff uint32_t model; 494162922Sariff uint32_t id; 495162922Sariff int type; 496165039Sariff int inverted; 497162922Sariff nid_t hpnid; 498162922Sariff nid_t spkrnid[8]; 499162922Sariff nid_t eapdnid; 500162922Sariff} hdac_hp_switch[] = { 501162922Sariff /* Specific OEM models */ 502165039Sariff { HP_V3000_SUBVENDOR, HDA_CODEC_CXVENICE, HDAC_HP_SWITCH_CTL, 0, 503162922Sariff 17, { 16, -1 }, 16 }, 504165039Sariff { HP_NX7400_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 0, 505162922Sariff 6, { 5, -1 }, 5 }, 506165039Sariff { HP_NX6310_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 0, 507162922Sariff 6, { 5, -1 }, 5 }, 508165281Sariff { HP_NX6325_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 0, 509165281Sariff 6, { 5, -1 }, 5 }, 510165770Sariff { TOSHIBA_U200_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 0, 511165770Sariff 6, { 5, -1 }, -1 }, 512165039Sariff { DELL_D820_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL, 0, 513162922Sariff 13, { 14, -1 }, -1 }, 514165039Sariff { DELL_I1300_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL, 0, 515162922Sariff 13, { 14, -1 }, -1 }, 516165039Sariff { APPLE_INTEL_MAC, HDA_CODEC_STAC9221, HDAC_HP_SWITCH_CTRL, 0, 517164828Sariff 10, { 13, -1 }, -1 }, 518165039Sariff { LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A, HDAC_HP_SWITCH_CTL, 1, 519165039Sariff 26, { 27, -1 }, -1 }, 520165281Sariff { LG_LW20_SUBVENDOR, HDA_CODEC_ALC880, HDAC_HP_SWITCH_CTL, 0, 521165281Sariff 27, { 20, -1 }, -1 }, 522165992Sariff { ACER_A5050_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, 0, 523165992Sariff 20, { 21, -1 }, -1 }, 524165992Sariff { MSI_MS1034_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, 0, 525165992Sariff 20, { 27, -1 }, -1 }, 526162922Sariff /* 527162922Sariff * All models that at least come from the same vendor with 528162922Sariff * simmilar codec. 529162922Sariff */ 530165039Sariff { HP_ALL_SUBVENDOR, HDA_CODEC_CXVENICE, HDAC_HP_SWITCH_CTL, 0, 531162922Sariff 17, { 16, -1 }, 16 }, 532165039Sariff { HP_ALL_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 0, 533162922Sariff 6, { 5, -1 }, 5 }, 534165770Sariff { TOSHIBA_ALL_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 0, 535165770Sariff 6, { 5, -1 }, -1 }, 536165039Sariff { DELL_ALL_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL, 0, 537162922Sariff 13, { 14, -1 }, -1 }, 538165039Sariff { LENOVO_ALL_SUBVENDOR, HDA_CODEC_AD1986A, HDAC_HP_SWITCH_CTL, 1, 539165039Sariff 26, { 27, -1 }, -1 }, 540166294Sariff#if 0 541165992Sariff { ACER_ALL_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, 0, 542165992Sariff 20, { 21, -1 }, -1 }, 543166294Sariff#endif 544162922Sariff}; 545162922Sariff#define HDAC_HP_SWITCH_LEN \ 546162922Sariff (sizeof(hdac_hp_switch) / sizeof(hdac_hp_switch[0])) 547162922Sariff 548162922Sariffstatic const struct { 549162965Sariff uint32_t model; 550162922Sariff uint32_t id; 551162922Sariff nid_t eapdnid; 552162922Sariff int hp_switch; 553162922Sariff} hdac_eapd_switch[] = { 554162922Sariff { HP_V3000_SUBVENDOR, HDA_CODEC_CXVENICE, 16, 1 }, 555162922Sariff { HP_NX7400_SUBVENDOR, HDA_CODEC_AD1981HD, 5, 1 }, 556162922Sariff { HP_NX6310_SUBVENDOR, HDA_CODEC_AD1981HD, 5, 1 }, 557162922Sariff}; 558162922Sariff#define HDAC_EAPD_SWITCH_LEN \ 559162922Sariff (sizeof(hdac_eapd_switch) / sizeof(hdac_eapd_switch[0])) 560162922Sariff 561162922Sariff/**************************************************************************** 562162922Sariff * Function prototypes 563162922Sariff ****************************************************************************/ 564162922Sariffstatic void hdac_intr_handler(void *); 565162922Sariffstatic int hdac_reset(struct hdac_softc *); 566162922Sariffstatic int hdac_get_capabilities(struct hdac_softc *); 567162922Sariffstatic void hdac_dma_cb(void *, bus_dma_segment_t *, int, int); 568162922Sariffstatic int hdac_dma_alloc(struct hdac_softc *, 569162922Sariff struct hdac_dma *, bus_size_t); 570162922Sariffstatic void hdac_dma_free(struct hdac_dma *); 571162922Sariffstatic int hdac_mem_alloc(struct hdac_softc *); 572162922Sariffstatic void hdac_mem_free(struct hdac_softc *); 573162922Sariffstatic int hdac_irq_alloc(struct hdac_softc *); 574162922Sariffstatic void hdac_irq_free(struct hdac_softc *); 575162922Sariffstatic void hdac_corb_init(struct hdac_softc *); 576162922Sariffstatic void hdac_rirb_init(struct hdac_softc *); 577162922Sariffstatic void hdac_corb_start(struct hdac_softc *); 578162922Sariffstatic void hdac_rirb_start(struct hdac_softc *); 579162922Sariffstatic void hdac_scan_codecs(struct hdac_softc *); 580162922Sariffstatic int hdac_probe_codec(struct hdac_codec *); 581162922Sariffstatic struct hdac_devinfo *hdac_probe_function(struct hdac_codec *, nid_t); 582162922Sariffstatic void hdac_add_child(struct hdac_softc *, struct hdac_devinfo *); 583162922Sariff 584162922Sariffstatic void hdac_attach2(void *); 585162922Sariff 586162922Sariffstatic uint32_t hdac_command_sendone_internal(struct hdac_softc *, 587162922Sariff uint32_t, int); 588162922Sariffstatic void hdac_command_send_internal(struct hdac_softc *, 589162922Sariff struct hdac_command_list *, int); 590162922Sariff 591162922Sariffstatic int hdac_probe(device_t); 592162922Sariffstatic int hdac_attach(device_t); 593162922Sariffstatic int hdac_detach(device_t); 594162922Sariffstatic void hdac_widget_connection_select(struct hdac_widget *, uint8_t); 595162922Sariffstatic void hdac_audio_ctl_amp_set(struct hdac_audio_ctl *, 596162922Sariff uint32_t, int, int); 597162922Sariffstatic struct hdac_audio_ctl *hdac_audio_ctl_amp_get(struct hdac_devinfo *, 598162922Sariff nid_t, int, int); 599162922Sariffstatic void hdac_audio_ctl_amp_set_internal(struct hdac_softc *, 600162922Sariff nid_t, nid_t, int, int, int, int, int, int); 601162922Sariffstatic int hdac_audio_ctl_ossmixer_getnextdev(struct hdac_devinfo *); 602162922Sariffstatic struct hdac_widget *hdac_widget_get(struct hdac_devinfo *, nid_t); 603162922Sariff 604164614Sariffstatic int hdac_rirb_flush(struct hdac_softc *sc); 605164614Sariffstatic int hdac_unsolq_flush(struct hdac_softc *sc); 606164614Sariff 607162922Sariff#define hdac_command(a1, a2, a3) \ 608162922Sariff hdac_command_sendone_internal(a1, a2, a3) 609162922Sariff 610162922Sariff#define hdac_codec_id(d) \ 611162922Sariff ((uint32_t)((d == NULL) ? 0x00000000 : \ 612162922Sariff ((((uint32_t)(d)->vendor_id & 0x0000ffff) << 16) | \ 613162922Sariff ((uint32_t)(d)->device_id & 0x0000ffff)))) 614162922Sariff 615162922Sariffstatic char * 616162922Sariffhdac_codec_name(struct hdac_devinfo *devinfo) 617162922Sariff{ 618162922Sariff uint32_t id; 619162922Sariff int i; 620162922Sariff 621162922Sariff id = hdac_codec_id(devinfo); 622162922Sariff 623162922Sariff for (i = 0; i < HDAC_CODECS_LEN; i++) { 624163257Sariff if (HDA_DEV_MATCH(hdac_codecs[i].id, id)) 625162922Sariff return (hdac_codecs[i].name); 626162922Sariff } 627162922Sariff 628162922Sariff return ((id == 0x00000000) ? "NULL Codec" : "Unknown Codec"); 629162922Sariff} 630162922Sariff 631162922Sariffstatic char * 632162922Sariffhdac_audio_ctl_ossmixer_mask2name(uint32_t devmask) 633162922Sariff{ 634162922Sariff static char *ossname[] = SOUND_DEVICE_NAMES; 635162922Sariff static char *unknown = "???"; 636162922Sariff int i; 637162922Sariff 638162922Sariff for (i = SOUND_MIXER_NRDEVICES - 1; i >= 0; i--) { 639162922Sariff if (devmask & (1 << i)) 640162922Sariff return (ossname[i]); 641162922Sariff } 642162922Sariff return (unknown); 643162922Sariff} 644162922Sariff 645162922Sariffstatic void 646162922Sariffhdac_audio_ctl_ossmixer_mask2allname(uint32_t mask, char *buf, size_t len) 647162922Sariff{ 648162922Sariff static char *ossname[] = SOUND_DEVICE_NAMES; 649162922Sariff int i, first = 1; 650162922Sariff 651162922Sariff bzero(buf, len); 652162922Sariff for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 653162922Sariff if (mask & (1 << i)) { 654162922Sariff if (first == 0) 655162922Sariff strlcat(buf, ", ", len); 656162922Sariff strlcat(buf, ossname[i], len); 657162922Sariff first = 0; 658162922Sariff } 659162922Sariff } 660162922Sariff} 661162922Sariff 662162922Sariffstatic struct hdac_audio_ctl * 663162922Sariffhdac_audio_ctl_each(struct hdac_devinfo *devinfo, int *index) 664162922Sariff{ 665162922Sariff if (devinfo == NULL || 666162922Sariff devinfo->node_type != HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO || 667162922Sariff index == NULL || devinfo->function.audio.ctl == NULL || 668162922Sariff devinfo->function.audio.ctlcnt < 1 || 669162922Sariff *index < 0 || *index >= devinfo->function.audio.ctlcnt) 670162922Sariff return (NULL); 671162922Sariff return (&devinfo->function.audio.ctl[(*index)++]); 672162922Sariff} 673162922Sariff 674162922Sariffstatic struct hdac_audio_ctl * 675162922Sariffhdac_audio_ctl_amp_get(struct hdac_devinfo *devinfo, nid_t nid, 676162922Sariff int index, int cnt) 677162922Sariff{ 678162922Sariff struct hdac_audio_ctl *ctl, *retctl = NULL; 679162922Sariff int i, at, atindex, found = 0; 680162922Sariff 681162922Sariff if (devinfo == NULL || devinfo->function.audio.ctl == NULL) 682162922Sariff return (NULL); 683162922Sariff 684162922Sariff at = cnt; 685162922Sariff if (at == 0) 686162922Sariff at = 1; 687162922Sariff else if (at < 0) 688162922Sariff at = -1; 689162922Sariff atindex = index; 690162922Sariff if (atindex < 0) 691162922Sariff atindex = -1; 692162922Sariff 693162922Sariff i = 0; 694162922Sariff while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 695162922Sariff if (ctl->enable == 0 || ctl->widget == NULL) 696162922Sariff continue; 697162922Sariff if (!(ctl->widget->nid == nid && (atindex == -1 || 698162922Sariff ctl->index == atindex))) 699162922Sariff continue; 700162922Sariff found++; 701162922Sariff if (found == cnt) 702162922Sariff return (ctl); 703162922Sariff retctl = ctl; 704162922Sariff } 705162922Sariff 706162922Sariff return ((at == -1) ? retctl : NULL); 707162922Sariff} 708162922Sariff 709162922Sariffstatic void 710162922Sariffhdac_hp_switch_handler(struct hdac_devinfo *devinfo) 711162922Sariff{ 712162922Sariff struct hdac_softc *sc; 713162922Sariff struct hdac_widget *w; 714162922Sariff struct hdac_audio_ctl *ctl; 715162922Sariff uint32_t id, res; 716162922Sariff int i = 0, j, forcemute; 717162922Sariff nid_t cad; 718162922Sariff 719162922Sariff if (devinfo == NULL || devinfo->codec == NULL || 720162922Sariff devinfo->codec->sc == NULL) 721162922Sariff return; 722162922Sariff 723162922Sariff sc = devinfo->codec->sc; 724162922Sariff cad = devinfo->codec->cad; 725162922Sariff id = hdac_codec_id(devinfo); 726162922Sariff for (i = 0; i < HDAC_HP_SWITCH_LEN; i++) { 727163257Sariff if (HDA_DEV_MATCH(hdac_hp_switch[i].model, 728162965Sariff sc->pci_subvendor) && 729162922Sariff hdac_hp_switch[i].id == id) 730162922Sariff break; 731162922Sariff } 732162922Sariff 733162922Sariff if (i >= HDAC_HP_SWITCH_LEN) 734162922Sariff return; 735162922Sariff 736162922Sariff forcemute = 0; 737162922Sariff if (hdac_hp_switch[i].eapdnid != -1) { 738162922Sariff w = hdac_widget_get(devinfo, hdac_hp_switch[i].eapdnid); 739162965Sariff if (w != NULL && w->param.eapdbtl != HDAC_INVALID) 740162922Sariff forcemute = (w->param.eapdbtl & 741162922Sariff HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD) ? 0 : 1; 742162922Sariff } 743162922Sariff 744162922Sariff res = hdac_command(sc, 745162922Sariff HDA_CMD_GET_PIN_SENSE(cad, hdac_hp_switch[i].hpnid), cad); 746163057Sariff HDA_BOOTVERBOSE( 747162922Sariff device_printf(sc->dev, 748163057Sariff "HDA_DEBUG: Pin sense: nid=%d res=0x%08x\n", 749162922Sariff hdac_hp_switch[i].hpnid, res); 750162922Sariff ); 751162922Sariff res >>= 31; 752165039Sariff res ^= hdac_hp_switch[i].inverted; 753162922Sariff 754162922Sariff switch (hdac_hp_switch[i].type) { 755162922Sariff case HDAC_HP_SWITCH_CTL: 756162922Sariff ctl = hdac_audio_ctl_amp_get(devinfo, 757162922Sariff hdac_hp_switch[i].hpnid, 0, 1); 758162922Sariff if (ctl != NULL) { 759162922Sariff ctl->muted = (res != 0 && forcemute == 0) ? 760162922Sariff HDA_AMP_MUTE_NONE : HDA_AMP_MUTE_ALL; 761162922Sariff hdac_audio_ctl_amp_set(ctl, 762162922Sariff HDA_AMP_MUTE_DEFAULT, ctl->left, 763162922Sariff ctl->right); 764162922Sariff } 765162922Sariff for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) { 766162922Sariff ctl = hdac_audio_ctl_amp_get(devinfo, 767162922Sariff hdac_hp_switch[i].spkrnid[j], 0, 1); 768162922Sariff if (ctl != NULL) { 769162922Sariff ctl->muted = (res != 0 || forcemute == 1) ? 770162922Sariff HDA_AMP_MUTE_ALL : HDA_AMP_MUTE_NONE; 771162922Sariff hdac_audio_ctl_amp_set(ctl, 772162922Sariff HDA_AMP_MUTE_DEFAULT, ctl->left, 773162922Sariff ctl->right); 774162922Sariff } 775162922Sariff } 776162922Sariff break; 777162922Sariff case HDAC_HP_SWITCH_CTRL: 778162922Sariff if (res != 0) { 779162922Sariff /* HP in */ 780162922Sariff w = hdac_widget_get(devinfo, hdac_hp_switch[i].hpnid); 781163057Sariff if (w != NULL && w->type == 782163057Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) { 783162922Sariff if (forcemute == 0) 784162922Sariff w->wclass.pin.ctrl |= 785162922Sariff HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; 786162922Sariff else 787162922Sariff w->wclass.pin.ctrl &= 788162922Sariff ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; 789162922Sariff hdac_command(sc, 790162922Sariff HDA_CMD_SET_PIN_WIDGET_CTRL(cad, w->nid, 791162922Sariff w->wclass.pin.ctrl), cad); 792162922Sariff } 793162922Sariff for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) { 794162922Sariff w = hdac_widget_get(devinfo, 795162922Sariff hdac_hp_switch[i].spkrnid[j]); 796163057Sariff if (w != NULL && w->type == 797163057Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) { 798162922Sariff w->wclass.pin.ctrl &= 799162922Sariff ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; 800162922Sariff hdac_command(sc, 801162922Sariff HDA_CMD_SET_PIN_WIDGET_CTRL(cad, 802162922Sariff w->nid, 803162922Sariff w->wclass.pin.ctrl), cad); 804162922Sariff } 805162922Sariff } 806162922Sariff } else { 807162922Sariff /* HP out */ 808162922Sariff w = hdac_widget_get(devinfo, hdac_hp_switch[i].hpnid); 809163057Sariff if (w != NULL && w->type == 810163057Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) { 811162922Sariff w->wclass.pin.ctrl &= 812162922Sariff ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; 813162922Sariff hdac_command(sc, 814162922Sariff HDA_CMD_SET_PIN_WIDGET_CTRL(cad, w->nid, 815162922Sariff w->wclass.pin.ctrl), cad); 816162922Sariff } 817162922Sariff for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) { 818162922Sariff w = hdac_widget_get(devinfo, 819162922Sariff hdac_hp_switch[i].spkrnid[j]); 820163057Sariff if (w != NULL && w->type == 821163057Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) { 822162922Sariff if (forcemute == 0) 823162922Sariff w->wclass.pin.ctrl |= 824162922Sariff HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; 825162922Sariff else 826162922Sariff w->wclass.pin.ctrl &= 827162922Sariff ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; 828162922Sariff hdac_command(sc, 829162922Sariff HDA_CMD_SET_PIN_WIDGET_CTRL(cad, 830162922Sariff w->nid, 831162922Sariff w->wclass.pin.ctrl), cad); 832162922Sariff } 833162922Sariff } 834162922Sariff } 835162922Sariff break; 836162922Sariff default: 837162922Sariff break; 838162922Sariff } 839162922Sariff} 840162922Sariff 841162922Sariffstatic void 842162922Sariffhdac_unsolicited_handler(struct hdac_codec *codec, uint32_t tag) 843162922Sariff{ 844162922Sariff struct hdac_softc *sc; 845162922Sariff struct hdac_devinfo *devinfo = NULL; 846162965Sariff device_t *devlist = NULL; 847162922Sariff int devcount, i; 848162922Sariff 849162922Sariff if (codec == NULL || codec->sc == NULL) 850162922Sariff return; 851162922Sariff 852162922Sariff sc = codec->sc; 853162922Sariff 854163057Sariff HDA_BOOTVERBOSE( 855163057Sariff device_printf(sc->dev, "HDA_DEBUG: Unsol Tag: 0x%08x\n", tag); 856162922Sariff ); 857162922Sariff 858162922Sariff device_get_children(sc->dev, &devlist, &devcount); 859162965Sariff for (i = 0; devlist != NULL && i < devcount; i++) { 860162965Sariff devinfo = (struct hdac_devinfo *)device_get_ivars(devlist[i]); 861162965Sariff if (devinfo != NULL && devinfo->node_type == 862162965Sariff HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO && 863162965Sariff devinfo->codec != NULL && 864162965Sariff devinfo->codec->cad == codec->cad) { 865162965Sariff break; 866162965Sariff } else 867162965Sariff devinfo = NULL; 868162922Sariff } 869162965Sariff if (devlist != NULL) 870162965Sariff free(devlist, M_TEMP); 871162965Sariff 872162922Sariff if (devinfo == NULL) 873162922Sariff return; 874162922Sariff 875162922Sariff switch (tag) { 876162922Sariff case HDAC_UNSOLTAG_EVENT_HP: 877162922Sariff hdac_hp_switch_handler(devinfo); 878162922Sariff break; 879162922Sariff default: 880162922Sariff break; 881162922Sariff } 882162922Sariff} 883162922Sariff 884164614Sariffstatic int 885162922Sariffhdac_stream_intr(struct hdac_softc *sc, struct hdac_chan *ch) 886162922Sariff{ 887162922Sariff /* XXX to be removed */ 888162922Sariff#ifdef HDAC_INTR_EXTRA 889162922Sariff uint32_t res; 890162922Sariff#endif 891162922Sariff 892162922Sariff if (ch->blkcnt == 0) 893164614Sariff return (0); 894162922Sariff 895162922Sariff /* XXX to be removed */ 896162922Sariff#ifdef HDAC_INTR_EXTRA 897162922Sariff res = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDSTS); 898162922Sariff#endif 899162922Sariff 900162922Sariff /* XXX to be removed */ 901162922Sariff#ifdef HDAC_INTR_EXTRA 902163057Sariff HDA_BOOTVERBOSE( 903163057Sariff if (res & (HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE)) 904163057Sariff device_printf(sc->dev, 905163057Sariff "PCMDIR_%s intr triggered beyond stream boundary:" 906163057Sariff "%08x\n", 907163057Sariff (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC", res); 908163057Sariff ); 909162922Sariff#endif 910162922Sariff 911162922Sariff HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDSTS, 912163057Sariff HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE | HDAC_SDSTS_BCIS ); 913162922Sariff 914162922Sariff /* XXX to be removed */ 915162922Sariff#ifdef HDAC_INTR_EXTRA 916162922Sariff if (res & HDAC_SDSTS_BCIS) { 917162922Sariff#endif 918164614Sariff return (1); 919162922Sariff /* XXX to be removed */ 920162922Sariff#ifdef HDAC_INTR_EXTRA 921162922Sariff } 922162922Sariff#endif 923164614Sariff 924164614Sariff return (0); 925162922Sariff} 926162922Sariff 927162922Sariff/**************************************************************************** 928162922Sariff * void hdac_intr_handler(void *) 929162922Sariff * 930162922Sariff * Interrupt handler. Processes interrupts received from the hdac. 931162922Sariff ****************************************************************************/ 932162922Sariffstatic void 933162922Sariffhdac_intr_handler(void *context) 934162922Sariff{ 935162922Sariff struct hdac_softc *sc; 936162922Sariff uint32_t intsts; 937162922Sariff uint8_t rirbsts; 938164614Sariff struct hdac_rirb *rirb_base; 939164614Sariff uint32_t trigger = 0; 940162922Sariff 941162922Sariff sc = (struct hdac_softc *)context; 942162922Sariff 943162922Sariff hdac_lock(sc); 944164614Sariff if (sc->polling != 0) { 945164614Sariff hdac_unlock(sc); 946164614Sariff return; 947164614Sariff } 948162922Sariff /* Do we have anything to do? */ 949162922Sariff intsts = HDAC_READ_4(&sc->mem, HDAC_INTSTS); 950163057Sariff if (!HDA_FLAG_MATCH(intsts, HDAC_INTSTS_GIS)) { 951162922Sariff hdac_unlock(sc); 952162922Sariff return; 953162922Sariff } 954162922Sariff 955162922Sariff /* Was this a controller interrupt? */ 956163057Sariff if (HDA_FLAG_MATCH(intsts, HDAC_INTSTS_CIS)) { 957162922Sariff rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr; 958162922Sariff rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS); 959162922Sariff /* Get as many responses that we can */ 960163057Sariff while (HDA_FLAG_MATCH(rirbsts, HDAC_RIRBSTS_RINTFL)) { 961164614Sariff HDAC_WRITE_1(&sc->mem, 962164614Sariff HDAC_RIRBSTS, HDAC_RIRBSTS_RINTFL); 963164614Sariff hdac_rirb_flush(sc); 964162922Sariff rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS); 965162922Sariff } 966162922Sariff /* XXX to be removed */ 967162922Sariff /* Clear interrupt and exit */ 968162922Sariff#ifdef HDAC_INTR_EXTRA 969162922Sariff HDAC_WRITE_4(&sc->mem, HDAC_INTSTS, HDAC_INTSTS_CIS); 970162922Sariff#endif 971162922Sariff } 972164614Sariff 973164614Sariff hdac_unsolq_flush(sc); 974164614Sariff 975163057Sariff if (intsts & HDAC_INTSTS_SIS_MASK) { 976164614Sariff if ((intsts & (1 << sc->num_iss)) && 977164614Sariff hdac_stream_intr(sc, &sc->play) != 0) 978164614Sariff trigger |= 1; 979164614Sariff if ((intsts & (1 << 0)) && 980164614Sariff hdac_stream_intr(sc, &sc->rec) != 0) 981164614Sariff trigger |= 2; 982162922Sariff /* XXX to be removed */ 983162922Sariff#ifdef HDAC_INTR_EXTRA 984164614Sariff HDAC_WRITE_4(&sc->mem, HDAC_INTSTS, intsts & 985164614Sariff HDAC_INTSTS_SIS_MASK); 986162922Sariff#endif 987162922Sariff } 988162922Sariff 989164614Sariff hdac_unlock(sc); 990162922Sariff 991164614Sariff if (trigger & 1) 992164614Sariff chn_intr(sc->play.c); 993164614Sariff if (trigger & 2) 994164614Sariff chn_intr(sc->rec.c); 995162922Sariff} 996162922Sariff 997162922Sariff/**************************************************************************** 998163057Sariff * int hdac_reset(hdac_softc *) 999162922Sariff * 1000162922Sariff * Reset the hdac to a quiescent and known state. 1001162922Sariff ****************************************************************************/ 1002162922Sariffstatic int 1003162922Sariffhdac_reset(struct hdac_softc *sc) 1004162922Sariff{ 1005162922Sariff uint32_t gctl; 1006162922Sariff int count, i; 1007162922Sariff 1008162922Sariff /* 1009162922Sariff * Stop all Streams DMA engine 1010162922Sariff */ 1011162922Sariff for (i = 0; i < sc->num_iss; i++) 1012162922Sariff HDAC_WRITE_4(&sc->mem, HDAC_ISDCTL(sc, i), 0x0); 1013162922Sariff for (i = 0; i < sc->num_oss; i++) 1014162922Sariff HDAC_WRITE_4(&sc->mem, HDAC_OSDCTL(sc, i), 0x0); 1015162922Sariff for (i = 0; i < sc->num_bss; i++) 1016162922Sariff HDAC_WRITE_4(&sc->mem, HDAC_BSDCTL(sc, i), 0x0); 1017162922Sariff 1018162922Sariff /* 1019162922Sariff * Stop Control DMA engines 1020162922Sariff */ 1021162922Sariff HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, 0x0); 1022162922Sariff HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, 0x0); 1023162922Sariff 1024162922Sariff /* 1025162922Sariff * Reset the controller. The reset must remain asserted for 1026162922Sariff * a minimum of 100us. 1027162922Sariff */ 1028162922Sariff gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL); 1029162922Sariff HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl & ~HDAC_GCTL_CRST); 1030162922Sariff count = 10000; 1031162922Sariff do { 1032162922Sariff gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL); 1033162922Sariff if (!(gctl & HDAC_GCTL_CRST)) 1034162922Sariff break; 1035162922Sariff DELAY(10); 1036162922Sariff } while (--count); 1037162922Sariff if (gctl & HDAC_GCTL_CRST) { 1038162922Sariff device_printf(sc->dev, "Unable to put hdac in reset\n"); 1039162922Sariff return (ENXIO); 1040162922Sariff } 1041162922Sariff DELAY(100); 1042162922Sariff gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL); 1043162922Sariff HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl | HDAC_GCTL_CRST); 1044162922Sariff count = 10000; 1045162922Sariff do { 1046162922Sariff gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL); 1047163057Sariff if (gctl & HDAC_GCTL_CRST) 1048162922Sariff break; 1049162922Sariff DELAY(10); 1050162922Sariff } while (--count); 1051162922Sariff if (!(gctl & HDAC_GCTL_CRST)) { 1052162922Sariff device_printf(sc->dev, "Device stuck in reset\n"); 1053162922Sariff return (ENXIO); 1054162922Sariff } 1055162922Sariff 1056162922Sariff /* 1057162922Sariff * Wait for codecs to finish their own reset sequence. The delay here 1058162922Sariff * should be of 250us but for some reasons, on it's not enough on my 1059162922Sariff * computer. Let's use twice as much as necessary to make sure that 1060162922Sariff * it's reset properly. 1061162922Sariff */ 1062162922Sariff DELAY(1000); 1063162922Sariff 1064162922Sariff return (0); 1065162922Sariff} 1066162922Sariff 1067162922Sariff 1068162922Sariff/**************************************************************************** 1069162922Sariff * int hdac_get_capabilities(struct hdac_softc *); 1070162922Sariff * 1071162922Sariff * Retreive the general capabilities of the hdac; 1072162922Sariff * Number of Input Streams 1073162922Sariff * Number of Output Streams 1074162922Sariff * Number of bidirectional Streams 1075162922Sariff * 64bit ready 1076162922Sariff * CORB and RIRB sizes 1077162922Sariff ****************************************************************************/ 1078162922Sariffstatic int 1079162922Sariffhdac_get_capabilities(struct hdac_softc *sc) 1080162922Sariff{ 1081162922Sariff uint16_t gcap; 1082162922Sariff uint8_t corbsize, rirbsize; 1083162922Sariff 1084162922Sariff gcap = HDAC_READ_2(&sc->mem, HDAC_GCAP); 1085162922Sariff sc->num_iss = HDAC_GCAP_ISS(gcap); 1086162922Sariff sc->num_oss = HDAC_GCAP_OSS(gcap); 1087162922Sariff sc->num_bss = HDAC_GCAP_BSS(gcap); 1088162922Sariff 1089163057Sariff sc->support_64bit = HDA_FLAG_MATCH(gcap, HDAC_GCAP_64OK); 1090162922Sariff 1091162922Sariff corbsize = HDAC_READ_1(&sc->mem, HDAC_CORBSIZE); 1092162922Sariff if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_256) == 1093162922Sariff HDAC_CORBSIZE_CORBSZCAP_256) 1094162922Sariff sc->corb_size = 256; 1095162922Sariff else if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_16) == 1096162922Sariff HDAC_CORBSIZE_CORBSZCAP_16) 1097162922Sariff sc->corb_size = 16; 1098162922Sariff else if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_2) == 1099162922Sariff HDAC_CORBSIZE_CORBSZCAP_2) 1100162922Sariff sc->corb_size = 2; 1101162922Sariff else { 1102162922Sariff device_printf(sc->dev, "%s: Invalid corb size (%x)\n", 1103162922Sariff __func__, corbsize); 1104162922Sariff return (ENXIO); 1105162922Sariff } 1106162922Sariff 1107162922Sariff rirbsize = HDAC_READ_1(&sc->mem, HDAC_RIRBSIZE); 1108162922Sariff if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_256) == 1109162922Sariff HDAC_RIRBSIZE_RIRBSZCAP_256) 1110162922Sariff sc->rirb_size = 256; 1111162922Sariff else if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_16) == 1112162922Sariff HDAC_RIRBSIZE_RIRBSZCAP_16) 1113162922Sariff sc->rirb_size = 16; 1114162922Sariff else if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_2) == 1115162922Sariff HDAC_RIRBSIZE_RIRBSZCAP_2) 1116162922Sariff sc->rirb_size = 2; 1117162922Sariff else { 1118162922Sariff device_printf(sc->dev, "%s: Invalid rirb size (%x)\n", 1119162922Sariff __func__, rirbsize); 1120162922Sariff return (ENXIO); 1121162922Sariff } 1122162922Sariff 1123162922Sariff return (0); 1124162922Sariff} 1125162922Sariff 1126162922Sariff 1127162922Sariff/**************************************************************************** 1128162922Sariff * void hdac_dma_cb 1129162922Sariff * 1130162922Sariff * This function is called by bus_dmamap_load when the mapping has been 1131162922Sariff * established. We just record the physical address of the mapping into 1132162922Sariff * the struct hdac_dma passed in. 1133162922Sariff ****************************************************************************/ 1134162922Sariffstatic void 1135162922Sariffhdac_dma_cb(void *callback_arg, bus_dma_segment_t *segs, int nseg, int error) 1136162922Sariff{ 1137162922Sariff struct hdac_dma *dma; 1138162922Sariff 1139162922Sariff if (error == 0) { 1140162922Sariff dma = (struct hdac_dma *)callback_arg; 1141162922Sariff dma->dma_paddr = segs[0].ds_addr; 1142162922Sariff } 1143162922Sariff} 1144162922Sariff 1145162922Sariffstatic void 1146162922Sariffhdac_dma_nocache(void *ptr) 1147162922Sariff{ 1148167609Sariff#if 0 1149162956Sariff#if defined(__i386__) || defined(__amd64__) 1150162922Sariff pt_entry_t *pte; 1151162922Sariff vm_offset_t va; 1152162922Sariff 1153162922Sariff va = (vm_offset_t)ptr; 1154162922Sariff pte = vtopte(va); 1155162922Sariff if (pte) { 1156162922Sariff *pte |= PG_N; 1157162922Sariff invltlb(); 1158162922Sariff } 1159162956Sariff#endif 1160167609Sariff#endif 1161162922Sariff} 1162162922Sariff 1163162922Sariff/**************************************************************************** 1164162922Sariff * int hdac_dma_alloc 1165162922Sariff * 1166162922Sariff * This function allocate and setup a dma region (struct hdac_dma). 1167162922Sariff * It must be freed by a corresponding hdac_dma_free. 1168162922Sariff ****************************************************************************/ 1169162922Sariffstatic int 1170162922Sariffhdac_dma_alloc(struct hdac_softc *sc, struct hdac_dma *dma, bus_size_t size) 1171162922Sariff{ 1172162922Sariff int result; 1173162922Sariff int lowaddr; 1174162922Sariff 1175162922Sariff lowaddr = (sc->support_64bit) ? BUS_SPACE_MAXADDR : 1176162922Sariff BUS_SPACE_MAXADDR_32BIT; 1177162922Sariff bzero(dma, sizeof(*dma)); 1178162922Sariff 1179162922Sariff /* 1180162922Sariff * Create a DMA tag 1181162922Sariff */ 1182162922Sariff result = bus_dma_tag_create(NULL, /* parent */ 1183162922Sariff HDAC_DMA_ALIGNMENT, /* alignment */ 1184162922Sariff 0, /* boundary */ 1185162922Sariff lowaddr, /* lowaddr */ 1186162922Sariff BUS_SPACE_MAXADDR, /* highaddr */ 1187162922Sariff NULL, /* filtfunc */ 1188162922Sariff NULL, /* fistfuncarg */ 1189162922Sariff size, /* maxsize */ 1190162922Sariff 1, /* nsegments */ 1191162922Sariff size, /* maxsegsz */ 1192162922Sariff 0, /* flags */ 1193162922Sariff NULL, /* lockfunc */ 1194162922Sariff NULL, /* lockfuncarg */ 1195162922Sariff &dma->dma_tag); /* dmat */ 1196162922Sariff if (result != 0) { 1197162922Sariff device_printf(sc->dev, "%s: bus_dma_tag_create failed (%x)\n", 1198162922Sariff __func__, result); 1199162922Sariff goto fail; 1200162922Sariff } 1201162922Sariff 1202162922Sariff /* 1203162922Sariff * Allocate DMA memory 1204162922Sariff */ 1205162965Sariff result = bus_dmamem_alloc(dma->dma_tag, (void **)&dma->dma_vaddr, 1206162922Sariff BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &dma->dma_map); 1207162922Sariff if (result != 0) { 1208162922Sariff device_printf(sc->dev, "%s: bus_dmamem_alloc failed (%x)\n", 1209162922Sariff __func__, result); 1210162922Sariff goto fail; 1211162922Sariff } 1212162922Sariff 1213162922Sariff /* 1214162922Sariff * Map the memory 1215162922Sariff */ 1216162922Sariff result = bus_dmamap_load(dma->dma_tag, dma->dma_map, 1217162922Sariff (void *)dma->dma_vaddr, size, hdac_dma_cb, (void *)dma, 1218162922Sariff BUS_DMA_NOWAIT); 1219162922Sariff if (result != 0 || dma->dma_paddr == 0) { 1220162922Sariff device_printf(sc->dev, "%s: bus_dmamem_load failed (%x)\n", 1221162922Sariff __func__, result); 1222162922Sariff goto fail; 1223162922Sariff } 1224162922Sariff bzero((void *)dma->dma_vaddr, size); 1225162922Sariff hdac_dma_nocache(dma->dma_vaddr); 1226162922Sariff 1227162922Sariff return (0); 1228162922Sarifffail: 1229162922Sariff if (dma->dma_map != NULL) 1230162922Sariff bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map); 1231162922Sariff if (dma->dma_tag != NULL) 1232162922Sariff bus_dma_tag_destroy(dma->dma_tag); 1233162922Sariff return (result); 1234162922Sariff} 1235162922Sariff 1236162922Sariff 1237162922Sariff/**************************************************************************** 1238162922Sariff * void hdac_dma_free(struct hdac_dma *) 1239162922Sariff * 1240162922Sariff * Free a struct dhac_dma that has been previously allocated via the 1241162922Sariff * hdac_dma_alloc function. 1242162922Sariff ****************************************************************************/ 1243162922Sariffstatic void 1244162922Sariffhdac_dma_free(struct hdac_dma *dma) 1245162922Sariff{ 1246162922Sariff if (dma->dma_tag != NULL) { 1247162922Sariff /* Flush caches */ 1248162922Sariff bus_dmamap_sync(dma->dma_tag, dma->dma_map, 1249162922Sariff BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1250162922Sariff bus_dmamap_unload(dma->dma_tag, dma->dma_map); 1251162922Sariff bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map); 1252162922Sariff bus_dma_tag_destroy(dma->dma_tag); 1253162922Sariff } 1254162922Sariff} 1255162922Sariff 1256162922Sariff/**************************************************************************** 1257162922Sariff * int hdac_mem_alloc(struct hdac_softc *) 1258162922Sariff * 1259162922Sariff * Allocate all the bus resources necessary to speak with the physical 1260162922Sariff * controller. 1261162922Sariff ****************************************************************************/ 1262162922Sariffstatic int 1263162922Sariffhdac_mem_alloc(struct hdac_softc *sc) 1264162922Sariff{ 1265162922Sariff struct hdac_mem *mem; 1266162922Sariff 1267162922Sariff mem = &sc->mem; 1268162922Sariff mem->mem_rid = PCIR_BAR(0); 1269162922Sariff mem->mem_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1270162922Sariff &mem->mem_rid, RF_ACTIVE); 1271162922Sariff if (mem->mem_res == NULL) { 1272162922Sariff device_printf(sc->dev, 1273162922Sariff "%s: Unable to allocate memory resource\n", __func__); 1274162922Sariff return (ENOMEM); 1275162922Sariff } 1276162922Sariff mem->mem_tag = rman_get_bustag(mem->mem_res); 1277162922Sariff mem->mem_handle = rman_get_bushandle(mem->mem_res); 1278162922Sariff 1279162922Sariff return (0); 1280162922Sariff} 1281162922Sariff 1282162922Sariff/**************************************************************************** 1283162922Sariff * void hdac_mem_free(struct hdac_softc *) 1284162922Sariff * 1285162922Sariff * Free up resources previously allocated by hdac_mem_alloc. 1286162922Sariff ****************************************************************************/ 1287162922Sariffstatic void 1288162922Sariffhdac_mem_free(struct hdac_softc *sc) 1289162922Sariff{ 1290162922Sariff struct hdac_mem *mem; 1291162922Sariff 1292162922Sariff mem = &sc->mem; 1293162922Sariff if (mem->mem_res != NULL) 1294162922Sariff bus_release_resource(sc->dev, SYS_RES_MEMORY, mem->mem_rid, 1295162922Sariff mem->mem_res); 1296164614Sariff mem->mem_res = NULL; 1297162922Sariff} 1298162922Sariff 1299162922Sariff/**************************************************************************** 1300162922Sariff * int hdac_irq_alloc(struct hdac_softc *) 1301162922Sariff * 1302162922Sariff * Allocate and setup the resources necessary for interrupt handling. 1303162922Sariff ****************************************************************************/ 1304162922Sariffstatic int 1305162922Sariffhdac_irq_alloc(struct hdac_softc *sc) 1306162922Sariff{ 1307162922Sariff struct hdac_irq *irq; 1308162922Sariff int result; 1309162922Sariff 1310162922Sariff irq = &sc->irq; 1311162922Sariff irq->irq_rid = 0x0; 1312162922Sariff irq->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, 1313162922Sariff &irq->irq_rid, RF_SHAREABLE | RF_ACTIVE); 1314162922Sariff if (irq->irq_res == NULL) { 1315162922Sariff device_printf(sc->dev, "%s: Unable to allocate irq\n", 1316162922Sariff __func__); 1317162922Sariff goto fail; 1318162922Sariff } 1319162922Sariff result = snd_setup_intr(sc->dev, irq->irq_res, INTR_MPSAFE, 1320164614Sariff hdac_intr_handler, sc, &irq->irq_handle); 1321162922Sariff if (result != 0) { 1322162922Sariff device_printf(sc->dev, 1323162922Sariff "%s: Unable to setup interrupt handler (%x)\n", 1324162922Sariff __func__, result); 1325162922Sariff goto fail; 1326162922Sariff } 1327162922Sariff 1328162922Sariff return (0); 1329162922Sariff 1330162922Sarifffail: 1331164614Sariff hdac_irq_free(sc); 1332164614Sariff 1333162922Sariff return (ENXIO); 1334162922Sariff} 1335162922Sariff 1336162922Sariff/**************************************************************************** 1337162922Sariff * void hdac_irq_free(struct hdac_softc *) 1338162922Sariff * 1339162922Sariff * Free up resources previously allocated by hdac_irq_alloc. 1340162922Sariff ****************************************************************************/ 1341162922Sariffstatic void 1342162922Sariffhdac_irq_free(struct hdac_softc *sc) 1343162922Sariff{ 1344162922Sariff struct hdac_irq *irq; 1345162922Sariff 1346162922Sariff irq = &sc->irq; 1347164614Sariff if (irq->irq_res != NULL && irq->irq_handle != NULL) 1348162922Sariff bus_teardown_intr(sc->dev, irq->irq_res, irq->irq_handle); 1349162922Sariff if (irq->irq_res != NULL) 1350162922Sariff bus_release_resource(sc->dev, SYS_RES_IRQ, irq->irq_rid, 1351162922Sariff irq->irq_res); 1352164614Sariff irq->irq_handle = NULL; 1353164614Sariff irq->irq_res = NULL; 1354162922Sariff} 1355162922Sariff 1356162922Sariff/**************************************************************************** 1357162922Sariff * void hdac_corb_init(struct hdac_softc *) 1358162922Sariff * 1359162922Sariff * Initialize the corb registers for operations but do not start it up yet. 1360162922Sariff * The CORB engine must not be running when this function is called. 1361162922Sariff ****************************************************************************/ 1362162922Sariffstatic void 1363162922Sariffhdac_corb_init(struct hdac_softc *sc) 1364162922Sariff{ 1365162922Sariff uint8_t corbsize; 1366162922Sariff uint64_t corbpaddr; 1367162922Sariff 1368162922Sariff /* Setup the CORB size. */ 1369162922Sariff switch (sc->corb_size) { 1370162922Sariff case 256: 1371162922Sariff corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_256); 1372162922Sariff break; 1373162922Sariff case 16: 1374162922Sariff corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_16); 1375162922Sariff break; 1376162922Sariff case 2: 1377162922Sariff corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_2); 1378162922Sariff break; 1379162922Sariff default: 1380162922Sariff panic("%s: Invalid CORB size (%x)\n", __func__, sc->corb_size); 1381162922Sariff } 1382162922Sariff HDAC_WRITE_1(&sc->mem, HDAC_CORBSIZE, corbsize); 1383162922Sariff 1384162922Sariff /* Setup the CORB Address in the hdac */ 1385162922Sariff corbpaddr = (uint64_t)sc->corb_dma.dma_paddr; 1386162922Sariff HDAC_WRITE_4(&sc->mem, HDAC_CORBLBASE, (uint32_t)corbpaddr); 1387162922Sariff HDAC_WRITE_4(&sc->mem, HDAC_CORBUBASE, (uint32_t)(corbpaddr >> 32)); 1388162922Sariff 1389162922Sariff /* Set the WP and RP */ 1390162922Sariff sc->corb_wp = 0; 1391162922Sariff HDAC_WRITE_2(&sc->mem, HDAC_CORBWP, sc->corb_wp); 1392162922Sariff HDAC_WRITE_2(&sc->mem, HDAC_CORBRP, HDAC_CORBRP_CORBRPRST); 1393162922Sariff /* 1394162922Sariff * The HDA specification indicates that the CORBRPRST bit will always 1395162922Sariff * read as zero. Unfortunately, it seems that at least the 82801G 1396162922Sariff * doesn't reset the bit to zero, which stalls the corb engine. 1397162922Sariff * manually reset the bit to zero before continuing. 1398162922Sariff */ 1399162922Sariff HDAC_WRITE_2(&sc->mem, HDAC_CORBRP, 0x0); 1400162922Sariff 1401162922Sariff /* Enable CORB error reporting */ 1402162922Sariff#if 0 1403162922Sariff HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, HDAC_CORBCTL_CMEIE); 1404162922Sariff#endif 1405162922Sariff} 1406162922Sariff 1407162922Sariff/**************************************************************************** 1408162922Sariff * void hdac_rirb_init(struct hdac_softc *) 1409162922Sariff * 1410162922Sariff * Initialize the rirb registers for operations but do not start it up yet. 1411162922Sariff * The RIRB engine must not be running when this function is called. 1412162922Sariff ****************************************************************************/ 1413162922Sariffstatic void 1414162922Sariffhdac_rirb_init(struct hdac_softc *sc) 1415162922Sariff{ 1416162922Sariff uint8_t rirbsize; 1417162922Sariff uint64_t rirbpaddr; 1418162922Sariff 1419162922Sariff /* Setup the RIRB size. */ 1420162922Sariff switch (sc->rirb_size) { 1421162922Sariff case 256: 1422162922Sariff rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_256); 1423162922Sariff break; 1424162922Sariff case 16: 1425162922Sariff rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_16); 1426162922Sariff break; 1427162922Sariff case 2: 1428162922Sariff rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_2); 1429162922Sariff break; 1430162922Sariff default: 1431162922Sariff panic("%s: Invalid RIRB size (%x)\n", __func__, sc->rirb_size); 1432162922Sariff } 1433162922Sariff HDAC_WRITE_1(&sc->mem, HDAC_RIRBSIZE, rirbsize); 1434162922Sariff 1435162922Sariff /* Setup the RIRB Address in the hdac */ 1436162922Sariff rirbpaddr = (uint64_t)sc->rirb_dma.dma_paddr; 1437162922Sariff HDAC_WRITE_4(&sc->mem, HDAC_RIRBLBASE, (uint32_t)rirbpaddr); 1438162922Sariff HDAC_WRITE_4(&sc->mem, HDAC_RIRBUBASE, (uint32_t)(rirbpaddr >> 32)); 1439162922Sariff 1440162922Sariff /* Setup the WP and RP */ 1441162922Sariff sc->rirb_rp = 0; 1442162922Sariff HDAC_WRITE_2(&sc->mem, HDAC_RIRBWP, HDAC_RIRBWP_RIRBWPRST); 1443162922Sariff 1444164614Sariff if (sc->polling == 0) { 1445164614Sariff /* Setup the interrupt threshold */ 1446164614Sariff HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT, sc->rirb_size / 2); 1447162922Sariff 1448164614Sariff /* Enable Overrun and response received reporting */ 1449162922Sariff#if 0 1450164614Sariff HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, 1451164614Sariff HDAC_RIRBCTL_RIRBOIC | HDAC_RIRBCTL_RINTCTL); 1452162922Sariff#else 1453164614Sariff HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, HDAC_RIRBCTL_RINTCTL); 1454162922Sariff#endif 1455164614Sariff } 1456162922Sariff 1457162922Sariff /* 1458162922Sariff * Make sure that the Host CPU cache doesn't contain any dirty 1459162922Sariff * cache lines that falls in the rirb. If I understood correctly, it 1460162922Sariff * should be sufficient to do this only once as the rirb is purely 1461162922Sariff * read-only from now on. 1462162922Sariff */ 1463162922Sariff bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map, 1464162922Sariff BUS_DMASYNC_PREREAD); 1465162922Sariff} 1466162922Sariff 1467162922Sariff/**************************************************************************** 1468162922Sariff * void hdac_corb_start(hdac_softc *) 1469162922Sariff * 1470162922Sariff * Startup the corb DMA engine 1471162922Sariff ****************************************************************************/ 1472162922Sariffstatic void 1473162922Sariffhdac_corb_start(struct hdac_softc *sc) 1474162922Sariff{ 1475162922Sariff uint32_t corbctl; 1476162922Sariff 1477162922Sariff corbctl = HDAC_READ_1(&sc->mem, HDAC_CORBCTL); 1478162922Sariff corbctl |= HDAC_CORBCTL_CORBRUN; 1479162922Sariff HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, corbctl); 1480162922Sariff} 1481162922Sariff 1482162922Sariff/**************************************************************************** 1483162922Sariff * void hdac_rirb_start(hdac_softc *) 1484162922Sariff * 1485162922Sariff * Startup the rirb DMA engine 1486162922Sariff ****************************************************************************/ 1487162922Sariffstatic void 1488162922Sariffhdac_rirb_start(struct hdac_softc *sc) 1489162922Sariff{ 1490162922Sariff uint32_t rirbctl; 1491162922Sariff 1492162922Sariff rirbctl = HDAC_READ_1(&sc->mem, HDAC_RIRBCTL); 1493162922Sariff rirbctl |= HDAC_RIRBCTL_RIRBDMAEN; 1494162922Sariff HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, rirbctl); 1495162922Sariff} 1496162922Sariff 1497162922Sariff 1498162922Sariff/**************************************************************************** 1499162922Sariff * void hdac_scan_codecs(struct hdac_softc *) 1500162922Sariff * 1501162922Sariff * Scan the bus for available codecs. 1502162922Sariff ****************************************************************************/ 1503162922Sariffstatic void 1504162922Sariffhdac_scan_codecs(struct hdac_softc *sc) 1505162922Sariff{ 1506162922Sariff struct hdac_codec *codec; 1507162922Sariff int i; 1508162922Sariff uint16_t statests; 1509162922Sariff 1510162922Sariff statests = HDAC_READ_2(&sc->mem, HDAC_STATESTS); 1511162922Sariff for (i = 0; i < HDAC_CODEC_MAX; i++) { 1512162922Sariff if (HDAC_STATESTS_SDIWAKE(statests, i)) { 1513162922Sariff /* We have found a codec. */ 1514162922Sariff hdac_unlock(sc); 1515162922Sariff codec = (struct hdac_codec *)malloc(sizeof(*codec), 1516162922Sariff M_HDAC, M_ZERO | M_NOWAIT); 1517162922Sariff hdac_lock(sc); 1518162922Sariff if (codec == NULL) { 1519162922Sariff device_printf(sc->dev, 1520162922Sariff "Unable to allocate memory for codec\n"); 1521162922Sariff continue; 1522162922Sariff } 1523164614Sariff codec->commands = NULL; 1524164614Sariff codec->responses_received = 0; 1525162922Sariff codec->verbs_sent = 0; 1526162922Sariff codec->sc = sc; 1527162922Sariff codec->cad = i; 1528162922Sariff sc->codecs[i] = codec; 1529162922Sariff if (hdac_probe_codec(codec) != 0) 1530162922Sariff break; 1531162922Sariff } 1532162922Sariff } 1533162922Sariff /* All codecs have been probed, now try to attach drivers to them */ 1534163057Sariff /* bus_generic_attach(sc->dev); */ 1535162922Sariff} 1536162922Sariff 1537162922Sariff/**************************************************************************** 1538162922Sariff * void hdac_probe_codec(struct hdac_softc *, int) 1539162922Sariff * 1540162922Sariff * Probe a the given codec_id for available function groups. 1541162922Sariff ****************************************************************************/ 1542162922Sariffstatic int 1543162922Sariffhdac_probe_codec(struct hdac_codec *codec) 1544162922Sariff{ 1545162922Sariff struct hdac_softc *sc = codec->sc; 1546162922Sariff struct hdac_devinfo *devinfo; 1547162922Sariff uint32_t vendorid, revisionid, subnode; 1548162922Sariff int startnode; 1549162922Sariff int endnode; 1550162922Sariff int i; 1551162922Sariff nid_t cad = codec->cad; 1552162922Sariff 1553163057Sariff HDA_BOOTVERBOSE( 1554163057Sariff device_printf(sc->dev, "HDA_DEBUG: Probing codec: %d\n", cad); 1555162922Sariff ); 1556162922Sariff vendorid = hdac_command(sc, 1557162922Sariff HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_VENDOR_ID), 1558162922Sariff cad); 1559162922Sariff revisionid = hdac_command(sc, 1560162922Sariff HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_REVISION_ID), 1561162922Sariff cad); 1562162922Sariff subnode = hdac_command(sc, 1563162922Sariff HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_SUB_NODE_COUNT), 1564162922Sariff cad); 1565162922Sariff startnode = HDA_PARAM_SUB_NODE_COUNT_START(subnode); 1566162922Sariff endnode = startnode + HDA_PARAM_SUB_NODE_COUNT_TOTAL(subnode); 1567162922Sariff 1568163057Sariff HDA_BOOTVERBOSE( 1569163057Sariff device_printf(sc->dev, "HDA_DEBUG: \tstartnode=%d endnode=%d\n", 1570163057Sariff startnode, endnode); 1571162922Sariff ); 1572162922Sariff for (i = startnode; i < endnode; i++) { 1573162922Sariff devinfo = hdac_probe_function(codec, i); 1574162922Sariff if (devinfo != NULL) { 1575162922Sariff /* XXX Ignore other FG. */ 1576162922Sariff devinfo->vendor_id = 1577162922Sariff HDA_PARAM_VENDOR_ID_VENDOR_ID(vendorid); 1578162922Sariff devinfo->device_id = 1579162922Sariff HDA_PARAM_VENDOR_ID_DEVICE_ID(vendorid); 1580162922Sariff devinfo->revision_id = 1581162922Sariff HDA_PARAM_REVISION_ID_REVISION_ID(revisionid); 1582162922Sariff devinfo->stepping_id = 1583162922Sariff HDA_PARAM_REVISION_ID_STEPPING_ID(revisionid); 1584163057Sariff HDA_BOOTVERBOSE( 1585162922Sariff device_printf(sc->dev, 1586163057Sariff "HDA_DEBUG: \tFound AFG nid=%d " 1587162922Sariff "[startnode=%d endnode=%d]\n", 1588163057Sariff devinfo->nid, startnode, endnode); 1589162922Sariff ); 1590162922Sariff return (1); 1591162922Sariff } 1592162922Sariff } 1593162922Sariff 1594163057Sariff HDA_BOOTVERBOSE( 1595163057Sariff device_printf(sc->dev, "HDA_DEBUG: \tAFG not found\n"); 1596162922Sariff ); 1597162922Sariff return (0); 1598162922Sariff} 1599162922Sariff 1600162922Sariffstatic struct hdac_devinfo * 1601162922Sariffhdac_probe_function(struct hdac_codec *codec, nid_t nid) 1602162922Sariff{ 1603162922Sariff struct hdac_softc *sc = codec->sc; 1604162922Sariff struct hdac_devinfo *devinfo; 1605162922Sariff uint32_t fctgrptype; 1606162922Sariff nid_t cad = codec->cad; 1607162922Sariff 1608162965Sariff fctgrptype = HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE(hdac_command(sc, 1609162965Sariff HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_FCT_GRP_TYPE), cad)); 1610162922Sariff 1611162922Sariff /* XXX For now, ignore other FG. */ 1612162965Sariff if (fctgrptype != HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) 1613162922Sariff return (NULL); 1614162922Sariff 1615162922Sariff hdac_unlock(sc); 1616162922Sariff devinfo = (struct hdac_devinfo *)malloc(sizeof(*devinfo), M_HDAC, 1617162922Sariff M_NOWAIT | M_ZERO); 1618162922Sariff hdac_lock(sc); 1619162922Sariff if (devinfo == NULL) { 1620162922Sariff device_printf(sc->dev, "%s: Unable to allocate ivar\n", 1621162922Sariff __func__); 1622162922Sariff return (NULL); 1623162922Sariff } 1624162922Sariff 1625162922Sariff devinfo->nid = nid; 1626162965Sariff devinfo->node_type = fctgrptype; 1627162922Sariff devinfo->codec = codec; 1628162922Sariff 1629162922Sariff hdac_add_child(sc, devinfo); 1630162922Sariff 1631162922Sariff return (devinfo); 1632162922Sariff} 1633162922Sariff 1634162922Sariffstatic void 1635162922Sariffhdac_add_child(struct hdac_softc *sc, struct hdac_devinfo *devinfo) 1636162922Sariff{ 1637162922Sariff devinfo->dev = device_add_child(sc->dev, NULL, -1); 1638162922Sariff device_set_ivars(devinfo->dev, (void *)devinfo); 1639162922Sariff /* XXX - Print more information when booting verbose??? */ 1640162922Sariff} 1641162922Sariff 1642162922Sariffstatic void 1643162922Sariffhdac_widget_connection_parse(struct hdac_widget *w) 1644162922Sariff{ 1645162922Sariff struct hdac_softc *sc = w->devinfo->codec->sc; 1646162922Sariff uint32_t res; 1647162922Sariff int i, j, max, found, entnum, cnid; 1648162922Sariff nid_t cad = w->devinfo->codec->cad; 1649162922Sariff nid_t nid = w->nid; 1650162922Sariff 1651162922Sariff res = hdac_command(sc, 1652162922Sariff HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_CONN_LIST_LENGTH), cad); 1653162922Sariff 1654162922Sariff w->nconns = HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH(res); 1655162922Sariff 1656162922Sariff if (w->nconns < 1) 1657162922Sariff return; 1658162922Sariff 1659162922Sariff entnum = HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM(res) ? 2 : 4; 1660162922Sariff res = 0; 1661162922Sariff i = 0; 1662162922Sariff found = 0; 1663162922Sariff max = (sizeof(w->conns) / sizeof(w->conns[0])) - 1; 1664162922Sariff 1665162922Sariff while (i < w->nconns) { 1666162922Sariff res = hdac_command(sc, 1667162922Sariff HDA_CMD_GET_CONN_LIST_ENTRY(cad, nid, i), cad); 1668162922Sariff for (j = 0; j < entnum; j++) { 1669162922Sariff cnid = res; 1670162922Sariff cnid >>= (32 / entnum) * j; 1671162922Sariff cnid &= (1 << (32 / entnum)) - 1; 1672162922Sariff if (cnid == 0) 1673162922Sariff continue; 1674162922Sariff if (found > max) { 1675162922Sariff device_printf(sc->dev, 1676162922Sariff "node %d: Adding %d: " 1677162922Sariff "Max connection reached!\n", 1678162922Sariff nid, cnid); 1679162922Sariff continue; 1680162922Sariff } 1681162922Sariff w->conns[found++] = cnid; 1682162922Sariff } 1683162922Sariff i += entnum; 1684162922Sariff } 1685162922Sariff 1686163057Sariff HDA_BOOTVERBOSE( 1687162922Sariff if (w->nconns != found) { 1688162922Sariff device_printf(sc->dev, 1689163057Sariff "HDA_DEBUG: nid=%d WARNING!!! Connection " 1690162922Sariff "length=%d != found=%d\n", 1691162922Sariff nid, w->nconns, found); 1692162922Sariff } 1693162922Sariff ); 1694162922Sariff} 1695162922Sariff 1696162922Sariffstatic uint32_t 1697162922Sariffhdac_widget_pin_getconfig(struct hdac_widget *w) 1698162922Sariff{ 1699162922Sariff struct hdac_softc *sc; 1700166965Sariff uint32_t config, orig, id; 1701162922Sariff nid_t cad, nid; 1702162922Sariff 1703162922Sariff sc = w->devinfo->codec->sc; 1704162922Sariff cad = w->devinfo->codec->cad; 1705162922Sariff nid = w->nid; 1706162922Sariff id = hdac_codec_id(w->devinfo); 1707162922Sariff 1708162922Sariff config = hdac_command(sc, 1709162922Sariff HDA_CMD_GET_CONFIGURATION_DEFAULT(cad, nid), 1710162922Sariff cad); 1711166965Sariff orig = config; 1712166965Sariff 1713162965Sariff /* 1714162965Sariff * XXX REWRITE!!!! Don't argue! 1715162965Sariff */ 1716165281Sariff if (id == HDA_CODEC_ALC880 && sc->pci_subvendor == LG_LW20_SUBVENDOR) { 1717165281Sariff switch (nid) { 1718165281Sariff case 26: 1719165281Sariff config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; 1720165281Sariff config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN; 1721165281Sariff break; 1722165281Sariff case 27: 1723165281Sariff config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; 1724165281Sariff config |= HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT; 1725165281Sariff break; 1726167610Sariff default: 1727167610Sariff break; 1728165281Sariff } 1729165281Sariff } else if (id == HDA_CODEC_ALC880 && 1730162965Sariff (sc->pci_subvendor == CLEVO_D900T_SUBVENDOR || 1731162965Sariff sc->pci_subvendor == ASUS_M5200_SUBVENDOR)) { 1732162922Sariff /* 1733162965Sariff * Super broken BIOS 1734162922Sariff */ 1735162922Sariff switch (nid) { 1736162922Sariff case 20: 1737162922Sariff break; 1738162922Sariff case 21: 1739162922Sariff break; 1740162922Sariff case 22: 1741162922Sariff break; 1742162922Sariff case 23: 1743162922Sariff break; 1744162922Sariff case 24: /* MIC1 */ 1745162922Sariff config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; 1746162922Sariff config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN; 1747162922Sariff break; 1748162922Sariff case 25: /* XXX MIC2 */ 1749162922Sariff config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; 1750162922Sariff config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN; 1751162922Sariff break; 1752162922Sariff case 26: /* LINE1 */ 1753162922Sariff config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; 1754162922Sariff config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN; 1755162922Sariff break; 1756162922Sariff case 27: /* XXX LINE2 */ 1757162922Sariff config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; 1758162922Sariff config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN; 1759162922Sariff break; 1760162922Sariff case 28: /* CD */ 1761162922Sariff config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; 1762162922Sariff config |= HDA_CONFIG_DEFAULTCONF_DEVICE_CD; 1763162922Sariff break; 1764162922Sariff case 30: 1765162922Sariff break; 1766162922Sariff case 31: 1767162922Sariff break; 1768162922Sariff default: 1769162922Sariff break; 1770162922Sariff } 1771166965Sariff } else if (id == HDA_CODEC_ALC883 && 1772166965Sariff HDA_DEV_MATCH(ACER_ALL_SUBVENDOR, sc->pci_subvendor)) { 1773166965Sariff switch (nid) { 1774166965Sariff case 25: 1775166965Sariff config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK | 1776166965Sariff HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK); 1777166965Sariff config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN | 1778166965Sariff HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED); 1779166965Sariff break; 1780166965Sariff default: 1781166965Sariff break; 1782166965Sariff } 1783166965Sariff } else if (id == HDA_CODEC_CXVENICE && sc->pci_subvendor == 1784166965Sariff HP_V3000_SUBVENDOR) { 1785166965Sariff switch (nid) { 1786166965Sariff case 18: 1787166965Sariff config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK; 1788166965Sariff config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE; 1789166965Sariff break; 1790166965Sariff case 20: 1791166965Sariff config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK | 1792166965Sariff HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK); 1793166965Sariff config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN | 1794166965Sariff HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED); 1795166965Sariff break; 1796167454Sariff case 21: 1797167454Sariff config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK | 1798167454Sariff HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK); 1799167454Sariff config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD | 1800167454Sariff HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED); 1801167454Sariff break; 1802166965Sariff default: 1803166965Sariff break; 1804166965Sariff } 1805162922Sariff } 1806162922Sariff 1807166965Sariff HDA_BOOTVERBOSE( 1808166965Sariff if (config != orig) 1809166965Sariff device_printf(sc->dev, 1810166965Sariff "HDA_DEBUG: Pin config nid=%u 0x%08x -> 0x%08x\n", 1811166965Sariff nid, orig, config); 1812166965Sariff ); 1813166965Sariff 1814162922Sariff return (config); 1815162922Sariff} 1816162922Sariff 1817166965Sariffstatic uint32_t 1818166965Sariffhdac_widget_pin_getcaps(struct hdac_widget *w) 1819166965Sariff{ 1820166965Sariff struct hdac_softc *sc; 1821166965Sariff uint32_t caps, orig, id; 1822166965Sariff nid_t cad, nid; 1823166965Sariff 1824166965Sariff sc = w->devinfo->codec->sc; 1825166965Sariff cad = w->devinfo->codec->cad; 1826166965Sariff nid = w->nid; 1827166965Sariff id = hdac_codec_id(w->devinfo); 1828166965Sariff 1829166965Sariff caps = hdac_command(sc, 1830166965Sariff HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_PIN_CAP), cad); 1831166965Sariff orig = caps; 1832166965Sariff 1833166965Sariff HDA_BOOTVERBOSE( 1834166965Sariff if (caps != orig) 1835166965Sariff device_printf(sc->dev, 1836166965Sariff "HDA_DEBUG: Pin caps nid=%u 0x%08x -> 0x%08x\n", 1837166965Sariff nid, orig, caps); 1838166965Sariff ); 1839166965Sariff 1840166965Sariff return (caps); 1841166965Sariff} 1842166965Sariff 1843162922Sariffstatic void 1844162922Sariffhdac_widget_pin_parse(struct hdac_widget *w) 1845162922Sariff{ 1846162922Sariff struct hdac_softc *sc = w->devinfo->codec->sc; 1847162922Sariff uint32_t config, pincap; 1848162922Sariff char *devstr, *connstr; 1849162922Sariff nid_t cad = w->devinfo->codec->cad; 1850162922Sariff nid_t nid = w->nid; 1851162922Sariff 1852162922Sariff config = hdac_widget_pin_getconfig(w); 1853162922Sariff w->wclass.pin.config = config; 1854162922Sariff 1855166965Sariff pincap = hdac_widget_pin_getcaps(w); 1856162922Sariff w->wclass.pin.cap = pincap; 1857162922Sariff 1858162922Sariff w->wclass.pin.ctrl = hdac_command(sc, 1859164614Sariff HDA_CMD_GET_PIN_WIDGET_CTRL(cad, nid), cad) & 1860164614Sariff ~(HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE | 1861164614Sariff HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE | 1862164614Sariff HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE); 1863162922Sariff 1864162922Sariff if (HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap)) 1865162922Sariff w->wclass.pin.ctrl |= HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE; 1866162922Sariff if (HDA_PARAM_PIN_CAP_OUTPUT_CAP(pincap)) 1867162922Sariff w->wclass.pin.ctrl |= HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; 1868162922Sariff if (HDA_PARAM_PIN_CAP_INPUT_CAP(pincap)) 1869162922Sariff w->wclass.pin.ctrl |= HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE; 1870162922Sariff if (HDA_PARAM_PIN_CAP_EAPD_CAP(pincap)) { 1871162922Sariff w->param.eapdbtl = hdac_command(sc, 1872162922Sariff HDA_CMD_GET_EAPD_BTL_ENABLE(cad, nid), cad); 1873162922Sariff w->param.eapdbtl &= 0x7; 1874162922Sariff w->param.eapdbtl |= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD; 1875162922Sariff } else 1876162965Sariff w->param.eapdbtl = HDAC_INVALID; 1877162922Sariff 1878162922Sariff switch (config & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) { 1879162922Sariff case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT: 1880162922Sariff devstr = "line out"; 1881162922Sariff break; 1882162922Sariff case HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER: 1883162922Sariff devstr = "speaker"; 1884162922Sariff break; 1885162922Sariff case HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT: 1886162922Sariff devstr = "headphones out"; 1887162922Sariff break; 1888162922Sariff case HDA_CONFIG_DEFAULTCONF_DEVICE_CD: 1889162922Sariff devstr = "CD"; 1890162922Sariff break; 1891162922Sariff case HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_OUT: 1892162922Sariff devstr = "SPDIF out"; 1893162922Sariff break; 1894162922Sariff case HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_OUT: 1895162922Sariff devstr = "digital (other) out"; 1896162922Sariff break; 1897162922Sariff case HDA_CONFIG_DEFAULTCONF_DEVICE_MODEM_LINE: 1898162922Sariff devstr = "modem, line side"; 1899162922Sariff break; 1900162922Sariff case HDA_CONFIG_DEFAULTCONF_DEVICE_MODEM_HANDSET: 1901162922Sariff devstr = "modem, handset side"; 1902162922Sariff break; 1903162922Sariff case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN: 1904162922Sariff devstr = "line in"; 1905162922Sariff break; 1906162922Sariff case HDA_CONFIG_DEFAULTCONF_DEVICE_AUX: 1907162922Sariff devstr = "AUX"; 1908162922Sariff break; 1909162922Sariff case HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN: 1910162922Sariff devstr = "Mic in"; 1911162922Sariff break; 1912162922Sariff case HDA_CONFIG_DEFAULTCONF_DEVICE_TELEPHONY: 1913162922Sariff devstr = "telephony"; 1914162922Sariff break; 1915162922Sariff case HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_IN: 1916162922Sariff devstr = "SPDIF in"; 1917162922Sariff break; 1918162922Sariff case HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_IN: 1919162922Sariff devstr = "digital (other) in"; 1920162922Sariff break; 1921162922Sariff case HDA_CONFIG_DEFAULTCONF_DEVICE_OTHER: 1922162922Sariff devstr = "other"; 1923162922Sariff break; 1924162922Sariff default: 1925162922Sariff devstr = "unknown"; 1926162922Sariff break; 1927162922Sariff } 1928162922Sariff 1929162922Sariff switch (config & HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) { 1930162922Sariff case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK: 1931162922Sariff connstr = "jack"; 1932162922Sariff break; 1933162922Sariff case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE: 1934162922Sariff connstr = "none"; 1935162922Sariff break; 1936162922Sariff case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED: 1937162922Sariff connstr = "fixed"; 1938162922Sariff break; 1939162922Sariff case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_BOTH: 1940162922Sariff connstr = "jack / fixed"; 1941162922Sariff break; 1942162922Sariff default: 1943162922Sariff connstr = "unknown"; 1944162922Sariff break; 1945162922Sariff } 1946162922Sariff 1947162922Sariff strlcat(w->name, ": ", sizeof(w->name)); 1948162922Sariff strlcat(w->name, devstr, sizeof(w->name)); 1949162922Sariff strlcat(w->name, " (", sizeof(w->name)); 1950162922Sariff strlcat(w->name, connstr, sizeof(w->name)); 1951162922Sariff strlcat(w->name, ")", sizeof(w->name)); 1952162922Sariff} 1953162922Sariff 1954162922Sariffstatic void 1955162922Sariffhdac_widget_parse(struct hdac_widget *w) 1956162922Sariff{ 1957162922Sariff struct hdac_softc *sc = w->devinfo->codec->sc; 1958162922Sariff uint32_t wcap, cap; 1959162922Sariff char *typestr; 1960162922Sariff nid_t cad = w->devinfo->codec->cad; 1961162922Sariff nid_t nid = w->nid; 1962162922Sariff 1963162922Sariff wcap = hdac_command(sc, 1964162922Sariff HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_AUDIO_WIDGET_CAP), 1965162922Sariff cad); 1966162922Sariff w->param.widget_cap = wcap; 1967162922Sariff w->type = HDA_PARAM_AUDIO_WIDGET_CAP_TYPE(wcap); 1968162922Sariff 1969162922Sariff switch (w->type) { 1970162922Sariff case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT: 1971162922Sariff typestr = "audio output"; 1972162922Sariff break; 1973162922Sariff case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT: 1974162922Sariff typestr = "audio input"; 1975162922Sariff break; 1976162922Sariff case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER: 1977162922Sariff typestr = "audio mixer"; 1978162922Sariff break; 1979162922Sariff case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR: 1980162922Sariff typestr = "audio selector"; 1981162922Sariff break; 1982162922Sariff case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX: 1983162922Sariff typestr = "pin"; 1984162922Sariff break; 1985162922Sariff case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_POWER_WIDGET: 1986162922Sariff typestr = "power widget"; 1987162922Sariff break; 1988162922Sariff case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VOLUME_WIDGET: 1989162922Sariff typestr = "volume widget"; 1990162922Sariff break; 1991162922Sariff case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET: 1992162922Sariff typestr = "beep widget"; 1993162922Sariff break; 1994162922Sariff case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VENDOR_WIDGET: 1995162922Sariff typestr = "vendor widget"; 1996162922Sariff break; 1997162922Sariff default: 1998162922Sariff typestr = "unknown type"; 1999162922Sariff break; 2000162922Sariff } 2001162922Sariff 2002162922Sariff strlcpy(w->name, typestr, sizeof(w->name)); 2003162922Sariff 2004162922Sariff if (HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL(wcap)) { 2005162922Sariff hdac_command(sc, 2006162922Sariff HDA_CMD_SET_POWER_STATE(cad, nid, HDA_CMD_POWER_STATE_D0), 2007162922Sariff cad); 2008162922Sariff DELAY(1000); 2009162922Sariff } 2010162922Sariff 2011162922Sariff hdac_widget_connection_parse(w); 2012162922Sariff 2013162922Sariff if (HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP(wcap)) { 2014162922Sariff if (HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR(wcap)) 2015162922Sariff w->param.outamp_cap = 2016162922Sariff hdac_command(sc, 2017162922Sariff HDA_CMD_GET_PARAMETER(cad, nid, 2018162922Sariff HDA_PARAM_OUTPUT_AMP_CAP), cad); 2019162922Sariff else 2020162922Sariff w->param.outamp_cap = 2021162922Sariff w->devinfo->function.audio.outamp_cap; 2022162922Sariff } else 2023162922Sariff w->param.outamp_cap = 0; 2024162922Sariff 2025162922Sariff if (HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP(wcap)) { 2026162922Sariff if (HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR(wcap)) 2027162922Sariff w->param.inamp_cap = 2028162922Sariff hdac_command(sc, 2029162922Sariff HDA_CMD_GET_PARAMETER(cad, nid, 2030162922Sariff HDA_PARAM_INPUT_AMP_CAP), cad); 2031162922Sariff else 2032162922Sariff w->param.inamp_cap = 2033162922Sariff w->devinfo->function.audio.inamp_cap; 2034162922Sariff } else 2035162922Sariff w->param.inamp_cap = 0; 2036162922Sariff 2037162922Sariff if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT || 2038162922Sariff w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) { 2039162922Sariff if (HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR(wcap)) { 2040162922Sariff cap = hdac_command(sc, 2041162922Sariff HDA_CMD_GET_PARAMETER(cad, nid, 2042162922Sariff HDA_PARAM_SUPP_STREAM_FORMATS), cad); 2043162922Sariff w->param.supp_stream_formats = (cap != 0) ? cap : 2044162922Sariff w->devinfo->function.audio.supp_stream_formats; 2045162922Sariff cap = hdac_command(sc, 2046162922Sariff HDA_CMD_GET_PARAMETER(cad, nid, 2047162922Sariff HDA_PARAM_SUPP_PCM_SIZE_RATE), cad); 2048162922Sariff w->param.supp_pcm_size_rate = (cap != 0) ? cap : 2049162922Sariff w->devinfo->function.audio.supp_pcm_size_rate; 2050162922Sariff } else { 2051162922Sariff w->param.supp_stream_formats = 2052162922Sariff w->devinfo->function.audio.supp_stream_formats; 2053162922Sariff w->param.supp_pcm_size_rate = 2054162922Sariff w->devinfo->function.audio.supp_pcm_size_rate; 2055162922Sariff } 2056162922Sariff } else { 2057162922Sariff w->param.supp_stream_formats = 0; 2058162922Sariff w->param.supp_pcm_size_rate = 0; 2059162922Sariff } 2060162922Sariff 2061162922Sariff if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) 2062162922Sariff hdac_widget_pin_parse(w); 2063162922Sariff} 2064162922Sariff 2065162922Sariffstatic struct hdac_widget * 2066162922Sariffhdac_widget_get(struct hdac_devinfo *devinfo, nid_t nid) 2067162922Sariff{ 2068162922Sariff if (devinfo == NULL || devinfo->widget == NULL || 2069162922Sariff nid < devinfo->startnode || nid >= devinfo->endnode) 2070162922Sariff return (NULL); 2071162922Sariff return (&devinfo->widget[nid - devinfo->startnode]); 2072162922Sariff} 2073162922Sariff 2074164614Sariffstatic __inline int 2075164614Sariffhda_poll_channel(struct hdac_chan *ch) 2076164614Sariff{ 2077164614Sariff uint32_t sz, delta; 2078164614Sariff volatile uint32_t ptr; 2079164614Sariff 2080164614Sariff if (ch->active == 0) 2081164614Sariff return (0); 2082164614Sariff 2083164614Sariff sz = ch->blksz * ch->blkcnt; 2084164614Sariff ptr = HDAC_READ_4(&ch->devinfo->codec->sc->mem, ch->off + HDAC_SDLPIB); 2085164614Sariff ch->ptr = ptr; 2086164614Sariff ptr %= sz; 2087164614Sariff ptr &= ~(ch->blksz - 1); 2088164614Sariff delta = (sz + ptr - ch->prevptr) % sz; 2089164614Sariff 2090164614Sariff if (delta < ch->blksz) 2091164614Sariff return (0); 2092164614Sariff 2093164614Sariff ch->prevptr = ptr; 2094164614Sariff 2095164614Sariff return (1); 2096164614Sariff} 2097164614Sariff 2098164614Sariff#define hda_chan_active(sc) ((sc)->play.active + (sc)->rec.active) 2099164614Sariff 2100162922Sariffstatic void 2101164614Sariffhda_poll_callback(void *arg) 2102164614Sariff{ 2103164614Sariff struct hdac_softc *sc = arg; 2104164614Sariff uint32_t trigger = 0; 2105164614Sariff 2106164614Sariff if (sc == NULL) 2107164614Sariff return; 2108164614Sariff 2109164614Sariff hdac_lock(sc); 2110164614Sariff if (sc->polling == 0 || hda_chan_active(sc) == 0) { 2111164614Sariff hdac_unlock(sc); 2112164614Sariff return; 2113164614Sariff } 2114164614Sariff 2115164614Sariff trigger |= (hda_poll_channel(&sc->play) != 0) ? 1 : 0; 2116164614Sariff trigger |= (hda_poll_channel(&sc->rec) != 0) ? 2 : 0; 2117164614Sariff 2118164614Sariff /* XXX */ 2119164614Sariff callout_reset(&sc->poll_hda, 1/*sc->poll_ticks*/, 2120164614Sariff hda_poll_callback, sc); 2121164614Sariff 2122164614Sariff hdac_unlock(sc); 2123164614Sariff 2124164614Sariff if (trigger & 1) 2125164614Sariff chn_intr(sc->play.c); 2126164614Sariff if (trigger & 2) 2127164614Sariff chn_intr(sc->rec.c); 2128164614Sariff} 2129164614Sariff 2130164614Sariffstatic int 2131164614Sariffhdac_rirb_flush(struct hdac_softc *sc) 2132164614Sariff{ 2133164614Sariff struct hdac_rirb *rirb_base, *rirb; 2134164614Sariff struct hdac_codec *codec; 2135164614Sariff struct hdac_command_list *commands; 2136164614Sariff nid_t cad; 2137164614Sariff uint32_t resp; 2138164614Sariff uint8_t rirbwp; 2139164614Sariff int ret = 0; 2140164614Sariff 2141164614Sariff rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr; 2142164614Sariff rirbwp = HDAC_READ_1(&sc->mem, HDAC_RIRBWP); 2143164614Sariff bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map, 2144164614Sariff BUS_DMASYNC_POSTREAD); 2145164614Sariff 2146164614Sariff while (sc->rirb_rp != rirbwp) { 2147164614Sariff sc->rirb_rp++; 2148164614Sariff sc->rirb_rp %= sc->rirb_size; 2149164614Sariff rirb = &rirb_base[sc->rirb_rp]; 2150164614Sariff cad = HDAC_RIRB_RESPONSE_EX_SDATA_IN(rirb->response_ex); 2151164614Sariff if (cad < 0 || cad >= HDAC_CODEC_MAX || 2152164614Sariff sc->codecs[cad] == NULL) 2153164614Sariff continue; 2154164614Sariff resp = rirb->response; 2155164614Sariff codec = sc->codecs[cad]; 2156164614Sariff commands = codec->commands; 2157164614Sariff if (rirb->response_ex & HDAC_RIRB_RESPONSE_EX_UNSOLICITED) { 2158164614Sariff sc->unsolq[sc->unsolq_wp++] = (cad << 16) | 2159164614Sariff ((resp >> 26) & 0xffff); 2160164614Sariff sc->unsolq_wp %= HDAC_UNSOLQ_MAX; 2161164614Sariff } else if (commands != NULL && commands->num_commands > 0 && 2162164614Sariff codec->responses_received < commands->num_commands) 2163164614Sariff commands->responses[codec->responses_received++] = 2164164614Sariff resp; 2165164614Sariff ret++; 2166164614Sariff } 2167164614Sariff 2168164614Sariff return (ret); 2169164614Sariff} 2170164614Sariff 2171164614Sariffstatic int 2172164614Sariffhdac_unsolq_flush(struct hdac_softc *sc) 2173164614Sariff{ 2174164614Sariff nid_t cad; 2175164614Sariff uint32_t tag; 2176164614Sariff int ret = 0; 2177164614Sariff 2178164614Sariff if (sc->unsolq_st == HDAC_UNSOLQ_READY) { 2179164614Sariff sc->unsolq_st = HDAC_UNSOLQ_BUSY; 2180164614Sariff while (sc->unsolq_rp != sc->unsolq_wp) { 2181164614Sariff cad = sc->unsolq[sc->unsolq_rp] >> 16; 2182164614Sariff tag = sc->unsolq[sc->unsolq_rp++] & 0xffff; 2183164614Sariff sc->unsolq_rp %= HDAC_UNSOLQ_MAX; 2184164614Sariff hdac_unsolicited_handler(sc->codecs[cad], tag); 2185164614Sariff ret++; 2186164614Sariff } 2187164614Sariff sc->unsolq_st = HDAC_UNSOLQ_READY; 2188164614Sariff } 2189164614Sariff 2190164614Sariff return (ret); 2191164614Sariff} 2192164614Sariff 2193164614Sariffstatic void 2194164614Sariffhdac_poll_callback(void *arg) 2195164614Sariff{ 2196164614Sariff struct hdac_softc *sc = arg; 2197164614Sariff if (sc == NULL) 2198164614Sariff return; 2199166796Sariff 2200164614Sariff hdac_lock(sc); 2201164614Sariff if (sc->polling == 0) { 2202164614Sariff hdac_unlock(sc); 2203164614Sariff return; 2204164614Sariff } 2205164614Sariff hdac_rirb_flush(sc); 2206164614Sariff hdac_unsolq_flush(sc); 2207164614Sariff callout_reset(&sc->poll_hdac, max(hz >> 2, 1), 2208164614Sariff hdac_poll_callback, sc); 2209164614Sariff hdac_unlock(sc); 2210164614Sariff} 2211164614Sariff 2212164614Sariffstatic void 2213162922Sariffhdac_stream_stop(struct hdac_chan *ch) 2214162922Sariff{ 2215162922Sariff struct hdac_softc *sc = ch->devinfo->codec->sc; 2216162922Sariff uint32_t ctl; 2217162922Sariff 2218162922Sariff ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0); 2219162922Sariff ctl &= ~(HDAC_SDCTL_IOCE | HDAC_SDCTL_FEIE | HDAC_SDCTL_DEIE | 2220162922Sariff HDAC_SDCTL_RUN); 2221162922Sariff HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl); 2222162922Sariff 2223164614Sariff ch->active = 0; 2224164614Sariff 2225164614Sariff if (sc->polling != 0) { 2226164614Sariff int pollticks; 2227164614Sariff 2228164614Sariff if (hda_chan_active(sc) == 0) { 2229164614Sariff callout_stop(&sc->poll_hda); 2230164614Sariff sc->poll_ticks = 1; 2231164614Sariff } else { 2232164614Sariff if (sc->play.active != 0) 2233164614Sariff ch = &sc->play; 2234164614Sariff else 2235164614Sariff ch = &sc->rec; 2236164614Sariff pollticks = ((uint64_t)hz * ch->blksz) / 2237164614Sariff ((uint64_t)sndbuf_getbps(ch->b) * 2238164614Sariff sndbuf_getspd(ch->b)); 2239164614Sariff pollticks >>= 2; 2240164614Sariff if (pollticks > hz) 2241164614Sariff pollticks = hz; 2242164614Sariff if (pollticks < 1) { 2243164614Sariff HDA_BOOTVERBOSE( 2244164614Sariff device_printf(sc->dev, 2245164614Sariff "%s: pollticks=%d < 1 !\n", 2246164614Sariff __func__, pollticks); 2247164614Sariff ); 2248164614Sariff pollticks = 1; 2249164614Sariff } 2250164614Sariff if (pollticks > sc->poll_ticks) { 2251164614Sariff HDA_BOOTVERBOSE( 2252164614Sariff device_printf(sc->dev, 2253164614Sariff "%s: pollticks %d -> %d\n", 2254164614Sariff __func__, sc->poll_ticks, 2255164614Sariff pollticks); 2256164614Sariff ); 2257164614Sariff sc->poll_ticks = pollticks; 2258164614Sariff callout_reset(&sc->poll_hda, 1, 2259164614Sariff hda_poll_callback, sc); 2260164614Sariff } 2261164614Sariff } 2262164614Sariff } else { 2263164614Sariff ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL); 2264164614Sariff ctl &= ~(1 << (ch->off >> 5)); 2265164614Sariff HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl); 2266164614Sariff } 2267162922Sariff} 2268162922Sariff 2269162922Sariffstatic void 2270162922Sariffhdac_stream_start(struct hdac_chan *ch) 2271162922Sariff{ 2272162922Sariff struct hdac_softc *sc = ch->devinfo->codec->sc; 2273162922Sariff uint32_t ctl; 2274162922Sariff 2275164614Sariff if (sc->polling != 0) { 2276164614Sariff int pollticks; 2277162922Sariff 2278164614Sariff pollticks = ((uint64_t)hz * ch->blksz) / 2279164614Sariff ((uint64_t)sndbuf_getbps(ch->b) * sndbuf_getspd(ch->b)); 2280164614Sariff pollticks >>= 2; 2281164614Sariff if (pollticks > hz) 2282164614Sariff pollticks = hz; 2283164614Sariff if (pollticks < 1) { 2284164614Sariff HDA_BOOTVERBOSE( 2285164614Sariff device_printf(sc->dev, 2286164614Sariff "%s: pollticks=%d < 1 !\n", 2287164614Sariff __func__, pollticks); 2288164614Sariff ); 2289164614Sariff pollticks = 1; 2290164614Sariff } 2291164614Sariff if (hda_chan_active(sc) == 0 || pollticks < sc->poll_ticks) { 2292164614Sariff HDA_BOOTVERBOSE( 2293164614Sariff if (hda_chan_active(sc) == 0) { 2294164614Sariff device_printf(sc->dev, 2295164614Sariff "%s: pollticks=%d\n", 2296164614Sariff __func__, pollticks); 2297164614Sariff } else { 2298164614Sariff device_printf(sc->dev, 2299164614Sariff "%s: pollticks %d -> %d\n", 2300164614Sariff __func__, sc->poll_ticks, 2301164614Sariff pollticks); 2302164614Sariff } 2303164614Sariff ); 2304164614Sariff sc->poll_ticks = pollticks; 2305164614Sariff callout_reset(&sc->poll_hda, 1, hda_poll_callback, 2306164614Sariff sc); 2307164614Sariff } 2308164614Sariff ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0); 2309164614Sariff ctl |= HDAC_SDCTL_RUN; 2310164614Sariff } else { 2311164614Sariff ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL); 2312164614Sariff ctl |= 1 << (ch->off >> 5); 2313164614Sariff HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl); 2314164614Sariff ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0); 2315164614Sariff ctl |= HDAC_SDCTL_IOCE | HDAC_SDCTL_FEIE | HDAC_SDCTL_DEIE | 2316164614Sariff HDAC_SDCTL_RUN; 2317164614Sariff } 2318162922Sariff HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl); 2319164614Sariff 2320164614Sariff ch->active = 1; 2321162922Sariff} 2322162922Sariff 2323162922Sariffstatic void 2324162922Sariffhdac_stream_reset(struct hdac_chan *ch) 2325162922Sariff{ 2326162922Sariff struct hdac_softc *sc = ch->devinfo->codec->sc; 2327162922Sariff int timeout = 1000; 2328162922Sariff int to = timeout; 2329162922Sariff uint32_t ctl; 2330162922Sariff 2331162922Sariff ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0); 2332162922Sariff ctl |= HDAC_SDCTL_SRST; 2333162922Sariff HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl); 2334162922Sariff do { 2335162922Sariff ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0); 2336162922Sariff if (ctl & HDAC_SDCTL_SRST) 2337162922Sariff break; 2338162922Sariff DELAY(10); 2339162922Sariff } while (--to); 2340162922Sariff if (!(ctl & HDAC_SDCTL_SRST)) { 2341162922Sariff device_printf(sc->dev, "timeout in reset\n"); 2342162922Sariff } 2343162922Sariff ctl &= ~HDAC_SDCTL_SRST; 2344162922Sariff HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl); 2345162922Sariff to = timeout; 2346162922Sariff do { 2347162922Sariff ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0); 2348162922Sariff if (!(ctl & HDAC_SDCTL_SRST)) 2349162922Sariff break; 2350162922Sariff DELAY(10); 2351162922Sariff } while (--to); 2352163057Sariff if (ctl & HDAC_SDCTL_SRST) 2353162922Sariff device_printf(sc->dev, "can't reset!\n"); 2354162922Sariff} 2355162922Sariff 2356162922Sariffstatic void 2357162922Sariffhdac_stream_setid(struct hdac_chan *ch) 2358162922Sariff{ 2359162922Sariff struct hdac_softc *sc = ch->devinfo->codec->sc; 2360162922Sariff uint32_t ctl; 2361162922Sariff 2362162922Sariff ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL2); 2363162922Sariff ctl &= ~HDAC_SDCTL2_STRM_MASK; 2364162922Sariff ctl |= ch->sid << HDAC_SDCTL2_STRM_SHIFT; 2365162922Sariff HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL2, ctl); 2366162922Sariff} 2367162922Sariff 2368162922Sariffstatic void 2369162922Sariffhdac_bdl_setup(struct hdac_chan *ch) 2370162922Sariff{ 2371162922Sariff struct hdac_softc *sc = ch->devinfo->codec->sc; 2372164614Sariff struct hdac_bdle *bdle; 2373162922Sariff uint64_t addr; 2374164614Sariff uint32_t blksz, blkcnt; 2375162922Sariff int i; 2376162922Sariff 2377162922Sariff addr = (uint64_t)sndbuf_getbufaddr(ch->b); 2378164614Sariff bdle = (struct hdac_bdle *)ch->bdl_dma.dma_vaddr; 2379162922Sariff 2380164614Sariff if (sc->polling != 0) { 2381164614Sariff blksz = ch->blksz * ch->blkcnt; 2382164614Sariff blkcnt = 1; 2383164614Sariff } else { 2384164614Sariff blksz = ch->blksz; 2385164614Sariff blkcnt = ch->blkcnt; 2386164614Sariff } 2387164614Sariff 2388164614Sariff for (i = 0; i < blkcnt; i++, bdle++) { 2389162922Sariff bdle->addrl = (uint32_t)addr; 2390162922Sariff bdle->addrh = (uint32_t)(addr >> 32); 2391164614Sariff bdle->len = blksz; 2392164614Sariff bdle->ioc = 1 ^ sc->polling; 2393164614Sariff addr += blksz; 2394162922Sariff } 2395162922Sariff 2396164614Sariff HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDCBL, blksz * blkcnt); 2397164614Sariff HDAC_WRITE_2(&sc->mem, ch->off + HDAC_SDLVI, blkcnt - 1); 2398162922Sariff addr = ch->bdl_dma.dma_paddr; 2399162922Sariff HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDBDPL, (uint32_t)addr); 2400162922Sariff HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDBDPU, (uint32_t)(addr >> 32)); 2401162922Sariff} 2402162922Sariff 2403162922Sariffstatic int 2404162922Sariffhdac_bdl_alloc(struct hdac_chan *ch) 2405162922Sariff{ 2406162922Sariff struct hdac_softc *sc = ch->devinfo->codec->sc; 2407162922Sariff int rc; 2408162922Sariff 2409162922Sariff rc = hdac_dma_alloc(sc, &ch->bdl_dma, 2410162922Sariff sizeof(struct hdac_bdle) * HDA_BDL_MAX); 2411162922Sariff if (rc) { 2412162922Sariff device_printf(sc->dev, "can't alloc bdl\n"); 2413162922Sariff return (rc); 2414162922Sariff } 2415162922Sariff hdac_dma_nocache(ch->bdl_dma.dma_vaddr); 2416162922Sariff 2417162922Sariff return (0); 2418162922Sariff} 2419162922Sariff 2420162922Sariffstatic void 2421162922Sariffhdac_audio_ctl_amp_set_internal(struct hdac_softc *sc, nid_t cad, nid_t nid, 2422162922Sariff int index, int lmute, int rmute, 2423162922Sariff int left, int right, int dir) 2424162922Sariff{ 2425162922Sariff uint16_t v = 0; 2426162922Sariff 2427162922Sariff if (sc == NULL) 2428162922Sariff return; 2429162922Sariff 2430162922Sariff if (left != right || lmute != rmute) { 2431162922Sariff v = (1 << (15 - dir)) | (1 << 13) | (index << 8) | 2432162922Sariff (lmute << 7) | left; 2433162922Sariff hdac_command(sc, 2434164614Sariff HDA_CMD_SET_AMP_GAIN_MUTE(cad, nid, v), cad); 2435162922Sariff v = (1 << (15 - dir)) | (1 << 12) | (index << 8) | 2436162922Sariff (rmute << 7) | right; 2437162922Sariff } else 2438162922Sariff v = (1 << (15 - dir)) | (3 << 12) | (index << 8) | 2439162922Sariff (lmute << 7) | left; 2440162922Sariff 2441162922Sariff hdac_command(sc, 2442162922Sariff HDA_CMD_SET_AMP_GAIN_MUTE(cad, nid, v), cad); 2443162922Sariff} 2444162922Sariff 2445162922Sariffstatic void 2446162922Sariffhdac_audio_ctl_amp_set(struct hdac_audio_ctl *ctl, uint32_t mute, 2447162922Sariff int left, int right) 2448162922Sariff{ 2449162922Sariff struct hdac_softc *sc; 2450162922Sariff nid_t nid, cad; 2451162922Sariff int lmute, rmute; 2452162922Sariff 2453162922Sariff if (ctl == NULL || ctl->widget == NULL || 2454162922Sariff ctl->widget->devinfo == NULL || 2455162922Sariff ctl->widget->devinfo->codec == NULL || 2456162922Sariff ctl->widget->devinfo->codec->sc == NULL) 2457162922Sariff return; 2458162922Sariff 2459162922Sariff sc = ctl->widget->devinfo->codec->sc; 2460162922Sariff cad = ctl->widget->devinfo->codec->cad; 2461162922Sariff nid = ctl->widget->nid; 2462162922Sariff 2463162922Sariff if (mute == HDA_AMP_MUTE_DEFAULT) { 2464162922Sariff lmute = HDA_AMP_LEFT_MUTED(ctl->muted); 2465162922Sariff rmute = HDA_AMP_RIGHT_MUTED(ctl->muted); 2466162922Sariff } else { 2467162922Sariff lmute = HDA_AMP_LEFT_MUTED(mute); 2468162922Sariff rmute = HDA_AMP_RIGHT_MUTED(mute); 2469162922Sariff } 2470162922Sariff 2471162922Sariff if (ctl->dir & HDA_CTL_OUT) 2472162922Sariff hdac_audio_ctl_amp_set_internal(sc, cad, nid, ctl->index, 2473162922Sariff lmute, rmute, left, right, 0); 2474162922Sariff if (ctl->dir & HDA_CTL_IN) 2475162922Sariff hdac_audio_ctl_amp_set_internal(sc, cad, nid, ctl->index, 2476162922Sariff lmute, rmute, left, right, 1); 2477162922Sariff ctl->left = left; 2478162922Sariff ctl->right = right; 2479162922Sariff} 2480162922Sariff 2481162922Sariffstatic void 2482162922Sariffhdac_widget_connection_select(struct hdac_widget *w, uint8_t index) 2483162922Sariff{ 2484162922Sariff if (w == NULL || w->nconns < 1 || index > (w->nconns - 1)) 2485162922Sariff return; 2486162922Sariff hdac_command(w->devinfo->codec->sc, 2487162922Sariff HDA_CMD_SET_CONNECTION_SELECT_CONTROL(w->devinfo->codec->cad, 2488162922Sariff w->nid, index), w->devinfo->codec->cad); 2489162922Sariff w->selconn = index; 2490162922Sariff} 2491162922Sariff 2492162922Sariff 2493162922Sariff/**************************************************************************** 2494162922Sariff * uint32_t hdac_command_sendone_internal 2495162922Sariff * 2496162922Sariff * Wrapper function that sends only one command to a given codec 2497162922Sariff ****************************************************************************/ 2498162922Sariffstatic uint32_t 2499162922Sariffhdac_command_sendone_internal(struct hdac_softc *sc, uint32_t verb, nid_t cad) 2500162922Sariff{ 2501162922Sariff struct hdac_command_list cl; 2502162965Sariff uint32_t response = HDAC_INVALID; 2503162922Sariff 2504163057Sariff if (!hdac_lockowned(sc)) 2505162922Sariff device_printf(sc->dev, "WARNING!!!! mtx not owned!!!!\n"); 2506162922Sariff cl.num_commands = 1; 2507162922Sariff cl.verbs = &verb; 2508162922Sariff cl.responses = &response; 2509162922Sariff 2510162922Sariff hdac_command_send_internal(sc, &cl, cad); 2511162922Sariff 2512162922Sariff return (response); 2513162922Sariff} 2514162922Sariff 2515162922Sariff/**************************************************************************** 2516162922Sariff * hdac_command_send_internal 2517162922Sariff * 2518162922Sariff * Send a command list to the codec via the corb. We queue as much verbs as 2519162922Sariff * we can and msleep on the codec. When the interrupt get the responses 2520162922Sariff * back from the rirb, it will wake us up so we can queue the remaining verbs 2521162922Sariff * if any. 2522162922Sariff ****************************************************************************/ 2523162922Sariffstatic void 2524162922Sariffhdac_command_send_internal(struct hdac_softc *sc, 2525162922Sariff struct hdac_command_list *commands, nid_t cad) 2526162922Sariff{ 2527162922Sariff struct hdac_codec *codec; 2528162922Sariff int corbrp; 2529162922Sariff uint32_t *corb; 2530162922Sariff int timeout; 2531162922Sariff int retry = 10; 2532164614Sariff struct hdac_rirb *rirb_base; 2533162922Sariff 2534164614Sariff if (sc == NULL || sc->codecs[cad] == NULL || commands == NULL || 2535164614Sariff commands->num_commands < 1) 2536162922Sariff return; 2537162922Sariff 2538162922Sariff codec = sc->codecs[cad]; 2539162922Sariff codec->commands = commands; 2540162922Sariff codec->responses_received = 0; 2541162922Sariff codec->verbs_sent = 0; 2542162922Sariff corb = (uint32_t *)sc->corb_dma.dma_vaddr; 2543162922Sariff rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr; 2544162922Sariff 2545162922Sariff do { 2546162922Sariff if (codec->verbs_sent != commands->num_commands) { 2547162922Sariff /* Queue as many verbs as possible */ 2548162922Sariff corbrp = HDAC_READ_2(&sc->mem, HDAC_CORBRP); 2549162922Sariff bus_dmamap_sync(sc->corb_dma.dma_tag, 2550162922Sariff sc->corb_dma.dma_map, BUS_DMASYNC_PREWRITE); 2551162922Sariff while (codec->verbs_sent != commands->num_commands && 2552162922Sariff ((sc->corb_wp + 1) % sc->corb_size) != corbrp) { 2553162922Sariff sc->corb_wp++; 2554162922Sariff sc->corb_wp %= sc->corb_size; 2555162922Sariff corb[sc->corb_wp] = 2556162922Sariff commands->verbs[codec->verbs_sent++]; 2557162922Sariff } 2558162922Sariff 2559162922Sariff /* Send the verbs to the codecs */ 2560162922Sariff bus_dmamap_sync(sc->corb_dma.dma_tag, 2561162922Sariff sc->corb_dma.dma_map, BUS_DMASYNC_POSTWRITE); 2562162922Sariff HDAC_WRITE_2(&sc->mem, HDAC_CORBWP, sc->corb_wp); 2563162922Sariff } 2564162922Sariff 2565162922Sariff timeout = 1000; 2566164614Sariff while (hdac_rirb_flush(sc) == 0 && --timeout) 2567162922Sariff DELAY(10); 2568162922Sariff } while ((codec->verbs_sent != commands->num_commands || 2569164614Sariff codec->responses_received != commands->num_commands) && --retry); 2570162922Sariff 2571162922Sariff if (retry == 0) 2572162922Sariff device_printf(sc->dev, 2573164614Sariff "%s: TIMEOUT numcmd=%d, sent=%d, received=%d\n", 2574164614Sariff __func__, commands->num_commands, codec->verbs_sent, 2575164614Sariff codec->responses_received); 2576162922Sariff 2577164614Sariff codec->commands = NULL; 2578164614Sariff codec->responses_received = 0; 2579162922Sariff codec->verbs_sent = 0; 2580162922Sariff 2581164614Sariff hdac_unsolq_flush(sc); 2582162922Sariff} 2583162922Sariff 2584162922Sariff 2585162922Sariff/**************************************************************************** 2586162922Sariff * Device Methods 2587162922Sariff ****************************************************************************/ 2588162922Sariff 2589162922Sariff/**************************************************************************** 2590162922Sariff * int hdac_probe(device_t) 2591162922Sariff * 2592162922Sariff * Probe for the presence of an hdac. If none is found, check for a generic 2593162922Sariff * match using the subclass of the device. 2594162922Sariff ****************************************************************************/ 2595162922Sariffstatic int 2596162922Sariffhdac_probe(device_t dev) 2597162922Sariff{ 2598162922Sariff int i, result; 2599163257Sariff uint32_t model; 2600163257Sariff uint16_t class, subclass; 2601162922Sariff char desc[64]; 2602162922Sariff 2603162922Sariff model = (uint32_t)pci_get_device(dev) << 16; 2604162922Sariff model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff; 2605162922Sariff class = pci_get_class(dev); 2606162922Sariff subclass = pci_get_subclass(dev); 2607162922Sariff 2608162922Sariff bzero(desc, sizeof(desc)); 2609162922Sariff result = ENXIO; 2610162922Sariff for (i = 0; i < HDAC_DEVICES_LEN; i++) { 2611162922Sariff if (hdac_devices[i].model == model) { 2612162922Sariff strlcpy(desc, hdac_devices[i].desc, sizeof(desc)); 2613162922Sariff result = BUS_PROBE_DEFAULT; 2614162922Sariff break; 2615162922Sariff } 2616163257Sariff if (HDA_DEV_MATCH(hdac_devices[i].model, model) && 2617162922Sariff class == PCIC_MULTIMEDIA && 2618162922Sariff subclass == PCIS_MULTIMEDIA_HDA) { 2619162922Sariff strlcpy(desc, hdac_devices[i].desc, sizeof(desc)); 2620162922Sariff result = BUS_PROBE_GENERIC; 2621162922Sariff break; 2622162922Sariff } 2623162922Sariff } 2624162922Sariff if (result == ENXIO && class == PCIC_MULTIMEDIA && 2625162922Sariff subclass == PCIS_MULTIMEDIA_HDA) { 2626162922Sariff strlcpy(desc, "Generic", sizeof(desc)); 2627162922Sariff result = BUS_PROBE_GENERIC; 2628162922Sariff } 2629162922Sariff if (result != ENXIO) { 2630162922Sariff strlcat(desc, " High Definition Audio Controller", 2631162922Sariff sizeof(desc)); 2632162922Sariff device_set_desc_copy(dev, desc); 2633162922Sariff } 2634162922Sariff 2635162922Sariff return (result); 2636162922Sariff} 2637162922Sariff 2638162922Sariffstatic void * 2639162922Sariffhdac_channel_init(kobj_t obj, void *data, struct snd_dbuf *b, 2640162922Sariff struct pcm_channel *c, int dir) 2641162922Sariff{ 2642162922Sariff struct hdac_devinfo *devinfo = data; 2643162922Sariff struct hdac_softc *sc = devinfo->codec->sc; 2644162922Sariff struct hdac_chan *ch; 2645162922Sariff 2646162922Sariff hdac_lock(sc); 2647162922Sariff if (dir == PCMDIR_PLAY) { 2648162922Sariff ch = &sc->play; 2649162922Sariff ch->off = (sc->num_iss + devinfo->function.audio.playcnt) << 5; 2650162922Sariff ch->dir = PCMDIR_PLAY; 2651162922Sariff ch->sid = ++sc->streamcnt; 2652162922Sariff devinfo->function.audio.playcnt++; 2653162922Sariff } else { 2654162922Sariff ch = &sc->rec; 2655162922Sariff ch->off = devinfo->function.audio.reccnt << 5; 2656162922Sariff ch->dir = PCMDIR_REC; 2657162922Sariff ch->sid = ++sc->streamcnt; 2658162922Sariff devinfo->function.audio.reccnt++; 2659162922Sariff } 2660162922Sariff if (devinfo->function.audio.quirks & HDA_QUIRK_FIXEDRATE) { 2661162922Sariff ch->caps.minspeed = ch->caps.maxspeed = 48000; 2662162922Sariff ch->pcmrates[0] = 48000; 2663162922Sariff ch->pcmrates[1] = 0; 2664162922Sariff } 2665162922Sariff ch->b = b; 2666162922Sariff ch->c = c; 2667162922Sariff ch->devinfo = devinfo; 2668162922Sariff ch->blksz = sc->chan_size / sc->chan_blkcnt; 2669162922Sariff ch->blkcnt = sc->chan_blkcnt; 2670162922Sariff hdac_unlock(sc); 2671162922Sariff 2672162922Sariff if (hdac_bdl_alloc(ch) != 0) { 2673162922Sariff ch->blkcnt = 0; 2674162922Sariff return (NULL); 2675162922Sariff } 2676162922Sariff 2677162922Sariff if (sndbuf_alloc(ch->b, sc->chan_dmat, sc->chan_size) != 0) 2678162922Sariff return (NULL); 2679162922Sariff 2680162922Sariff hdac_dma_nocache(ch->b->buf); 2681162922Sariff 2682162922Sariff return (ch); 2683162922Sariff} 2684162922Sariff 2685162922Sariffstatic int 2686162922Sariffhdac_channel_setformat(kobj_t obj, void *data, uint32_t format) 2687162922Sariff{ 2688162922Sariff struct hdac_chan *ch = data; 2689162922Sariff int i; 2690162922Sariff 2691162922Sariff for (i = 0; ch->caps.fmtlist[i] != 0; i++) { 2692162922Sariff if (format == ch->caps.fmtlist[i]) { 2693162922Sariff ch->fmt = format; 2694162922Sariff return (0); 2695162922Sariff } 2696162922Sariff } 2697162922Sariff 2698162922Sariff return (EINVAL); 2699162922Sariff} 2700162922Sariff 2701162922Sariffstatic int 2702162922Sariffhdac_channel_setspeed(kobj_t obj, void *data, uint32_t speed) 2703162922Sariff{ 2704162922Sariff struct hdac_chan *ch = data; 2705164614Sariff uint32_t spd = 0, threshold; 2706162922Sariff int i; 2707162922Sariff 2708162922Sariff for (i = 0; ch->pcmrates[i] != 0; i++) { 2709162922Sariff spd = ch->pcmrates[i]; 2710164614Sariff threshold = spd + ((ch->pcmrates[i + 1] != 0) ? 2711164614Sariff ((ch->pcmrates[i + 1] - spd) >> 1) : 0); 2712164614Sariff if (speed < threshold) 2713162922Sariff break; 2714162922Sariff } 2715162922Sariff 2716164614Sariff if (spd == 0) /* impossible */ 2717162922Sariff ch->spd = 48000; 2718162922Sariff else 2719162922Sariff ch->spd = spd; 2720162922Sariff 2721162922Sariff return (ch->spd); 2722162922Sariff} 2723162922Sariff 2724162922Sariffstatic void 2725162922Sariffhdac_stream_setup(struct hdac_chan *ch) 2726162922Sariff{ 2727162922Sariff struct hdac_softc *sc = ch->devinfo->codec->sc; 2728162922Sariff int i; 2729162922Sariff nid_t cad = ch->devinfo->codec->cad; 2730162922Sariff uint16_t fmt; 2731162922Sariff 2732162922Sariff fmt = 0; 2733162922Sariff if (ch->fmt & AFMT_S16_LE) 2734162922Sariff fmt |= ch->bit16 << 4; 2735162922Sariff else if (ch->fmt & AFMT_S32_LE) 2736162922Sariff fmt |= ch->bit32 << 4; 2737162922Sariff else 2738162922Sariff fmt |= 1 << 4; 2739162922Sariff 2740162922Sariff for (i = 0; i < HDA_RATE_TAB_LEN; i++) { 2741162922Sariff if (hda_rate_tab[i].valid && ch->spd == hda_rate_tab[i].rate) { 2742162922Sariff fmt |= hda_rate_tab[i].base; 2743162922Sariff fmt |= hda_rate_tab[i].mul; 2744162922Sariff fmt |= hda_rate_tab[i].div; 2745162922Sariff break; 2746162922Sariff } 2747162922Sariff } 2748162922Sariff 2749162922Sariff if (ch->fmt & AFMT_STEREO) 2750162922Sariff fmt |= 1; 2751162922Sariff 2752162922Sariff HDAC_WRITE_2(&sc->mem, ch->off + HDAC_SDFMT, fmt); 2753162922Sariff 2754162922Sariff for (i = 0; ch->io[i] != -1; i++) { 2755163057Sariff HDA_BOOTVERBOSE( 2756162922Sariff device_printf(sc->dev, 2757163057Sariff "HDA_DEBUG: PCMDIR_%s: Stream setup nid=%d " 2758163057Sariff "fmt=0x%08x\n", 2759162922Sariff (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC", 2760162922Sariff ch->io[i], fmt); 2761162922Sariff ); 2762162922Sariff hdac_command(sc, 2763162922Sariff HDA_CMD_SET_CONV_FMT(cad, ch->io[i], fmt), cad); 2764162922Sariff hdac_command(sc, 2765162922Sariff HDA_CMD_SET_CONV_STREAM_CHAN(cad, ch->io[i], 2766162922Sariff ch->sid << 4), cad); 2767162922Sariff } 2768162922Sariff} 2769162922Sariff 2770162922Sariffstatic int 2771167648Sariffhdac_channel_setfragments(kobj_t obj, void *data, 2772167648Sariff uint32_t blksz, uint32_t blkcnt) 2773162922Sariff{ 2774162922Sariff struct hdac_chan *ch = data; 2775164614Sariff struct hdac_softc *sc = ch->devinfo->codec->sc; 2776162922Sariff 2777167648Sariff blksz &= HDA_BLK_ALIGN; 2778162922Sariff 2779167648Sariff if (blksz > (sndbuf_getmaxsize(ch->b) / HDA_BDL_MIN)) 2780167648Sariff blksz = sndbuf_getmaxsize(ch->b) / HDA_BDL_MIN; 2781167648Sariff if (blksz < HDA_BLK_MIN) 2782167648Sariff blksz = HDA_BLK_MIN; 2783167648Sariff if (blkcnt > HDA_BDL_MAX) 2784167648Sariff blkcnt = HDA_BDL_MAX; 2785167648Sariff if (blkcnt < HDA_BDL_MIN) 2786167648Sariff blkcnt = HDA_BDL_MIN; 2787164614Sariff 2788167648Sariff while ((blksz * blkcnt) > sndbuf_getmaxsize(ch->b)) { 2789167648Sariff if ((blkcnt >> 1) >= HDA_BDL_MIN) 2790167648Sariff blkcnt >>= 1; 2791167648Sariff else if ((blksz >> 1) >= HDA_BLK_MIN) 2792167648Sariff blksz >>= 1; 2793167648Sariff else 2794167648Sariff break; 2795167648Sariff } 2796167648Sariff 2797164614Sariff if ((sndbuf_getblksz(ch->b) != blksz || 2798167648Sariff sndbuf_getblkcnt(ch->b) != blkcnt) && 2799167648Sariff sndbuf_resize(ch->b, blkcnt, blksz) != 0) 2800164614Sariff device_printf(sc->dev, "%s: failed blksz=%u blkcnt=%u\n", 2801167648Sariff __func__, blksz, blkcnt); 2802164614Sariff 2803164614Sariff ch->blksz = sndbuf_getblksz(ch->b); 2804167648Sariff ch->blkcnt = sndbuf_getblkcnt(ch->b); 2805164614Sariff 2806167648Sariff return (1); 2807167648Sariff} 2808167648Sariff 2809167648Sariffstatic int 2810167648Sariffhdac_channel_setblocksize(kobj_t obj, void *data, uint32_t blksz) 2811167648Sariff{ 2812167648Sariff struct hdac_chan *ch = data; 2813167648Sariff struct hdac_softc *sc = ch->devinfo->codec->sc; 2814167648Sariff 2815167648Sariff hdac_channel_setfragments(obj, data, blksz, sc->chan_blkcnt); 2816167648Sariff 2817162922Sariff return (ch->blksz); 2818162922Sariff} 2819162922Sariff 2820162922Sariffstatic void 2821162922Sariffhdac_channel_stop(struct hdac_softc *sc, struct hdac_chan *ch) 2822162922Sariff{ 2823162922Sariff struct hdac_devinfo *devinfo = ch->devinfo; 2824162922Sariff nid_t cad = devinfo->codec->cad; 2825162922Sariff int i; 2826162922Sariff 2827162922Sariff hdac_stream_stop(ch); 2828162922Sariff 2829162922Sariff for (i = 0; ch->io[i] != -1; i++) { 2830162922Sariff hdac_command(sc, 2831162922Sariff HDA_CMD_SET_CONV_STREAM_CHAN(cad, ch->io[i], 2832162922Sariff 0), cad); 2833162922Sariff } 2834162922Sariff} 2835162922Sariff 2836162922Sariffstatic void 2837162922Sariffhdac_channel_start(struct hdac_softc *sc, struct hdac_chan *ch) 2838162922Sariff{ 2839162922Sariff ch->ptr = 0; 2840162922Sariff ch->prevptr = 0; 2841162922Sariff hdac_stream_stop(ch); 2842162922Sariff hdac_stream_reset(ch); 2843162922Sariff hdac_bdl_setup(ch); 2844162922Sariff hdac_stream_setid(ch); 2845162922Sariff hdac_stream_setup(ch); 2846162922Sariff hdac_stream_start(ch); 2847162922Sariff} 2848162922Sariff 2849162922Sariffstatic int 2850162922Sariffhdac_channel_trigger(kobj_t obj, void *data, int go) 2851162922Sariff{ 2852162922Sariff struct hdac_chan *ch = data; 2853162922Sariff struct hdac_softc *sc = ch->devinfo->codec->sc; 2854162922Sariff 2855162922Sariff hdac_lock(sc); 2856162922Sariff switch (go) { 2857162922Sariff case PCMTRIG_START: 2858162922Sariff hdac_channel_start(sc, ch); 2859162922Sariff break; 2860162922Sariff case PCMTRIG_STOP: 2861162922Sariff case PCMTRIG_ABORT: 2862162922Sariff hdac_channel_stop(sc, ch); 2863162922Sariff break; 2864167610Sariff default: 2865167610Sariff break; 2866162922Sariff } 2867162922Sariff hdac_unlock(sc); 2868162922Sariff 2869162922Sariff return (0); 2870162922Sariff} 2871162922Sariff 2872162922Sariffstatic int 2873162922Sariffhdac_channel_getptr(kobj_t obj, void *data) 2874162922Sariff{ 2875162922Sariff struct hdac_chan *ch = data; 2876162922Sariff struct hdac_softc *sc = ch->devinfo->codec->sc; 2877162922Sariff uint32_t ptr; 2878162922Sariff 2879162922Sariff hdac_lock(sc); 2880164614Sariff if (sc->polling != 0) 2881164614Sariff ptr = ch->ptr; 2882164614Sariff else 2883164614Sariff ptr = HDAC_READ_4(&sc->mem, ch->off + HDAC_SDLPIB); 2884162922Sariff hdac_unlock(sc); 2885162922Sariff 2886164614Sariff /* 2887164614Sariff * Round to available space and force 128 bytes aligment. 2888164614Sariff */ 2889164614Sariff ptr %= ch->blksz * ch->blkcnt; 2890167648Sariff ptr &= HDA_BLK_ALIGN; 2891162922Sariff 2892162922Sariff return (ptr); 2893162922Sariff} 2894162922Sariff 2895162922Sariffstatic struct pcmchan_caps * 2896162922Sariffhdac_channel_getcaps(kobj_t obj, void *data) 2897162922Sariff{ 2898162922Sariff return (&((struct hdac_chan *)data)->caps); 2899162922Sariff} 2900162922Sariff 2901162922Sariffstatic kobj_method_t hdac_channel_methods[] = { 2902162922Sariff KOBJMETHOD(channel_init, hdac_channel_init), 2903162922Sariff KOBJMETHOD(channel_setformat, hdac_channel_setformat), 2904162922Sariff KOBJMETHOD(channel_setspeed, hdac_channel_setspeed), 2905162922Sariff KOBJMETHOD(channel_setblocksize, hdac_channel_setblocksize), 2906167648Sariff KOBJMETHOD(channel_setfragments, hdac_channel_setfragments), 2907162922Sariff KOBJMETHOD(channel_trigger, hdac_channel_trigger), 2908162922Sariff KOBJMETHOD(channel_getptr, hdac_channel_getptr), 2909162922Sariff KOBJMETHOD(channel_getcaps, hdac_channel_getcaps), 2910162922Sariff { 0, 0 } 2911162922Sariff}; 2912162922SariffCHANNEL_DECLARE(hdac_channel); 2913162922Sariff 2914162922Sariffstatic int 2915162922Sariffhdac_audio_ctl_ossmixer_init(struct snd_mixer *m) 2916162922Sariff{ 2917162922Sariff struct hdac_devinfo *devinfo = mix_getdevinfo(m); 2918162922Sariff struct hdac_softc *sc = devinfo->codec->sc; 2919162922Sariff struct hdac_widget *w, *cw; 2920162922Sariff struct hdac_audio_ctl *ctl; 2921162922Sariff uint32_t mask, recmask, id; 2922162922Sariff int i, j, softpcmvol; 2923162922Sariff nid_t cad; 2924162922Sariff 2925162922Sariff hdac_lock(sc); 2926162922Sariff 2927162922Sariff mask = 0; 2928162922Sariff recmask = 0; 2929162922Sariff 2930162922Sariff id = hdac_codec_id(devinfo); 2931162922Sariff cad = devinfo->codec->cad; 2932162922Sariff for (i = 0; i < HDAC_HP_SWITCH_LEN; i++) { 2933163257Sariff if (!(HDA_DEV_MATCH(hdac_hp_switch[i].model, 2934162965Sariff sc->pci_subvendor) && 2935162922Sariff hdac_hp_switch[i].id == id)) 2936162922Sariff continue; 2937162922Sariff w = hdac_widget_get(devinfo, hdac_hp_switch[i].hpnid); 2938162922Sariff if (w != NULL && w->enable != 0 2939162922Sariff && w->type == 2940162922Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX && 2941162922Sariff HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap)) { 2942162922Sariff hdac_command(sc, 2943162922Sariff HDA_CMD_SET_UNSOLICITED_RESPONSE(cad, 2944162922Sariff w->nid, 2945162922Sariff HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE| 2946162922Sariff HDAC_UNSOLTAG_EVENT_HP), cad); 2947162922Sariff hdac_hp_switch_handler(devinfo); 2948163057Sariff HDA_BOOTVERBOSE( 2949163057Sariff device_printf(sc->dev, 2950163057Sariff "HDA_DEBUG: Enabling headphone/speaker " 2951163057Sariff "audio routing switching:\n"); 2952163057Sariff device_printf(sc->dev, 2953163057Sariff "HDA_DEBUG: \tindex=%d nid=%d " 2954163057Sariff "pci_subvendor=0x%08x " 2955163057Sariff "codec=0x%08x\n", 2956163057Sariff i, w->nid, sc->pci_subvendor, id); 2957163057Sariff ); 2958162922Sariff } 2959162922Sariff break; 2960162922Sariff } 2961162922Sariff for (i = 0; i < HDAC_EAPD_SWITCH_LEN; i++) { 2962163257Sariff if (!(HDA_DEV_MATCH(hdac_eapd_switch[i].model, 2963162965Sariff sc->pci_subvendor) && 2964162965Sariff hdac_eapd_switch[i].id == id)) 2965162922Sariff continue; 2966162922Sariff w = hdac_widget_get(devinfo, hdac_eapd_switch[i].eapdnid); 2967162922Sariff if (w == NULL || w->enable == 0) 2968162922Sariff break; 2969162922Sariff if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX || 2970162965Sariff w->param.eapdbtl == HDAC_INVALID) 2971162922Sariff break; 2972162922Sariff mask |= SOUND_MASK_OGAIN; 2973162922Sariff break; 2974162922Sariff } 2975162922Sariff 2976162922Sariff for (i = devinfo->startnode; i < devinfo->endnode; i++) { 2977162922Sariff w = hdac_widget_get(devinfo, i); 2978162922Sariff if (w == NULL || w->enable == 0) 2979162922Sariff continue; 2980162922Sariff mask |= w->ctlflags; 2981162922Sariff if (!(w->pflags & HDA_ADC_RECSEL)) 2982162922Sariff continue; 2983162922Sariff for (j = 0; j < w->nconns; j++) { 2984162922Sariff cw = hdac_widget_get(devinfo, w->conns[j]); 2985162922Sariff if (cw == NULL || cw->enable == 0) 2986162922Sariff continue; 2987162922Sariff recmask |= cw->ctlflags; 2988162922Sariff } 2989162922Sariff } 2990162922Sariff 2991162922Sariff if (!(mask & SOUND_MASK_PCM)) { 2992162922Sariff softpcmvol = 1; 2993162922Sariff mask |= SOUND_MASK_PCM; 2994163057Sariff } else 2995163057Sariff softpcmvol = (devinfo->function.audio.quirks & 2996163057Sariff HDA_QUIRK_SOFTPCMVOL) ? 1 : 0; 2997162922Sariff 2998162922Sariff i = 0; 2999162922Sariff ctl = NULL; 3000162922Sariff while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 3001162922Sariff if (ctl->widget == NULL || ctl->enable == 0) 3002162922Sariff continue; 3003162922Sariff if (!(ctl->ossmask & SOUND_MASK_PCM)) 3004162922Sariff continue; 3005162922Sariff if (ctl->step > 0) 3006162922Sariff break; 3007162922Sariff } 3008162922Sariff 3009162922Sariff if (softpcmvol == 1 || ctl == NULL) { 3010162922Sariff struct snddev_info *d = NULL; 3011162922Sariff d = device_get_softc(sc->dev); 3012162922Sariff if (d != NULL) { 3013162922Sariff d->flags |= SD_F_SOFTPCMVOL; 3014163057Sariff HDA_BOOTVERBOSE( 3015162922Sariff device_printf(sc->dev, 3016163057Sariff "HDA_DEBUG: %s Soft PCM volume\n", 3017162922Sariff (softpcmvol == 1) ? 3018162922Sariff "Forcing" : "Enabling"); 3019162922Sariff ); 3020162922Sariff } 3021162922Sariff i = 0; 3022162922Sariff /* 3023162922Sariff * XXX Temporary quirk for STAC9220, until the parser 3024162922Sariff * become smarter. 3025162922Sariff */ 3026162922Sariff if (id == HDA_CODEC_STAC9220) { 3027162922Sariff mask |= SOUND_MASK_VOLUME; 3028162922Sariff while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != 3029162922Sariff NULL) { 3030162922Sariff if (ctl->widget == NULL || ctl->enable == 0) 3031162922Sariff continue; 3032162922Sariff if (ctl->widget->nid == 11 && ctl->index == 0) { 3033162922Sariff ctl->ossmask = SOUND_MASK_VOLUME; 3034162922Sariff ctl->ossval = 100 | (100 << 8); 3035162922Sariff } else 3036162922Sariff ctl->ossmask &= ~SOUND_MASK_VOLUME; 3037162922Sariff } 3038165992Sariff } else if (id == HDA_CODEC_STAC9221) { 3039165992Sariff mask |= SOUND_MASK_VOLUME; 3040165992Sariff while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != 3041165992Sariff NULL) { 3042165992Sariff if (ctl->widget == NULL) 3043165992Sariff continue; 3044165992Sariff if (ctl->widget->nid == 2 && ctl->index == 0) { 3045165992Sariff ctl->enable = 1; 3046165992Sariff ctl->ossmask = SOUND_MASK_VOLUME; 3047165992Sariff ctl->ossval = 100 | (100 << 8); 3048165992Sariff } else if (ctl->enable == 0) 3049165992Sariff continue; 3050165992Sariff else 3051165992Sariff ctl->ossmask &= ~SOUND_MASK_VOLUME; 3052165992Sariff } 3053162922Sariff } else { 3054162922Sariff mix_setparentchild(m, SOUND_MIXER_VOLUME, 3055162922Sariff SOUND_MASK_PCM); 3056162922Sariff if (!(mask & SOUND_MASK_VOLUME)) 3057162922Sariff mix_setrealdev(m, SOUND_MIXER_VOLUME, 3058162922Sariff SOUND_MIXER_NONE); 3059162922Sariff while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != 3060162922Sariff NULL) { 3061162922Sariff if (ctl->widget == NULL || ctl->enable == 0) 3062162922Sariff continue; 3063163057Sariff if (!HDA_FLAG_MATCH(ctl->ossmask, 3064163057Sariff SOUND_MASK_VOLUME | SOUND_MASK_PCM)) 3065162922Sariff continue; 3066162922Sariff if (!(ctl->mute == 1 && ctl->step == 0)) 3067162922Sariff ctl->enable = 0; 3068162922Sariff } 3069162922Sariff } 3070162922Sariff } 3071162922Sariff 3072162922Sariff recmask &= ~(SOUND_MASK_PCM | SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER); 3073162922Sariff 3074162922Sariff mix_setrecdevs(m, recmask); 3075162922Sariff mix_setdevs(m, mask); 3076162922Sariff 3077162922Sariff hdac_unlock(sc); 3078162922Sariff 3079162922Sariff return (0); 3080162922Sariff} 3081162922Sariff 3082162922Sariffstatic int 3083162922Sariffhdac_audio_ctl_ossmixer_set(struct snd_mixer *m, unsigned dev, 3084162922Sariff unsigned left, unsigned right) 3085162922Sariff{ 3086162922Sariff struct hdac_devinfo *devinfo = mix_getdevinfo(m); 3087162922Sariff struct hdac_softc *sc = devinfo->codec->sc; 3088162922Sariff struct hdac_widget *w; 3089162922Sariff struct hdac_audio_ctl *ctl; 3090162922Sariff uint32_t id, mute; 3091162922Sariff int lvol, rvol, mlvol, mrvol; 3092162922Sariff int i = 0; 3093162922Sariff 3094162922Sariff hdac_lock(sc); 3095162922Sariff if (dev == SOUND_MIXER_OGAIN) { 3096163257Sariff uint32_t orig; 3097162922Sariff /*if (left != right || !(left == 0 || left == 1)) { 3098162922Sariff hdac_unlock(sc); 3099162922Sariff return (-1); 3100162922Sariff }*/ 3101162922Sariff id = hdac_codec_id(devinfo); 3102162922Sariff for (i = 0; i < HDAC_EAPD_SWITCH_LEN; i++) { 3103163257Sariff if (HDA_DEV_MATCH(hdac_eapd_switch[i].model, 3104162965Sariff sc->pci_subvendor) && 3105162922Sariff hdac_eapd_switch[i].id == id) 3106162922Sariff break; 3107162922Sariff } 3108162922Sariff if (i >= HDAC_EAPD_SWITCH_LEN) { 3109162922Sariff hdac_unlock(sc); 3110162922Sariff return (-1); 3111162922Sariff } 3112162922Sariff w = hdac_widget_get(devinfo, hdac_eapd_switch[i].eapdnid); 3113162922Sariff if (w == NULL || 3114162922Sariff w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX || 3115162965Sariff w->param.eapdbtl == HDAC_INVALID) { 3116162922Sariff hdac_unlock(sc); 3117162922Sariff return (-1); 3118162922Sariff } 3119163257Sariff orig = w->param.eapdbtl; 3120163432Sariff if (left == 0) 3121162922Sariff w->param.eapdbtl &= ~HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD; 3122162922Sariff else 3123162922Sariff w->param.eapdbtl |= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD; 3124163257Sariff if (orig != w->param.eapdbtl) { 3125163432Sariff uint32_t val; 3126163432Sariff 3127163257Sariff if (hdac_eapd_switch[i].hp_switch != 0) 3128163257Sariff hdac_hp_switch_handler(devinfo); 3129163432Sariff val = w->param.eapdbtl; 3130163432Sariff if (devinfo->function.audio.quirks & HDA_QUIRK_EAPDINV) 3131163432Sariff val ^= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD; 3132163257Sariff hdac_command(sc, 3133163257Sariff HDA_CMD_SET_EAPD_BTL_ENABLE(devinfo->codec->cad, 3134163432Sariff w->nid, val), devinfo->codec->cad); 3135163257Sariff } 3136162922Sariff hdac_unlock(sc); 3137162922Sariff return (left | (left << 8)); 3138162922Sariff } 3139162922Sariff if (dev == SOUND_MIXER_VOLUME) 3140162922Sariff devinfo->function.audio.mvol = left | (right << 8); 3141162922Sariff 3142162922Sariff mlvol = devinfo->function.audio.mvol & 0x7f; 3143162922Sariff mrvol = (devinfo->function.audio.mvol >> 8) & 0x7f; 3144162922Sariff lvol = 0; 3145162922Sariff rvol = 0; 3146162922Sariff 3147162922Sariff i = 0; 3148162922Sariff while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 3149162922Sariff if (ctl->widget == NULL || ctl->enable == 0 || 3150162922Sariff !(ctl->ossmask & (1 << dev))) 3151162922Sariff continue; 3152162922Sariff switch (dev) { 3153162922Sariff case SOUND_MIXER_VOLUME: 3154162922Sariff lvol = ((ctl->ossval & 0x7f) * left) / 100; 3155162922Sariff lvol = (lvol * ctl->step) / 100; 3156162922Sariff rvol = (((ctl->ossval >> 8) & 0x7f) * right) / 100; 3157162922Sariff rvol = (rvol * ctl->step) / 100; 3158162922Sariff break; 3159162922Sariff default: 3160162922Sariff if (ctl->ossmask & SOUND_MASK_VOLUME) { 3161162922Sariff lvol = (left * mlvol) / 100; 3162162922Sariff lvol = (lvol * ctl->step) / 100; 3163162922Sariff rvol = (right * mrvol) / 100; 3164162922Sariff rvol = (rvol * ctl->step) / 100; 3165162922Sariff } else { 3166162922Sariff lvol = (left * ctl->step) / 100; 3167162922Sariff rvol = (right * ctl->step) / 100; 3168162922Sariff } 3169162922Sariff ctl->ossval = left | (right << 8); 3170162922Sariff break; 3171162922Sariff } 3172162922Sariff mute = 0; 3173162922Sariff if (ctl->step < 1) { 3174162922Sariff mute |= (left == 0) ? HDA_AMP_MUTE_LEFT : 3175162922Sariff (ctl->muted & HDA_AMP_MUTE_LEFT); 3176162922Sariff mute |= (right == 0) ? HDA_AMP_MUTE_RIGHT : 3177162922Sariff (ctl->muted & HDA_AMP_MUTE_RIGHT); 3178162922Sariff } else { 3179162922Sariff mute |= (lvol == 0) ? HDA_AMP_MUTE_LEFT : 3180162922Sariff (ctl->muted & HDA_AMP_MUTE_LEFT); 3181162922Sariff mute |= (rvol == 0) ? HDA_AMP_MUTE_RIGHT : 3182162922Sariff (ctl->muted & HDA_AMP_MUTE_RIGHT); 3183162922Sariff } 3184162922Sariff hdac_audio_ctl_amp_set(ctl, mute, lvol, rvol); 3185162922Sariff } 3186162922Sariff hdac_unlock(sc); 3187162922Sariff 3188162922Sariff return (left | (right << 8)); 3189162922Sariff} 3190162922Sariff 3191162922Sariffstatic int 3192162922Sariffhdac_audio_ctl_ossmixer_setrecsrc(struct snd_mixer *m, uint32_t src) 3193162922Sariff{ 3194162922Sariff struct hdac_devinfo *devinfo = mix_getdevinfo(m); 3195162922Sariff struct hdac_widget *w, *cw; 3196162922Sariff struct hdac_softc *sc = devinfo->codec->sc; 3197162922Sariff uint32_t ret = src, target; 3198162922Sariff int i, j; 3199162922Sariff 3200162922Sariff target = 0; 3201162922Sariff for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 3202162922Sariff if (src & (1 << i)) { 3203162922Sariff target = 1 << i; 3204162922Sariff break; 3205162922Sariff } 3206162922Sariff } 3207162922Sariff 3208162922Sariff hdac_lock(sc); 3209162922Sariff 3210162922Sariff for (i = devinfo->startnode; i < devinfo->endnode; i++) { 3211162922Sariff w = hdac_widget_get(devinfo, i); 3212162965Sariff if (w == NULL || w->enable == 0) 3213162922Sariff continue; 3214162922Sariff if (!(w->pflags & HDA_ADC_RECSEL)) 3215162922Sariff continue; 3216162922Sariff for (j = 0; j < w->nconns; j++) { 3217162922Sariff cw = hdac_widget_get(devinfo, w->conns[j]); 3218162922Sariff if (cw == NULL || cw->enable == 0) 3219162922Sariff continue; 3220162922Sariff if ((target == SOUND_MASK_VOLUME && 3221162922Sariff cw->type != 3222162922Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) || 3223162922Sariff (target != SOUND_MASK_VOLUME && 3224162922Sariff cw->type == 3225162922Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)) 3226162922Sariff continue; 3227162922Sariff if (cw->ctlflags & target) { 3228162922Sariff hdac_widget_connection_select(w, j); 3229162922Sariff ret = target; 3230162922Sariff j += w->nconns; 3231162922Sariff } 3232162922Sariff } 3233162922Sariff } 3234162922Sariff 3235162922Sariff hdac_unlock(sc); 3236162922Sariff 3237162922Sariff return (ret); 3238162922Sariff} 3239162922Sariff 3240162922Sariffstatic kobj_method_t hdac_audio_ctl_ossmixer_methods[] = { 3241162922Sariff KOBJMETHOD(mixer_init, hdac_audio_ctl_ossmixer_init), 3242162922Sariff KOBJMETHOD(mixer_set, hdac_audio_ctl_ossmixer_set), 3243162922Sariff KOBJMETHOD(mixer_setrecsrc, hdac_audio_ctl_ossmixer_setrecsrc), 3244162922Sariff { 0, 0 } 3245162922Sariff}; 3246162922SariffMIXER_DECLARE(hdac_audio_ctl_ossmixer); 3247162922Sariff 3248162922Sariff/**************************************************************************** 3249162922Sariff * int hdac_attach(device_t) 3250162922Sariff * 3251162922Sariff * Attach the device into the kernel. Interrupts usually won't be enabled 3252162922Sariff * when this function is called. Setup everything that doesn't require 3253162922Sariff * interrupts and defer probing of codecs until interrupts are enabled. 3254162922Sariff ****************************************************************************/ 3255162922Sariffstatic int 3256162922Sariffhdac_attach(device_t dev) 3257162922Sariff{ 3258162922Sariff struct hdac_softc *sc; 3259162922Sariff int result; 3260162922Sariff int i = 0; 3261162922Sariff 3262162922Sariff sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT | M_ZERO); 3263162922Sariff if (sc == NULL) { 3264162922Sariff device_printf(dev, "cannot allocate softc\n"); 3265162922Sariff return (ENOMEM); 3266162922Sariff } 3267163057Sariff 3268163057Sariff sc->lock = snd_mtxcreate(device_get_nameunit(dev), HDAC_MTX_NAME); 3269162922Sariff sc->dev = dev; 3270163257Sariff sc->pci_subvendor = (uint32_t)pci_get_subdevice(sc->dev) << 16; 3271163257Sariff sc->pci_subvendor |= (uint32_t)pci_get_subvendor(sc->dev) & 0x0000ffff; 3272162922Sariff 3273165281Sariff if (sc->pci_subvendor == HP_NX6325_SUBVENDORX) { 3274165281Sariff /* Screw nx6325 - subdevice/subvendor swapped */ 3275165281Sariff sc->pci_subvendor = HP_NX6325_SUBVENDOR; 3276165281Sariff } 3277165281Sariff 3278164614Sariff callout_init(&sc->poll_hda, CALLOUT_MPSAFE); 3279164614Sariff callout_init(&sc->poll_hdac, CALLOUT_MPSAFE); 3280164614Sariff 3281164614Sariff sc->poll_ticks = 1; 3282164614Sariff if (resource_int_value(device_get_name(sc->dev), 3283164614Sariff device_get_unit(sc->dev), "polling", &i) == 0 && i != 0) 3284164614Sariff sc->polling = 1; 3285164614Sariff else 3286164614Sariff sc->polling = 0; 3287164614Sariff 3288162922Sariff sc->chan_size = pcm_getbuffersize(dev, 3289164614Sariff HDA_BUFSZ_MIN, HDA_BUFSZ_DEFAULT, HDA_BUFSZ_MAX); 3290164614Sariff 3291162922Sariff if (resource_int_value(device_get_name(sc->dev), 3292164614Sariff device_get_unit(sc->dev), "blocksize", &i) == 0 && i > 0) { 3293167648Sariff i &= HDA_BLK_ALIGN; 3294167648Sariff if (i < HDA_BLK_MIN) 3295167648Sariff i = HDA_BLK_MIN; 3296162922Sariff sc->chan_blkcnt = sc->chan_size / i; 3297162922Sariff i = 0; 3298162922Sariff while (sc->chan_blkcnt >> i) 3299162922Sariff i++; 3300162922Sariff sc->chan_blkcnt = 1 << (i - 1); 3301162922Sariff if (sc->chan_blkcnt < HDA_BDL_MIN) 3302162922Sariff sc->chan_blkcnt = HDA_BDL_MIN; 3303162922Sariff else if (sc->chan_blkcnt > HDA_BDL_MAX) 3304162922Sariff sc->chan_blkcnt = HDA_BDL_MAX; 3305162922Sariff } else 3306162922Sariff sc->chan_blkcnt = HDA_BDL_DEFAULT; 3307162922Sariff 3308162922Sariff result = bus_dma_tag_create(NULL, /* parent */ 3309162922Sariff HDAC_DMA_ALIGNMENT, /* alignment */ 3310162922Sariff 0, /* boundary */ 3311162922Sariff BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 3312162922Sariff BUS_SPACE_MAXADDR, /* highaddr */ 3313162922Sariff NULL, /* filtfunc */ 3314162922Sariff NULL, /* fistfuncarg */ 3315165281Sariff sc->chan_size, /* maxsize */ 3316162922Sariff 1, /* nsegments */ 3317165281Sariff sc->chan_size, /* maxsegsz */ 3318162922Sariff 0, /* flags */ 3319162922Sariff NULL, /* lockfunc */ 3320162922Sariff NULL, /* lockfuncarg */ 3321162922Sariff &sc->chan_dmat); /* dmat */ 3322162922Sariff if (result != 0) { 3323162922Sariff device_printf(sc->dev, "%s: bus_dma_tag_create failed (%x)\n", 3324162922Sariff __func__, result); 3325163057Sariff snd_mtxfree(sc->lock); 3326162922Sariff free(sc, M_DEVBUF); 3327162922Sariff return (ENXIO); 3328162922Sariff } 3329162922Sariff 3330162922Sariff 3331162922Sariff sc->hdabus = NULL; 3332162922Sariff for (i = 0; i < HDAC_CODEC_MAX; i++) 3333162922Sariff sc->codecs[i] = NULL; 3334162922Sariff 3335162922Sariff pci_enable_busmaster(dev); 3336162922Sariff 3337162922Sariff /* Allocate resources */ 3338162922Sariff result = hdac_mem_alloc(sc); 3339162922Sariff if (result != 0) 3340163057Sariff goto hdac_attach_fail; 3341162922Sariff result = hdac_irq_alloc(sc); 3342162922Sariff if (result != 0) 3343163057Sariff goto hdac_attach_fail; 3344162922Sariff 3345162922Sariff /* Get Capabilities */ 3346162922Sariff result = hdac_get_capabilities(sc); 3347162922Sariff if (result != 0) 3348163057Sariff goto hdac_attach_fail; 3349162922Sariff 3350162922Sariff /* Allocate CORB and RIRB dma memory */ 3351162922Sariff result = hdac_dma_alloc(sc, &sc->corb_dma, 3352162922Sariff sc->corb_size * sizeof(uint32_t)); 3353162922Sariff if (result != 0) 3354163057Sariff goto hdac_attach_fail; 3355162922Sariff result = hdac_dma_alloc(sc, &sc->rirb_dma, 3356162922Sariff sc->rirb_size * sizeof(struct hdac_rirb)); 3357162922Sariff if (result != 0) 3358163057Sariff goto hdac_attach_fail; 3359162922Sariff 3360162922Sariff /* Quiesce everything */ 3361162922Sariff hdac_reset(sc); 3362162922Sariff 3363162922Sariff /* Disable PCI-Express QOS */ 3364162922Sariff pci_write_config(sc->dev, 0x44, 3365162922Sariff pci_read_config(sc->dev, 0x44, 1) & 0xf8, 1); 3366162922Sariff 3367162922Sariff /* Initialize the CORB and RIRB */ 3368162922Sariff hdac_corb_init(sc); 3369162922Sariff hdac_rirb_init(sc); 3370162922Sariff 3371162922Sariff /* Defer remaining of initialization until interrupts are enabled */ 3372162922Sariff sc->intrhook.ich_func = hdac_attach2; 3373162922Sariff sc->intrhook.ich_arg = (void *)sc; 3374162922Sariff if (cold == 0 || config_intrhook_establish(&sc->intrhook) != 0) { 3375162922Sariff sc->intrhook.ich_func = NULL; 3376162922Sariff hdac_attach2((void *)sc); 3377162922Sariff } 3378162922Sariff 3379163057Sariff return (0); 3380162922Sariff 3381163057Sariffhdac_attach_fail: 3382162922Sariff hdac_dma_free(&sc->rirb_dma); 3383162922Sariff hdac_dma_free(&sc->corb_dma); 3384162922Sariff hdac_irq_free(sc); 3385162922Sariff hdac_mem_free(sc); 3386162922Sariff snd_mtxfree(sc->lock); 3387163057Sariff free(sc, M_DEVBUF); 3388162922Sariff 3389163057Sariff return (ENXIO); 3390162922Sariff} 3391162922Sariff 3392162922Sariffstatic void 3393162922Sariffhdac_audio_parse(struct hdac_devinfo *devinfo) 3394162922Sariff{ 3395162922Sariff struct hdac_softc *sc = devinfo->codec->sc; 3396162922Sariff struct hdac_widget *w; 3397162922Sariff uint32_t res; 3398162922Sariff int i; 3399162922Sariff nid_t cad, nid; 3400162922Sariff 3401162922Sariff cad = devinfo->codec->cad; 3402162922Sariff nid = devinfo->nid; 3403162922Sariff 3404162922Sariff hdac_command(sc, 3405162922Sariff HDA_CMD_SET_POWER_STATE(cad, nid, HDA_CMD_POWER_STATE_D0), cad); 3406162922Sariff 3407162922Sariff DELAY(100); 3408162922Sariff 3409162922Sariff res = hdac_command(sc, 3410162922Sariff HDA_CMD_GET_PARAMETER(cad , nid, HDA_PARAM_SUB_NODE_COUNT), cad); 3411162922Sariff 3412162922Sariff devinfo->nodecnt = HDA_PARAM_SUB_NODE_COUNT_TOTAL(res); 3413162922Sariff devinfo->startnode = HDA_PARAM_SUB_NODE_COUNT_START(res); 3414162922Sariff devinfo->endnode = devinfo->startnode + devinfo->nodecnt; 3415162922Sariff 3416163057Sariff HDA_BOOTVERBOSE( 3417162922Sariff device_printf(sc->dev, " Vendor: 0x%08x\n", 3418162922Sariff devinfo->vendor_id); 3419162922Sariff device_printf(sc->dev, " Device: 0x%08x\n", 3420162922Sariff devinfo->device_id); 3421162922Sariff device_printf(sc->dev, " Revision: 0x%08x\n", 3422162922Sariff devinfo->revision_id); 3423162922Sariff device_printf(sc->dev, " Stepping: 0x%08x\n", 3424162922Sariff devinfo->stepping_id); 3425162922Sariff device_printf(sc->dev, "PCI Subvendor: 0x%08x\n", 3426162922Sariff sc->pci_subvendor); 3427162922Sariff device_printf(sc->dev, " Nodes: start=%d " 3428162922Sariff "endnode=%d total=%d\n", 3429162922Sariff devinfo->startnode, devinfo->endnode, devinfo->nodecnt); 3430162922Sariff ); 3431162922Sariff 3432162922Sariff res = hdac_command(sc, 3433162922Sariff HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_SUPP_STREAM_FORMATS), 3434162922Sariff cad); 3435162922Sariff devinfo->function.audio.supp_stream_formats = res; 3436162922Sariff 3437162922Sariff res = hdac_command(sc, 3438162922Sariff HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_SUPP_PCM_SIZE_RATE), 3439162922Sariff cad); 3440162922Sariff devinfo->function.audio.supp_pcm_size_rate = res; 3441162922Sariff 3442162922Sariff res = hdac_command(sc, 3443162922Sariff HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_OUTPUT_AMP_CAP), 3444162922Sariff cad); 3445162922Sariff devinfo->function.audio.outamp_cap = res; 3446162922Sariff 3447162922Sariff res = hdac_command(sc, 3448162922Sariff HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_INPUT_AMP_CAP), 3449162922Sariff cad); 3450162922Sariff devinfo->function.audio.inamp_cap = res; 3451162922Sariff 3452162922Sariff if (devinfo->nodecnt > 0) { 3453162922Sariff hdac_unlock(sc); 3454162922Sariff devinfo->widget = (struct hdac_widget *)malloc( 3455162922Sariff sizeof(*(devinfo->widget)) * devinfo->nodecnt, M_HDAC, 3456162922Sariff M_NOWAIT | M_ZERO); 3457162922Sariff hdac_lock(sc); 3458162922Sariff } else 3459162922Sariff devinfo->widget = NULL; 3460162922Sariff 3461162922Sariff if (devinfo->widget == NULL) { 3462162922Sariff device_printf(sc->dev, "unable to allocate widgets!\n"); 3463162922Sariff devinfo->endnode = devinfo->startnode; 3464162922Sariff devinfo->nodecnt = 0; 3465162922Sariff return; 3466162922Sariff } 3467162922Sariff 3468162922Sariff for (i = devinfo->startnode; i < devinfo->endnode; i++) { 3469162922Sariff w = hdac_widget_get(devinfo, i); 3470162922Sariff if (w == NULL) 3471162922Sariff device_printf(sc->dev, "Ghost widget! nid=%d!\n", i); 3472162922Sariff else { 3473162922Sariff w->devinfo = devinfo; 3474162922Sariff w->nid = i; 3475162922Sariff w->enable = 1; 3476162922Sariff w->selconn = -1; 3477162922Sariff w->pflags = 0; 3478162922Sariff w->ctlflags = 0; 3479162965Sariff w->param.eapdbtl = HDAC_INVALID; 3480162922Sariff hdac_widget_parse(w); 3481162922Sariff } 3482162922Sariff } 3483162922Sariff} 3484162922Sariff 3485162922Sariffstatic void 3486162922Sariffhdac_audio_ctl_parse(struct hdac_devinfo *devinfo) 3487162922Sariff{ 3488162922Sariff struct hdac_softc *sc = devinfo->codec->sc; 3489162922Sariff struct hdac_audio_ctl *ctls; 3490162922Sariff struct hdac_widget *w, *cw; 3491162922Sariff int i, j, cnt, max, ocap, icap; 3492163057Sariff int mute, offset, step, size; 3493162922Sariff 3494162922Sariff /* XXX This is redundant */ 3495162922Sariff max = 0; 3496162922Sariff for (i = devinfo->startnode; i < devinfo->endnode; i++) { 3497162922Sariff w = hdac_widget_get(devinfo, i); 3498162922Sariff if (w == NULL || w->enable == 0) 3499162922Sariff continue; 3500162922Sariff if (w->param.outamp_cap != 0) 3501162922Sariff max++; 3502162922Sariff if (w->param.inamp_cap != 0) { 3503162922Sariff switch (w->type) { 3504162922Sariff case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR: 3505162922Sariff case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER: 3506162922Sariff for (j = 0; j < w->nconns; j++) { 3507162922Sariff cw = hdac_widget_get(devinfo, 3508162922Sariff w->conns[j]); 3509162922Sariff if (cw == NULL || cw->enable == 0) 3510162922Sariff continue; 3511162922Sariff max++; 3512162922Sariff } 3513162922Sariff break; 3514162922Sariff default: 3515162922Sariff max++; 3516162922Sariff break; 3517162922Sariff } 3518162922Sariff } 3519162922Sariff } 3520162922Sariff 3521162922Sariff devinfo->function.audio.ctlcnt = max; 3522162922Sariff 3523162922Sariff if (max < 1) 3524162922Sariff return; 3525162922Sariff 3526162922Sariff hdac_unlock(sc); 3527162922Sariff ctls = (struct hdac_audio_ctl *)malloc( 3528162922Sariff sizeof(*ctls) * max, M_HDAC, M_ZERO | M_NOWAIT); 3529162922Sariff hdac_lock(sc); 3530162922Sariff 3531162922Sariff if (ctls == NULL) { 3532162922Sariff /* Blekh! */ 3533162922Sariff device_printf(sc->dev, "unable to allocate ctls!\n"); 3534162922Sariff devinfo->function.audio.ctlcnt = 0; 3535162922Sariff return; 3536162922Sariff } 3537162922Sariff 3538162922Sariff cnt = 0; 3539162922Sariff for (i = devinfo->startnode; cnt < max && i < devinfo->endnode; i++) { 3540162922Sariff if (cnt >= max) { 3541162922Sariff device_printf(sc->dev, "%s: Ctl overflow!\n", 3542162922Sariff __func__); 3543162922Sariff break; 3544162922Sariff } 3545162922Sariff w = hdac_widget_get(devinfo, i); 3546162922Sariff if (w == NULL || w->enable == 0) 3547162922Sariff continue; 3548162922Sariff ocap = w->param.outamp_cap; 3549162922Sariff icap = w->param.inamp_cap; 3550162922Sariff if (ocap != 0) { 3551163057Sariff mute = HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(ocap); 3552163057Sariff step = HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(ocap); 3553163057Sariff size = HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(ocap); 3554163057Sariff offset = HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(ocap); 3555163057Sariff /*if (offset > step) { 3556163057Sariff HDA_BOOTVERBOSE( 3557163057Sariff device_printf(sc->dev, 3558163057Sariff "HDA_DEBUG: BUGGY outamp: nid=%d " 3559163057Sariff "[offset=%d > step=%d]\n", 3560163057Sariff w->nid, offset, step); 3561163057Sariff ); 3562163057Sariff offset = step; 3563163057Sariff }*/ 3564162922Sariff ctls[cnt].enable = 1; 3565162922Sariff ctls[cnt].widget = w; 3566163057Sariff ctls[cnt].mute = mute; 3567163057Sariff ctls[cnt].step = step; 3568163057Sariff ctls[cnt].size = size; 3569163057Sariff ctls[cnt].offset = offset; 3570163057Sariff ctls[cnt].left = offset; 3571163057Sariff ctls[cnt].right = offset; 3572162922Sariff ctls[cnt++].dir = HDA_CTL_OUT; 3573162922Sariff } 3574162922Sariff 3575162922Sariff if (icap != 0) { 3576163057Sariff mute = HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(icap); 3577163057Sariff step = HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(icap); 3578163057Sariff size = HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(icap); 3579163057Sariff offset = HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(icap); 3580163057Sariff /*if (offset > step) { 3581163057Sariff HDA_BOOTVERBOSE( 3582163057Sariff device_printf(sc->dev, 3583163057Sariff "HDA_DEBUG: BUGGY inamp: nid=%d " 3584163057Sariff "[offset=%d > step=%d]\n", 3585163057Sariff w->nid, offset, step); 3586163057Sariff ); 3587163057Sariff offset = step; 3588163057Sariff }*/ 3589162922Sariff switch (w->type) { 3590162922Sariff case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR: 3591162922Sariff case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER: 3592162922Sariff for (j = 0; j < w->nconns; j++) { 3593162922Sariff if (cnt >= max) { 3594162922Sariff device_printf(sc->dev, 3595162922Sariff "%s: Ctl overflow!\n", 3596162922Sariff __func__); 3597162922Sariff break; 3598162922Sariff } 3599162922Sariff cw = hdac_widget_get(devinfo, 3600162922Sariff w->conns[j]); 3601162922Sariff if (cw == NULL || cw->enable == 0) 3602162922Sariff continue; 3603162922Sariff ctls[cnt].enable = 1; 3604162922Sariff ctls[cnt].widget = w; 3605162922Sariff ctls[cnt].childwidget = cw; 3606162922Sariff ctls[cnt].index = j; 3607163057Sariff ctls[cnt].mute = mute; 3608163057Sariff ctls[cnt].step = step; 3609163057Sariff ctls[cnt].size = size; 3610163057Sariff ctls[cnt].offset = offset; 3611163057Sariff ctls[cnt].left = offset; 3612163057Sariff ctls[cnt].right = offset; 3613162922Sariff ctls[cnt++].dir = HDA_CTL_IN; 3614162922Sariff } 3615162922Sariff break; 3616162922Sariff default: 3617162922Sariff if (cnt >= max) { 3618162922Sariff device_printf(sc->dev, 3619162922Sariff "%s: Ctl overflow!\n", 3620162922Sariff __func__); 3621162922Sariff break; 3622162922Sariff } 3623162922Sariff ctls[cnt].enable = 1; 3624162922Sariff ctls[cnt].widget = w; 3625163057Sariff ctls[cnt].mute = mute; 3626163057Sariff ctls[cnt].step = step; 3627163057Sariff ctls[cnt].size = size; 3628163057Sariff ctls[cnt].offset = offset; 3629163057Sariff ctls[cnt].left = offset; 3630163057Sariff ctls[cnt].right = offset; 3631162922Sariff ctls[cnt++].dir = HDA_CTL_IN; 3632162922Sariff break; 3633162922Sariff } 3634162922Sariff } 3635162922Sariff } 3636162922Sariff 3637162922Sariff devinfo->function.audio.ctl = ctls; 3638162922Sariff} 3639162922Sariff 3640162965Sariffstatic const struct { 3641162965Sariff uint32_t model; 3642162965Sariff uint32_t id; 3643162965Sariff uint32_t set, unset; 3644162965Sariff} hdac_quirks[] = { 3645163057Sariff /* 3646163057Sariff * XXX Force stereo quirk. Monoural recording / playback 3647163057Sariff * on few codecs (especially ALC880) seems broken or 3648163057Sariff * perhaps unsupported. 3649163057Sariff */ 3650163057Sariff { HDA_MATCH_ALL, HDA_MATCH_ALL, 3651165069Sariff HDA_QUIRK_FORCESTEREO | HDA_QUIRK_VREF, 0 }, 3652162965Sariff { ACER_ALL_SUBVENDOR, HDA_MATCH_ALL, 3653165039Sariff HDA_QUIRK_GPIO0, 0 }, 3654162965Sariff { ASUS_M5200_SUBVENDOR, HDA_CODEC_ALC880, 3655165039Sariff HDA_QUIRK_GPIO0, 0 }, 3656165281Sariff { ASUS_A7M_SUBVENDOR, HDA_CODEC_ALC880, 3657165281Sariff HDA_QUIRK_GPIO0, 0 }, 3658167623Sariff { ASUS_A7T_SUBVENDOR, HDA_CODEC_ALC882, 3659167623Sariff HDA_QUIRK_GPIO0, 0 }, 3660163276Sariff { ASUS_U5F_SUBVENDOR, HDA_CODEC_AD1986A, 3661163276Sariff HDA_QUIRK_EAPDINV, 0 }, 3662163432Sariff { ASUS_A8JC_SUBVENDOR, HDA_CODEC_AD1986A, 3663163432Sariff HDA_QUIRK_EAPDINV, 0 }, 3664165281Sariff { MEDION_MD95257_SUBVENDOR, HDA_CODEC_ALC880, 3665165281Sariff HDA_QUIRK_GPIO1, 0 }, 3666164657Sariff { LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A, 3667164614Sariff HDA_QUIRK_EAPDINV, 0 }, 3668164657Sariff { SAMSUNG_Q1_SUBVENDOR, HDA_CODEC_AD1986A, 3669164657Sariff HDA_QUIRK_EAPDINV, 0 }, 3670165039Sariff { APPLE_INTEL_MAC, HDA_CODEC_STAC9221, 3671165039Sariff HDA_QUIRK_GPIO0 | HDA_QUIRK_GPIO1, 0 }, 3672162965Sariff { HDA_MATCH_ALL, HDA_CODEC_CXVENICE, 3673162965Sariff 0, HDA_QUIRK_FORCESTEREO }, 3674162965Sariff { HDA_MATCH_ALL, HDA_CODEC_STACXXXX, 3675162965Sariff HDA_QUIRK_SOFTPCMVOL, 0 } 3676162965Sariff}; 3677162965Sariff#define HDAC_QUIRKS_LEN (sizeof(hdac_quirks) / sizeof(hdac_quirks[0])) 3678162965Sariff 3679162922Sariffstatic void 3680162922Sariffhdac_vendor_patch_parse(struct hdac_devinfo *devinfo) 3681162922Sariff{ 3682162922Sariff struct hdac_widget *w; 3683165466Sariff struct hdac_audio_ctl *ctl; 3684162965Sariff uint32_t id, subvendor; 3685162922Sariff int i; 3686162922Sariff 3687163057Sariff id = hdac_codec_id(devinfo); 3688163057Sariff subvendor = devinfo->codec->sc->pci_subvendor; 3689163057Sariff 3690162922Sariff /* 3691163057Sariff * Quirks 3692162922Sariff */ 3693163057Sariff for (i = 0; i < HDAC_QUIRKS_LEN; i++) { 3694163257Sariff if (!(HDA_DEV_MATCH(hdac_quirks[i].model, subvendor) && 3695163257Sariff HDA_DEV_MATCH(hdac_quirks[i].id, id))) 3696163057Sariff continue; 3697163057Sariff if (hdac_quirks[i].set != 0) 3698163057Sariff devinfo->function.audio.quirks |= 3699163057Sariff hdac_quirks[i].set; 3700163057Sariff if (hdac_quirks[i].unset != 0) 3701163057Sariff devinfo->function.audio.quirks &= 3702163057Sariff ~(hdac_quirks[i].unset); 3703163057Sariff } 3704163057Sariff 3705162922Sariff switch (id) { 3706162922Sariff case HDA_CODEC_ALC260: 3707162922Sariff for (i = devinfo->startnode; i < devinfo->endnode; i++) { 3708162922Sariff w = hdac_widget_get(devinfo, i); 3709162922Sariff if (w == NULL || w->enable == 0) 3710162922Sariff continue; 3711162922Sariff if (w->type != 3712162922Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) 3713162922Sariff continue; 3714162922Sariff if (w->nid != 5) 3715162922Sariff w->enable = 0; 3716162922Sariff } 3717166294Sariff if (subvendor == HP_XW4300_SUBVENDOR) { 3718166294Sariff ctl = hdac_audio_ctl_amp_get(devinfo, 16, 0, 1); 3719166294Sariff if (ctl != NULL && ctl->widget != NULL) { 3720166294Sariff ctl->ossmask = SOUND_MASK_SPEAKER; 3721166294Sariff ctl->widget->ctlflags |= SOUND_MASK_SPEAKER; 3722166294Sariff } 3723166294Sariff ctl = hdac_audio_ctl_amp_get(devinfo, 17, 0, 1); 3724166294Sariff if (ctl != NULL && ctl->widget != NULL) { 3725166294Sariff ctl->ossmask = SOUND_MASK_SPEAKER; 3726166294Sariff ctl->widget->ctlflags |= SOUND_MASK_SPEAKER; 3727166294Sariff } 3728166294Sariff } 3729162922Sariff break; 3730165103Sariff case HDA_CODEC_ALC861: 3731165466Sariff ctl = hdac_audio_ctl_amp_get(devinfo, 28, 1, 1); 3732165466Sariff if (ctl != NULL) 3733165466Sariff ctl->muted = HDA_AMP_MUTE_ALL; 3734165103Sariff break; 3735162922Sariff case HDA_CODEC_ALC880: 3736162922Sariff for (i = devinfo->startnode; i < devinfo->endnode; i++) { 3737162922Sariff w = hdac_widget_get(devinfo, i); 3738162922Sariff if (w == NULL || w->enable == 0) 3739162922Sariff continue; 3740162922Sariff if (w->type == 3741162922Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT && 3742162922Sariff w->nid != 9 && w->nid != 29) { 3743162922Sariff w->enable = 0; 3744162922Sariff } else if (w->type != 3745162922Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET && 3746162922Sariff w->nid == 29) { 3747163057Sariff w->type = 3748163057Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET; 3749163057Sariff w->param.widget_cap &= 3750163057Sariff ~HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK; 3751162922Sariff w->param.widget_cap |= 3752162922Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET << 3753162922Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT; 3754162922Sariff strlcpy(w->name, "beep widget", sizeof(w->name)); 3755162922Sariff } 3756162922Sariff } 3757162922Sariff break; 3758166965Sariff case HDA_CODEC_ALC883: 3759166965Sariff /* 3760166965Sariff * nid: 24/25 = External (jack) or Internal (fixed) Mic. 3761166965Sariff * Clear vref cap for jack connectivity. 3762166965Sariff */ 3763166965Sariff w = hdac_widget_get(devinfo, 24); 3764166965Sariff if (w != NULL && w->enable != 0 && w->type == 3765166965Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX && 3766166965Sariff (w->wclass.pin.config & 3767166965Sariff HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) == 3768166965Sariff HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK) 3769166965Sariff w->wclass.pin.cap &= ~( 3770166965Sariff HDA_PARAM_PIN_CAP_VREF_CTRL_100_MASK | 3771166965Sariff HDA_PARAM_PIN_CAP_VREF_CTRL_80_MASK | 3772166965Sariff HDA_PARAM_PIN_CAP_VREF_CTRL_50_MASK); 3773166965Sariff w = hdac_widget_get(devinfo, 25); 3774166965Sariff if (w != NULL && w->enable != 0 && w->type == 3775166965Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX && 3776166965Sariff (w->wclass.pin.config & 3777166965Sariff HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) == 3778166965Sariff HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK) 3779166965Sariff w->wclass.pin.cap &= ~( 3780166965Sariff HDA_PARAM_PIN_CAP_VREF_CTRL_100_MASK | 3781166965Sariff HDA_PARAM_PIN_CAP_VREF_CTRL_80_MASK | 3782166965Sariff HDA_PARAM_PIN_CAP_VREF_CTRL_50_MASK); 3783166965Sariff /* 3784166965Sariff * nid: 26 = Line-in, leave it alone. 3785166965Sariff */ 3786166965Sariff break; 3787163257Sariff case HDA_CODEC_AD1981HD: 3788163257Sariff w = hdac_widget_get(devinfo, 11); 3789163257Sariff if (w != NULL && w->enable != 0 && w->nconns > 3) 3790163257Sariff w->selconn = 3; 3791163257Sariff if (subvendor == IBM_M52_SUBVENDOR) { 3792163257Sariff ctl = hdac_audio_ctl_amp_get(devinfo, 7, 0, 1); 3793163257Sariff if (ctl != NULL) 3794163257Sariff ctl->ossmask = SOUND_MASK_SPEAKER; 3795163257Sariff } 3796163257Sariff break; 3797162922Sariff case HDA_CODEC_AD1986A: 3798162922Sariff for (i = devinfo->startnode; i < devinfo->endnode; i++) { 3799162922Sariff w = hdac_widget_get(devinfo, i); 3800162922Sariff if (w == NULL || w->enable == 0) 3801162922Sariff continue; 3802162922Sariff if (w->type != 3803162922Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT) 3804162922Sariff continue; 3805162922Sariff if (w->nid != 3) 3806162922Sariff w->enable = 0; 3807162922Sariff } 3808162922Sariff break; 3809162922Sariff case HDA_CODEC_STAC9221: 3810162922Sariff for (i = devinfo->startnode; i < devinfo->endnode; i++) { 3811162922Sariff w = hdac_widget_get(devinfo, i); 3812162922Sariff if (w == NULL || w->enable == 0) 3813162922Sariff continue; 3814162922Sariff if (w->type != 3815162922Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT) 3816162922Sariff continue; 3817162922Sariff if (w->nid != 2) 3818162922Sariff w->enable = 0; 3819162922Sariff } 3820162922Sariff break; 3821162922Sariff case HDA_CODEC_STAC9221D: 3822162922Sariff for (i = devinfo->startnode; i < devinfo->endnode; i++) { 3823162922Sariff w = hdac_widget_get(devinfo, i); 3824162922Sariff if (w == NULL || w->enable == 0) 3825162922Sariff continue; 3826162922Sariff if (w->type == 3827162922Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT && 3828162922Sariff w->nid != 6) 3829162922Sariff w->enable = 0; 3830162922Sariff 3831162922Sariff } 3832162922Sariff break; 3833162922Sariff default: 3834162922Sariff break; 3835162922Sariff } 3836162922Sariff} 3837162922Sariff 3838162922Sariffstatic int 3839162922Sariffhdac_audio_ctl_ossmixer_getnextdev(struct hdac_devinfo *devinfo) 3840162922Sariff{ 3841162922Sariff int *dev = &devinfo->function.audio.ossidx; 3842162922Sariff 3843162922Sariff while (*dev < SOUND_MIXER_NRDEVICES) { 3844162922Sariff switch (*dev) { 3845162922Sariff case SOUND_MIXER_VOLUME: 3846162922Sariff case SOUND_MIXER_BASS: 3847162922Sariff case SOUND_MIXER_TREBLE: 3848162922Sariff case SOUND_MIXER_PCM: 3849162922Sariff case SOUND_MIXER_SPEAKER: 3850162922Sariff case SOUND_MIXER_LINE: 3851162922Sariff case SOUND_MIXER_MIC: 3852162922Sariff case SOUND_MIXER_CD: 3853162922Sariff case SOUND_MIXER_RECLEV: 3854162922Sariff case SOUND_MIXER_OGAIN: /* reserved for EAPD switch */ 3855162922Sariff (*dev)++; 3856162922Sariff break; 3857162922Sariff default: 3858162922Sariff return (*dev)++; 3859162922Sariff break; 3860162922Sariff } 3861162922Sariff } 3862162922Sariff 3863162922Sariff return (-1); 3864162922Sariff} 3865162922Sariff 3866162922Sariffstatic int 3867162922Sariffhdac_widget_find_dac_path(struct hdac_devinfo *devinfo, nid_t nid, int depth) 3868162922Sariff{ 3869162922Sariff struct hdac_widget *w; 3870162922Sariff int i, ret = 0; 3871162922Sariff 3872162922Sariff if (depth > HDA_PARSE_MAXDEPTH) 3873162922Sariff return (0); 3874162922Sariff w = hdac_widget_get(devinfo, nid); 3875162922Sariff if (w == NULL || w->enable == 0) 3876162922Sariff return (0); 3877162922Sariff switch (w->type) { 3878162922Sariff case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT: 3879162922Sariff w->pflags |= HDA_DAC_PATH; 3880162922Sariff ret = 1; 3881162922Sariff break; 3882162922Sariff case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER: 3883162922Sariff case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR: 3884162922Sariff for (i = 0; i < w->nconns; i++) { 3885162922Sariff if (hdac_widget_find_dac_path(devinfo, 3886162922Sariff w->conns[i], depth + 1) != 0) { 3887162922Sariff if (w->selconn == -1) 3888162922Sariff w->selconn = i; 3889162922Sariff ret = 1; 3890162922Sariff w->pflags |= HDA_DAC_PATH; 3891162922Sariff } 3892162922Sariff } 3893162922Sariff break; 3894162922Sariff default: 3895162922Sariff break; 3896162922Sariff } 3897162922Sariff return (ret); 3898162922Sariff} 3899162922Sariff 3900162922Sariffstatic int 3901162922Sariffhdac_widget_find_adc_path(struct hdac_devinfo *devinfo, nid_t nid, int depth) 3902162922Sariff{ 3903162922Sariff struct hdac_widget *w; 3904162922Sariff int i, conndev, ret = 0; 3905162922Sariff 3906162922Sariff if (depth > HDA_PARSE_MAXDEPTH) 3907162922Sariff return (0); 3908162922Sariff w = hdac_widget_get(devinfo, nid); 3909162922Sariff if (w == NULL || w->enable == 0) 3910162922Sariff return (0); 3911162922Sariff switch (w->type) { 3912162922Sariff case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT: 3913162922Sariff case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR: 3914162922Sariff case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER: 3915162922Sariff for (i = 0; i < w->nconns; i++) { 3916162922Sariff if (hdac_widget_find_adc_path(devinfo, w->conns[i], 3917162922Sariff depth + 1) != 0) { 3918162922Sariff if (w->selconn == -1) 3919162922Sariff w->selconn = i; 3920162922Sariff w->pflags |= HDA_ADC_PATH; 3921162922Sariff ret = 1; 3922162922Sariff } 3923162922Sariff } 3924162922Sariff break; 3925162922Sariff case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX: 3926162922Sariff conndev = w->wclass.pin.config & 3927162922Sariff HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; 3928162922Sariff if (HDA_PARAM_PIN_CAP_INPUT_CAP(w->wclass.pin.cap) && 3929162922Sariff (conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_CD || 3930162922Sariff conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN || 3931162922Sariff conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN)) { 3932162922Sariff w->pflags |= HDA_ADC_PATH; 3933162922Sariff ret = 1; 3934162922Sariff } 3935162922Sariff break; 3936162922Sariff /*case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER: 3937162922Sariff if (w->pflags & HDA_DAC_PATH) { 3938162922Sariff w->pflags |= HDA_ADC_PATH; 3939162922Sariff ret = 1; 3940162922Sariff } 3941162922Sariff break;*/ 3942162922Sariff default: 3943162922Sariff break; 3944162922Sariff } 3945162922Sariff return (ret); 3946162922Sariff} 3947162922Sariff 3948162922Sariffstatic uint32_t 3949162922Sariffhdac_audio_ctl_outamp_build(struct hdac_devinfo *devinfo, 3950162922Sariff nid_t nid, nid_t pnid, int index, int depth) 3951162922Sariff{ 3952162922Sariff struct hdac_widget *w, *pw; 3953162922Sariff struct hdac_audio_ctl *ctl; 3954162922Sariff uint32_t fl = 0; 3955162922Sariff int i, ossdev, conndev, strategy; 3956162922Sariff 3957162922Sariff if (depth > HDA_PARSE_MAXDEPTH) 3958162922Sariff return (0); 3959162922Sariff 3960162922Sariff w = hdac_widget_get(devinfo, nid); 3961162922Sariff if (w == NULL || w->enable == 0) 3962162922Sariff return (0); 3963162922Sariff 3964162922Sariff pw = hdac_widget_get(devinfo, pnid); 3965162922Sariff strategy = devinfo->function.audio.parsing_strategy; 3966162922Sariff 3967162922Sariff if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER 3968162922Sariff || w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR) { 3969162922Sariff for (i = 0; i < w->nconns; i++) { 3970162922Sariff fl |= hdac_audio_ctl_outamp_build(devinfo, w->conns[i], 3971162922Sariff w->nid, i, depth + 1); 3972162922Sariff } 3973162922Sariff w->ctlflags |= fl; 3974162922Sariff return (fl); 3975162922Sariff } else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT && 3976162922Sariff (w->pflags & HDA_DAC_PATH)) { 3977162922Sariff i = 0; 3978162922Sariff while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 3979162922Sariff if (ctl->enable == 0 || ctl->widget == NULL) 3980162922Sariff continue; 3981163057Sariff /* XXX This should be compressed! */ 3982162922Sariff if ((ctl->widget->nid == w->nid) || 3983162922Sariff (ctl->widget->nid == pnid && ctl->index == index && 3984162922Sariff (ctl->dir & HDA_CTL_IN)) || 3985162922Sariff (ctl->widget->nid == pnid && pw != NULL && 3986162922Sariff pw->type == 3987162922Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR && 3988162922Sariff (pw->nconns < 2 || pw->selconn == index || 3989162922Sariff pw->selconn == -1) && 3990162922Sariff (ctl->dir & HDA_CTL_OUT)) || 3991162922Sariff (strategy == HDA_PARSE_DIRECT && 3992162922Sariff ctl->widget->nid == w->nid)) { 3993163057Sariff /*if (pw != NULL && pw->selconn == -1) 3994162922Sariff pw->selconn = index; 3995162922Sariff fl |= SOUND_MASK_VOLUME; 3996162922Sariff fl |= SOUND_MASK_PCM; 3997162922Sariff ctl->ossmask |= SOUND_MASK_VOLUME; 3998162922Sariff ctl->ossmask |= SOUND_MASK_PCM; 3999163057Sariff ctl->ossdev = SOUND_MIXER_PCM;*/ 4000163057Sariff if (!(w->ctlflags & SOUND_MASK_PCM) || 4001163057Sariff (pw != NULL && 4002163057Sariff !(pw->ctlflags & SOUND_MASK_PCM))) { 4003163057Sariff fl |= SOUND_MASK_VOLUME; 4004163057Sariff fl |= SOUND_MASK_PCM; 4005163057Sariff ctl->ossmask |= SOUND_MASK_VOLUME; 4006163057Sariff ctl->ossmask |= SOUND_MASK_PCM; 4007163057Sariff ctl->ossdev = SOUND_MIXER_PCM; 4008163057Sariff w->ctlflags |= SOUND_MASK_VOLUME; 4009163057Sariff w->ctlflags |= SOUND_MASK_PCM; 4010163057Sariff if (pw != NULL) { 4011163057Sariff if (pw->selconn == -1) 4012163057Sariff pw->selconn = index; 4013163057Sariff pw->ctlflags |= 4014163057Sariff SOUND_MASK_VOLUME; 4015163057Sariff pw->ctlflags |= 4016163057Sariff SOUND_MASK_PCM; 4017163057Sariff } 4018163057Sariff } 4019162922Sariff } 4020162922Sariff } 4021162922Sariff w->ctlflags |= fl; 4022162922Sariff return (fl); 4023164614Sariff } else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX && 4024164614Sariff HDA_PARAM_PIN_CAP_INPUT_CAP(w->wclass.pin.cap) && 4025162922Sariff (w->pflags & HDA_ADC_PATH)) { 4026162922Sariff conndev = w->wclass.pin.config & 4027162922Sariff HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; 4028162922Sariff i = 0; 4029162922Sariff while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 4030162922Sariff if (ctl->enable == 0 || ctl->widget == NULL) 4031162922Sariff continue; 4032163057Sariff /* XXX This should be compressed! */ 4033162922Sariff if (((ctl->widget->nid == pnid && ctl->index == index && 4034162922Sariff (ctl->dir & HDA_CTL_IN)) || 4035162922Sariff (ctl->widget->nid == pnid && pw != NULL && 4036162922Sariff pw->type == 4037162922Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR && 4038162922Sariff (pw->nconns < 2 || pw->selconn == index || 4039162922Sariff pw->selconn == -1) && 4040162922Sariff (ctl->dir & HDA_CTL_OUT)) || 4041162922Sariff (strategy == HDA_PARSE_DIRECT && 4042162922Sariff ctl->widget->nid == w->nid)) && 4043163057Sariff !(ctl->ossmask & ~SOUND_MASK_VOLUME)) { 4044162922Sariff if (pw != NULL && pw->selconn == -1) 4045162922Sariff pw->selconn = index; 4046162922Sariff ossdev = 0; 4047162922Sariff switch (conndev) { 4048162922Sariff case HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN: 4049162922Sariff ossdev = SOUND_MIXER_MIC; 4050162922Sariff break; 4051162922Sariff case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN: 4052162922Sariff ossdev = SOUND_MIXER_LINE; 4053162922Sariff break; 4054162922Sariff case HDA_CONFIG_DEFAULTCONF_DEVICE_CD: 4055162922Sariff ossdev = SOUND_MIXER_CD; 4056162922Sariff break; 4057162922Sariff default: 4058162922Sariff ossdev = 4059162922Sariff hdac_audio_ctl_ossmixer_getnextdev( 4060162922Sariff devinfo); 4061162922Sariff if (ossdev < 0) 4062162922Sariff ossdev = 0; 4063162922Sariff break; 4064162922Sariff } 4065162922Sariff if (strategy == HDA_PARSE_MIXER) { 4066162922Sariff fl |= SOUND_MASK_VOLUME; 4067162922Sariff ctl->ossmask |= SOUND_MASK_VOLUME; 4068162922Sariff } 4069162922Sariff fl |= 1 << ossdev; 4070162922Sariff ctl->ossmask |= 1 << ossdev; 4071162922Sariff ctl->ossdev = ossdev; 4072162922Sariff } 4073162922Sariff } 4074162922Sariff w->ctlflags |= fl; 4075162922Sariff return (fl); 4076162922Sariff } else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET) { 4077162922Sariff i = 0; 4078162922Sariff while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 4079162922Sariff if (ctl->enable == 0 || ctl->widget == NULL) 4080162922Sariff continue; 4081163057Sariff /* XXX This should be compressed! */ 4082162922Sariff if (((ctl->widget->nid == pnid && ctl->index == index && 4083162922Sariff (ctl->dir & HDA_CTL_IN)) || 4084162922Sariff (ctl->widget->nid == pnid && pw != NULL && 4085162922Sariff pw->type == 4086162922Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR && 4087162922Sariff (pw->nconns < 2 || pw->selconn == index || 4088162922Sariff pw->selconn == -1) && 4089162922Sariff (ctl->dir & HDA_CTL_OUT)) || 4090162922Sariff (strategy == HDA_PARSE_DIRECT && 4091162922Sariff ctl->widget->nid == w->nid)) && 4092163057Sariff !(ctl->ossmask & ~SOUND_MASK_VOLUME)) { 4093162922Sariff if (pw != NULL && pw->selconn == -1) 4094162922Sariff pw->selconn = index; 4095162922Sariff fl |= SOUND_MASK_VOLUME; 4096162922Sariff fl |= SOUND_MASK_SPEAKER; 4097162922Sariff ctl->ossmask |= SOUND_MASK_VOLUME; 4098162922Sariff ctl->ossmask |= SOUND_MASK_SPEAKER; 4099162922Sariff ctl->ossdev = SOUND_MIXER_SPEAKER; 4100162922Sariff } 4101162922Sariff } 4102162922Sariff w->ctlflags |= fl; 4103162922Sariff return (fl); 4104162922Sariff } 4105162922Sariff return (0); 4106162922Sariff} 4107162922Sariff 4108162922Sariffstatic uint32_t 4109162922Sariffhdac_audio_ctl_inamp_build(struct hdac_devinfo *devinfo, nid_t nid, int depth) 4110162922Sariff{ 4111162922Sariff struct hdac_widget *w, *cw; 4112162922Sariff struct hdac_audio_ctl *ctl; 4113162922Sariff uint32_t fl; 4114162922Sariff int i; 4115162922Sariff 4116162922Sariff if (depth > HDA_PARSE_MAXDEPTH) 4117162922Sariff return (0); 4118162922Sariff 4119162922Sariff w = hdac_widget_get(devinfo, nid); 4120162922Sariff if (w == NULL || w->enable == 0) 4121162922Sariff return (0); 4122162922Sariff /*if (!(w->pflags & HDA_ADC_PATH)) 4123162922Sariff return (0); 4124162922Sariff if (!(w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT || 4125162922Sariff w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR)) 4126162922Sariff return (0);*/ 4127162922Sariff i = 0; 4128162922Sariff while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 4129162922Sariff if (ctl->enable == 0 || ctl->widget == NULL) 4130162922Sariff continue; 4131162922Sariff if (ctl->widget->nid == nid) { 4132162922Sariff ctl->ossmask |= SOUND_MASK_RECLEV; 4133162922Sariff w->ctlflags |= SOUND_MASK_RECLEV; 4134162922Sariff return (SOUND_MASK_RECLEV); 4135162922Sariff } 4136162922Sariff } 4137162922Sariff for (i = 0; i < w->nconns; i++) { 4138162922Sariff cw = hdac_widget_get(devinfo, w->conns[i]); 4139162922Sariff if (cw == NULL || cw->enable == 0) 4140162922Sariff continue; 4141162922Sariff if (cw->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR) 4142162922Sariff continue; 4143162922Sariff fl = hdac_audio_ctl_inamp_build(devinfo, cw->nid, depth + 1); 4144162922Sariff if (fl != 0) { 4145162922Sariff cw->ctlflags |= fl; 4146162922Sariff w->ctlflags |= fl; 4147162922Sariff return (fl); 4148162922Sariff } 4149162922Sariff } 4150162922Sariff return (0); 4151162922Sariff} 4152162922Sariff 4153162922Sariffstatic int 4154162922Sariffhdac_audio_ctl_recsel_build(struct hdac_devinfo *devinfo, nid_t nid, int depth) 4155162922Sariff{ 4156162922Sariff struct hdac_widget *w, *cw; 4157162922Sariff int i, child = 0; 4158162922Sariff 4159162922Sariff if (depth > HDA_PARSE_MAXDEPTH) 4160162922Sariff return (0); 4161162922Sariff 4162162922Sariff w = hdac_widget_get(devinfo, nid); 4163162922Sariff if (w == NULL || w->enable == 0) 4164162922Sariff return (0); 4165162922Sariff /*if (!(w->pflags & HDA_ADC_PATH)) 4166162922Sariff return (0); 4167162922Sariff if (!(w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT || 4168162922Sariff w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR)) 4169162922Sariff return (0);*/ 4170162922Sariff /* XXX weak! */ 4171162922Sariff for (i = 0; i < w->nconns; i++) { 4172162922Sariff cw = hdac_widget_get(devinfo, w->conns[i]); 4173162922Sariff if (cw == NULL) 4174162922Sariff continue; 4175162922Sariff if (++child > 1) { 4176162922Sariff w->pflags |= HDA_ADC_RECSEL; 4177162922Sariff return (1); 4178162922Sariff } 4179162922Sariff } 4180162922Sariff for (i = 0; i < w->nconns; i++) { 4181162922Sariff if (hdac_audio_ctl_recsel_build(devinfo, 4182162922Sariff w->conns[i], depth + 1) != 0) 4183162922Sariff return (1); 4184162922Sariff } 4185162922Sariff return (0); 4186162922Sariff} 4187162922Sariff 4188162922Sariffstatic int 4189162922Sariffhdac_audio_build_tree_strategy(struct hdac_devinfo *devinfo) 4190162922Sariff{ 4191162922Sariff struct hdac_widget *w, *cw; 4192162922Sariff int i, j, conndev, found_dac = 0; 4193162922Sariff int strategy; 4194162922Sariff 4195162922Sariff strategy = devinfo->function.audio.parsing_strategy; 4196162922Sariff 4197162922Sariff for (i = devinfo->startnode; i < devinfo->endnode; i++) { 4198162922Sariff w = hdac_widget_get(devinfo, i); 4199162922Sariff if (w == NULL || w->enable == 0) 4200162922Sariff continue; 4201162922Sariff if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) 4202162922Sariff continue; 4203162922Sariff if (!HDA_PARAM_PIN_CAP_OUTPUT_CAP(w->wclass.pin.cap)) 4204162922Sariff continue; 4205162922Sariff conndev = w->wclass.pin.config & 4206162922Sariff HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; 4207162922Sariff if (!(conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT || 4208162922Sariff conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER || 4209162922Sariff conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT)) 4210162922Sariff continue; 4211162922Sariff for (j = 0; j < w->nconns; j++) { 4212162922Sariff cw = hdac_widget_get(devinfo, w->conns[j]); 4213162922Sariff if (cw == NULL || cw->enable == 0) 4214162922Sariff continue; 4215162922Sariff if (strategy == HDA_PARSE_MIXER && !(cw->type == 4216162922Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER || 4217162922Sariff cw->type == 4218162922Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR)) 4219162922Sariff continue; 4220162922Sariff if (hdac_widget_find_dac_path(devinfo, cw->nid, 0) 4221162922Sariff != 0) { 4222162922Sariff if (w->selconn == -1) 4223162922Sariff w->selconn = j; 4224162922Sariff w->pflags |= HDA_DAC_PATH; 4225162922Sariff found_dac++; 4226162922Sariff } 4227162922Sariff } 4228162922Sariff } 4229162922Sariff 4230162922Sariff return (found_dac); 4231162922Sariff} 4232162922Sariff 4233162922Sariffstatic void 4234162922Sariffhdac_audio_build_tree(struct hdac_devinfo *devinfo) 4235162922Sariff{ 4236162922Sariff struct hdac_widget *w; 4237162922Sariff struct hdac_audio_ctl *ctl; 4238162922Sariff int i, j, dacs, strategy; 4239162922Sariff 4240162922Sariff /* Construct DAC path */ 4241162922Sariff strategy = HDA_PARSE_MIXER; 4242162922Sariff devinfo->function.audio.parsing_strategy = strategy; 4243163057Sariff HDA_BOOTVERBOSE( 4244162922Sariff device_printf(devinfo->codec->sc->dev, 4245163057Sariff "HDA_DEBUG: HWiP: HDA Widget Parser - Revision %d\n", 4246162922Sariff HDA_WIDGET_PARSER_REV); 4247162922Sariff ); 4248162922Sariff dacs = hdac_audio_build_tree_strategy(devinfo); 4249162922Sariff if (dacs == 0) { 4250163057Sariff HDA_BOOTVERBOSE( 4251162922Sariff device_printf(devinfo->codec->sc->dev, 4252163057Sariff "HDA_DEBUG: HWiP: 0 DAC path found! " 4253163057Sariff "Retrying parser " 4254162922Sariff "using HDA_PARSE_DIRECT strategy.\n"); 4255162922Sariff ); 4256162922Sariff strategy = HDA_PARSE_DIRECT; 4257162922Sariff devinfo->function.audio.parsing_strategy = strategy; 4258162922Sariff dacs = hdac_audio_build_tree_strategy(devinfo); 4259162922Sariff } 4260162922Sariff 4261163057Sariff HDA_BOOTVERBOSE( 4262162922Sariff device_printf(devinfo->codec->sc->dev, 4263163057Sariff "HDA_DEBUG: HWiP: Found %d DAC path using HDA_PARSE_%s " 4264163057Sariff "strategy.\n", 4265162922Sariff dacs, (strategy == HDA_PARSE_MIXER) ? "MIXER" : "DIRECT"); 4266162922Sariff ); 4267162922Sariff 4268162922Sariff /* Construct ADC path */ 4269162922Sariff for (i = devinfo->startnode; i < devinfo->endnode; i++) { 4270162922Sariff w = hdac_widget_get(devinfo, i); 4271162922Sariff if (w == NULL || w->enable == 0) 4272162922Sariff continue; 4273162922Sariff if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) 4274162922Sariff continue; 4275162922Sariff (void)hdac_widget_find_adc_path(devinfo, w->nid, 0); 4276162922Sariff } 4277162922Sariff 4278162922Sariff /* Output mixers */ 4279162922Sariff for (i = devinfo->startnode; i < devinfo->endnode; i++) { 4280162922Sariff w = hdac_widget_get(devinfo, i); 4281162922Sariff if (w == NULL || w->enable == 0) 4282162922Sariff continue; 4283162922Sariff if ((strategy == HDA_PARSE_MIXER && 4284162922Sariff (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER || 4285162922Sariff w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR) 4286162922Sariff && (w->pflags & HDA_DAC_PATH)) || 4287162922Sariff (strategy == HDA_PARSE_DIRECT && (w->pflags & 4288162922Sariff (HDA_DAC_PATH | HDA_ADC_PATH)))) { 4289162922Sariff w->ctlflags |= hdac_audio_ctl_outamp_build(devinfo, 4290162922Sariff w->nid, devinfo->startnode - 1, 0, 0); 4291162922Sariff } else if (w->type == 4292162922Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET) { 4293162922Sariff j = 0; 4294162922Sariff while ((ctl = hdac_audio_ctl_each(devinfo, &j)) != 4295162922Sariff NULL) { 4296162922Sariff if (ctl->enable == 0 || ctl->widget == NULL) 4297162922Sariff continue; 4298162922Sariff if (ctl->widget->nid != w->nid) 4299162922Sariff continue; 4300162922Sariff ctl->ossmask |= SOUND_MASK_VOLUME; 4301162922Sariff ctl->ossmask |= SOUND_MASK_SPEAKER; 4302162922Sariff ctl->ossdev = SOUND_MIXER_SPEAKER; 4303162922Sariff w->ctlflags |= SOUND_MASK_VOLUME; 4304162922Sariff w->ctlflags |= SOUND_MASK_SPEAKER; 4305162922Sariff } 4306162922Sariff } 4307162922Sariff } 4308162922Sariff 4309162922Sariff /* Input mixers (rec) */ 4310162922Sariff for (i = devinfo->startnode; i < devinfo->endnode; i++) { 4311162922Sariff w = hdac_widget_get(devinfo, i); 4312162922Sariff if (w == NULL || w->enable == 0) 4313162922Sariff continue; 4314162922Sariff if (!(w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT && 4315162922Sariff w->pflags & HDA_ADC_PATH)) 4316162922Sariff continue; 4317162922Sariff hdac_audio_ctl_inamp_build(devinfo, w->nid, 0); 4318162922Sariff hdac_audio_ctl_recsel_build(devinfo, w->nid, 0); 4319162922Sariff } 4320162922Sariff} 4321162922Sariff 4322162922Sariff#define HDA_COMMIT_CONN (1 << 0) 4323162922Sariff#define HDA_COMMIT_CTRL (1 << 1) 4324162922Sariff#define HDA_COMMIT_EAPD (1 << 2) 4325162922Sariff#define HDA_COMMIT_GPIO (1 << 3) 4326162922Sariff#define HDA_COMMIT_ALL (HDA_COMMIT_CONN | HDA_COMMIT_CTRL | \ 4327162922Sariff HDA_COMMIT_EAPD | HDA_COMMIT_GPIO) 4328162922Sariff 4329162922Sariffstatic void 4330162922Sariffhdac_audio_commit(struct hdac_devinfo *devinfo, uint32_t cfl) 4331162922Sariff{ 4332162922Sariff struct hdac_softc *sc = devinfo->codec->sc; 4333162922Sariff struct hdac_widget *w; 4334164750Sariff nid_t cad; 4335164750Sariff int i; 4336162922Sariff 4337162922Sariff if (!(cfl & HDA_COMMIT_ALL)) 4338162922Sariff return; 4339162922Sariff 4340162922Sariff cad = devinfo->codec->cad; 4341162922Sariff 4342163057Sariff if (cfl & HDA_COMMIT_GPIO) { 4343165039Sariff uint32_t gdata, gmask, gdir; 4344165039Sariff int commitgpio = 0; 4345164828Sariff 4346165039Sariff gdata = 0; 4347165039Sariff gmask = 0; 4348165039Sariff gdir = 0; 4349166796Sariff 4350165039Sariff if (sc->pci_subvendor == APPLE_INTEL_MAC) 4351164828Sariff hdac_command(sc, HDA_CMD_12BIT(cad, devinfo->nid, 4352164828Sariff 0x7e7, 0), cad); 4353165039Sariff 4354165039Sariff if (devinfo->function.audio.quirks & HDA_QUIRK_GPIOFLUSH) 4355165039Sariff commitgpio = 1; 4356165039Sariff else { 4357165039Sariff for (i = 0; i < HDA_GPIO_MAX; i++) { 4358165039Sariff if (!(devinfo->function.audio.quirks & 4359165039Sariff (1 << i))) 4360165039Sariff continue; 4361165039Sariff if (commitgpio == 0) { 4362165039Sariff commitgpio = 1; 4363165039Sariff gdata = hdac_command(sc, 4364165039Sariff HDA_CMD_GET_GPIO_DATA(cad, 4365165039Sariff devinfo->nid), cad); 4366165039Sariff gmask = hdac_command(sc, 4367165039Sariff HDA_CMD_GET_GPIO_ENABLE_MASK(cad, 4368165039Sariff devinfo->nid), cad); 4369165039Sariff gdir = hdac_command(sc, 4370165039Sariff HDA_CMD_GET_GPIO_DIRECTION(cad, 4371165039Sariff devinfo->nid), cad); 4372165039Sariff HDA_BOOTVERBOSE( 4373165039Sariff device_printf(sc->dev, 4374165039Sariff "GPIO init: data=0x%08x " 4375165039Sariff "mask=0x%08x dir=0x%08x\n", 4376165039Sariff gdata, gmask, gdir); 4377165039Sariff ); 4378165039Sariff } 4379165039Sariff gdata |= 1 << i; 4380165039Sariff gmask |= 1 << i; 4381165039Sariff gdir |= 1 << i; 4382165039Sariff } 4383165039Sariff } 4384165039Sariff 4385165039Sariff if (commitgpio != 0) { 4386165039Sariff HDA_BOOTVERBOSE( 4387165039Sariff device_printf(sc->dev, 4388165039Sariff "GPIO commit: data=0x%08x mask=0x%08x " 4389165039Sariff "dir=0x%08x\n", 4390165039Sariff gdata, gmask, gdir); 4391165039Sariff ); 4392162922Sariff hdac_command(sc, 4393164828Sariff HDA_CMD_SET_GPIO_ENABLE_MASK(cad, devinfo->nid, 4394164828Sariff gmask), cad); 4395164828Sariff hdac_command(sc, 4396164828Sariff HDA_CMD_SET_GPIO_DIRECTION(cad, devinfo->nid, 4397164828Sariff gdir), cad); 4398164828Sariff hdac_command(sc, 4399164828Sariff HDA_CMD_SET_GPIO_DATA(cad, devinfo->nid, 4400164828Sariff gdata), cad); 4401162922Sariff } 4402162922Sariff } 4403162922Sariff 4404162922Sariff for (i = 0; i < devinfo->nodecnt; i++) { 4405162922Sariff w = &devinfo->widget[i]; 4406162922Sariff if (w == NULL || w->enable == 0) 4407162922Sariff continue; 4408162922Sariff if (cfl & HDA_COMMIT_CONN) { 4409162922Sariff if (w->selconn == -1) 4410162922Sariff w->selconn = 0; 4411162922Sariff if (w->nconns > 0) 4412162922Sariff hdac_widget_connection_select(w, w->selconn); 4413162922Sariff } 4414162922Sariff if ((cfl & HDA_COMMIT_CTRL) && 4415162922Sariff w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) { 4416162922Sariff if ((w->pflags & (HDA_DAC_PATH | HDA_ADC_PATH)) == 4417162922Sariff (HDA_DAC_PATH | HDA_ADC_PATH)) 4418162922Sariff device_printf(sc->dev, "WARNING: node %d " 4419162922Sariff "participate both for DAC/ADC!\n", w->nid); 4420162922Sariff if (w->pflags & HDA_DAC_PATH) { 4421162922Sariff w->wclass.pin.ctrl &= 4422162922Sariff ~HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE; 4423162922Sariff if ((w->wclass.pin.config & 4424162922Sariff HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) != 4425162922Sariff HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT) 4426162922Sariff w->wclass.pin.ctrl &= 4427162922Sariff ~HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE; 4428162922Sariff } else if (w->pflags & HDA_ADC_PATH) { 4429162922Sariff w->wclass.pin.ctrl &= 4430162922Sariff ~(HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE | 4431162922Sariff HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE); 4432165069Sariff if (w->devinfo->function.audio.quirks & HDA_QUIRK_VREF) { 4433165069Sariff uint32_t pincap = w->wclass.pin.cap; 4434165069Sariff if (HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap)) 4435165069Sariff w->wclass.pin.ctrl |= 4436165069Sariff HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE( 4437165069Sariff HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100 4438165069Sariff ); 4439165069Sariff else if (HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap)) 4440165069Sariff w->wclass.pin.ctrl |= 4441165069Sariff HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE( 4442165069Sariff HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80 4443165069Sariff ); 4444165069Sariff else if (HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap)) 4445165069Sariff w->wclass.pin.ctrl |= 4446165069Sariff HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE( 4447165069Sariff HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50 4448165069Sariff ); 4449165069Sariff } 4450162922Sariff } else 4451162922Sariff w->wclass.pin.ctrl &= ~( 4452162922Sariff HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE | 4453162922Sariff HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE | 4454165069Sariff HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE | 4455165069Sariff HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK); 4456162922Sariff hdac_command(sc, 4457162922Sariff HDA_CMD_SET_PIN_WIDGET_CTRL(cad, w->nid, 4458162922Sariff w->wclass.pin.ctrl), cad); 4459162922Sariff } 4460162922Sariff if ((cfl & HDA_COMMIT_EAPD) && 4461163276Sariff w->param.eapdbtl != HDAC_INVALID) { 4462163432Sariff uint32_t val; 4463163432Sariff 4464163432Sariff val = w->param.eapdbtl; 4465163276Sariff if (devinfo->function.audio.quirks & 4466163432Sariff HDA_QUIRK_EAPDINV) 4467163432Sariff val ^= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD; 4468162922Sariff hdac_command(sc, 4469162922Sariff HDA_CMD_SET_EAPD_BTL_ENABLE(cad, w->nid, 4470163432Sariff val), cad); 4471162922Sariff 4472163276Sariff } 4473162922Sariff DELAY(1000); 4474162922Sariff } 4475162922Sariff} 4476162922Sariff 4477162922Sariffstatic void 4478162922Sariffhdac_audio_ctl_commit(struct hdac_devinfo *devinfo) 4479162922Sariff{ 4480162922Sariff struct hdac_softc *sc = devinfo->codec->sc; 4481162922Sariff struct hdac_audio_ctl *ctl; 4482162922Sariff int i; 4483162922Sariff 4484162922Sariff devinfo->function.audio.mvol = 100 | (100 << 8); 4485162922Sariff i = 0; 4486162922Sariff while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 4487162922Sariff if (ctl->enable == 0 || ctl->widget == NULL) { 4488163057Sariff HDA_BOOTVERBOSE( 4489162922Sariff device_printf(sc->dev, "[%2d] Ctl nid=%d", 4490162922Sariff i, (ctl->widget != NULL) ? 4491162922Sariff ctl->widget->nid : -1); 4492162922Sariff if (ctl->childwidget != NULL) 4493162922Sariff printf(" childnid=%d", 4494162922Sariff ctl->childwidget->nid); 4495162922Sariff if (ctl->widget == NULL) 4496162922Sariff printf(" NULL WIDGET!"); 4497162922Sariff printf(" DISABLED\n"); 4498162922Sariff ); 4499162922Sariff continue; 4500162922Sariff } 4501163057Sariff HDA_BOOTVERBOSE( 4502162922Sariff if (ctl->ossmask == 0) { 4503162922Sariff device_printf(sc->dev, "[%2d] Ctl nid=%d", 4504162922Sariff i, ctl->widget->nid); 4505162922Sariff if (ctl->childwidget != NULL) 4506162922Sariff printf(" childnid=%d", 4507162922Sariff ctl->childwidget->nid); 4508162922Sariff printf(" Bind to NONE\n"); 4509166294Sariff } 4510162922Sariff ); 4511162922Sariff if (ctl->step > 0) { 4512162922Sariff ctl->ossval = (ctl->left * 100) / ctl->step; 4513162922Sariff ctl->ossval |= ((ctl->right * 100) / ctl->step) << 8; 4514162922Sariff } else 4515162922Sariff ctl->ossval = 0; 4516162922Sariff hdac_audio_ctl_amp_set(ctl, HDA_AMP_MUTE_DEFAULT, 4517162922Sariff ctl->left, ctl->right); 4518162922Sariff } 4519162922Sariff} 4520162922Sariff 4521162922Sariffstatic int 4522162922Sariffhdac_pcmchannel_setup(struct hdac_devinfo *devinfo, int dir) 4523162922Sariff{ 4524162922Sariff struct hdac_chan *ch; 4525162922Sariff struct hdac_widget *w; 4526162922Sariff uint32_t cap, fmtcap, pcmcap, path; 4527162922Sariff int i, type, ret, max; 4528162922Sariff 4529162922Sariff if (dir == PCMDIR_PLAY) { 4530162922Sariff type = HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT; 4531162922Sariff ch = &devinfo->codec->sc->play; 4532162922Sariff path = HDA_DAC_PATH; 4533162922Sariff } else { 4534162922Sariff type = HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT; 4535162922Sariff ch = &devinfo->codec->sc->rec; 4536162922Sariff path = HDA_ADC_PATH; 4537162922Sariff } 4538162922Sariff 4539162922Sariff ch->caps = hdac_caps; 4540162922Sariff ch->caps.fmtlist = ch->fmtlist; 4541162922Sariff ch->bit16 = 1; 4542162922Sariff ch->bit32 = 0; 4543162922Sariff ch->pcmrates[0] = 48000; 4544162922Sariff ch->pcmrates[1] = 0; 4545162922Sariff 4546162922Sariff ret = 0; 4547162922Sariff fmtcap = devinfo->function.audio.supp_stream_formats; 4548162922Sariff pcmcap = devinfo->function.audio.supp_pcm_size_rate; 4549162922Sariff max = (sizeof(ch->io) / sizeof(ch->io[0])) - 1; 4550162922Sariff 4551162922Sariff for (i = devinfo->startnode; i < devinfo->endnode && ret < max; i++) { 4552162922Sariff w = hdac_widget_get(devinfo, i); 4553162922Sariff if (w == NULL || w->enable == 0 || w->type != type || 4554163057Sariff !(w->pflags & path)) 4555162922Sariff continue; 4556162922Sariff cap = w->param.widget_cap; 4557162922Sariff /*if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(cap)) 4558162922Sariff continue;*/ 4559162922Sariff if (!HDA_PARAM_AUDIO_WIDGET_CAP_STEREO(cap)) 4560162922Sariff continue; 4561162922Sariff cap = w->param.supp_stream_formats; 4562162922Sariff /*if (HDA_PARAM_SUPP_STREAM_FORMATS_AC3(cap)) { 4563162922Sariff } 4564162922Sariff if (HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32(cap)) { 4565162922Sariff }*/ 4566162922Sariff if (!HDA_PARAM_SUPP_STREAM_FORMATS_PCM(cap)) 4567162922Sariff continue; 4568164614Sariff if (ret == 0) { 4569164614Sariff fmtcap = w->param.supp_stream_formats; 4570164614Sariff pcmcap = w->param.supp_pcm_size_rate; 4571164614Sariff } else { 4572164614Sariff fmtcap &= w->param.supp_stream_formats; 4573164614Sariff pcmcap &= w->param.supp_pcm_size_rate; 4574164614Sariff } 4575162922Sariff ch->io[ret++] = i; 4576162922Sariff } 4577162922Sariff ch->io[ret] = -1; 4578162922Sariff 4579162922Sariff ch->supp_stream_formats = fmtcap; 4580162922Sariff ch->supp_pcm_size_rate = pcmcap; 4581162922Sariff 4582162922Sariff /* 4583162922Sariff * 8bit = 0 4584162922Sariff * 16bit = 1 4585162922Sariff * 20bit = 2 4586162922Sariff * 24bit = 3 4587162922Sariff * 32bit = 4 4588162922Sariff */ 4589162922Sariff if (ret > 0) { 4590162922Sariff cap = pcmcap; 4591162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(cap)) 4592162922Sariff ch->bit16 = 1; 4593162922Sariff else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(cap)) 4594162922Sariff ch->bit16 = 0; 4595162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(cap)) 4596162922Sariff ch->bit32 = 4; 4597162922Sariff else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT(cap)) 4598162922Sariff ch->bit32 = 3; 4599162922Sariff else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT(cap)) 4600162922Sariff ch->bit32 = 2; 4601162922Sariff i = 0; 4602162922Sariff if (!(devinfo->function.audio.quirks & HDA_QUIRK_FORCESTEREO)) 4603162922Sariff ch->fmtlist[i++] = AFMT_S16_LE; 4604162922Sariff ch->fmtlist[i++] = AFMT_S16_LE | AFMT_STEREO; 4605162922Sariff if (ch->bit32 > 0) { 4606162922Sariff if (!(devinfo->function.audio.quirks & 4607162922Sariff HDA_QUIRK_FORCESTEREO)) 4608162922Sariff ch->fmtlist[i++] = AFMT_S32_LE; 4609162922Sariff ch->fmtlist[i++] = AFMT_S32_LE | AFMT_STEREO; 4610162922Sariff } 4611162922Sariff ch->fmtlist[i] = 0; 4612162922Sariff i = 0; 4613162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(cap)) 4614162922Sariff ch->pcmrates[i++] = 8000; 4615162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(cap)) 4616162922Sariff ch->pcmrates[i++] = 11025; 4617162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ(cap)) 4618162922Sariff ch->pcmrates[i++] = 16000; 4619162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ(cap)) 4620162922Sariff ch->pcmrates[i++] = 22050; 4621162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ(cap)) 4622162922Sariff ch->pcmrates[i++] = 32000; 4623162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ(cap)) 4624162922Sariff ch->pcmrates[i++] = 44100; 4625162922Sariff /* if (HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ(cap)) */ 4626162922Sariff ch->pcmrates[i++] = 48000; 4627162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ(cap)) 4628162922Sariff ch->pcmrates[i++] = 88200; 4629162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ(cap)) 4630162922Sariff ch->pcmrates[i++] = 96000; 4631162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ(cap)) 4632162922Sariff ch->pcmrates[i++] = 176400; 4633162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ(cap)) 4634162922Sariff ch->pcmrates[i++] = 192000; 4635162922Sariff /* if (HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ(cap)) */ 4636162922Sariff ch->pcmrates[i] = 0; 4637162922Sariff if (i > 0) { 4638162922Sariff ch->caps.minspeed = ch->pcmrates[0]; 4639162922Sariff ch->caps.maxspeed = ch->pcmrates[i - 1]; 4640162922Sariff } 4641162922Sariff } 4642162922Sariff 4643162922Sariff return (ret); 4644162922Sariff} 4645162922Sariff 4646162922Sariffstatic void 4647162922Sariffhdac_dump_ctls(struct hdac_devinfo *devinfo, const char *banner, uint32_t flag) 4648162922Sariff{ 4649162922Sariff struct hdac_audio_ctl *ctl; 4650162922Sariff struct hdac_softc *sc = devinfo->codec->sc; 4651162922Sariff int i; 4652162922Sariff uint32_t fl = 0; 4653162922Sariff 4654162922Sariff 4655162922Sariff if (flag == 0) { 4656162922Sariff fl = SOUND_MASK_VOLUME | SOUND_MASK_PCM | 4657162922Sariff SOUND_MASK_CD | SOUND_MASK_LINE | SOUND_MASK_RECLEV | 4658162922Sariff SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_OGAIN; 4659162922Sariff } 4660162922Sariff 4661162922Sariff i = 0; 4662162922Sariff while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 4663162922Sariff if (ctl->enable == 0 || ctl->widget == NULL || 4664162922Sariff ctl->widget->enable == 0) 4665162922Sariff continue; 4666162922Sariff if ((flag == 0 && (ctl->ossmask & ~fl)) || 4667162922Sariff (flag != 0 && (ctl->ossmask & flag))) { 4668162922Sariff if (banner != NULL) { 4669162922Sariff device_printf(sc->dev, "\n"); 4670162922Sariff device_printf(sc->dev, "%s\n", banner); 4671162922Sariff } 4672162922Sariff goto hdac_ctl_dump_it_all; 4673162922Sariff } 4674162922Sariff } 4675162922Sariff 4676162922Sariff return; 4677162922Sariff 4678162922Sariffhdac_ctl_dump_it_all: 4679162922Sariff i = 0; 4680162922Sariff while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 4681162922Sariff if (ctl->enable == 0 || ctl->widget == NULL || 4682162922Sariff ctl->widget->enable == 0) 4683162922Sariff continue; 4684162922Sariff if (!((flag == 0 && (ctl->ossmask & ~fl)) || 4685162922Sariff (flag != 0 && (ctl->ossmask & flag)))) 4686162922Sariff continue; 4687162922Sariff if (flag == 0) { 4688162922Sariff device_printf(sc->dev, "\n"); 4689162922Sariff device_printf(sc->dev, "Unknown Ctl (OSS: %s)\n", 4690162922Sariff hdac_audio_ctl_ossmixer_mask2name(ctl->ossmask)); 4691162922Sariff } 4692162922Sariff device_printf(sc->dev, " |\n"); 4693162922Sariff device_printf(sc->dev, " +- nid: %2d index: %2d ", 4694162922Sariff ctl->widget->nid, ctl->index); 4695162922Sariff if (ctl->childwidget != NULL) 4696162922Sariff printf("(nid: %2d) ", ctl->childwidget->nid); 4697162922Sariff else 4698162922Sariff printf(" "); 4699162922Sariff printf("mute: %d step: %3d size: %3d off: %3d dir=0x%x ossmask=0x%08x\n", 4700162922Sariff ctl->mute, ctl->step, ctl->size, ctl->offset, ctl->dir, 4701162922Sariff ctl->ossmask); 4702162922Sariff } 4703162922Sariff} 4704162922Sariff 4705162922Sariffstatic void 4706162922Sariffhdac_dump_audio_formats(struct hdac_softc *sc, uint32_t fcap, uint32_t pcmcap) 4707162922Sariff{ 4708162922Sariff uint32_t cap; 4709162922Sariff 4710162922Sariff cap = fcap; 4711162922Sariff if (cap != 0) { 4712162922Sariff device_printf(sc->dev, " Stream cap: 0x%08x\n", cap); 4713162922Sariff device_printf(sc->dev, " Format:"); 4714162922Sariff if (HDA_PARAM_SUPP_STREAM_FORMATS_AC3(cap)) 4715162922Sariff printf(" AC3"); 4716162922Sariff if (HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32(cap)) 4717162922Sariff printf(" FLOAT32"); 4718162922Sariff if (HDA_PARAM_SUPP_STREAM_FORMATS_PCM(cap)) 4719162922Sariff printf(" PCM"); 4720162922Sariff printf("\n"); 4721162922Sariff } 4722162922Sariff cap = pcmcap; 4723162922Sariff if (cap != 0) { 4724162922Sariff device_printf(sc->dev, " PCM cap: 0x%08x\n", cap); 4725162922Sariff device_printf(sc->dev, " PCM size:"); 4726162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(cap)) 4727162922Sariff printf(" 8"); 4728162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(cap)) 4729162922Sariff printf(" 16"); 4730162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT(cap)) 4731162922Sariff printf(" 20"); 4732162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT(cap)) 4733162922Sariff printf(" 24"); 4734162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(cap)) 4735162922Sariff printf(" 32"); 4736162922Sariff printf("\n"); 4737162922Sariff device_printf(sc->dev, " PCM rate:"); 4738162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(cap)) 4739162922Sariff printf(" 8"); 4740162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(cap)) 4741162922Sariff printf(" 11"); 4742162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ(cap)) 4743162922Sariff printf(" 16"); 4744162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ(cap)) 4745162922Sariff printf(" 22"); 4746162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ(cap)) 4747162922Sariff printf(" 32"); 4748162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ(cap)) 4749162922Sariff printf(" 44"); 4750162922Sariff printf(" 48"); 4751162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ(cap)) 4752162922Sariff printf(" 88"); 4753162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ(cap)) 4754162922Sariff printf(" 96"); 4755162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ(cap)) 4756162922Sariff printf(" 176"); 4757162922Sariff if (HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ(cap)) 4758162922Sariff printf(" 192"); 4759162922Sariff printf("\n"); 4760162922Sariff } 4761162922Sariff} 4762162922Sariff 4763162922Sariffstatic void 4764162922Sariffhdac_dump_pin(struct hdac_softc *sc, struct hdac_widget *w) 4765162922Sariff{ 4766162922Sariff uint32_t pincap, wcap; 4767162922Sariff 4768162922Sariff pincap = w->wclass.pin.cap; 4769162922Sariff wcap = w->param.widget_cap; 4770162922Sariff 4771162922Sariff device_printf(sc->dev, " Pin cap: 0x%08x\n", pincap); 4772162922Sariff device_printf(sc->dev, " "); 4773162922Sariff if (HDA_PARAM_PIN_CAP_IMP_SENSE_CAP(pincap)) 4774162922Sariff printf(" ISC"); 4775162922Sariff if (HDA_PARAM_PIN_CAP_TRIGGER_REQD(pincap)) 4776162922Sariff printf(" TRQD"); 4777162922Sariff if (HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(pincap)) 4778162922Sariff printf(" PDC"); 4779162922Sariff if (HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap)) 4780162922Sariff printf(" HP"); 4781162922Sariff if (HDA_PARAM_PIN_CAP_OUTPUT_CAP(pincap)) 4782162922Sariff printf(" OUT"); 4783162922Sariff if (HDA_PARAM_PIN_CAP_INPUT_CAP(pincap)) 4784162922Sariff printf(" IN"); 4785162922Sariff if (HDA_PARAM_PIN_CAP_BALANCED_IO_PINS(pincap)) 4786162922Sariff printf(" BAL"); 4787165069Sariff if (HDA_PARAM_PIN_CAP_VREF_CTRL(pincap)) { 4788165069Sariff printf(" VREF["); 4789165069Sariff if (HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap)) 4790165069Sariff printf(" 50"); 4791165069Sariff if (HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap)) 4792165069Sariff printf(" 80"); 4793165069Sariff if (HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap)) 4794165069Sariff printf(" 100"); 4795165069Sariff if (HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND(pincap)) 4796165069Sariff printf(" GROUND"); 4797165069Sariff if (HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ(pincap)) 4798165069Sariff printf(" HIZ"); 4799165069Sariff printf(" ]"); 4800165069Sariff } 4801162922Sariff if (HDA_PARAM_PIN_CAP_EAPD_CAP(pincap)) 4802162922Sariff printf(" EAPD"); 4803162922Sariff if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(wcap)) 4804162922Sariff printf(" : UNSOL"); 4805162922Sariff printf("\n"); 4806162922Sariff device_printf(sc->dev, " Pin config: 0x%08x\n", 4807162922Sariff w->wclass.pin.config); 4808162922Sariff device_printf(sc->dev, " Pin control: 0x%08x", w->wclass.pin.ctrl); 4809162922Sariff if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE) 4810162922Sariff printf(" HP"); 4811162922Sariff if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE) 4812162922Sariff printf(" IN"); 4813162922Sariff if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE) 4814162922Sariff printf(" OUT"); 4815162922Sariff printf("\n"); 4816162922Sariff} 4817162922Sariff 4818162922Sariffstatic void 4819162922Sariffhdac_dump_amp(struct hdac_softc *sc, uint32_t cap, char *banner) 4820162922Sariff{ 4821163057Sariff device_printf(sc->dev, " %s amp: 0x%08x\n", banner, cap); 4822162922Sariff device_printf(sc->dev, " " 4823162922Sariff "mute=%d step=%d size=%d offset=%d\n", 4824162922Sariff HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(cap), 4825162922Sariff HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(cap), 4826162922Sariff HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(cap), 4827162922Sariff HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(cap)); 4828162922Sariff} 4829162922Sariff 4830162922Sariffstatic void 4831162922Sariffhdac_dump_nodes(struct hdac_devinfo *devinfo) 4832162922Sariff{ 4833162922Sariff struct hdac_softc *sc = devinfo->codec->sc; 4834162922Sariff struct hdac_widget *w, *cw; 4835162922Sariff int i, j; 4836162922Sariff 4837162922Sariff device_printf(sc->dev, "\n"); 4838162922Sariff device_printf(sc->dev, "Default Parameter\n"); 4839162922Sariff device_printf(sc->dev, "-----------------\n"); 4840162922Sariff hdac_dump_audio_formats(sc, 4841162922Sariff devinfo->function.audio.supp_stream_formats, 4842162922Sariff devinfo->function.audio.supp_pcm_size_rate); 4843162922Sariff device_printf(sc->dev, " IN amp: 0x%08x\n", 4844162922Sariff devinfo->function.audio.inamp_cap); 4845162922Sariff device_printf(sc->dev, " OUT amp: 0x%08x\n", 4846162922Sariff devinfo->function.audio.outamp_cap); 4847162922Sariff for (i = devinfo->startnode; i < devinfo->endnode; i++) { 4848162922Sariff w = hdac_widget_get(devinfo, i); 4849162922Sariff if (w == NULL) { 4850162922Sariff device_printf(sc->dev, "Ghost widget nid=%d\n", i); 4851162922Sariff continue; 4852162922Sariff } 4853162922Sariff device_printf(sc->dev, "\n"); 4854162922Sariff device_printf(sc->dev, " nid: %d [%s]%s\n", w->nid, 4855162922Sariff HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap) ? 4856162922Sariff "DIGITAL" : "ANALOG", 4857162922Sariff (w->enable == 0) ? " [DISABLED]" : ""); 4858162922Sariff device_printf(sc->dev, " name: %s\n", w->name); 4859162922Sariff device_printf(sc->dev, " widget_cap: 0x%08x\n", 4860162922Sariff w->param.widget_cap); 4861162922Sariff device_printf(sc->dev, " Parse flags: 0x%08x\n", 4862162922Sariff w->pflags); 4863162922Sariff device_printf(sc->dev, " Ctl flags: 0x%08x\n", 4864162922Sariff w->ctlflags); 4865162922Sariff if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT || 4866162922Sariff w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) { 4867162922Sariff hdac_dump_audio_formats(sc, 4868162922Sariff w->param.supp_stream_formats, 4869162922Sariff w->param.supp_pcm_size_rate); 4870162922Sariff } else if (w->type == 4871162922Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) 4872162922Sariff hdac_dump_pin(sc, w); 4873162965Sariff if (w->param.eapdbtl != HDAC_INVALID) 4874162922Sariff device_printf(sc->dev, " EAPD: 0x%08x\n", 4875162922Sariff w->param.eapdbtl); 4876163057Sariff if (HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP(w->param.widget_cap) && 4877163057Sariff w->param.outamp_cap != 0) 4878162922Sariff hdac_dump_amp(sc, w->param.outamp_cap, "Output"); 4879163057Sariff if (HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP(w->param.widget_cap) && 4880163057Sariff w->param.inamp_cap != 0) 4881162922Sariff hdac_dump_amp(sc, w->param.inamp_cap, " Input"); 4882162922Sariff device_printf(sc->dev, " connections: %d\n", w->nconns); 4883162922Sariff for (j = 0; j < w->nconns; j++) { 4884162922Sariff cw = hdac_widget_get(devinfo, w->conns[j]); 4885162922Sariff device_printf(sc->dev, " |\n"); 4886162922Sariff device_printf(sc->dev, " + <- nid=%d [%s]", 4887162922Sariff w->conns[j], (cw == NULL) ? "GHOST!" : cw->name); 4888162922Sariff if (cw == NULL) 4889162922Sariff printf(" [UNKNOWN]"); 4890162922Sariff else if (cw->enable == 0) 4891162922Sariff printf(" [DISABLED]"); 4892162922Sariff if (w->nconns > 1 && w->selconn == j && w->type != 4893162922Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) 4894162922Sariff printf(" (selected)"); 4895162922Sariff printf("\n"); 4896162922Sariff } 4897162922Sariff } 4898162922Sariff 4899162922Sariff} 4900162922Sariff 4901163057Sariffstatic int 4902163057Sariffhdac_dump_dac_internal(struct hdac_devinfo *devinfo, nid_t nid, int depth) 4903163057Sariff{ 4904163057Sariff struct hdac_widget *w, *cw; 4905163057Sariff struct hdac_softc *sc = devinfo->codec->sc; 4906163057Sariff int i; 4907163057Sariff 4908163057Sariff if (depth > HDA_PARSE_MAXDEPTH) 4909163057Sariff return (0); 4910163057Sariff 4911163057Sariff w = hdac_widget_get(devinfo, nid); 4912163057Sariff if (w == NULL || w->enable == 0 || !(w->pflags & HDA_DAC_PATH)) 4913163057Sariff return (0); 4914163057Sariff 4915163057Sariff if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) { 4916163057Sariff device_printf(sc->dev, "\n"); 4917163057Sariff device_printf(sc->dev, " nid=%d [%s]\n", w->nid, w->name); 4918163057Sariff device_printf(sc->dev, " ^\n"); 4919163057Sariff device_printf(sc->dev, " |\n"); 4920163057Sariff device_printf(sc->dev, " +-----<------+\n"); 4921163057Sariff } else { 4922163057Sariff device_printf(sc->dev, " ^\n"); 4923163057Sariff device_printf(sc->dev, " |\n"); 4924163057Sariff device_printf(sc->dev, " "); 4925163057Sariff printf(" nid=%d [%s]\n", w->nid, w->name); 4926163057Sariff } 4927163057Sariff 4928163057Sariff if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT) { 4929163057Sariff return (1); 4930163057Sariff } else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) { 4931163057Sariff for (i = 0; i < w->nconns; i++) { 4932163057Sariff cw = hdac_widget_get(devinfo, w->conns[i]); 4933163057Sariff if (cw == NULL || cw->enable == 0 || cw->type == 4934163057Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) 4935163057Sariff continue; 4936163057Sariff if (hdac_dump_dac_internal(devinfo, cw->nid, 4937163057Sariff depth + 1) != 0) 4938163057Sariff return (1); 4939163057Sariff } 4940163057Sariff } else if ((w->type == 4941163057Sariff HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR || 4942163057Sariff w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) && 4943163057Sariff w->selconn > -1 && w->selconn < w->nconns) { 4944163057Sariff if (hdac_dump_dac_internal(devinfo, w->conns[w->selconn], 4945163057Sariff depth + 1) != 0) 4946163057Sariff return (1); 4947163057Sariff } 4948163057Sariff 4949163057Sariff return (0); 4950163057Sariff} 4951163057Sariff 4952162922Sariffstatic void 4953162922Sariffhdac_dump_dac(struct hdac_devinfo *devinfo) 4954162922Sariff{ 4955163057Sariff struct hdac_widget *w; 4956163057Sariff struct hdac_softc *sc = devinfo->codec->sc; 4957163057Sariff int i, printed = 0; 4958163057Sariff 4959163057Sariff for (i = devinfo->startnode; i < devinfo->endnode; i++) { 4960163057Sariff w = hdac_widget_get(devinfo, i); 4961163057Sariff if (w == NULL || w->enable == 0) 4962163057Sariff continue; 4963163057Sariff if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX || 4964163057Sariff !(w->pflags & HDA_DAC_PATH)) 4965163057Sariff continue; 4966163057Sariff if (printed == 0) { 4967163057Sariff printed = 1; 4968163057Sariff device_printf(sc->dev, "\n"); 4969163057Sariff device_printf(sc->dev, "Playback path:\n"); 4970163057Sariff } 4971163057Sariff hdac_dump_dac_internal(devinfo, w->nid, 0); 4972163057Sariff } 4973162922Sariff} 4974162922Sariff 4975162922Sariffstatic void 4976162922Sariffhdac_dump_adc(struct hdac_devinfo *devinfo) 4977162922Sariff{ 4978162922Sariff struct hdac_widget *w, *cw; 4979162922Sariff struct hdac_softc *sc = devinfo->codec->sc; 4980162922Sariff int i, j; 4981162922Sariff int printed = 0; 4982162922Sariff char ossdevs[256]; 4983162922Sariff 4984162922Sariff for (i = devinfo->startnode; i < devinfo->endnode; i++) { 4985162922Sariff w = hdac_widget_get(devinfo, i); 4986162922Sariff if (w == NULL || w->enable == 0) 4987162922Sariff continue; 4988162922Sariff if (!(w->pflags & HDA_ADC_RECSEL)) 4989162922Sariff continue; 4990162922Sariff if (printed == 0) { 4991162922Sariff printed = 1; 4992162922Sariff device_printf(sc->dev, "\n"); 4993162922Sariff device_printf(sc->dev, "Recording sources:\n"); 4994162922Sariff } 4995162922Sariff device_printf(sc->dev, "\n"); 4996162922Sariff device_printf(sc->dev, " nid=%d [%s]\n", w->nid, w->name); 4997162922Sariff for (j = 0; j < w->nconns; j++) { 4998162922Sariff cw = hdac_widget_get(devinfo, w->conns[j]); 4999162922Sariff if (cw == NULL || cw->enable == 0) 5000162922Sariff continue; 5001162922Sariff hdac_audio_ctl_ossmixer_mask2allname(cw->ctlflags, 5002162922Sariff ossdevs, sizeof(ossdevs)); 5003162922Sariff device_printf(sc->dev, " |\n"); 5004162922Sariff device_printf(sc->dev, " + <- nid=%d [%s]", 5005162922Sariff cw->nid, cw->name); 5006162922Sariff if (strlen(ossdevs) > 0) { 5007162922Sariff printf(" [recsrc: %s]", ossdevs); 5008162922Sariff } 5009162922Sariff printf("\n"); 5010162922Sariff } 5011162922Sariff } 5012162922Sariff} 5013162922Sariff 5014162922Sariffstatic void 5015162922Sariffhdac_dump_pcmchannels(struct hdac_softc *sc, int pcnt, int rcnt) 5016162922Sariff{ 5017162922Sariff nid_t *nids; 5018162922Sariff 5019162922Sariff if (pcnt > 0) { 5020162922Sariff device_printf(sc->dev, "\n"); 5021162922Sariff device_printf(sc->dev, " PCM Playback: %d\n", pcnt); 5022162922Sariff hdac_dump_audio_formats(sc, sc->play.supp_stream_formats, 5023162922Sariff sc->play.supp_pcm_size_rate); 5024162922Sariff device_printf(sc->dev, " DAC:"); 5025162922Sariff for (nids = sc->play.io; *nids != -1; nids++) 5026162922Sariff printf(" %d", *nids); 5027162922Sariff printf("\n"); 5028162922Sariff } 5029162922Sariff 5030162922Sariff if (rcnt > 0) { 5031162922Sariff device_printf(sc->dev, "\n"); 5032162922Sariff device_printf(sc->dev, " PCM Record: %d\n", rcnt); 5033162922Sariff hdac_dump_audio_formats(sc, sc->play.supp_stream_formats, 5034162922Sariff sc->rec.supp_pcm_size_rate); 5035162922Sariff device_printf(sc->dev, " ADC:"); 5036162922Sariff for (nids = sc->rec.io; *nids != -1; nids++) 5037162922Sariff printf(" %d", *nids); 5038162922Sariff printf("\n"); 5039162922Sariff } 5040162922Sariff} 5041162922Sariff 5042162922Sariffstatic void 5043163057Sariffhdac_release_resources(struct hdac_softc *sc) 5044163057Sariff{ 5045163057Sariff struct hdac_devinfo *devinfo = NULL; 5046163057Sariff device_t *devlist = NULL; 5047163057Sariff int i, devcount; 5048163057Sariff 5049163057Sariff if (sc == NULL) 5050163057Sariff return; 5051163057Sariff 5052163057Sariff hdac_lock(sc); 5053164614Sariff if (sc->polling != 0) 5054164614Sariff callout_stop(&sc->poll_hdac); 5055163057Sariff hdac_reset(sc); 5056163057Sariff hdac_unlock(sc); 5057163057Sariff snd_mtxfree(sc->lock); 5058163057Sariff 5059163057Sariff device_get_children(sc->dev, &devlist, &devcount); 5060163057Sariff for (i = 0; devlist != NULL && i < devcount; i++) { 5061163057Sariff devinfo = (struct hdac_devinfo *)device_get_ivars(devlist[i]); 5062163057Sariff if (devinfo == NULL) 5063163057Sariff continue; 5064163057Sariff if (devinfo->widget != NULL) 5065163057Sariff free(devinfo->widget, M_HDAC); 5066163057Sariff if (devinfo->node_type == 5067163057Sariff HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO && 5068163057Sariff devinfo->function.audio.ctl != NULL) 5069163057Sariff free(devinfo->function.audio.ctl, M_HDAC); 5070163057Sariff free(devinfo, M_HDAC); 5071163057Sariff device_delete_child(sc->dev, devlist[i]); 5072163057Sariff } 5073163057Sariff if (devlist != NULL) 5074163057Sariff free(devlist, M_TEMP); 5075163057Sariff 5076163057Sariff for (i = 0; i < HDAC_CODEC_MAX; i++) { 5077163057Sariff if (sc->codecs[i] != NULL) 5078163057Sariff free(sc->codecs[i], M_HDAC); 5079163057Sariff sc->codecs[i] = NULL; 5080163057Sariff } 5081163057Sariff 5082163057Sariff hdac_dma_free(&sc->rirb_dma); 5083163057Sariff hdac_dma_free(&sc->corb_dma); 5084163057Sariff if (sc->play.blkcnt > 0) 5085163057Sariff hdac_dma_free(&sc->play.bdl_dma); 5086163057Sariff if (sc->rec.blkcnt > 0) 5087163057Sariff hdac_dma_free(&sc->rec.bdl_dma); 5088167702Sariff if (sc->chan_dmat != NULL) { 5089167702Sariff bus_dma_tag_destroy(sc->chan_dmat); 5090167702Sariff sc->chan_dmat = NULL; 5091167702Sariff } 5092163057Sariff hdac_irq_free(sc); 5093163057Sariff hdac_mem_free(sc); 5094163057Sariff free(sc, M_DEVBUF); 5095163057Sariff} 5096163057Sariff 5097163057Sariff/* This function surely going to make its way into upper level someday. */ 5098163057Sariffstatic void 5099163057Sariffhdac_config_fetch(struct hdac_softc *sc, uint32_t *on, uint32_t *off) 5100163057Sariff{ 5101163057Sariff const char *res = NULL; 5102163057Sariff int i = 0, j, k, len, inv; 5103163057Sariff 5104163057Sariff if (on != NULL) 5105163057Sariff *on = 0; 5106163057Sariff if (off != NULL) 5107163057Sariff *off = 0; 5108163057Sariff if (sc == NULL) 5109163057Sariff return; 5110163057Sariff if (resource_string_value(device_get_name(sc->dev), 5111163057Sariff device_get_unit(sc->dev), "config", &res) != 0) 5112163057Sariff return; 5113163057Sariff if (!(res != NULL && strlen(res) > 0)) 5114163057Sariff return; 5115163057Sariff HDA_BOOTVERBOSE( 5116163057Sariff device_printf(sc->dev, "HDA_DEBUG: HDA Config:"); 5117163057Sariff ); 5118163057Sariff for (;;) { 5119163057Sariff while (res[i] != '\0' && 5120163057Sariff (res[i] == ',' || isspace(res[i]) != 0)) 5121163057Sariff i++; 5122163057Sariff if (res[i] == '\0') { 5123163057Sariff HDA_BOOTVERBOSE( 5124163057Sariff printf("\n"); 5125163057Sariff ); 5126163057Sariff return; 5127163057Sariff } 5128163057Sariff j = i; 5129163057Sariff while (res[j] != '\0' && 5130163057Sariff !(res[j] == ',' || isspace(res[j]) != 0)) 5131163057Sariff j++; 5132163057Sariff len = j - i; 5133163057Sariff if (len > 2 && strncmp(res + i, "no", 2) == 0) 5134163057Sariff inv = 2; 5135163057Sariff else 5136163057Sariff inv = 0; 5137163057Sariff for (k = 0; len > inv && k < HDAC_QUIRKS_TAB_LEN; k++) { 5138163057Sariff if (strncmp(res + i + inv, 5139163057Sariff hdac_quirks_tab[k].key, len - inv) != 0) 5140163057Sariff continue; 5141163057Sariff if (len - inv != strlen(hdac_quirks_tab[k].key)) 5142163057Sariff break; 5143163057Sariff HDA_BOOTVERBOSE( 5144163057Sariff printf(" %s%s", (inv != 0) ? "no" : "", 5145163057Sariff hdac_quirks_tab[k].key); 5146163057Sariff ); 5147163057Sariff if (inv == 0 && on != NULL) 5148163057Sariff *on |= hdac_quirks_tab[k].value; 5149163057Sariff else if (inv != 0 && off != NULL) 5150163057Sariff *off |= hdac_quirks_tab[k].value; 5151163057Sariff break; 5152163057Sariff } 5153163057Sariff i = j; 5154163057Sariff } 5155163057Sariff} 5156163057Sariff 5157164614Sariff#ifdef SND_DYNSYSCTL 5158164614Sariffstatic int 5159164614Sariffsysctl_hdac_polling(SYSCTL_HANDLER_ARGS) 5160164614Sariff{ 5161164614Sariff struct hdac_softc *sc; 5162164614Sariff struct hdac_devinfo *devinfo; 5163164614Sariff device_t dev; 5164164614Sariff uint32_t ctl; 5165164614Sariff int err, val; 5166164614Sariff 5167164614Sariff dev = oidp->oid_arg1; 5168164614Sariff devinfo = pcm_getdevinfo(dev); 5169164614Sariff if (devinfo == NULL || devinfo->codec == NULL || 5170164614Sariff devinfo->codec->sc == NULL) 5171164614Sariff return (EINVAL); 5172164614Sariff sc = devinfo->codec->sc; 5173164614Sariff hdac_lock(sc); 5174164614Sariff val = sc->polling; 5175164614Sariff hdac_unlock(sc); 5176164614Sariff err = sysctl_handle_int(oidp, &val, sizeof(val), req); 5177164614Sariff 5178164614Sariff if (err || req->newptr == NULL) 5179164614Sariff return (err); 5180164614Sariff if (val < 0 || val > 1) 5181164614Sariff return (EINVAL); 5182164614Sariff 5183164614Sariff hdac_lock(sc); 5184164614Sariff if (val != sc->polling) { 5185164614Sariff if (hda_chan_active(sc) != 0) 5186164614Sariff err = EBUSY; 5187164614Sariff else if (val == 0) { 5188164614Sariff callout_stop(&sc->poll_hdac); 5189164614Sariff HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT, 5190164614Sariff sc->rirb_size / 2); 5191164614Sariff ctl = HDAC_READ_1(&sc->mem, HDAC_RIRBCTL); 5192164614Sariff ctl |= HDAC_RIRBCTL_RINTCTL; 5193164614Sariff HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, ctl); 5194164614Sariff HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, 5195164614Sariff HDAC_INTCTL_CIE | HDAC_INTCTL_GIE); 5196164614Sariff sc->polling = 0; 5197164614Sariff DELAY(1000); 5198164614Sariff } else { 5199164614Sariff HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, 0); 5200164614Sariff HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT, 0); 5201164614Sariff ctl = HDAC_READ_1(&sc->mem, HDAC_RIRBCTL); 5202164614Sariff ctl &= ~HDAC_RIRBCTL_RINTCTL; 5203164614Sariff HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, ctl); 5204164614Sariff callout_reset(&sc->poll_hdac, 1, hdac_poll_callback, 5205164614Sariff sc); 5206164614Sariff sc->polling = 1; 5207164614Sariff DELAY(1000); 5208164614Sariff } 5209164614Sariff } 5210164614Sariff hdac_unlock(sc); 5211164614Sariff 5212164614Sariff return (err); 5213164614Sariff} 5214164614Sariff#endif 5215164614Sariff 5216163057Sariffstatic void 5217162922Sariffhdac_attach2(void *arg) 5218162922Sariff{ 5219162922Sariff struct hdac_softc *sc; 5220162922Sariff struct hdac_widget *w; 5221162922Sariff struct hdac_audio_ctl *ctl; 5222163057Sariff uint32_t quirks_on, quirks_off; 5223162922Sariff int pcnt, rcnt; 5224162922Sariff int i; 5225162922Sariff char status[SND_STATUSLEN]; 5226162965Sariff device_t *devlist = NULL; 5227162922Sariff int devcount; 5228162922Sariff struct hdac_devinfo *devinfo = NULL; 5229162922Sariff 5230162922Sariff sc = (struct hdac_softc *)arg; 5231162922Sariff 5232163057Sariff hdac_config_fetch(sc, &quirks_on, &quirks_off); 5233162922Sariff 5234163057Sariff HDA_BOOTVERBOSE( 5235163057Sariff device_printf(sc->dev, "HDA_DEBUG: HDA Config: on=0x%08x off=0x%08x\n", 5236163057Sariff quirks_on, quirks_off); 5237163057Sariff ); 5238163057Sariff 5239162922Sariff hdac_lock(sc); 5240162922Sariff 5241162922Sariff /* Remove ourselves from the config hooks */ 5242162922Sariff if (sc->intrhook.ich_func != NULL) { 5243162922Sariff config_intrhook_disestablish(&sc->intrhook); 5244162922Sariff sc->intrhook.ich_func = NULL; 5245162922Sariff } 5246162922Sariff 5247162922Sariff /* Start the corb and rirb engines */ 5248163057Sariff HDA_BOOTVERBOSE( 5249162922Sariff device_printf(sc->dev, "HDA_DEBUG: Starting CORB Engine...\n"); 5250162922Sariff ); 5251162922Sariff hdac_corb_start(sc); 5252163057Sariff HDA_BOOTVERBOSE( 5253162922Sariff device_printf(sc->dev, "HDA_DEBUG: Starting RIRB Engine...\n"); 5254162922Sariff ); 5255162922Sariff hdac_rirb_start(sc); 5256162922Sariff 5257163057Sariff HDA_BOOTVERBOSE( 5258162922Sariff device_printf(sc->dev, 5259162922Sariff "HDA_DEBUG: Enabling controller interrupt...\n"); 5260162922Sariff ); 5261164614Sariff if (sc->polling == 0) 5262164614Sariff HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, 5263164614Sariff HDAC_INTCTL_CIE | HDAC_INTCTL_GIE); 5264163057Sariff HDAC_WRITE_4(&sc->mem, HDAC_GCTL, HDAC_READ_4(&sc->mem, HDAC_GCTL) | 5265163057Sariff HDAC_GCTL_UNSOL); 5266162922Sariff 5267162922Sariff DELAY(1000); 5268162922Sariff 5269163057Sariff HDA_BOOTVERBOSE( 5270162922Sariff device_printf(sc->dev, "HDA_DEBUG: Scanning HDA codecs...\n"); 5271162922Sariff ); 5272162922Sariff hdac_scan_codecs(sc); 5273162922Sariff 5274162922Sariff device_get_children(sc->dev, &devlist, &devcount); 5275162965Sariff for (i = 0; devlist != NULL && i < devcount; i++) { 5276162965Sariff devinfo = (struct hdac_devinfo *)device_get_ivars(devlist[i]); 5277162965Sariff if (devinfo != NULL && devinfo->node_type == 5278162965Sariff HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) { 5279162965Sariff break; 5280162965Sariff } else 5281162965Sariff devinfo = NULL; 5282162922Sariff } 5283162965Sariff if (devlist != NULL) 5284162965Sariff free(devlist, M_TEMP); 5285162922Sariff 5286162922Sariff if (devinfo == NULL) { 5287162922Sariff hdac_unlock(sc); 5288162922Sariff device_printf(sc->dev, "Audio Function Group not found!\n"); 5289163057Sariff hdac_release_resources(sc); 5290162922Sariff return; 5291162922Sariff } 5292162922Sariff 5293163057Sariff HDA_BOOTVERBOSE( 5294162922Sariff device_printf(sc->dev, 5295162922Sariff "HDA_DEBUG: Parsing AFG nid=%d cad=%d\n", 5296162922Sariff devinfo->nid, devinfo->codec->cad); 5297162922Sariff ); 5298162922Sariff hdac_audio_parse(devinfo); 5299163057Sariff HDA_BOOTVERBOSE( 5300162922Sariff device_printf(sc->dev, "HDA_DEBUG: Parsing Ctls...\n"); 5301162922Sariff ); 5302162922Sariff hdac_audio_ctl_parse(devinfo); 5303163057Sariff HDA_BOOTVERBOSE( 5304162922Sariff device_printf(sc->dev, "HDA_DEBUG: Parsing vendor patch...\n"); 5305162922Sariff ); 5306162922Sariff hdac_vendor_patch_parse(devinfo); 5307163057Sariff if (quirks_on != 0) 5308163057Sariff devinfo->function.audio.quirks |= quirks_on; 5309163057Sariff if (quirks_off != 0) 5310163057Sariff devinfo->function.audio.quirks &= ~quirks_off; 5311162922Sariff 5312162922Sariff /* XXX Disable all DIGITAL path. */ 5313162922Sariff for (i = devinfo->startnode; i < devinfo->endnode; i++) { 5314162922Sariff w = hdac_widget_get(devinfo, i); 5315162922Sariff if (w == NULL) 5316162922Sariff continue; 5317162922Sariff if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) { 5318162922Sariff w->enable = 0; 5319162922Sariff continue; 5320162922Sariff } 5321162922Sariff /* XXX Disable useless pin ? */ 5322162922Sariff if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX && 5323162922Sariff (w->wclass.pin.config & 5324162922Sariff HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) == 5325162922Sariff HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE) 5326162922Sariff w->enable = 0; 5327162922Sariff } 5328162922Sariff i = 0; 5329162922Sariff while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 5330162922Sariff if (ctl->widget == NULL) 5331162922Sariff continue; 5332162922Sariff w = ctl->widget; 5333162922Sariff if (w->enable == 0) 5334162922Sariff ctl->enable = 0; 5335162922Sariff if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) 5336162922Sariff ctl->enable = 0; 5337162922Sariff w = ctl->childwidget; 5338162922Sariff if (w == NULL) 5339162922Sariff continue; 5340162922Sariff if (w->enable == 0 || 5341162922Sariff HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) 5342162922Sariff ctl->enable = 0; 5343162922Sariff } 5344162922Sariff 5345163057Sariff HDA_BOOTVERBOSE( 5346162922Sariff device_printf(sc->dev, "HDA_DEBUG: Building AFG tree...\n"); 5347162922Sariff ); 5348162922Sariff hdac_audio_build_tree(devinfo); 5349162922Sariff 5350163057Sariff HDA_BOOTVERBOSE( 5351162922Sariff device_printf(sc->dev, "HDA_DEBUG: AFG commit...\n"); 5352162922Sariff ); 5353162922Sariff hdac_audio_commit(devinfo, HDA_COMMIT_ALL); 5354163057Sariff HDA_BOOTVERBOSE( 5355162922Sariff device_printf(sc->dev, "HDA_DEBUG: Ctls commit...\n"); 5356162922Sariff ); 5357162922Sariff hdac_audio_ctl_commit(devinfo); 5358162922Sariff 5359163057Sariff HDA_BOOTVERBOSE( 5360162922Sariff device_printf(sc->dev, "HDA_DEBUG: PCMDIR_PLAY setup...\n"); 5361162922Sariff ); 5362162922Sariff pcnt = hdac_pcmchannel_setup(devinfo, PCMDIR_PLAY); 5363163057Sariff HDA_BOOTVERBOSE( 5364162922Sariff device_printf(sc->dev, "HDA_DEBUG: PCMDIR_REC setup...\n"); 5365162922Sariff ); 5366162922Sariff rcnt = hdac_pcmchannel_setup(devinfo, PCMDIR_REC); 5367162922Sariff 5368162922Sariff hdac_unlock(sc); 5369163057Sariff HDA_BOOTVERBOSE( 5370162922Sariff device_printf(sc->dev, 5371162922Sariff "HDA_DEBUG: OSS mixer initialization...\n"); 5372162922Sariff ); 5373163057Sariff 5374163057Sariff /* 5375163057Sariff * There is no point of return after this. If the driver failed, 5376163057Sariff * so be it. Let the detach procedure do all the cleanup. 5377163057Sariff */ 5378163057Sariff if (mixer_init(sc->dev, &hdac_audio_ctl_ossmixer_class, devinfo) != 0) 5379162922Sariff device_printf(sc->dev, "Can't register mixer\n"); 5380162922Sariff 5381162922Sariff if (pcnt > 0) 5382162922Sariff pcnt = 1; 5383162922Sariff if (rcnt > 0) 5384162922Sariff rcnt = 1; 5385162922Sariff 5386163057Sariff HDA_BOOTVERBOSE( 5387162922Sariff device_printf(sc->dev, 5388162922Sariff "HDA_DEBUG: Registering PCM channels...\n"); 5389162922Sariff ); 5390163057Sariff if (pcm_register(sc->dev, devinfo, pcnt, rcnt) != 0) 5391162922Sariff device_printf(sc->dev, "Can't register PCM\n"); 5392162922Sariff 5393162922Sariff sc->registered++; 5394162922Sariff 5395162922Sariff for (i = 0; i < pcnt; i++) 5396162922Sariff pcm_addchan(sc->dev, PCMDIR_PLAY, &hdac_channel_class, devinfo); 5397162922Sariff for (i = 0; i < rcnt; i++) 5398162922Sariff pcm_addchan(sc->dev, PCMDIR_REC, &hdac_channel_class, devinfo); 5399162922Sariff 5400164614Sariff#ifdef SND_DYNSYSCTL 5401164614Sariff SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev), 5402164614Sariff SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO, 5403164614Sariff "polling", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev), 5404164614Sariff sysctl_hdac_polling, "I", "Enable polling mode"); 5405164614Sariff#endif 5406164614Sariff 5407162922Sariff snprintf(status, SND_STATUSLEN, "at memory 0x%lx irq %ld %s [%s]", 5408164614Sariff rman_get_start(sc->mem.mem_res), rman_get_start(sc->irq.irq_res), 5409164614Sariff PCM_KLDSTRING(snd_hda), HDA_DRV_TEST_REV); 5410162922Sariff pcm_setstatus(sc->dev, status); 5411162922Sariff device_printf(sc->dev, "<HDA Codec: %s>\n", hdac_codec_name(devinfo)); 5412163057Sariff HDA_BOOTVERBOSE( 5413163057Sariff device_printf(sc->dev, "<HDA Codec ID: 0x%08x>\n", 5414163057Sariff hdac_codec_id(devinfo)); 5415163057Sariff ); 5416164614Sariff device_printf(sc->dev, "<HDA Driver Revision: %s>\n", 5417164614Sariff HDA_DRV_TEST_REV); 5418162922Sariff 5419163057Sariff HDA_BOOTVERBOSE( 5420162922Sariff if (devinfo->function.audio.quirks != 0) { 5421162922Sariff device_printf(sc->dev, "\n"); 5422163057Sariff device_printf(sc->dev, "HDA config/quirks:"); 5423163057Sariff for (i = 0; i < HDAC_QUIRKS_TAB_LEN; i++) { 5424163057Sariff if (devinfo->function.audio.quirks & 5425163057Sariff hdac_quirks_tab[i].value) 5426163057Sariff printf(" %s", hdac_quirks_tab[i].key); 5427163057Sariff } 5428162922Sariff printf("\n"); 5429162922Sariff } 5430162922Sariff device_printf(sc->dev, "\n"); 5431162922Sariff device_printf(sc->dev, "+-------------------+\n"); 5432162922Sariff device_printf(sc->dev, "| DUMPING HDA NODES |\n"); 5433162922Sariff device_printf(sc->dev, "+-------------------+\n"); 5434162922Sariff hdac_dump_nodes(devinfo); 5435162922Sariff device_printf(sc->dev, "\n"); 5436162922Sariff device_printf(sc->dev, "+------------------------+\n"); 5437162922Sariff device_printf(sc->dev, "| DUMPING HDA AMPLIFIERS |\n"); 5438162922Sariff device_printf(sc->dev, "+------------------------+\n"); 5439162922Sariff device_printf(sc->dev, "\n"); 5440162922Sariff i = 0; 5441162922Sariff while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { 5442162922Sariff device_printf(sc->dev, "%3d: nid=%d", i, 5443162922Sariff (ctl->widget != NULL) ? ctl->widget->nid : -1); 5444162922Sariff if (ctl->childwidget != NULL) 5445162922Sariff printf(" cnid=%d", ctl->childwidget->nid); 5446162922Sariff printf(" dir=0x%x index=%d " 5447162922Sariff "ossmask=0x%08x ossdev=%d%s\n", 5448162922Sariff ctl->dir, ctl->index, 5449162922Sariff ctl->ossmask, ctl->ossdev, 5450162922Sariff (ctl->enable == 0) ? " [DISABLED]" : ""); 5451162922Sariff } 5452162922Sariff device_printf(sc->dev, "\n"); 5453162922Sariff device_printf(sc->dev, "+-----------------------------------+\n"); 5454162922Sariff device_printf(sc->dev, "| DUMPING HDA AUDIO/VOLUME CONTROLS |\n"); 5455162922Sariff device_printf(sc->dev, "+-----------------------------------+\n"); 5456162922Sariff hdac_dump_ctls(devinfo, "Master Volume (OSS: vol)", SOUND_MASK_VOLUME); 5457162922Sariff hdac_dump_ctls(devinfo, "PCM Volume (OSS: pcm)", SOUND_MASK_PCM); 5458162922Sariff hdac_dump_ctls(devinfo, "CD Volume (OSS: cd)", SOUND_MASK_CD); 5459162922Sariff hdac_dump_ctls(devinfo, "Microphone Volume (OSS: mic)", SOUND_MASK_MIC); 5460162922Sariff hdac_dump_ctls(devinfo, "Line-in Volume (OSS: line)", SOUND_MASK_LINE); 5461162922Sariff hdac_dump_ctls(devinfo, "Recording Level (OSS: rec)", SOUND_MASK_RECLEV); 5462162922Sariff hdac_dump_ctls(devinfo, "Speaker/Beep (OSS: speaker)", SOUND_MASK_SPEAKER); 5463162922Sariff hdac_dump_ctls(devinfo, NULL, 0); 5464162922Sariff hdac_dump_dac(devinfo); 5465162922Sariff hdac_dump_adc(devinfo); 5466162922Sariff device_printf(sc->dev, "\n"); 5467162922Sariff device_printf(sc->dev, "+--------------------------------------+\n"); 5468162922Sariff device_printf(sc->dev, "| DUMPING PCM Playback/Record Channels |\n"); 5469162922Sariff device_printf(sc->dev, "+--------------------------------------+\n"); 5470162922Sariff hdac_dump_pcmchannels(sc, pcnt, rcnt); 5471162922Sariff ); 5472164614Sariff 5473164614Sariff if (sc->polling != 0) { 5474164614Sariff hdac_lock(sc); 5475164614Sariff callout_reset(&sc->poll_hdac, 1, hdac_poll_callback, sc); 5476164614Sariff hdac_unlock(sc); 5477164614Sariff } 5478162922Sariff} 5479162922Sariff 5480162922Sariff/**************************************************************************** 5481162922Sariff * int hdac_detach(device_t) 5482162922Sariff * 5483162922Sariff * Detach and free up resources utilized by the hdac device. 5484162922Sariff ****************************************************************************/ 5485162922Sariffstatic int 5486162922Sariffhdac_detach(device_t dev) 5487162922Sariff{ 5488162922Sariff struct hdac_softc *sc = NULL; 5489162922Sariff struct hdac_devinfo *devinfo = NULL; 5490163057Sariff int err; 5491162922Sariff 5492162922Sariff devinfo = (struct hdac_devinfo *)pcm_getdevinfo(dev); 5493162922Sariff if (devinfo != NULL && devinfo->codec != NULL) 5494162922Sariff sc = devinfo->codec->sc; 5495162922Sariff if (sc == NULL) 5496163057Sariff return (0); 5497162922Sariff 5498162922Sariff if (sc->registered > 0) { 5499163057Sariff err = pcm_unregister(dev); 5500163057Sariff if (err != 0) 5501163057Sariff return (err); 5502162922Sariff } 5503162922Sariff 5504163057Sariff hdac_release_resources(sc); 5505162922Sariff 5506162922Sariff return (0); 5507162922Sariff} 5508162922Sariff 5509162922Sariffstatic device_method_t hdac_methods[] = { 5510162922Sariff /* device interface */ 5511162922Sariff DEVMETHOD(device_probe, hdac_probe), 5512162922Sariff DEVMETHOD(device_attach, hdac_attach), 5513162922Sariff DEVMETHOD(device_detach, hdac_detach), 5514162922Sariff { 0, 0 } 5515162922Sariff}; 5516162922Sariff 5517162922Sariffstatic driver_t hdac_driver = { 5518162922Sariff "pcm", 5519162922Sariff hdac_methods, 5520162922Sariff PCM_SOFTC_SIZE, 5521162922Sariff}; 5522162922Sariff 5523162922SariffDRIVER_MODULE(snd_hda, pci, hdac_driver, pcm_devclass, 0, 0); 5524162922SariffMODULE_DEPEND(snd_hda, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 5525162922SariffMODULE_VERSION(snd_hda, 1); 5526