summaryrefslogtreecommitdiffstats
path: root/sys/dev/sound/pci
diff options
context:
space:
mode:
authorariff <ariff@FreeBSD.org>2007-05-05 09:17:36 +0000
committerariff <ariff@FreeBSD.org>2007-05-05 09:17:36 +0000
commitf4b77f9353a9599ccde909b9f397d705e7d0b9b7 (patch)
treeb880db2ce94d3b9b78cfe967dd7771f97521d5a1 /sys/dev/sound/pci
parenta037728652f99e0b41bdb6131e00446ba7a8f5ec (diff)
downloadFreeBSD-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.c1304
-rw-r--r--sys/dev/sound/pci/hda/hdac_private.h7
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
OpenPOWER on IntegriCloud