diff options
author | ariff <ariff@FreeBSD.org> | 2007-05-05 09:17:36 +0000 |
---|---|---|
committer | ariff <ariff@FreeBSD.org> | 2007-05-05 09:17:36 +0000 |
commit | f4b77f9353a9599ccde909b9f397d705e7d0b9b7 (patch) | |
tree | b880db2ce94d3b9b78cfe967dd7771f97521d5a1 /sys/dev/sound/pci | |
parent | a037728652f99e0b41bdb6131e00446ba7a8f5ec (diff) | |
download | FreeBSD-src-f4b77f9353a9599ccde909b9f397d705e7d0b9b7.zip FreeBSD-src-f4b77f9353a9599ccde909b9f397d705e7d0b9b7.tar.gz |
Miscellaneous changes and fix:
- Remove explicit call to pmap_change_attr(), since we now have proper
and functional definition of BUS_DMA_NOCACHE.
- Enable PCI(e) bus snooping for non i386/amd64 as an alternative for
uncacheable DMA.
- Codecs changes:
* Analag Device -> Analog Devices, AD1988.
* New codec: VIA VT1708 and VT1709, Realtek ALC262, ALC861-VD and
ALC885.
* Various fixups for Conexant Waikiki, fix recording (read: microphone)
on various Analog Devices codecs due to vendor BIOS mess, various
quirks for several ASUS laptops/boards.
- Fix connection list handling, closely following the specification to
handle range of nids.
- Basic Jack sense polling infrastructure for possible hardwares with
broken unsolicited response interrupt.
Ideas/Submitted/Tested by: Andriy Gapon <avg@icyb.net.ua>,
#freebsd-azalia, many.
Diffstat (limited to 'sys/dev/sound/pci')
-rw-r--r-- | sys/dev/sound/pci/hda/hdac.c | 1304 | ||||
-rw-r--r-- | sys/dev/sound/pci/hda/hdac_private.h | 7 |
2 files changed, 999 insertions, 312 deletions
diff --git a/sys/dev/sound/pci/hda/hdac.c b/sys/dev/sound/pci/hda/hdac.c index 7b50bd6..8b44240 100644 --- a/sys/dev/sound/pci/hda/hdac.c +++ b/sys/dev/sound/pci/hda/hdac.c @@ -80,41 +80,15 @@ #include "mixer_if.h" -/* - * XXX PAT superhero, until we have true support for BUS_DMA_NOCACHE. - * Blindly assume that pmap_change_attr() exist if PAT_UNCACHEABLE - * is defined. If not, fetch it from our cute little-pmap. - */ -#if defined(__i386__) || defined(__amd64__) -#include <machine/specialreg.h> -#ifndef PAT_UNCACHEABLE -#include <dev/sound/pci/hda/lpmap.c> -#endif -#endif - -#define HDAC_DMA_UNCACHEABLE 0 -#define HDAC_DMA_WRITEBACK 1 - -#define HDA_DRV_TEST_REV "20070320_0043" +#define HDA_DRV_TEST_REV "20070505_0044" #define HDA_WIDGET_PARSER_REV 1 SND_DECLARE_FILE("$FreeBSD$"); -#undef HDA_DEBUG_ENABLED -#define HDA_DEBUG_ENABLED 1 - -#ifdef HDA_DEBUG_ENABLED -#define HDA_DEBUG(stmt) do { \ - stmt \ -} while(0) -#else -#define HDA_DEBUG(stmt) -#endif - -#define HDA_BOOTVERBOSE(stmt) do { \ - if (bootverbose) { \ - stmt \ - } \ +#define HDA_BOOTVERBOSE(stmt) do { \ + if (bootverbose != 0 || snd_verbose > 3) { \ + stmt \ + } \ } while(0) #if 1 @@ -137,6 +111,9 @@ SND_DECLARE_FILE("$FreeBSD$"); #define HDA_MATCH_ALL 0xffffffff #define HDAC_INVALID 0xffffffff +/* Default controller / jack sense poll: 250ms */ +#define HDAC_POLL_INTERVAL max(hz >> 2, 1) + #define HDA_MODEL_CONSTRUCT(vendor, model) \ (((uint32_t)(model) << 16) | ((vendor##_VENDORID) & 0xffff)) @@ -188,6 +165,8 @@ SND_DECLARE_FILE("$FreeBSD$"); #define HP_NX6310_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x30aa) #define HP_NX6325_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x30b0) #define HP_XW4300_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x3013) +#define HP_3010_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x3010) +#define HP_DV5000_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0x30a5) #define HP_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(HP, 0xffff) /* What is wrong with XN 2563 anyway? (Got the picture ?) */ #define HP_NX6325_SUBVENDORX 0x103c30b0 @@ -196,6 +175,8 @@ SND_DECLARE_FILE("$FreeBSD$"); #define DELL_VENDORID 0x1028 #define DELL_D820_SUBVENDOR HDA_MODEL_CONSTRUCT(DELL, 0x01cc) #define DELL_I1300_SUBVENDOR HDA_MODEL_CONSTRUCT(DELL, 0x01c9) +#define DELL_XPSM1210_SUBVENDOR HDA_MODEL_CONSTRUCT(DELL, 0x01d7) +#define DELL_OPLX745_SUBVENDOR HDA_MODEL_CONSTRUCT(DELL, 0x01da) #define DELL_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(DELL, 0xffff) /* Clevo */ @@ -206,6 +187,7 @@ SND_DECLARE_FILE("$FreeBSD$"); /* Acer */ #define ACER_VENDORID 0x1025 #define ACER_A5050_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0x010f) +#define ACER_3681WXM_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0x0110) #define ACER_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0xffff) /* Asus */ @@ -217,6 +199,10 @@ SND_DECLARE_FILE("$FreeBSD$"); #define ASUS_A7M_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1323) #define ASUS_A7T_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x13c2) #define ASUS_W6F_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1263) +#define ASUS_W2J_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1971) +#define ASUS_F3JC_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1338) +#define ASUS_M2N_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x8234) +#define ASUS_M2NPVMX_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x81cb) #define ASUS_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0xffff) /* IBM / Lenovo */ @@ -266,6 +252,11 @@ SND_DECLARE_FILE("$FreeBSD$"); #define MSI_MS1034_SUBVENDOR HDA_MODEL_CONSTRUCT(MSI, 0x0349) #define MSI_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(MSI, 0xffff) +/* Uniwill ? */ +#define UNIWILL_VENDORID 0x1584 +#define UNIWILL_9075_SUBVENDOR HDA_MODEL_CONSTRUCT(UNIWILL, 0x9075) + + /* Misc constants.. */ #define HDA_AMP_MUTE_DEFAULT (0xffffffff) #define HDA_AMP_MUTE_NONE (0) @@ -280,21 +271,48 @@ SND_DECLARE_FILE("$FreeBSD$"); #define HDA_ADC_PATH (1 << 1) #define HDA_ADC_RECSEL (1 << 2) +#define HDA_DAC_LOCKED (1 << 3) +#define HDA_ADC_LOCKED (1 << 4) + #define HDA_CTL_OUT (1 << 0) #define HDA_CTL_IN (1 << 1) #define HDA_CTL_BOTH (HDA_CTL_IN | HDA_CTL_OUT) -#define HDA_GPIO_MAX 15 -/* 0 - 14 = GPIO */ +#define HDA_GPIO_MAX 8 +/* 0 - 7 = GPIO , 8 = Flush */ #define HDA_QUIRK_GPIO0 (1 << 0) #define HDA_QUIRK_GPIO1 (1 << 1) #define HDA_QUIRK_GPIO2 (1 << 2) -#define HDA_QUIRK_GPIOFLUSH (1 << 15) -#define HDA_QUIRK_SOFTPCMVOL (1 << 16) -#define HDA_QUIRK_FIXEDRATE (1 << 17) -#define HDA_QUIRK_FORCESTEREO (1 << 18) -#define HDA_QUIRK_EAPDINV (1 << 19) -#define HDA_QUIRK_VREF (1 << 20) +#define HDA_QUIRK_GPIO3 (1 << 3) +#define HDA_QUIRK_GPIO4 (1 << 4) +#define HDA_QUIRK_GPIO5 (1 << 5) +#define HDA_QUIRK_GPIO6 (1 << 6) +#define HDA_QUIRK_GPIO7 (1 << 7) +#define HDA_QUIRK_GPIOFLUSH (1 << 8) + +/* 9 - 25 = anything else */ +#define HDA_QUIRK_SOFTPCMVOL (1 << 9) +#define HDA_QUIRK_FIXEDRATE (1 << 10) +#define HDA_QUIRK_FORCESTEREO (1 << 11) +#define HDA_QUIRK_EAPDINV (1 << 12) +#define HDA_QUIRK_DMAPOS (1 << 13) + +/* 26 - 31 = vrefs */ +#define HDA_QUIRK_IVREF50 (1 << 26) +#define HDA_QUIRK_IVREF80 (1 << 27) +#define HDA_QUIRK_IVREF100 (1 << 28) +#define HDA_QUIRK_OVREF50 (1 << 29) +#define HDA_QUIRK_OVREF80 (1 << 30) +#define HDA_QUIRK_OVREF100 (1 << 31) + +#define HDA_QUIRK_IVREF (HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF80 | \ + HDA_QUIRK_IVREF100) +#define HDA_QUIRK_OVREF (HDA_QUIRK_OVREF50 | HDA_QUIRK_OVREF80 | \ + HDA_QUIRK_OVREF100) +#define HDA_QUIRK_VREF (HDA_QUIRK_IVREF | HDA_QUIRK_OVREF) + +#define SOUND_MASK_SKIP (1 << 30) +#define SOUND_MASK_DISABLE (1 << 31) static const struct { char *key; @@ -303,11 +321,25 @@ static const struct { { "gpio0", HDA_QUIRK_GPIO0 }, { "gpio1", HDA_QUIRK_GPIO1 }, { "gpio2", HDA_QUIRK_GPIO2 }, + { "gpio3", HDA_QUIRK_GPIO3 }, + { "gpio4", HDA_QUIRK_GPIO4 }, + { "gpio5", HDA_QUIRK_GPIO5 }, + { "gpio6", HDA_QUIRK_GPIO6 }, + { "gpio7", HDA_QUIRK_GPIO7 }, { "gpioflush", HDA_QUIRK_GPIOFLUSH }, { "softpcmvol", HDA_QUIRK_SOFTPCMVOL }, { "fixedrate", HDA_QUIRK_FIXEDRATE }, { "forcestereo", HDA_QUIRK_FORCESTEREO }, { "eapdinv", HDA_QUIRK_EAPDINV }, + { "dmapos", HDA_QUIRK_DMAPOS }, + { "ivref50", HDA_QUIRK_IVREF50 }, + { "ivref80", HDA_QUIRK_IVREF80 }, + { "ivref100", HDA_QUIRK_IVREF100 }, + { "ovref50", HDA_QUIRK_OVREF50 }, + { "ovref80", HDA_QUIRK_OVREF80 }, + { "ovref100", HDA_QUIRK_OVREF100 }, + { "ivref", HDA_QUIRK_IVREF }, + { "ovref", HDA_QUIRK_OVREF }, { "vref", HDA_QUIRK_VREF }, }; #define HDAC_QUIRKS_TAB_LEN \ @@ -317,7 +349,7 @@ static const struct { #define HDA_BDL_MAX 256 #define HDA_BDL_DEFAULT HDA_BDL_MIN -#define HDA_BLK_MIN 128 +#define HDA_BLK_MIN HDAC_DMA_ALIGNMENT #define HDA_BLK_ALIGN (~(HDA_BLK_MIN - 1)) #define HDA_BUFSZ_MIN 4096 @@ -326,7 +358,8 @@ static const struct { #define HDA_PARSE_MAXDEPTH 10 -#define HDAC_UNSOLTAG_EVENT_HP 0x00 +#define HDAC_UNSOLTAG_EVENT_HP 0x00 +#define HDAC_UNSOLTAG_EVENT_TEST 0x01 MALLOC_DEFINE(M_HDAC, "hdac", "High Definition Audio Controller"); @@ -371,6 +404,19 @@ static const struct { #define HDAC_DEVICES_LEN (sizeof(hdac_devices) / sizeof(hdac_devices[0])) static const struct { + uint16_t vendor; + uint8_t reg; + uint8_t mask; + uint8_t enable; +} hdac_pcie_snoop[] = { + { INTEL_VENDORID, 0x00, 0x00, 0x00 }, + { ATI_VENDORID, 0x42, 0xf8, 0x02 }, + { NVIDIA_VENDORID, 0x4e, 0xf0, 0x0f }, +}; +#define HDAC_PCIESNOOP_LEN \ + (sizeof(hdac_pcie_snoop) / sizeof(hdac_pcie_snoop[0])) + +static const struct { uint32_t rate; int valid; uint16_t base; @@ -422,19 +468,23 @@ static const struct { /* Realtek */ #define REALTEK_VENDORID 0x10ec #define HDA_CODEC_ALC260 HDA_CODEC_CONSTRUCT(REALTEK, 0x0260) +#define HDA_CODEC_ALC262 HDA_CODEC_CONSTRUCT(REALTEK, 0x0262) #define HDA_CODEC_ALC861 HDA_CODEC_CONSTRUCT(REALTEK, 0x0861) +#define HDA_CODEC_ALC861VD HDA_CODEC_CONSTRUCT(REALTEK, 0x0862) #define HDA_CODEC_ALC880 HDA_CODEC_CONSTRUCT(REALTEK, 0x0880) #define HDA_CODEC_ALC882 HDA_CODEC_CONSTRUCT(REALTEK, 0x0882) #define HDA_CODEC_ALC883 HDA_CODEC_CONSTRUCT(REALTEK, 0x0883) +#define HDA_CODEC_ALC885 HDA_CODEC_CONSTRUCT(REALTEK, 0x0885) #define HDA_CODEC_ALC888 HDA_CODEC_CONSTRUCT(REALTEK, 0x0888) #define HDA_CODEC_ALCXXXX HDA_CODEC_CONSTRUCT(REALTEK, 0xffff) -/* Analog Device */ -#define ANALOGDEVICE_VENDORID 0x11d4 -#define HDA_CODEC_AD1981HD HDA_CODEC_CONSTRUCT(ANALOGDEVICE, 0x1981) -#define HDA_CODEC_AD1983 HDA_CODEC_CONSTRUCT(ANALOGDEVICE, 0x1983) -#define HDA_CODEC_AD1986A HDA_CODEC_CONSTRUCT(ANALOGDEVICE, 0x1986) -#define HDA_CODEC_ADXXXX HDA_CODEC_CONSTRUCT(ANALOGDEVICE, 0xffff) +/* Analog Devices */ +#define ANALOGDEVICES_VENDORID 0x11d4 +#define HDA_CODEC_AD1981HD HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1981) +#define HDA_CODEC_AD1983 HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1983) +#define HDA_CODEC_AD1986A HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1986) +#define HDA_CODEC_AD1988 HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1988) +#define HDA_CODEC_ADXXXX HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0xffff) /* CMedia */ #define CMEDIA_VENDORID 0x434d @@ -466,6 +516,21 @@ static const struct { #define HDA_CODEC_CXWAIKIKI HDA_CODEC_CONSTRUCT(CONEXANT, 0x5047) #define HDA_CODEC_CXXXXX HDA_CODEC_CONSTRUCT(CONEXANT, 0xffff) +/* VIA */ +#define HDA_CODEC_VT1708_8 HDA_CODEC_CONSTRUCT(VIA, 0x1708) +#define HDA_CODEC_VT1708_9 HDA_CODEC_CONSTRUCT(VIA, 0x1709) +#define HDA_CODEC_VT1708_A HDA_CODEC_CONSTRUCT(VIA, 0x170a) +#define HDA_CODEC_VT1708_B HDA_CODEC_CONSTRUCT(VIA, 0x170b) +#define HDA_CODEC_VT1709_0 HDA_CODEC_CONSTRUCT(VIA, 0xe710) +#define HDA_CODEC_VT1709_1 HDA_CODEC_CONSTRUCT(VIA, 0xe711) +#define HDA_CODEC_VT1709_2 HDA_CODEC_CONSTRUCT(VIA, 0xe712) +#define HDA_CODEC_VT1709_3 HDA_CODEC_CONSTRUCT(VIA, 0xe713) +#define HDA_CODEC_VT1709_4 HDA_CODEC_CONSTRUCT(VIA, 0xe714) +#define HDA_CODEC_VT1709_5 HDA_CODEC_CONSTRUCT(VIA, 0xe715) +#define HDA_CODEC_VT1709_6 HDA_CODEC_CONSTRUCT(VIA, 0xe716) +#define HDA_CODEC_VT1709_7 HDA_CODEC_CONSTRUCT(VIA, 0xe717) +#define HDA_CODEC_VTXXXX HDA_CODEC_CONSTRUCT(VIA, 0xffff) + /* Codecs */ static const struct { @@ -473,14 +538,18 @@ static const struct { char *name; } hdac_codecs[] = { { HDA_CODEC_ALC260, "Realtek ALC260" }, + { HDA_CODEC_ALC262, "Realtek ALC262" }, { HDA_CODEC_ALC861, "Realtek ALC861" }, + { HDA_CODEC_ALC861VD, "Realtek ALC861-VD" }, { HDA_CODEC_ALC880, "Realtek ALC880" }, { HDA_CODEC_ALC882, "Realtek ALC882" }, { HDA_CODEC_ALC883, "Realtek ALC883" }, + { HDA_CODEC_ALC885, "Realtek ALC885" }, { HDA_CODEC_ALC888, "Realtek ALC888" }, - { HDA_CODEC_AD1981HD, "Analog Device AD1981HD" }, - { HDA_CODEC_AD1983, "Analog Device AD1983" }, - { HDA_CODEC_AD1986A, "Analog Device AD1986A" }, + { HDA_CODEC_AD1981HD, "Analog Devices AD1981HD" }, + { HDA_CODEC_AD1983, "Analog Devices AD1983" }, + { HDA_CODEC_AD1986A, "Analog Devices AD1986A" }, + { HDA_CODEC_AD1988, "Analog Devices AD1988" }, { HDA_CODEC_CMI9880, "CMedia CMI9880" }, { HDA_CODEC_STAC9221, "Sigmatel STAC9221" }, { HDA_CODEC_STAC9221D, "Sigmatel STAC9221D" }, @@ -490,18 +559,32 @@ static const struct { { HDA_CODEC_STAC9271D, "Sigmatel STAC9271D" }, { HDA_CODEC_CXVENICE, "Conexant Venice" }, { HDA_CODEC_CXWAIKIKI, "Conexant Waikiki" }, + { HDA_CODEC_VT1708_8, "VIA VT1708_8" }, + { HDA_CODEC_VT1708_9, "VIA VT1708_9" }, + { HDA_CODEC_VT1708_A, "VIA VT1708_A" }, + { HDA_CODEC_VT1708_B, "VIA VT1708_B" }, + { HDA_CODEC_VT1709_0, "VIA VT1709_0" }, + { HDA_CODEC_VT1709_1, "VIA VT1709_1" }, + { HDA_CODEC_VT1709_2, "VIA VT1709_2" }, + { HDA_CODEC_VT1709_3, "VIA VT1709_3" }, + { HDA_CODEC_VT1709_4, "VIA VT1709_4" }, + { HDA_CODEC_VT1709_5, "VIA VT1709_5" }, + { HDA_CODEC_VT1709_6, "VIA VT1709_6" }, + { HDA_CODEC_VT1709_7, "VIA VT1709_7" }, /* Unknown codec */ { HDA_CODEC_ALCXXXX, "Realtek (Unknown)" }, - { HDA_CODEC_ADXXXX, "Analog Device (Unknown)" }, + { HDA_CODEC_ADXXXX, "Analog Devices (Unknown)" }, { HDA_CODEC_CMIXXXX, "CMedia (Unknown)" }, { HDA_CODEC_STACXXXX, "Sigmatel (Unknown)" }, { HDA_CODEC_CXXXXX, "Conexant (Unknown)" }, + { HDA_CODEC_VTXXXX, "VIA (Unknown)" }, }; #define HDAC_CODECS_LEN (sizeof(hdac_codecs) / sizeof(hdac_codecs[0])) enum { HDAC_HP_SWITCH_CTL, - HDAC_HP_SWITCH_CTRL + HDAC_HP_SWITCH_CTRL, + HDAC_HP_SWITCH_DEBUG }; static const struct { @@ -509,52 +592,62 @@ static const struct { uint32_t id; int type; int inverted; + int polling; + int execsense; nid_t hpnid; nid_t spkrnid[8]; nid_t eapdnid; } hdac_hp_switch[] = { /* Specific OEM models */ - { HP_V3000_SUBVENDOR, HDA_CODEC_CXVENICE, HDAC_HP_SWITCH_CTL, 0, - 17, { 16, -1 }, 16 }, - { HP_NX7400_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 0, - 6, { 5, -1 }, 5 }, - { HP_NX6310_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 0, - 6, { 5, -1 }, 5 }, - { HP_NX6325_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 0, - 6, { 5, -1 }, 5 }, - { TOSHIBA_U200_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 0, - 6, { 5, -1 }, -1 }, - { DELL_D820_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL, 0, - 13, { 14, -1 }, -1 }, - { DELL_I1300_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL, 0, - 13, { 14, -1 }, -1 }, - { APPLE_INTEL_MAC, HDA_CODEC_STAC9221, HDAC_HP_SWITCH_CTRL, 0, - 10, { 13, -1 }, -1 }, - { LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A, HDAC_HP_SWITCH_CTL, 1, - 26, { 27, -1 }, -1 }, - { LG_LW20_SUBVENDOR, HDA_CODEC_ALC880, HDAC_HP_SWITCH_CTL, 0, - 27, { 20, -1 }, -1 }, - { ACER_A5050_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, 0, - 20, { 21, -1 }, -1 }, - { MSI_MS1034_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, 0, - 20, { 27, -1 }, -1 }, + { HP_V3000_SUBVENDOR, HDA_CODEC_CXVENICE, HDAC_HP_SWITCH_CTL, + 0, 0, -1, 17, { 16, -1 }, 16 }, + /* { HP_XW4300_SUBVENDOR, HDA_CODEC_ALC260, HDAC_HP_SWITCH_CTL, + 0, 0, -1, 21, { 16, 17, -1 }, -1 } */ + /*{ HP_3010_SUBVENDOR, HDA_CODEC_ALC260, HDAC_HP_SWITCH_DEBUG, + 0, 1, 0, 16, { 15, 18, 19, 20, 21, -1 }, -1 },*/ + { HP_NX7400_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, + 0, 0, -1, 6, { 5, -1 }, 5 }, + { HP_NX6310_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, + 0, 0, -1, 6, { 5, -1 }, 5 }, + { HP_NX6325_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, + 0, 0, -1, 6, { 5, -1 }, 5 }, + { TOSHIBA_U200_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, + 0, 0, -1, 6, { 5, -1 }, -1 }, + { DELL_D820_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL, + 0, 0, -1, 13, { 14, -1 }, -1 }, + { DELL_I1300_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL, + 0, 0, -1, 13, { 14, -1 }, -1 }, + { DELL_OPLX745_SUBVENDOR, HDA_CODEC_AD1983, HDAC_HP_SWITCH_CTL, + 0, 0, -1, 6, { 5, 7, -1 }, -1 }, + { APPLE_INTEL_MAC, HDA_CODEC_STAC9221, HDAC_HP_SWITCH_CTRL, + 0, 0, -1, 10, { 13, -1 }, -1 }, + { LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A, HDAC_HP_SWITCH_CTL, + 1, 0, -1, 26, { 27, -1 }, -1 }, + { LG_LW20_SUBVENDOR, HDA_CODEC_ALC880, HDAC_HP_SWITCH_CTL, + 0, 0, -1, 27, { 20, -1 }, -1 }, + { ACER_A5050_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, + 0, 0, -1, 20, { 21, -1 }, -1 }, + { ACER_3681WXM_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, + 0, 0, -1, 20, { 21, -1 }, -1 }, + { MSI_MS1034_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, + 0, 0, -1, 20, { 27, -1 }, -1 }, /* * All models that at least come from the same vendor with * simmilar codec. */ - { HP_ALL_SUBVENDOR, HDA_CODEC_CXVENICE, HDAC_HP_SWITCH_CTL, 0, - 17, { 16, -1 }, 16 }, - { HP_ALL_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 0, - 6, { 5, -1 }, 5 }, - { TOSHIBA_ALL_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 0, - 6, { 5, -1 }, -1 }, - { DELL_ALL_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL, 0, - 13, { 14, -1 }, -1 }, - { LENOVO_ALL_SUBVENDOR, HDA_CODEC_AD1986A, HDAC_HP_SWITCH_CTL, 1, - 26, { 27, -1 }, -1 }, + { HP_ALL_SUBVENDOR, HDA_CODEC_CXVENICE, HDAC_HP_SWITCH_CTL, + 0, 0, -1, 17, { 16, -1 }, 16 }, + { HP_ALL_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, + 0, 0, -1, 6, { 5, -1 }, 5 }, + { TOSHIBA_ALL_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, + 0, 0, -1, 6, { 5, -1 }, -1 }, + { DELL_ALL_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL, + 0, 0, -1, 13, { 14, -1 }, -1 }, + { LENOVO_ALL_SUBVENDOR, HDA_CODEC_AD1986A, HDAC_HP_SWITCH_CTL, + 1, 0, -1, 26, { 27, -1 }, -1 }, #if 0 - { ACER_ALL_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, 0, - 20, { 21, -1 }, -1 }, + { ACER_ALL_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, + 0, 0, -1, 20, { 21, -1 }, -1 }, #endif }; #define HDAC_HP_SWITCH_LEN \ @@ -582,7 +675,7 @@ static int hdac_get_capabilities(struct hdac_softc *); static void hdac_dma_cb(void *, bus_dma_segment_t *, int, int); static int hdac_dma_alloc(struct hdac_softc *, struct hdac_dma *, bus_size_t); -static void hdac_dma_free(struct hdac_dma *); +static void hdac_dma_free(struct hdac_softc *, struct hdac_dma *); static int hdac_mem_alloc(struct hdac_softc *); static void hdac_mem_free(struct hdac_softc *); static int hdac_irq_alloc(struct hdac_softc *); @@ -727,7 +820,7 @@ hdac_hp_switch_handler(struct hdac_devinfo *devinfo) struct hdac_softc *sc; struct hdac_widget *w; struct hdac_audio_ctl *ctl; - uint32_t id, res; + uint32_t val, id, res; int i = 0, j, forcemute; nid_t cad; @@ -756,6 +849,10 @@ hdac_hp_switch_handler(struct hdac_devinfo *devinfo) HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD) ? 0 : 1; } + if (hdac_hp_switch[i].execsense != -1) + hdac_command(sc, + HDA_CMD_SET_PIN_SENSE(cad, hdac_hp_switch[i].hpnid, + hdac_hp_switch[i].execsense), cad); res = hdac_command(sc, HDA_CMD_GET_PIN_SENSE(cad, hdac_hp_switch[i].hpnid), cad); HDA_BOOTVERBOSE( @@ -763,7 +860,7 @@ hdac_hp_switch_handler(struct hdac_devinfo *devinfo) "HDA_DEBUG: Pin sense: nid=%d res=0x%08x\n", hdac_hp_switch[i].hpnid, res); ); - res >>= 31; + res = HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT(res); res ^= hdac_hp_switch[i].inverted; switch (hdac_hp_switch[i].type) { @@ -771,23 +868,28 @@ hdac_hp_switch_handler(struct hdac_devinfo *devinfo) ctl = hdac_audio_ctl_amp_get(devinfo, hdac_hp_switch[i].hpnid, 0, 1); if (ctl != NULL) { - ctl->muted = (res != 0 && forcemute == 0) ? + val = (res != 0 && forcemute == 0) ? HDA_AMP_MUTE_NONE : HDA_AMP_MUTE_ALL; - hdac_audio_ctl_amp_set(ctl, - HDA_AMP_MUTE_DEFAULT, ctl->left, - ctl->right); - } - for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) { - ctl = hdac_audio_ctl_amp_get(devinfo, - hdac_hp_switch[i].spkrnid[j], 0, 1); - if (ctl != NULL) { - ctl->muted = (res != 0 || forcemute == 1) ? - HDA_AMP_MUTE_ALL : HDA_AMP_MUTE_NONE; + if (val != ctl->muted) { + ctl->muted = val; hdac_audio_ctl_amp_set(ctl, HDA_AMP_MUTE_DEFAULT, ctl->left, ctl->right); } } + for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) { + ctl = hdac_audio_ctl_amp_get(devinfo, + hdac_hp_switch[i].spkrnid[j], 0, 1); + if (ctl == NULL) + continue; + val = (res != 0 || forcemute == 1) ? + HDA_AMP_MUTE_ALL : HDA_AMP_MUTE_NONE; + if (val == ctl->muted) + continue; + ctl->muted = val; + hdac_audio_ctl_amp_set(ctl, HDA_AMP_MUTE_DEFAULT, + ctl->left, ctl->right); + } break; case HDAC_HP_SWITCH_CTRL: if (res != 0) { @@ -796,58 +898,93 @@ hdac_hp_switch_handler(struct hdac_devinfo *devinfo) if (w != NULL && w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) { if (forcemute == 0) - w->wclass.pin.ctrl |= + val = w->wclass.pin.ctrl | HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; else - w->wclass.pin.ctrl &= + val = w->wclass.pin.ctrl & ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; - hdac_command(sc, - HDA_CMD_SET_PIN_WIDGET_CTRL(cad, w->nid, - w->wclass.pin.ctrl), cad); + if (val != w->wclass.pin.ctrl) { + w->wclass.pin.ctrl = val; + hdac_command(sc, + HDA_CMD_SET_PIN_WIDGET_CTRL(cad, + w->nid, w->wclass.pin.ctrl), cad); + } } for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) { w = hdac_widget_get(devinfo, hdac_hp_switch[i].spkrnid[j]); - if (w != NULL && w->type == - HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) { - w->wclass.pin.ctrl &= - ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; - hdac_command(sc, - HDA_CMD_SET_PIN_WIDGET_CTRL(cad, - w->nid, - w->wclass.pin.ctrl), cad); - } + if (w == NULL || w->type != + HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) + continue; + val = w->wclass.pin.ctrl & + ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; + if (val == w->wclass.pin.ctrl) + continue; + w->wclass.pin.ctrl = val; + hdac_command(sc, HDA_CMD_SET_PIN_WIDGET_CTRL( + cad, w->nid, w->wclass.pin.ctrl), cad); } } else { /* HP out */ w = hdac_widget_get(devinfo, hdac_hp_switch[i].hpnid); if (w != NULL && w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) { - w->wclass.pin.ctrl &= + val = w->wclass.pin.ctrl & ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; - hdac_command(sc, - HDA_CMD_SET_PIN_WIDGET_CTRL(cad, w->nid, - w->wclass.pin.ctrl), cad); + if (val != w->wclass.pin.ctrl) { + w->wclass.pin.ctrl = val; + hdac_command(sc, + HDA_CMD_SET_PIN_WIDGET_CTRL(cad, + w->nid, w->wclass.pin.ctrl), cad); + } } for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) { w = hdac_widget_get(devinfo, hdac_hp_switch[i].spkrnid[j]); - if (w != NULL && w->type == - HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) { - if (forcemute == 0) - w->wclass.pin.ctrl |= - HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; - else - w->wclass.pin.ctrl &= - ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; - hdac_command(sc, - HDA_CMD_SET_PIN_WIDGET_CTRL(cad, - w->nid, - w->wclass.pin.ctrl), cad); - } + if (w == NULL || w->type != + HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) + continue; + if (forcemute == 0) + val = w->wclass.pin.ctrl | + HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; + else + val = w->wclass.pin.ctrl & + ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; + if (val == w->wclass.pin.ctrl) + continue; + w->wclass.pin.ctrl = val; + hdac_command(sc, HDA_CMD_SET_PIN_WIDGET_CTRL( + cad, w->nid, w->wclass.pin.ctrl), cad); } } break; + case HDAC_HP_SWITCH_DEBUG: + if (hdac_hp_switch[i].execsense != -1) + hdac_command(sc, + HDA_CMD_SET_PIN_SENSE(cad, hdac_hp_switch[i].hpnid, + hdac_hp_switch[i].execsense), cad); + res = hdac_command(sc, + HDA_CMD_GET_PIN_SENSE(cad, hdac_hp_switch[i].hpnid), cad); + device_printf(sc->dev, + "[ 0] HDA_DEBUG: Pin sense: nid=%d res=0x%08x\n", + hdac_hp_switch[i].hpnid, res); + for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) { + w = hdac_widget_get(devinfo, + hdac_hp_switch[i].spkrnid[j]); + if (w == NULL || w->type != + HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) + continue; + if (hdac_hp_switch[i].execsense != -1) + hdac_command(sc, + HDA_CMD_SET_PIN_SENSE(cad, w->nid, + hdac_hp_switch[i].execsense), cad); + res = hdac_command(sc, + HDA_CMD_GET_PIN_SENSE(cad, w->nid), cad); + device_printf(sc->dev, + "[%2d] HDA_DEBUG: Pin sense: nid=%d res=0x%08x\n", + j + 1, w->nid, res); + } + break; default: break; } @@ -891,6 +1028,9 @@ hdac_unsolicited_handler(struct hdac_codec *codec, uint32_t tag) case HDAC_UNSOLTAG_EVENT_HP: hdac_hp_switch_handler(devinfo); break; + case HDAC_UNSOLTAG_EVENT_TEST: + device_printf(sc->dev, "Unsol Test!\n"); + break; default: break; } @@ -1031,12 +1171,18 @@ hdac_reset(struct hdac_softc *sc) HDAC_WRITE_4(&sc->mem, HDAC_BSDCTL(sc, i), 0x0); /* - * Stop Control DMA engines + * Stop Control DMA engines. */ HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, 0x0); HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, 0x0); /* + * Reset DMA position buffer. + */ + HDAC_WRITE_4(&sc->mem, HDAC_DPIBLBASE, 0x0); + HDAC_WRITE_4(&sc->mem, HDAC_DPIBUBASE, 0x0); + + /* * Reset the controller. The reset must remain asserted for * a minimum of 100us. */ @@ -1157,22 +1303,6 @@ hdac_dma_cb(void *callback_arg, bus_dma_segment_t *segs, int nseg, int error) } } -static void -hdac_dma_attr(vm_offset_t va, vm_size_t size, int mode) -{ -#if defined(__i386__) || defined(__amd64__) - switch (mode) { - case HDAC_DMA_UNCACHEABLE: - pmap_change_attr(va, size, PAT_UNCACHEABLE); - break; - case HDAC_DMA_WRITEBACK: - pmap_change_attr(va, size, PAT_WRITE_BACK); - break; - default: - break; - } -#endif -} /**************************************************************************** * int hdac_dma_alloc @@ -1183,9 +1313,11 @@ hdac_dma_attr(vm_offset_t va, vm_size_t size, int mode) static int hdac_dma_alloc(struct hdac_softc *sc, struct hdac_dma *dma, bus_size_t size) { + bus_size_t roundsz; int result; int lowaddr; + roundsz = roundup2(size, HDAC_DMA_ALIGNMENT); lowaddr = (sc->support_64bit) ? BUS_SPACE_MAXADDR : BUS_SPACE_MAXADDR_32BIT; bzero(dma, sizeof(*dma)); @@ -1200,9 +1332,9 @@ hdac_dma_alloc(struct hdac_softc *sc, struct hdac_dma *dma, bus_size_t size) BUS_SPACE_MAXADDR, /* highaddr */ NULL, /* filtfunc */ NULL, /* fistfuncarg */ - size, /* maxsize */ + roundsz, /* maxsize */ 1, /* nsegments */ - size, /* maxsegsz */ + roundsz, /* maxsegsz */ 0, /* flags */ NULL, /* lockfunc */ NULL, /* lockfuncarg */ @@ -1217,19 +1349,21 @@ hdac_dma_alloc(struct hdac_softc *sc, struct hdac_dma *dma, bus_size_t size) * Allocate DMA memory */ result = bus_dmamem_alloc(dma->dma_tag, (void **)&dma->dma_vaddr, - BUS_DMA_NOWAIT | BUS_DMA_ZERO, &dma->dma_map); + BUS_DMA_NOWAIT | BUS_DMA_ZERO | + ((sc->nocache != 0) ? BUS_DMA_NOCACHE : 0), &dma->dma_map); if (result != 0) { device_printf(sc->dev, "%s: bus_dmamem_alloc failed (%x)\n", __func__, result); goto hdac_dma_alloc_fail; } + dma->dma_size = roundsz; + /* * Map the memory */ result = bus_dmamap_load(dma->dma_tag, dma->dma_map, - (void *)dma->dma_vaddr, size, hdac_dma_cb, (void *)dma, - BUS_DMA_NOWAIT); + (void *)dma->dma_vaddr, roundsz, hdac_dma_cb, (void *)dma, 0); if (result != 0 || dma->dma_paddr == 0) { if (result == 0) result = ENOMEM; @@ -1237,36 +1371,39 @@ hdac_dma_alloc(struct hdac_softc *sc, struct hdac_dma *dma, bus_size_t size) __func__, result); goto hdac_dma_alloc_fail; } - hdac_dma_attr((vm_offset_t)dma->dma_vaddr, size, HDAC_DMA_UNCACHEABLE); - dma->dma_size = size; + + HDA_BOOTVERBOSE( + device_printf(sc->dev, "%s: size=%ju -> roundsz=%ju\n", + __func__, (uintmax_t)size, (uintmax_t)roundsz); + ); return (0); + hdac_dma_alloc_fail: - hdac_dma_free(dma); + hdac_dma_free(sc, dma); return (result); } /**************************************************************************** - * void hdac_dma_free(struct hdac_dma *) + * void hdac_dma_free(struct hdac_softc *, struct hdac_dma *) * * Free a struct dhac_dma that has been previously allocated via the * hdac_dma_alloc function. ****************************************************************************/ static void -hdac_dma_free(struct hdac_dma *dma) +hdac_dma_free(struct hdac_softc *sc, struct hdac_dma *dma) { if (dma->dma_map != NULL) { +#if 0 /* Flush caches */ bus_dmamap_sync(dma->dma_tag, dma->dma_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); +#endif bus_dmamap_unload(dma->dma_tag, dma->dma_map); } if (dma->dma_vaddr != NULL) { - if (dma->dma_size > 0) - hdac_dma_attr((vm_offset_t)dma->dma_vaddr, - dma->dma_size, HDAC_DMA_WRITEBACK); bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map); dma->dma_vaddr = NULL; } @@ -1479,6 +1616,7 @@ hdac_rirb_init(struct hdac_softc *sc) #endif } +#if 0 /* * Make sure that the Host CPU cache doesn't contain any dirty * cache lines that falls in the rirb. If I understood correctly, it @@ -1487,6 +1625,7 @@ hdac_rirb_init(struct hdac_softc *sc) */ bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map, BUS_DMASYNC_PREREAD); +#endif } /**************************************************************************** @@ -1536,10 +1675,8 @@ hdac_scan_codecs(struct hdac_softc *sc) for (i = 0; i < HDAC_CODEC_MAX; i++) { if (HDAC_STATESTS_SDIWAKE(statests, i)) { /* We have found a codec. */ - hdac_unlock(sc); codec = (struct hdac_codec *)malloc(sizeof(*codec), M_HDAC, M_ZERO | M_NOWAIT); - hdac_lock(sc); if (codec == NULL) { device_printf(sc->dev, "Unable to allocate memory for codec\n"); @@ -1637,10 +1774,8 @@ hdac_probe_function(struct hdac_codec *codec, nid_t nid) if (fctgrptype != HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) return (NULL); - hdac_unlock(sc); devinfo = (struct hdac_devinfo *)malloc(sizeof(*devinfo), M_HDAC, M_NOWAIT | M_ZERO); - hdac_lock(sc); if (devinfo == NULL) { device_printf(sc->dev, "%s: Unable to allocate ivar\n", __func__); @@ -1669,53 +1804,89 @@ hdac_widget_connection_parse(struct hdac_widget *w) { struct hdac_softc *sc = w->devinfo->codec->sc; uint32_t res; - int i, j, max, found, entnum, cnid; + int i, j, max, ents, entnum; nid_t cad = w->devinfo->codec->cad; nid_t nid = w->nid; + nid_t cnid, addcnid, prevcnid; + + w->nconns = 0; res = hdac_command(sc, HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_CONN_LIST_LENGTH), cad); - w->nconns = HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH(res); + ents = HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH(res); - if (w->nconns < 1) + if (ents < 1) return; entnum = HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM(res) ? 2 : 4; - res = 0; - i = 0; - found = 0; max = (sizeof(w->conns) / sizeof(w->conns[0])) - 1; + prevcnid = 0; - while (i < w->nconns) { +#define CONN_RMASK(e) (1 << ((32 / (e)) - 1)) +#define CONN_NMASK(e) (CONN_RMASK(e) - 1) +#define CONN_RESVAL(r, e, n) ((r) >> ((32 / (e)) * (n))) +#define CONN_RANGE(r, e, n) (CONN_RESVAL(r, e, n) & CONN_RMASK(e)) +#define CONN_CNID(r, e, n) (CONN_RESVAL(r, e, n) & CONN_NMASK(e)) + + for (i = 0; i < ents; i += entnum) { res = hdac_command(sc, HDA_CMD_GET_CONN_LIST_ENTRY(cad, nid, i), cad); for (j = 0; j < entnum; j++) { - cnid = res; - cnid >>= (32 / entnum) * j; - cnid &= (1 << (32 / entnum)) - 1; - if (cnid == 0) - continue; - if (found > max) { + cnid = CONN_CNID(res, entnum, j); + if (cnid == 0) { + if (w->nconns < ents) + device_printf(sc->dev, + "%s: nid=%d WARNING: zero cnid " + "entnum=%d j=%d index=%d " + "entries=%d found=%d res=0x%08x\n", + __func__, nid, entnum, j, i, + ents, w->nconns, res); + else + goto getconns_out; + } + if (cnid < w->devinfo->startnode || + cnid >= w->devinfo->endnode) { + HDA_BOOTVERBOSE( + device_printf(sc->dev, + "%s: GHOST: nid=%d j=%d " + "entnum=%d index=%d res=0x%08x\n", + __func__, nid, j, entnum, i, res); + ); + } + if (CONN_RANGE(res, entnum, j) == 0) + addcnid = cnid; + else if (prevcnid == 0 || prevcnid >= cnid) { device_printf(sc->dev, - "node %d: Adding %d: " - "Max connection reached!\n", - nid, cnid); - continue; + "%s: WARNING: Invalid child range " + "nid=%d index=%d j=%d entnum=%d " + "prevcnid=%d cnid=%d res=0x%08x\n", + __func__, nid, i, j, entnum, prevcnid, + cnid, res); + addcnid = cnid; + } else + addcnid = prevcnid + 1; + while (addcnid <= cnid) { + if (w->nconns > max) { + device_printf(sc->dev, + "%s: nid=%d: Adding %d: " + "Max connection reached! max=%d\n", + __func__, nid, addcnid, max + 1); + goto getconns_out; + } + w->conns[w->nconns++] = addcnid++; } - w->conns[found++] = cnid; + prevcnid = cnid; } - i += entnum; } +getconns_out: HDA_BOOTVERBOSE( - if (w->nconns != found) { - device_printf(sc->dev, - "HDA_DEBUG: nid=%d WARNING!!! Connection " - "length=%d != found=%d\n", - nid, w->nconns, found); - } + device_printf(sc->dev, + "HDA_DEBUG: %s: nid=%d entries=%d found=%d\n", + __func__, nid, ents, w->nconns); ); + return; } static uint32_t @@ -1802,6 +1973,12 @@ hdac_widget_pin_getconfig(struct hdac_widget *w) config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN | HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED); break; + case 28: + config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK | + HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK); + config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD | + HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED); + break; default: break; } @@ -1827,6 +2004,61 @@ hdac_widget_pin_getconfig(struct hdac_widget *w) default: break; } + } else if (id == HDA_CODEC_CXWAIKIKI && sc->pci_subvendor == + HP_DV5000_SUBVENDOR) { + switch (nid) { + case 20: + case 21: + config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK; + config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE; + break; + default: + break; + } + } else if (id == HDA_CODEC_ALC861 && sc->pci_subvendor == + ASUS_W6F_SUBVENDOR) { + switch (nid) { + case 11: + config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK | + HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK); + config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT | + HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED); + break; + case 15: + config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK | + HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK); + config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT | + HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK); + break; + default: + break; + } + } else if (id == HDA_CODEC_ALC861 && sc->pci_subvendor == + UNIWILL_9075_SUBVENDOR) { + switch (nid) { + case 15: + config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK | + HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK); + config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT | + HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK); + break; + default: + break; + } + } else if (id == HDA_CODEC_AD1986A && sc->pci_subvendor == + ASUS_M2NPVMX_SUBVENDOR) { + switch (nid) { + case 28: /* LINE */ + config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; + config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN; + break; + case 29: /* MIC */ + config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK; + config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN; + break; + default: + break; + } } HDA_BOOTVERBOSE( @@ -1884,7 +2116,8 @@ hdac_widget_pin_parse(struct hdac_widget *w) HDA_CMD_GET_PIN_WIDGET_CTRL(cad, nid), cad) & ~(HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE | HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE | - HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE); + HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE | + HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK); if (HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap)) w->wclass.pin.ctrl |= HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE; @@ -2106,7 +2339,11 @@ hda_poll_channel(struct hdac_chan *ch) return (0); sz = ch->blksz * ch->blkcnt; - ptr = HDAC_READ_4(&ch->devinfo->codec->sc->mem, ch->off + HDAC_SDLPIB); + if (ch->dmapos != NULL) + ptr = *(ch->dmapos); + else + ptr = HDAC_READ_4(&ch->devinfo->codec->sc->mem, + ch->off + HDAC_SDLPIB); ch->ptr = ptr; ptr %= sz; ptr &= ~(ch->blksz - 1); @@ -2165,8 +2402,10 @@ hdac_rirb_flush(struct hdac_softc *sc) rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr; rirbwp = HDAC_READ_1(&sc->mem, HDAC_RIRBWP); +#if 0 bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map, BUS_DMASYNC_POSTREAD); +#endif while (sc->rirb_rp != rirbwp) { sc->rirb_rp++; @@ -2223,14 +2462,13 @@ hdac_poll_callback(void *arg) return; hdac_lock(sc); - if (sc->polling == 0) { + if (sc->polling == 0 || sc->poll_ival == 0) { hdac_unlock(sc); return; } hdac_rirb_flush(sc); hdac_unsolq_flush(sc); - callout_reset(&sc->poll_hdac, max(hz >> 2, 1), - hdac_poll_callback, sc); + callout_reset(&sc->poll_hdac, sc->poll_ival, hdac_poll_callback, sc); hdac_unlock(sc); } @@ -2423,6 +2661,13 @@ hdac_bdl_setup(struct hdac_chan *ch) addr = ch->bdl_dma.dma_paddr; HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDBDPL, (uint32_t)addr); HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDBDPU, (uint32_t)(addr >> 32)); + if (ch->dmapos != NULL && + !(HDAC_READ_4(&sc->mem, HDAC_DPIBLBASE) & 0x00000001)) { + addr = sc->pos_dma.dma_paddr; + HDAC_WRITE_4(&sc->mem, HDAC_DPIBLBASE, + ((uint32_t)addr & HDAC_DPLBASE_DPLBASE_MASK) | 0x00000001); + HDAC_WRITE_4(&sc->mem, HDAC_DPIBUBASE, (uint32_t)(addr >> 32)); + } } static int @@ -2570,8 +2815,10 @@ hdac_command_send_internal(struct hdac_softc *sc, if (codec->verbs_sent != commands->num_commands) { /* Queue as many verbs as possible */ corbrp = HDAC_READ_2(&sc->mem, HDAC_CORBRP); +#if 0 bus_dmamap_sync(sc->corb_dma.dma_tag, sc->corb_dma.dma_map, BUS_DMASYNC_PREWRITE); +#endif while (codec->verbs_sent != commands->num_commands && ((sc->corb_wp + 1) % sc->corb_size) != corbrp) { sc->corb_wp++; @@ -2581,8 +2828,10 @@ hdac_command_send_internal(struct hdac_softc *sc, } /* Send the verbs to the codecs */ +#if 0 bus_dmamap_sync(sc->corb_dma.dma_tag, sc->corb_dma.dma_map, BUS_DMASYNC_POSTWRITE); +#endif HDAC_WRITE_2(&sc->mem, HDAC_CORBWP, sc->corb_wp); } @@ -2659,18 +2908,6 @@ hdac_probe(device_t dev) return (result); } -static int -hdac_channel_free(kobj_t obj, void *data) -{ - struct hdac_chan *ch = data; - - if (ch != NULL && ch->b != NULL && ch->b->buf != NULL) - hdac_dma_attr((vm_offset_t)ch->b->buf, sndbuf_getmaxsize(ch->b), - HDAC_DMA_WRITEBACK); - - return (1); -} - static void * hdac_channel_init(kobj_t obj, void *data, struct snd_dbuf *b, struct pcm_channel *c, int dir) @@ -2683,14 +2920,10 @@ hdac_channel_init(kobj_t obj, void *data, struct snd_dbuf *b, if (dir == PCMDIR_PLAY) { ch = &sc->play; ch->off = (sc->num_iss + devinfo->function.audio.playcnt) << 5; - ch->dir = PCMDIR_PLAY; - ch->sid = ++sc->streamcnt; devinfo->function.audio.playcnt++; } else { ch = &sc->rec; ch->off = devinfo->function.audio.reccnt << 5; - ch->dir = PCMDIR_REC; - ch->sid = ++sc->streamcnt; devinfo->function.audio.reccnt++; } if (devinfo->function.audio.quirks & HDA_QUIRK_FIXEDRATE) { @@ -2698,6 +2931,13 @@ hdac_channel_init(kobj_t obj, void *data, struct snd_dbuf *b, ch->pcmrates[0] = 48000; ch->pcmrates[1] = 0; } + if (sc->pos_dma.dma_vaddr != NULL) + ch->dmapos = (uint32_t *)(sc->pos_dma.dma_vaddr + + (sc->streamcnt * 8)); + else + ch->dmapos = NULL; + ch->sid = ++sc->streamcnt; + ch->dir = dir; ch->b = b; ch->c = c; ch->devinfo = devinfo; @@ -2710,12 +2950,10 @@ hdac_channel_init(kobj_t obj, void *data, struct snd_dbuf *b, return (NULL); } - if (sndbuf_alloc(ch->b, sc->chan_dmat, 0, sc->chan_size) != 0) + if (sndbuf_alloc(ch->b, sc->chan_dmat, + (sc->nocache != 0) ? BUS_DMA_NOCACHE : 0, sc->chan_size) != 0) return (NULL); - hdac_dma_attr((vm_offset_t)ch->b->buf, sndbuf_getmaxsize(ch->b), - HDAC_DMA_UNCACHEABLE); - return (ch); } @@ -2916,6 +3154,8 @@ hdac_channel_getptr(kobj_t obj, void *data) hdac_lock(sc); if (sc->polling != 0) ptr = ch->ptr; + else if (ch->dmapos != NULL) + ptr = *(ch->dmapos); else ptr = HDAC_READ_4(&sc->mem, ch->off + HDAC_SDLPIB); hdac_unlock(sc); @@ -2937,7 +3177,6 @@ hdac_channel_getcaps(kobj_t obj, void *data) static kobj_method_t hdac_channel_methods[] = { KOBJMETHOD(channel_init, hdac_channel_init), - KOBJMETHOD(channel_free, hdac_channel_free), KOBJMETHOD(channel_setformat, hdac_channel_setformat), KOBJMETHOD(channel_setspeed, hdac_channel_setspeed), KOBJMETHOD(channel_setblocksize, hdac_channel_setblocksize), @@ -2949,6 +3188,27 @@ static kobj_method_t hdac_channel_methods[] = { }; CHANNEL_DECLARE(hdac_channel); +static void +hdac_jack_poll_callback(void *arg) +{ + struct hdac_devinfo *devinfo = arg; + struct hdac_softc *sc; + + if (devinfo == NULL || devinfo->codec == NULL || + devinfo->codec->sc == NULL) + return; + sc = devinfo->codec->sc; + hdac_lock(sc); + if (sc->poll_ival == 0) { + hdac_unlock(sc); + return; + } + hdac_hp_switch_handler(devinfo); + callout_reset(&sc->poll_jack, sc->poll_ival, + hdac_jack_poll_callback, devinfo); + hdac_unlock(sc); +} + static int hdac_audio_ctl_ossmixer_init(struct snd_mixer *m) { @@ -2969,31 +3229,35 @@ hdac_audio_ctl_ossmixer_init(struct snd_mixer *m) cad = devinfo->codec->cad; for (i = 0; i < HDAC_HP_SWITCH_LEN; i++) { if (!(HDA_DEV_MATCH(hdac_hp_switch[i].model, - sc->pci_subvendor) && - hdac_hp_switch[i].id == id)) + sc->pci_subvendor) && hdac_hp_switch[i].id == id)) continue; w = hdac_widget_get(devinfo, hdac_hp_switch[i].hpnid); - if (w != NULL && w->enable != 0 - && w->type == - HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX && - HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap)) { + if (w == NULL || w->enable == 0 || w->type != + HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) + continue; + if (hdac_hp_switch[i].polling != 0) + callout_reset(&sc->poll_jack, 1, + hdac_jack_poll_callback, devinfo); + else if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap)) hdac_command(sc, - HDA_CMD_SET_UNSOLICITED_RESPONSE(cad, - w->nid, - HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE| + HDA_CMD_SET_UNSOLICITED_RESPONSE(cad, w->nid, + HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE | HDAC_UNSOLTAG_EVENT_HP), cad); - hdac_hp_switch_handler(devinfo); - HDA_BOOTVERBOSE( - device_printf(sc->dev, - "HDA_DEBUG: Enabling headphone/speaker " - "audio routing switching:\n"); - device_printf(sc->dev, - "HDA_DEBUG: \tindex=%d nid=%d " - "pci_subvendor=0x%08x " - "codec=0x%08x\n", - i, w->nid, sc->pci_subvendor, id); - ); - } + else + continue; + hdac_hp_switch_handler(devinfo); + HDA_BOOTVERBOSE( + device_printf(sc->dev, + "HDA_DEBUG: Enabling headphone/speaker " + "audio routing switching:\n"); + device_printf(sc->dev, + "HDA_DEBUG: \tindex=%d nid=%d " + "pci_subvendor=0x%08x " + "codec=0x%08x [%s]\n", + i, w->nid, sc->pci_subvendor, id, + (hdac_hp_switch[i].polling != 0) ? "POLL" : + "UNSOL"); + ); break; } for (i = 0; i < HDAC_EAPD_SWITCH_LEN; i++) { @@ -3079,7 +3343,10 @@ hdac_audio_ctl_ossmixer_init(struct snd_mixer *m) NULL) { if (ctl->widget == NULL) continue; - if (ctl->widget->nid == 2 && ctl->index == 0) { + if (ctl->widget->type == + HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT && + ctl->index == 0 && (ctl->widget->nid == 2 || + ctl->widget->enable != 0)) { ctl->enable = 1; ctl->ossmask = SOUND_MASK_VOLUME; ctl->ossval = 100 | (100 << 8); @@ -3107,7 +3374,11 @@ hdac_audio_ctl_ossmixer_init(struct snd_mixer *m) } } - recmask &= ~(SOUND_MASK_PCM | SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER); + recmask &= ~(SOUND_MASK_PCM | SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER | + SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_IGAIN | + SOUND_MASK_OGAIN); + recmask &= (1 << SOUND_MIXER_NRDEVICES) - 1; + mask &= (1 << SOUND_MIXER_NRDEVICES) - 1; mix_setrecdevs(m, recmask); mix_setdevs(m, mask); @@ -3263,7 +3534,8 @@ hdac_audio_ctl_ossmixer_setrecsrc(struct snd_mixer *m, uint32_t src) HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)) continue; if (cw->ctlflags & target) { - hdac_widget_connection_select(w, j); + if (!(w->pflags & HDA_ADC_LOCKED)) + hdac_widget_connection_select(w, j); ret = target; j += w->nconns; } @@ -3295,7 +3567,9 @@ hdac_attach(device_t dev) { struct hdac_softc *sc; int result; - int i = 0; + int i; + uint16_t vendor; + uint8_t v; sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT | M_ZERO); if (sc == NULL) { @@ -3307,6 +3581,7 @@ hdac_attach(device_t dev) sc->dev = dev; sc->pci_subvendor = (uint32_t)pci_get_subdevice(sc->dev) << 16; sc->pci_subvendor |= (uint32_t)pci_get_subvendor(sc->dev) & 0x0000ffff; + vendor = pci_get_vendor(dev); if (sc->pci_subvendor == HP_NX6325_SUBVENDORX) { /* Screw nx6325 - subdevice/subvendor swapped */ @@ -3315,10 +3590,12 @@ hdac_attach(device_t dev) callout_init(&sc->poll_hda, CALLOUT_MPSAFE); callout_init(&sc->poll_hdac, CALLOUT_MPSAFE); + callout_init(&sc->poll_jack, CALLOUT_MPSAFE); sc->poll_ticks = 1; - if (resource_int_value(device_get_name(sc->dev), - device_get_unit(sc->dev), "polling", &i) == 0 && i != 0) + sc->poll_ival = HDAC_POLL_INTERVAL; + if (resource_int_value(device_get_name(dev), + device_get_unit(dev), "polling", &i) == 0 && i != 0) sc->polling = 1; else sc->polling = 0; @@ -3326,8 +3603,8 @@ hdac_attach(device_t dev) sc->chan_size = pcm_getbuffersize(dev, HDA_BUFSZ_MIN, HDA_BUFSZ_DEFAULT, HDA_BUFSZ_MAX); - if (resource_int_value(device_get_name(sc->dev), - device_get_unit(sc->dev), "blocksize", &i) == 0 && i > 0) { + if (resource_int_value(device_get_name(dev), + device_get_unit(dev), "blocksize", &i) == 0 && i > 0) { i &= HDA_BLK_ALIGN; if (i < HDA_BLK_MIN) i = HDA_BLK_MIN; @@ -3358,7 +3635,7 @@ hdac_attach(device_t dev) NULL, /* lockfuncarg */ &sc->chan_dmat); /* dmat */ if (result != 0) { - device_printf(sc->dev, "%s: bus_dma_tag_create failed (%x)\n", + device_printf(dev, "%s: bus_dma_tag_create failed (%x)\n", __func__, result); snd_mtxfree(sc->lock); free(sc, M_DEVBUF); @@ -3372,6 +3649,70 @@ hdac_attach(device_t dev) pci_enable_busmaster(dev); + if (vendor == INTEL_VENDORID) { + /* TCSEL -> TC0 */ + v = pci_read_config(dev, 0x44, 1); + pci_write_config(dev, 0x44, v & 0xf8, 1); + HDA_BOOTVERBOSE( + device_printf(dev, "TCSEL: 0x%02d -> 0x%02d\n", v, + pci_read_config(dev, 0x44, 1)); + ); + } + +#if defined(__i386__) || defined(__amd64__) + sc->nocache = 1; + + if (resource_int_value(device_get_name(dev), + device_get_unit(dev), "snoop", &i) == 0 && i != 0) { +#else + sc->nocache = 0; +#endif + /* + * Try to enable PCIe snoop to avoid messing around with + * uncacheable DMA attribute. Since PCIe snoop register + * config is pretty much vendor specific, there are no + * general solutions on how to enable it, forcing us (even + * Microsoft) to enable uncacheable or write combined DMA + * by default. + * + * http://msdn2.microsoft.com/en-us/library/ms790324.aspx + */ + for (i = 0; i < HDAC_PCIESNOOP_LEN; i++) { + if (hdac_pcie_snoop[i].vendor != vendor) + continue; + sc->nocache = 0; + if (hdac_pcie_snoop[i].reg == 0x00) + break; + v = pci_read_config(dev, hdac_pcie_snoop[i].reg, 1); + if ((v & hdac_pcie_snoop[i].enable) == + hdac_pcie_snoop[i].enable) + break; + v &= hdac_pcie_snoop[i].mask; + v |= hdac_pcie_snoop[i].enable; + pci_write_config(dev, hdac_pcie_snoop[i].reg, v, 1); + v = pci_read_config(dev, hdac_pcie_snoop[i].reg, 1); + if ((v & hdac_pcie_snoop[i].enable) != + hdac_pcie_snoop[i].enable) { + HDA_BOOTVERBOSE( + device_printf(dev, + "WARNING: Failed to enable PCIe " + "snoop!\n"); + ); +#if defined(__i386__) || defined(__amd64__) + sc->nocache = 1; +#endif + } + break; + } +#if defined(__i386__) || defined(__amd64__) + } +#endif + + HDA_BOOTVERBOSE( + device_printf(dev, "DMA Coherency: %s / vendor=0x%04x\n", + (sc->nocache == 0) ? "PCIe snoop" : "Uncacheable", vendor); + ); + /* Allocate resources */ result = hdac_mem_alloc(sc); if (result != 0) @@ -3398,10 +3739,6 @@ hdac_attach(device_t dev) /* Quiesce everything */ hdac_reset(sc); - /* Disable PCI-Express QOS */ - pci_write_config(sc->dev, 0x44, - pci_read_config(sc->dev, 0x44, 1) & 0xf8, 1); - /* Initialize the CORB and RIRB */ hdac_corb_init(sc); hdac_rirb_init(sc); @@ -3417,9 +3754,9 @@ hdac_attach(device_t dev) return (0); hdac_attach_fail: - hdac_dma_free(&sc->rirb_dma); - hdac_dma_free(&sc->corb_dma); hdac_irq_free(sc); + hdac_dma_free(sc, &sc->rirb_dma); + hdac_dma_free(sc, &sc->corb_dma); hdac_mem_free(sc); snd_mtxfree(sc->lock); free(sc, M_DEVBUF); @@ -3451,6 +3788,10 @@ hdac_audio_parse(struct hdac_devinfo *devinfo) devinfo->startnode = HDA_PARAM_SUB_NODE_COUNT_START(res); devinfo->endnode = devinfo->startnode + devinfo->nodecnt; + res = hdac_command(sc, + HDA_CMD_GET_PARAMETER(cad , nid, HDA_PARAM_GPIO_COUNT), cad); + devinfo->function.audio.gpio = res; + HDA_BOOTVERBOSE( device_printf(sc->dev, " Vendor: 0x%08x\n", devinfo->vendor_id); @@ -3465,6 +3806,19 @@ hdac_audio_parse(struct hdac_devinfo *devinfo) device_printf(sc->dev, " Nodes: start=%d " "endnode=%d total=%d\n", devinfo->startnode, devinfo->endnode, devinfo->nodecnt); + device_printf(sc->dev, " CORB size: %d\n", sc->corb_size); + device_printf(sc->dev, " RIRB size: %d\n", sc->rirb_size); + device_printf(sc->dev, " Streams: ISS=%d OSS=%d BSS=%d\n", + sc->num_iss, sc->num_oss, sc->num_bss); + device_printf(sc->dev, " GPIO: 0x%08x\n", + devinfo->function.audio.gpio); + device_printf(sc->dev, " NumGPIO=%d NumGPO=%d " + "NumGPI=%d GPIWake=%d GPIUnsol=%d\n", + HDA_PARAM_GPIO_COUNT_NUM_GPIO(devinfo->function.audio.gpio), + HDA_PARAM_GPIO_COUNT_NUM_GPO(devinfo->function.audio.gpio), + HDA_PARAM_GPIO_COUNT_NUM_GPI(devinfo->function.audio.gpio), + HDA_PARAM_GPIO_COUNT_GPI_WAKE(devinfo->function.audio.gpio), + HDA_PARAM_GPIO_COUNT_GPI_UNSOL(devinfo->function.audio.gpio)); ); res = hdac_command(sc, @@ -3487,13 +3841,11 @@ hdac_audio_parse(struct hdac_devinfo *devinfo) cad); devinfo->function.audio.inamp_cap = res; - if (devinfo->nodecnt > 0) { - hdac_unlock(sc); + if (devinfo->nodecnt > 0) devinfo->widget = (struct hdac_widget *)malloc( sizeof(*(devinfo->widget)) * devinfo->nodecnt, M_HDAC, M_NOWAIT | M_ZERO); - hdac_lock(sc); - } else + else devinfo->widget = NULL; if (devinfo->widget == NULL) { @@ -3561,10 +3913,8 @@ hdac_audio_ctl_parse(struct hdac_devinfo *devinfo) if (max < 1) return; - hdac_unlock(sc); ctls = (struct hdac_audio_ctl *)malloc( sizeof(*ctls) * max, M_HDAC, M_ZERO | M_NOWAIT); - hdac_lock(sc); if (ctls == NULL) { /* Blekh! */ @@ -3686,7 +4036,7 @@ static const struct { * perhaps unsupported. */ { HDA_MATCH_ALL, HDA_MATCH_ALL, - HDA_QUIRK_FORCESTEREO | HDA_QUIRK_VREF, 0 }, + HDA_QUIRK_FORCESTEREO | HDA_QUIRK_IVREF, 0 }, { ACER_ALL_SUBVENDOR, HDA_MATCH_ALL, HDA_QUIRK_GPIO0, 0 }, { ASUS_M5200_SUBVENDOR, HDA_CODEC_ALC880, @@ -3695,10 +4045,20 @@ static const struct { HDA_QUIRK_GPIO0, 0 }, { ASUS_A7T_SUBVENDOR, HDA_CODEC_ALC882, HDA_QUIRK_GPIO0, 0 }, + { ASUS_W2J_SUBVENDOR, HDA_CODEC_ALC882, + HDA_QUIRK_GPIO0, 0 }, { ASUS_U5F_SUBVENDOR, HDA_CODEC_AD1986A, HDA_QUIRK_EAPDINV, 0 }, { ASUS_A8JC_SUBVENDOR, HDA_CODEC_AD1986A, HDA_QUIRK_EAPDINV, 0 }, + { ASUS_F3JC_SUBVENDOR, HDA_CODEC_ALC861, + HDA_QUIRK_OVREF, 0 }, + { ASUS_W6F_SUBVENDOR, HDA_CODEC_ALC861, + HDA_QUIRK_OVREF, 0 }, + { UNIWILL_9075_SUBVENDOR, HDA_CODEC_ALC861, + HDA_QUIRK_OVREF, 0 }, + /*{ ASUS_M2N_SUBVENDOR, HDA_CODEC_AD1988, + HDA_QUIRK_IVREF80, HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF100 },*/ { MEDION_MD95257_SUBVENDOR, HDA_CODEC_ALC880, HDA_QUIRK_GPIO1, 0 }, { LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A, @@ -3707,6 +4067,8 @@ static const struct { HDA_QUIRK_EAPDINV, 0 }, { APPLE_INTEL_MAC, HDA_CODEC_STAC9221, HDA_QUIRK_GPIO0 | HDA_QUIRK_GPIO1, 0 }, + { HDA_MATCH_ALL, HDA_CODEC_AD1988, + HDA_QUIRK_IVREF80, HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF100 }, { HDA_MATCH_ALL, HDA_CODEC_CXVENICE, 0, HDA_QUIRK_FORCESTEREO }, { HDA_MATCH_ALL, HDA_CODEC_STACXXXX, @@ -3763,10 +4125,21 @@ hdac_vendor_patch_parse(struct hdac_devinfo *devinfo) ctl->ossmask = SOUND_MASK_SPEAKER; ctl->widget->ctlflags |= SOUND_MASK_SPEAKER; } + } else if (subvendor == HP_3010_SUBVENDOR) { + ctl = hdac_audio_ctl_amp_get(devinfo, 17, 0, 1); + if (ctl != NULL && ctl->widget != NULL) { + ctl->ossmask = SOUND_MASK_SPEAKER; + ctl->widget->ctlflags |= SOUND_MASK_SPEAKER; + } + ctl = hdac_audio_ctl_amp_get(devinfo, 21, 0, 1); + if (ctl != NULL && ctl->widget != NULL) { + ctl->ossmask = SOUND_MASK_SPEAKER; + ctl->widget->ctlflags |= SOUND_MASK_SPEAKER; + } } break; case HDA_CODEC_ALC861: - ctl = hdac_audio_ctl_amp_get(devinfo, 28, 1, 1); + ctl = hdac_audio_ctl_amp_get(devinfo, 21, 2, 1); if (ctl != NULL) ctl->muted = HDA_AMP_MUTE_ALL; break; @@ -3843,8 +4216,74 @@ hdac_vendor_patch_parse(struct hdac_devinfo *devinfo) if (w->nid != 3) w->enable = 0; } + if (subvendor == ASUS_M2NPVMX_SUBVENDOR) { + /* nid 28 is mic, nid 29 is line-in */ + w = hdac_widget_get(devinfo, 15); + if (w != NULL) + w->selconn = 2; + w = hdac_widget_get(devinfo, 16); + if (w != NULL) + w->selconn = 1; + } + break; + case HDA_CODEC_AD1988: + /*w = hdac_widget_get(devinfo, 12); + if (w != NULL) { + w->selconn = 1; + w->pflags |= HDA_ADC_LOCKED; + } + w = hdac_widget_get(devinfo, 13); + if (w != NULL) { + w->selconn = 4; + w->pflags |= HDA_ADC_LOCKED; + } + w = hdac_widget_get(devinfo, 14); + if (w != NULL) { + w->selconn = 2; + w->pflags |= HDA_ADC_LOCKED; + }*/ + ctl = hdac_audio_ctl_amp_get(devinfo, 57, 0, 1); + if (ctl != NULL) { + ctl->ossmask = SOUND_MASK_IGAIN; + ctl->widget->ctlflags |= SOUND_MASK_IGAIN; + } + ctl = hdac_audio_ctl_amp_get(devinfo, 58, 0, 1); + if (ctl != NULL) { + ctl->ossmask = SOUND_MASK_IGAIN; + ctl->widget->ctlflags |= SOUND_MASK_IGAIN; + } + ctl = hdac_audio_ctl_amp_get(devinfo, 60, 0, 1); + if (ctl != NULL) { + ctl->ossmask = SOUND_MASK_IGAIN; + ctl->widget->ctlflags |= SOUND_MASK_IGAIN; + } + ctl = hdac_audio_ctl_amp_get(devinfo, 32, 0, 1); + if (ctl != NULL) { + ctl->ossmask = SOUND_MASK_MIC | SOUND_MASK_VOLUME; + ctl->widget->ctlflags |= SOUND_MASK_MIC; + } + ctl = hdac_audio_ctl_amp_get(devinfo, 32, 4, 1); + if (ctl != NULL) { + ctl->ossmask = SOUND_MASK_MIC | SOUND_MASK_VOLUME; + ctl->widget->ctlflags |= SOUND_MASK_MIC; + } + ctl = hdac_audio_ctl_amp_get(devinfo, 32, 1, 1); + if (ctl != NULL) { + ctl->ossmask = SOUND_MASK_LINE | SOUND_MASK_VOLUME; + ctl->widget->ctlflags |= SOUND_MASK_LINE; + } + ctl = hdac_audio_ctl_amp_get(devinfo, 32, 7, 1); + if (ctl != NULL) { + ctl->ossmask = SOUND_MASK_SPEAKER | SOUND_MASK_VOLUME; + ctl->widget->ctlflags |= SOUND_MASK_SPEAKER; + } break; case HDA_CODEC_STAC9221: + /* + * Dell XPS M1210 need all DACs for each output jacks + */ + if (subvendor == DELL_XPSM1210_SUBVENDOR) + break; for (i = devinfo->startnode; i < devinfo->endnode; i++) { w = hdac_widget_get(devinfo, i); if (w == NULL || w->enable == 0) @@ -3868,6 +4307,48 @@ hdac_vendor_patch_parse(struct hdac_devinfo *devinfo) } break; + case HDA_CODEC_STAC9227: + w = hdac_widget_get(devinfo, 8); + if (w != NULL) + w->enable = 0; + w = hdac_widget_get(devinfo, 9); + if (w != NULL) + w->enable = 0; + break; + case HDA_CODEC_CXWAIKIKI: + if (subvendor == HP_DV5000_SUBVENDOR) { + w = hdac_widget_get(devinfo, 27); + if (w != NULL) + w->enable = 0; + } + ctl = hdac_audio_ctl_amp_get(devinfo, 16, 0, 1); + if (ctl != NULL) + ctl->ossmask = SOUND_MASK_SKIP; + ctl = hdac_audio_ctl_amp_get(devinfo, 25, 0, 1); + if (ctl != NULL && ctl->childwidget != NULL && + ctl->childwidget->enable != 0) { + ctl->ossmask = SOUND_MASK_PCM | SOUND_MASK_VOLUME; + ctl->childwidget->ctlflags |= SOUND_MASK_PCM; + } + ctl = hdac_audio_ctl_amp_get(devinfo, 25, 1, 1); + if (ctl != NULL && ctl->childwidget != NULL && + ctl->childwidget->enable != 0) { + ctl->ossmask = SOUND_MASK_LINE | SOUND_MASK_VOLUME; + ctl->childwidget->ctlflags |= SOUND_MASK_LINE; + } + ctl = hdac_audio_ctl_amp_get(devinfo, 25, 2, 1); + if (ctl != NULL && ctl->childwidget != NULL && + ctl->childwidget->enable != 0) { + ctl->ossmask = SOUND_MASK_MIC | SOUND_MASK_VOLUME; + ctl->childwidget->ctlflags |= SOUND_MASK_MIC; + } + ctl = hdac_audio_ctl_amp_get(devinfo, 26, 0, 1); + if (ctl != NULL) { + ctl->ossmask = SOUND_MASK_SKIP; + /* XXX mixer \=rec mic broken.. why?!? */ + /* ctl->widget->ctlflags |= SOUND_MASK_MIC; */ + } + break; default: break; } @@ -3889,6 +4370,7 @@ hdac_audio_ctl_ossmixer_getnextdev(struct hdac_devinfo *devinfo) case SOUND_MIXER_MIC: case SOUND_MIXER_CD: case SOUND_MIXER_RECLEV: + case SOUND_MIXER_IGAIN: case SOUND_MIXER_OGAIN: /* reserved for EAPD switch */ (*dev)++; break; @@ -4017,7 +4499,7 @@ hdac_audio_ctl_outamp_build(struct hdac_devinfo *devinfo, if (ctl->enable == 0 || ctl->widget == NULL) continue; /* XXX This should be compressed! */ - if ((ctl->widget->nid == w->nid) || + if (((ctl->widget->nid == w->nid) || (ctl->widget->nid == pnid && ctl->index == index && (ctl->dir & HDA_CTL_IN)) || (ctl->widget->nid == pnid && pw != NULL && @@ -4027,7 +4509,8 @@ hdac_audio_ctl_outamp_build(struct hdac_devinfo *devinfo, pw->selconn == -1) && (ctl->dir & HDA_CTL_OUT)) || (strategy == HDA_PARSE_DIRECT && - ctl->widget->nid == w->nid)) { + ctl->widget->nid == w->nid)) && + !(ctl->ossmask & ~SOUND_MASK_VOLUME)) { /*if (pw != NULL && pw->selconn == -1) pw->selconn = index; fl |= SOUND_MASK_VOLUME; @@ -4361,8 +4844,9 @@ hdac_audio_build_tree(struct hdac_devinfo *devinfo) #define HDA_COMMIT_CTRL (1 << 1) #define HDA_COMMIT_EAPD (1 << 2) #define HDA_COMMIT_GPIO (1 << 3) +#define HDA_COMMIT_MISC (1 << 4) #define HDA_COMMIT_ALL (HDA_COMMIT_CONN | HDA_COMMIT_CTRL | \ - HDA_COMMIT_EAPD | HDA_COMMIT_GPIO) + HDA_COMMIT_EAPD | HDA_COMMIT_GPIO | HDA_COMMIT_MISC) static void hdac_audio_commit(struct hdac_devinfo *devinfo, uint32_t cfl) @@ -4377,41 +4861,50 @@ hdac_audio_commit(struct hdac_devinfo *devinfo, uint32_t cfl) cad = devinfo->codec->cad; + if ((cfl & HDA_COMMIT_MISC)) { + if (sc->pci_subvendor == APPLE_INTEL_MAC) + hdac_command(sc, HDA_CMD_12BIT(cad, devinfo->nid, + 0x7e7, 0), cad); + } + if (cfl & HDA_COMMIT_GPIO) { uint32_t gdata, gmask, gdir; - int commitgpio = 0; + int commitgpio, numgpio; gdata = 0; gmask = 0; gdir = 0; + commitgpio = 0; - if (sc->pci_subvendor == APPLE_INTEL_MAC) - hdac_command(sc, HDA_CMD_12BIT(cad, devinfo->nid, - 0x7e7, 0), cad); + numgpio = HDA_PARAM_GPIO_COUNT_NUM_GPIO( + devinfo->function.audio.gpio); if (devinfo->function.audio.quirks & HDA_QUIRK_GPIOFLUSH) - commitgpio = 1; + commitgpio = (numgpio > 0) ? 1 : 0; else { - for (i = 0; i < HDA_GPIO_MAX; i++) { + for (i = 0; i < numgpio && i < HDA_GPIO_MAX; i++) { if (!(devinfo->function.audio.quirks & (1 << i))) continue; if (commitgpio == 0) { commitgpio = 1; - gdata = hdac_command(sc, - HDA_CMD_GET_GPIO_DATA(cad, - devinfo->nid), cad); - gmask = hdac_command(sc, - HDA_CMD_GET_GPIO_ENABLE_MASK(cad, - devinfo->nid), cad); - gdir = hdac_command(sc, - HDA_CMD_GET_GPIO_DIRECTION(cad, - devinfo->nid), cad); HDA_BOOTVERBOSE( + gdata = hdac_command(sc, + HDA_CMD_GET_GPIO_DATA(cad, + devinfo->nid), cad); + gmask = hdac_command(sc, + HDA_CMD_GET_GPIO_ENABLE_MASK(cad, + devinfo->nid), cad); + gdir = hdac_command(sc, + HDA_CMD_GET_GPIO_DIRECTION(cad, + devinfo->nid), cad); device_printf(sc->dev, "GPIO init: data=0x%08x " "mask=0x%08x dir=0x%08x\n", gdata, gmask, gdir); + gdata = 0; + gmask = 0; + gdir = 0; ); } gdata |= 1 << i; @@ -4451,6 +4944,10 @@ hdac_audio_commit(struct hdac_devinfo *devinfo, uint32_t cfl) } if ((cfl & HDA_COMMIT_CTRL) && w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) { + uint32_t pincap; + + pincap = w->wclass.pin.cap; + if ((w->pflags & (HDA_DAC_PATH | HDA_ADC_PATH)) == (HDA_DAC_PATH | HDA_ADC_PATH)) device_printf(sc->dev, "WARNING: node %d " @@ -4463,28 +4960,40 @@ hdac_audio_commit(struct hdac_devinfo *devinfo, uint32_t cfl) HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT) w->wclass.pin.ctrl &= ~HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE; + if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF100) && + HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap)) + w->wclass.pin.ctrl |= + HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE( + HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100); + else if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF80) && + HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap)) + w->wclass.pin.ctrl |= + HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE( + HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80); + else if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF50) && + HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap)) + w->wclass.pin.ctrl |= + HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE( + HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50); } else if (w->pflags & HDA_ADC_PATH) { w->wclass.pin.ctrl &= ~(HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE | HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE); - if (w->devinfo->function.audio.quirks & HDA_QUIRK_VREF) { - uint32_t pincap = w->wclass.pin.cap; - if (HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap)) - w->wclass.pin.ctrl |= - HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE( - HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100 - ); - else if (HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap)) - w->wclass.pin.ctrl |= - HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE( - HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80 - ); - else if (HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap)) - w->wclass.pin.ctrl |= - HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE( - HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50 - ); - } + if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF100) && + HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap)) + w->wclass.pin.ctrl |= + HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE( + HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100); + else if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF80) && + HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap)) + w->wclass.pin.ctrl |= + HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE( + HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80); + else if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF50) && + HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap)) + w->wclass.pin.ctrl |= + HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE( + HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50); } else w->wclass.pin.ctrl &= ~( HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE | @@ -4699,7 +5208,8 @@ hdac_dump_ctls(struct hdac_devinfo *devinfo, const char *banner, uint32_t flag) i = 0; while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { if (ctl->enable == 0 || ctl->widget == NULL || - ctl->widget->enable == 0) + ctl->widget->enable == 0 || (ctl->ossmask & + (SOUND_MASK_SKIP | SOUND_MASK_DISABLE))) continue; if ((flag == 0 && (ctl->ossmask & ~fl)) || (flag != 0 && (ctl->ossmask & flag))) { @@ -5088,11 +5598,17 @@ hdac_release_resources(struct hdac_softc *sc) return; hdac_lock(sc); - if (sc->polling != 0) - callout_stop(&sc->poll_hdac); + sc->polling = 0; + sc->poll_ival = 0; + callout_stop(&sc->poll_hdac); + callout_stop(&sc->poll_jack); hdac_reset(sc); hdac_unlock(sc); - snd_mtxfree(sc->lock); + callout_drain(&sc->poll_hdac); + callout_drain(&sc->poll_jack); + hdac_lock(sc); + + hdac_irq_free(sc); device_get_children(sc->dev, &devlist, &devcount); for (i = 0; devlist != NULL && i < devcount; i++) { @@ -5117,18 +5633,19 @@ hdac_release_resources(struct hdac_softc *sc) sc->codecs[i] = NULL; } - hdac_dma_free(&sc->rirb_dma); - hdac_dma_free(&sc->corb_dma); + hdac_dma_free(sc, &sc->pos_dma); + hdac_dma_free(sc, &sc->rirb_dma); + hdac_dma_free(sc, &sc->corb_dma); if (sc->play.blkcnt > 0) - hdac_dma_free(&sc->play.bdl_dma); + hdac_dma_free(sc, &sc->play.bdl_dma); if (sc->rec.blkcnt > 0) - hdac_dma_free(&sc->rec.bdl_dma); + hdac_dma_free(sc, &sc->rec.bdl_dma); if (sc->chan_dmat != NULL) { bus_dma_tag_destroy(sc->chan_dmat); sc->chan_dmat = NULL; } - hdac_irq_free(sc); hdac_mem_free(sc); + snd_mtxfree(sc->lock); free(sc, M_DEVBUF); } @@ -5213,7 +5730,7 @@ sysctl_hdac_polling(SYSCTL_HANDLER_ARGS) hdac_unlock(sc); err = sysctl_handle_int(oidp, &val, sizeof(val), req); - if (err || req->newptr == NULL) + if (err != 0 || req->newptr == NULL) return (err); if (val < 0 || val > 1) return (EINVAL); @@ -5224,6 +5741,9 @@ sysctl_hdac_polling(SYSCTL_HANDLER_ARGS) err = EBUSY; else if (val == 0) { callout_stop(&sc->poll_hdac); + hdac_unlock(sc); + callout_drain(&sc->poll_hdac); + hdac_lock(sc); HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT, sc->rirb_size / 2); ctl = HDAC_READ_1(&sc->mem, HDAC_RIRBCTL); @@ -5249,6 +5769,139 @@ sysctl_hdac_polling(SYSCTL_HANDLER_ARGS) return (err); } + +static int +sysctl_hdac_polling_interval(SYSCTL_HANDLER_ARGS) +{ + struct hdac_softc *sc; + struct hdac_devinfo *devinfo; + device_t dev; + int err, val; + + dev = oidp->oid_arg1; + devinfo = pcm_getdevinfo(dev); + if (devinfo == NULL || devinfo->codec == NULL || + devinfo->codec->sc == NULL) + return (EINVAL); + sc = devinfo->codec->sc; + hdac_lock(sc); + val = ((uint64_t)sc->poll_ival * 1000) / hz; + hdac_unlock(sc); + err = sysctl_handle_int(oidp, &val, sizeof(val), req); + + if (err != 0 || req->newptr == NULL) + return (err); + + if (val < 1) + val = 1; + if (val > 5000) + val = 5000; + val = ((uint64_t)val * hz) / 1000; + if (val < 1) + val = 1; + if (val > (hz * 5)) + val = hz * 5; + + hdac_lock(sc); + sc->poll_ival = val; + hdac_unlock(sc); + + return (err); +} + +#ifdef SND_DEBUG +static int +sysctl_hdac_dump(SYSCTL_HANDLER_ARGS) +{ + struct hdac_softc *sc; + struct hdac_devinfo *devinfo; + struct hdac_widget *w; + device_t dev; + uint32_t res, execres; + int i, err, val; + nid_t cad; + + dev = oidp->oid_arg1; + devinfo = pcm_getdevinfo(dev); + if (devinfo == NULL || devinfo->codec == NULL || + devinfo->codec->sc == NULL) + return (EINVAL); + val = 0; + err = sysctl_handle_int(oidp, &val, sizeof(val), req); + if (err != 0 || req->newptr == NULL || val == 0) + return (err); + sc = devinfo->codec->sc; + cad = devinfo->codec->cad; + hdac_lock(sc); + device_printf(dev, "HDAC Dump AFG [nid=%d]:\n", devinfo->nid); + for (i = devinfo->startnode; i < devinfo->endnode; i++) { + w = hdac_widget_get(devinfo, i); + if (w == NULL || w->type != + HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) + continue; + execres = hdac_command(sc, HDA_CMD_SET_PIN_SENSE(cad, w->nid, 0), + cad); + res = hdac_command(sc, HDA_CMD_GET_PIN_SENSE(cad, w->nid), cad); + device_printf(dev, "nid=%-3d exec=0x%08x sense=0x%08x [%s]\n", + w->nid, execres, res, + (w->enable == 0) ? "DISABLED" : "ENABLED"); + } + device_printf(dev, + "NumGPIO=%d NumGPO=%d NumGPI=%d GPIWake=%d GPIUnsol=%d\n", + HDA_PARAM_GPIO_COUNT_NUM_GPIO(devinfo->function.audio.gpio), + HDA_PARAM_GPIO_COUNT_NUM_GPO(devinfo->function.audio.gpio), + HDA_PARAM_GPIO_COUNT_NUM_GPI(devinfo->function.audio.gpio), + HDA_PARAM_GPIO_COUNT_GPI_WAKE(devinfo->function.audio.gpio), + HDA_PARAM_GPIO_COUNT_GPI_UNSOL(devinfo->function.audio.gpio)); + if (1 || HDA_PARAM_GPIO_COUNT_NUM_GPI(devinfo->function.audio.gpio) > 0) { + device_printf(dev, " GPI:"); + res = hdac_command(sc, + HDA_CMD_GET_GPI_DATA(cad, devinfo->nid), cad); + printf(" data=0x%08x", res); + res = hdac_command(sc, + HDA_CMD_GET_GPI_WAKE_ENABLE_MASK(cad, devinfo->nid), + cad); + printf(" wake=0x%08x", res); + res = hdac_command(sc, + HDA_CMD_GET_GPI_UNSOLICITED_ENABLE_MASK(cad, devinfo->nid), + cad); + printf(" unsol=0x%08x", res); + res = hdac_command(sc, + HDA_CMD_GET_GPI_STICKY_MASK(cad, devinfo->nid), cad); + printf(" sticky=0x%08x\n", res); + } + if (1 || HDA_PARAM_GPIO_COUNT_NUM_GPO(devinfo->function.audio.gpio) > 0) { + device_printf(dev, " GPO:"); + res = hdac_command(sc, + HDA_CMD_GET_GPO_DATA(cad, devinfo->nid), cad); + printf(" data=0x%08x\n", res); + } + if (1 || HDA_PARAM_GPIO_COUNT_NUM_GPIO(devinfo->function.audio.gpio) > 0) { + device_printf(dev, "GPI0:"); + res = hdac_command(sc, + HDA_CMD_GET_GPIO_DATA(cad, devinfo->nid), cad); + printf(" data=0x%08x", res); + res = hdac_command(sc, + HDA_CMD_GET_GPIO_ENABLE_MASK(cad, devinfo->nid), cad); + printf(" enable=0x%08x", res); + res = hdac_command(sc, + HDA_CMD_GET_GPIO_DIRECTION(cad, devinfo->nid), cad); + printf(" direction=0x%08x\n", res); + res = hdac_command(sc, + HDA_CMD_GET_GPIO_WAKE_ENABLE_MASK(cad, devinfo->nid), cad); + device_printf(dev, " wake=0x%08x", res); + res = hdac_command(sc, + HDA_CMD_GET_GPIO_UNSOLICITED_ENABLE_MASK(cad, devinfo->nid), + cad); + printf(" unsol=0x%08x", res); + res = hdac_command(sc, + HDA_CMD_GET_GPIO_STICKY_MASK(cad, devinfo->nid), cad); + printf(" sticky=0x%08x\n", res); + } + hdac_unlock(sc); + return (0); +} +#endif #endif static void @@ -5367,10 +6020,11 @@ hdac_attach2(void *arg) while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { if (ctl->widget == NULL) continue; - w = ctl->widget; - if (w->enable == 0) + if (ctl->ossmask & SOUND_MASK_DISABLE) ctl->enable = 0; - if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) + w = ctl->widget; + if (w->enable == 0 || + HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) ctl->enable = 0; w = ctl->childwidget; if (w == NULL) @@ -5385,6 +6039,11 @@ hdac_attach2(void *arg) ); hdac_audio_build_tree(devinfo); + i = 0; + while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) { + if (ctl->ossmask & (SOUND_MASK_SKIP | SOUND_MASK_DISABLE)) + ctl->ossmask = 0; + } HDA_BOOTVERBOSE( device_printf(sc->dev, "HDA_DEBUG: AFG commit...\n"); ); @@ -5430,6 +6089,15 @@ hdac_attach2(void *arg) sc->registered++; + if ((devinfo->function.audio.quirks & HDA_QUIRK_DMAPOS) && + hdac_dma_alloc(sc, &sc->pos_dma, + (sc->num_iss + sc->num_oss + sc->num_bss) * 8) != 0) { + HDA_BOOTVERBOSE( + device_printf(sc->dev, + "Failed to allocate DMA pos buffer (non-fatal)\n"); + ); + } + for (i = 0; i < pcnt; i++) pcm_addchan(sc->dev, PCMDIR_PLAY, &hdac_channel_class, devinfo); for (i = 0; i < rcnt; i++) @@ -5440,6 +6108,17 @@ hdac_attach2(void *arg) SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO, "polling", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev), sysctl_hdac_polling, "I", "Enable polling mode"); + SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO, + "polling_interval", CTLTYPE_INT | CTLFLAG_RW, sc->dev, + sizeof(sc->dev), sysctl_hdac_polling_interval, "I", + "Controller/Jack Sense polling interval (1-1000 ms)"); +#ifdef SND_DEBUG + SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO, + "dump", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev), + sysctl_hdac_dump, "I", "Dump states"); +#endif #endif snprintf(status, SND_STATUSLEN, "at memory 0x%lx irq %ld %s [%s]", @@ -5459,7 +6138,8 @@ hdac_attach2(void *arg) device_printf(sc->dev, "\n"); device_printf(sc->dev, "HDA config/quirks:"); for (i = 0; i < HDAC_QUIRKS_TAB_LEN; i++) { - if (devinfo->function.audio.quirks & + if ((devinfo->function.audio.quirks & + hdac_quirks_tab[i].value) == hdac_quirks_tab[i].value) printf(" %s", hdac_quirks_tab[i].key); } diff --git a/sys/dev/sound/pci/hda/hdac_private.h b/sys/dev/sound/pci/hda/hdac_private.h index ad46367..48b0b55 100644 --- a/sys/dev/sound/pci/hda/hdac_private.h +++ b/sys/dev/sound/pci/hda/hdac_private.h @@ -251,6 +251,7 @@ struct hdac_devinfo { struct hdac_audio_ctl *ctl; uint32_t mvol; uint32_t quirks; + uint32_t gpio; int ossidx; int playcnt, reccnt; int parsing_strategy; @@ -268,6 +269,7 @@ struct hdac_chan { uint32_t spd, fmt, fmtlist[8], pcmrates[16]; uint32_t supp_stream_formats, supp_pcm_size_rate; uint32_t ptr, prevptr, blkcnt, blksz; + uint32_t *dmapos; int active; int dir; int off; @@ -292,6 +294,7 @@ struct hdac_softc { struct hdac_irq irq; uint32_t pci_subvendor; + int nocache; int num_iss; int num_oss; @@ -307,6 +310,8 @@ struct hdac_softc { struct hdac_dma rirb_dma; int rirb_rp; + struct hdac_dma pos_dma; + struct hdac_chan play, rec; bus_dma_tag_t chan_dmat; int chan_size; @@ -317,8 +322,10 @@ struct hdac_softc { */ int polling; int poll_ticks; + int poll_ival; struct callout poll_hda; struct callout poll_hdac; + struct callout poll_jack; #define HDAC_UNSOLQ_MAX 64 #define HDAC_UNSOLQ_READY 0 |