summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorariff <ariff@FreeBSD.org>2006-10-12 04:19:37 +0000
committerariff <ariff@FreeBSD.org>2006-10-12 04:19:37 +0000
commitebead789319da2ddfca42c73f976127ca987f591 (patch)
tree1bd257fff555e56035cb60205f7e3841650306b8 /sys
parenta44c175cd043cf6351d1b4fd8714b0a915298ecc (diff)
downloadFreeBSD-src-ebead789319da2ddfca42c73f976127ca987f591.zip
FreeBSD-src-ebead789319da2ddfca42c73f976127ca987f591.tar.gz
Fix support for IBM/Lenovo Thinkcentre M52 series. Its vendorid / 0x1014
accidentally match with HP vendorid / 0x103c. Reported by: Robert Noland <rnoland@2hip.net>
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/sound/pci/hda/hdac.c60
1 files changed, 44 insertions, 16 deletions
diff --git a/sys/dev/sound/pci/hda/hdac.c b/sys/dev/sound/pci/hda/hdac.c
index ae7c841..9837243 100644
--- a/sys/dev/sound/pci/hda/hdac.c
+++ b/sys/dev/sound/pci/hda/hdac.c
@@ -113,6 +113,12 @@ SND_DECLARE_FILE("$FreeBSD$");
#define hdac_lockowned(sc) mtx_owned((sc)->lock)
#define HDA_FLAG_MATCH(fl, v) (((fl) & (v)) == (v))
+#define HDA_DEV_MATCH(fl, v) ((fl) == (v) || \
+ (fl) == 0xffffffff || \
+ (((fl) & 0xffff0000) == 0xffff0000 && \
+ ((fl) & 0x0000ffff) == ((v) & 0x0000ffff)) || \
+ (((fl) & 0x0000ffff) == 0x0000ffff && \
+ ((fl) & 0xffff0000) == ((v) & 0xffff0000)))
#define HDA_MATCH_ALL 0xffffffff
#define HDAC_INVALID 0xffffffff
@@ -184,6 +190,11 @@ SND_DECLARE_FILE("$FreeBSD$");
#define ASUS_M5200_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0x1993)
#define ASUS_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(ASUS, 0xffff)
+/* IBM / Lenovo */
+#define IBM_VENDORID 0x1014
+#define IBM_M52_SUBVENDOR HDA_MODEL_CONSTRUCT(IBM, 0x02f6)
+#define IBM_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(IBM, 0xffff)
+
/* Misc constants.. */
#define HDA_AMP_MUTE_DEFAULT (0xffffffff)
@@ -514,7 +525,7 @@ hdac_codec_name(struct hdac_devinfo *devinfo)
id = hdac_codec_id(devinfo);
for (i = 0; i < HDAC_CODECS_LEN; i++) {
- if (HDA_FLAG_MATCH(hdac_codecs[i].id, id))
+ if (HDA_DEV_MATCH(hdac_codecs[i].id, id))
return (hdac_codecs[i].name);
}
@@ -617,7 +628,7 @@ hdac_hp_switch_handler(struct hdac_devinfo *devinfo)
cad = devinfo->codec->cad;
id = hdac_codec_id(devinfo);
for (i = 0; i < HDAC_HP_SWITCH_LEN; i++) {
- if (HDA_FLAG_MATCH(hdac_hp_switch[i].model,
+ if (HDA_DEV_MATCH(hdac_hp_switch[i].model,
sc->pci_subvendor) &&
hdac_hp_switch[i].id == id)
break;
@@ -2231,7 +2242,8 @@ static int
hdac_probe(device_t dev)
{
int i, result;
- uint32_t model, class, subclass;
+ uint32_t model;
+ uint16_t class, subclass;
char desc[64];
model = (uint32_t)pci_get_device(dev) << 16;
@@ -2247,7 +2259,7 @@ hdac_probe(device_t dev)
result = BUS_PROBE_DEFAULT;
break;
}
- if (HDA_FLAG_MATCH(hdac_devices[i].model, model) &&
+ if (HDA_DEV_MATCH(hdac_devices[i].model, model) &&
class == PCIC_MULTIMEDIA &&
subclass == PCIS_MULTIMEDIA_HDA) {
strlcpy(desc, hdac_devices[i].desc, sizeof(desc));
@@ -2525,7 +2537,7 @@ hdac_audio_ctl_ossmixer_init(struct snd_mixer *m)
id = hdac_codec_id(devinfo);
cad = devinfo->codec->cad;
for (i = 0; i < HDAC_HP_SWITCH_LEN; i++) {
- if (!(HDA_FLAG_MATCH(hdac_hp_switch[i].model,
+ if (!(HDA_DEV_MATCH(hdac_hp_switch[i].model,
sc->pci_subvendor) &&
hdac_hp_switch[i].id == id))
continue;
@@ -2554,7 +2566,7 @@ hdac_audio_ctl_ossmixer_init(struct snd_mixer *m)
break;
}
for (i = 0; i < HDAC_EAPD_SWITCH_LEN; i++) {
- if (!(HDA_FLAG_MATCH(hdac_eapd_switch[i].model,
+ if (!(HDA_DEV_MATCH(hdac_eapd_switch[i].model,
sc->pci_subvendor) &&
hdac_eapd_switch[i].id == id))
continue;
@@ -2673,13 +2685,14 @@ hdac_audio_ctl_ossmixer_set(struct snd_mixer *m, unsigned dev,
hdac_lock(sc);
if (dev == SOUND_MIXER_OGAIN) {
+ uint32_t orig;
/*if (left != right || !(left == 0 || left == 1)) {
hdac_unlock(sc);
return (-1);
}*/
id = hdac_codec_id(devinfo);
for (i = 0; i < HDAC_EAPD_SWITCH_LEN; i++) {
- if (HDA_FLAG_MATCH(hdac_eapd_switch[i].model,
+ if (HDA_DEV_MATCH(hdac_eapd_switch[i].model,
sc->pci_subvendor) &&
hdac_eapd_switch[i].id == id)
break;
@@ -2695,15 +2708,18 @@ hdac_audio_ctl_ossmixer_set(struct snd_mixer *m, unsigned dev,
hdac_unlock(sc);
return (-1);
}
+ orig = w->param.eapdbtl;
if (left == 0)
w->param.eapdbtl &= ~HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
else
w->param.eapdbtl |= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
- if (hdac_eapd_switch[i].hp_switch != 0)
- hdac_hp_switch_handler(devinfo);
- hdac_command(sc,
- HDA_CMD_SET_EAPD_BTL_ENABLE(devinfo->codec->cad, w->nid,
- w->param.eapdbtl), devinfo->codec->cad);
+ if (orig != w->param.eapdbtl) {
+ if (hdac_eapd_switch[i].hp_switch != 0)
+ hdac_hp_switch_handler(devinfo);
+ hdac_command(sc,
+ HDA_CMD_SET_EAPD_BTL_ENABLE(devinfo->codec->cad,
+ w->nid, w->param.eapdbtl), devinfo->codec->cad);
+ }
hdac_unlock(sc);
return (left | (left << 8));
}
@@ -2844,8 +2860,8 @@ hdac_attach(device_t dev)
}
sc->dev = dev;
- sc->pci_subvendor = pci_get_subdevice(sc->dev) << 16;
- sc->pci_subvendor |= pci_get_subvendor(sc->dev);
+ sc->pci_subvendor = (uint32_t)pci_get_subdevice(sc->dev) << 16;
+ sc->pci_subvendor |= (uint32_t)pci_get_subvendor(sc->dev) & 0x0000ffff;
sc->chan_size = pcm_getbuffersize(dev,
HDA_BUFSZ_MIN, HDA_BUFSZ_DEFAULT, HDA_BUFSZ_DEFAULT);
@@ -3236,8 +3252,8 @@ hdac_vendor_patch_parse(struct hdac_devinfo *devinfo)
* Quirks
*/
for (i = 0; i < HDAC_QUIRKS_LEN; i++) {
- if (!(HDA_FLAG_MATCH(hdac_quirks[i].model, subvendor) &&
- HDA_FLAG_MATCH(hdac_quirks[i].id, id)))
+ if (!(HDA_DEV_MATCH(hdac_quirks[i].model, subvendor) &&
+ HDA_DEV_MATCH(hdac_quirks[i].id, id)))
continue;
if (hdac_quirks[i].set != 0)
devinfo->function.audio.quirks |=
@@ -3283,6 +3299,18 @@ hdac_vendor_patch_parse(struct hdac_devinfo *devinfo)
}
}
break;
+ case HDA_CODEC_AD1981HD:
+ w = hdac_widget_get(devinfo, 11);
+ if (w != NULL && w->enable != 0 && w->nconns > 3)
+ w->selconn = 3;
+ if (subvendor == IBM_M52_SUBVENDOR) {
+ struct hdac_audio_ctl *ctl;
+
+ ctl = hdac_audio_ctl_amp_get(devinfo, 7, 0, 1);
+ if (ctl != NULL)
+ ctl->ossmask = SOUND_MASK_SPEAKER;
+ }
+ break;
case HDA_CODEC_AD1986A:
for (i = devinfo->startnode; i < devinfo->endnode; i++) {
w = hdac_widget_get(devinfo, i);
OpenPOWER on IntegriCloud