aboutsummaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2009-06-10 07:26:31 +0200
committerTakashi Iwai <tiwai@suse.de>2009-06-10 07:26:31 +0200
commit81ad969dbf8b10c3e79c5811b8328c054c21ef39 (patch)
tree88f9d582d9c88dcb65f203160ee5701c1514ccb6 /sound
parent2f0dabcc5f5fde67c64a6f71e9fb369aed39d56f (diff)
parentf03ecf50534a81b06544c58a713076d59d54baf9 (diff)
Merge branch 'topic/hda' into for-linus
* topic/hda: (51 commits) ALSA: hda - Fix the previous tagra-8ch patch ALSA: hda - Add 7.1 support for MSI GX620 ALSA: support Sony Vaio TT ALSA: hda_intel: fix build error when !PM ALSA: hda - More Aspire 8930G fixes ALSA: hda - Acer Aspire 8930G support ALSA: hda - Limit codec-verb retry to limited hardwares ALSA: hda - Add codec bus reset and verb-retry at critical errors ALSA: hda - Reorder and clean-up ALC268 quirk table ALSA: hda - fix audio on LG R510 ALSA: hda - Macbook[Pro] 5 6ch support ALSA: hda-intel: improve initialization for ALC262_HP_BPC model ALSA: hda - Jack Mode changes for Sigmatel boards ALSA: hda - Support NVIDIA 8 channel HDMI audio ALSA: hda - Fix a typo in the previous patch ALSA: hda - Fix reverted LED setup for HP ALSA: hda - Add more register bits definitions ALSA: hda - Always sync writes in single_cmd mode ALSA: hda - Support sync after writing a verb ALSA: hda - Allow concurrent RIRB access in single_cmd mode ...
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/hda/Kconfig13
-rw-r--r--sound/pci/hda/Makefile4
-rw-r--r--sound/pci/hda/hda_beep.c55
-rw-r--r--sound/pci/hda/hda_beep.h5
-rw-r--r--sound/pci/hda/hda_codec.c239
-rw-r--r--sound/pci/hda/hda_codec.h13
-rw-r--r--sound/pci/hda/hda_hwdep.c9
-rw-r--r--sound/pci/hda/hda_intel.c197
-rw-r--r--sound/pci/hda/hda_proc.c8
-rw-r--r--sound/pci/hda/patch_ca0110.c573
-rw-r--r--sound/pci/hda/patch_nvhdmi.c279
-rw-r--r--sound/pci/hda/patch_realtek.c2328
-rw-r--r--sound/pci/hda/patch_sigmatel.c275
-rw-r--r--sound/pci/hda/patch_via.c111
14 files changed, 2779 insertions, 1330 deletions
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index eb2a19b894a..c710150d506 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -139,6 +139,19 @@ config SND_HDA_CODEC_CONEXANT
snd-hda-codec-conexant.
This module is automatically loaded at probing.
+config SND_HDA_CODEC_CA0110
+ bool "Build Creative CA0110-IBG codec support"
+ depends on SND_HDA_INTEL
+ default y
+ help
+ Say Y here to include Creative CA0110-IBG codec support in
+ snd-hda-intel driver, found on some Creative X-Fi cards.
+
+ When the HD-audio driver is built as a module, the codec
+ support code is also built as another module,
+ snd-hda-codec-ca0110.
+ This module is automatically loaded at probing.
+
config SND_HDA_CODEC_CMEDIA
bool "Build C-Media HD-audio codec support"
default y
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index 50f9d096725..e3081d4586c 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -13,6 +13,7 @@ snd-hda-codec-analog-objs := patch_analog.o
snd-hda-codec-idt-objs := patch_sigmatel.o
snd-hda-codec-si3054-objs := patch_si3054.o
snd-hda-codec-atihdmi-objs := patch_atihdmi.o
+snd-hda-codec-ca0110-objs := patch_ca0110.o
snd-hda-codec-conexant-objs := patch_conexant.o
snd-hda-codec-via-objs := patch_via.o
snd-hda-codec-nvhdmi-objs := patch_nvhdmi.o
@@ -40,6 +41,9 @@ endif
ifdef CONFIG_SND_HDA_CODEC_ATIHDMI
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o
endif
+ifdef CONFIG_SND_HDA_CODEC_CA0110
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0110.o
+endif
ifdef CONFIG_SND_HDA_CODEC_CONEXANT
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-conexant.o
endif
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
index 4de5bacd392..29272f2e95a 100644
--- a/sound/pci/hda/hda_beep.c
+++ b/sound/pci/hda/hda_beep.c
@@ -45,6 +45,46 @@ static void snd_hda_generate_beep(struct work_struct *work)
AC_VERB_SET_BEEP_CONTROL, beep->tone);
}
+/* (non-standard) Linear beep tone calculation for IDT/STAC codecs
+ *
+ * The tone frequency of beep generator on IDT/STAC codecs is
+ * defined from the 8bit tone parameter, in Hz,
+ * freq = 48000 * (257 - tone) / 1024
+ * that is from 12kHz to 93.75kHz in step of 46.875 hz
+ */
+static int beep_linear_tone(struct hda_beep *beep, int hz)
+{
+ hz *= 1000; /* fixed point */
+ hz = hz - DIGBEEP_HZ_MIN;
+ if (hz < 0)
+ hz = 0; /* turn off PC beep*/
+ else if (hz >= (DIGBEEP_HZ_MAX - DIGBEEP_HZ_MIN))
+ hz = 0xff;
+ else {
+ hz /= DIGBEEP_HZ_STEP;
+ hz++;
+ }
+ return hz;
+}
+
+/* HD-audio standard beep tone parameter calculation
+ *
+ * The tone frequency in Hz is calculated as
+ * freq = 48000 / (tone * 4)
+ * from 47Hz to 12kHz
+ */
+static int beep_standard_tone(struct hda_beep *beep, int hz)
+{
+ if (hz <= 0)
+ return 0; /* disabled */
+ hz = 12000 / hz;
+ if (hz > 0xff)
+ return 0xff;
+ if (hz <= 0)
+ return 1;
+ return hz;
+}
+
static int snd_hda_beep_event(struct input_dev *dev, unsigned int type,
unsigned int code, int hz)
{
@@ -55,21 +95,14 @@ static int snd_hda_beep_event(struct input_dev *dev, unsigned int type,
if (hz)
hz = 1000;
case SND_TONE:
- hz *= 1000; /* fixed point */
- hz = hz - DIGBEEP_HZ_MIN;
- if (hz < 0)
- hz = 0; /* turn off PC beep*/
- else if (hz >= (DIGBEEP_HZ_MAX - DIGBEEP_HZ_MIN))
- hz = 0xff;
- else {
- hz /= DIGBEEP_HZ_STEP;
- hz++;
- }
+ if (beep->linear_tone)
+ beep->tone = beep_linear_tone(beep, hz);
+ else
+ beep->tone = beep_standard_tone(beep, hz);
break;
default:
return -1;
}
- beep->tone = hz;
/* schedule beep event */
schedule_work(&beep->beep_work);
diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h
index 51bf6a5daf3..0c3de787c71 100644
--- a/sound/pci/hda/hda_beep.h
+++ b/sound/pci/hda/hda_beep.h
@@ -30,8 +30,9 @@ struct hda_beep {
struct hda_codec *codec;
char phys[32];
int tone;
- int nid;
- int enabled;
+ hda_nid_t nid;
+ unsigned int enabled:1;
+ unsigned int linear_tone:1; /* linear tone for IDT/STAC codec */
struct work_struct beep_work; /* scheduled task for beep event */
};
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 8820faf6c9d..562403a2348 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -48,6 +48,7 @@ static struct hda_vendor_id hda_vendor_ids[] = {
{ 0x1095, "Silicon Image" },
{ 0x10de, "Nvidia" },
{ 0x10ec, "Realtek" },
+ { 0x1102, "Creative" },
{ 0x1106, "VIA" },
{ 0x111d, "IDT" },
{ 0x11c1, "LSI" },
@@ -157,6 +158,39 @@ make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
return val;
}
+/*
+ * Send and receive a verb
+ */
+static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
+ unsigned int *res)
+{
+ struct hda_bus *bus = codec->bus;
+ int err;
+
+ if (res)
+ *res = -1;
+ again:
+ snd_hda_power_up(codec);
+ mutex_lock(&bus->cmd_mutex);
+ err = bus->ops.command(bus, cmd);
+ if (!err && res)
+ *res = bus->ops.get_response(bus);
+ mutex_unlock(&bus->cmd_mutex);
+ snd_hda_power_down(codec);
+ if (res && *res == -1 && bus->rirb_error) {
+ if (bus->response_reset) {
+ snd_printd("hda_codec: resetting BUS due to "
+ "fatal communication error\n");
+ bus->ops.bus_reset(bus);
+ }
+ goto again;
+ }
+ /* clear reset-flag when the communication gets recovered */
+ if (!err)
+ bus->response_reset = 0;
+ return err;
+}
+
/**
* snd_hda_codec_read - send a command and get the response
* @codec: the HDA codec
@@ -173,18 +207,9 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid,
int direct,
unsigned int verb, unsigned int parm)
{
- struct hda_bus *bus = codec->bus;
+ unsigned cmd = make_codec_cmd(codec, nid, direct, verb, parm);
unsigned int res;
-
- res = make_codec_cmd(codec, nid, direct, verb, parm);
- snd_hda_power_up(codec);
- mutex_lock(&bus->cmd_mutex);
- if (!bus->ops.command(bus, res))
- res = bus->ops.get_response(bus);
- else
- res = (unsigned int)-1;
- mutex_unlock(&bus->cmd_mutex);
- snd_hda_power_down(codec);
+ codec_exec_verb(codec, cmd, &res);
return res;
}
EXPORT_SYMBOL_HDA(snd_hda_codec_read);
@@ -204,17 +229,10 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_read);
int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct,
unsigned int verb, unsigned int parm)
{
- struct hda_bus *bus = codec->bus;
+ unsigned int cmd = make_codec_cmd(codec, nid, direct, verb, parm);
unsigned int res;
- int err;
-
- res = make_codec_cmd(codec, nid, direct, verb, parm);
- snd_hda_power_up(codec);
- mutex_lock(&bus->cmd_mutex);
- err = bus->ops.command(bus, res);
- mutex_unlock(&bus->cmd_mutex);
- snd_hda_power_down(codec);
- return err;
+ return codec_exec_verb(codec, cmd,
+ codec->bus->sync_write ? &res : NULL);
}
EXPORT_SYMBOL_HDA(snd_hda_codec_write);
@@ -613,7 +631,10 @@ static int get_codec_name(struct hda_codec *codec)
const struct hda_vendor_id *c;
const char *vendor = NULL;
u16 vendor_id = codec->vendor_id >> 16;
- char tmp[16], name[32];
+ char tmp[16];
+
+ if (codec->vendor_name)
+ goto get_chip_name;
for (c = hda_vendor_ids; c->id; c++) {
if (c->id == vendor_id) {
@@ -625,14 +646,21 @@ static int get_codec_name(struct hda_codec *codec)
sprintf(tmp, "Generic %04x", vendor_id);
vendor = tmp;
}
+ codec->vendor_name = kstrdup(vendor, GFP_KERNEL);
+ if (!codec->vendor_name)
+ return -ENOMEM;
+
+ get_chip_name:
+ if (codec->chip_name)
+ return 0;
+
if (codec->preset && codec->preset->name)
- snprintf(name, sizeof(name), "%s %s", vendor,
- codec->preset->name);
- else
- snprintf(name, sizeof(name), "%s ID %x", vendor,
- codec->vendor_id & 0xffff);
- codec->name = kstrdup(name, GFP_KERNEL);
- if (!codec->name)
+ codec->chip_name = kstrdup(codec->preset->name, GFP_KERNEL);
+ else {
+ sprintf(tmp, "ID %x", codec->vendor_id & 0xffff);
+ codec->chip_name = kstrdup(tmp, GFP_KERNEL);
+ }
+ if (!codec->chip_name)
return -ENOMEM;
return 0;
}
@@ -838,7 +866,8 @@ static void snd_hda_codec_free(struct hda_codec *codec)
module_put(codec->owner);
free_hda_cache(&codec->amp_cache);
free_hda_cache(&codec->cmd_cache);
- kfree(codec->name);
+ kfree(codec->vendor_name);
+ kfree(codec->chip_name);
kfree(codec->modelname);
kfree(codec->wcaps);
kfree(codec);
@@ -979,15 +1008,16 @@ int snd_hda_codec_configure(struct hda_codec *codec)
int err;
codec->preset = find_codec_preset(codec);
- if (!codec->name) {
+ if (!codec->vendor_name || !codec->chip_name) {
err = get_codec_name(codec);
if (err < 0)
return err;
}
/* audio codec should override the mixer name */
if (codec->afg || !*codec->bus->card->mixername)
- strlcpy(codec->bus->card->mixername, codec->name,
- sizeof(codec->bus->card->mixername));
+ snprintf(codec->bus->card->mixername,
+ sizeof(codec->bus->card->mixername),
+ "%s %s", codec->vendor_name, codec->chip_name);
if (is_generic_config(codec)) {
err = snd_hda_parse_generic_codec(codec);
@@ -1055,6 +1085,8 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream);
/* FIXME: more better hash key? */
#define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24))
#define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24))
+#define HDA_HASH_PARPCM_KEY(nid) (u32)((nid) + (0x03 << 24))
+#define HDA_HASH_PARSTR_KEY(nid) (u32)((nid) + (0x04 << 24))
#define INFO_AMP_CAPS (1<<0)
#define INFO_AMP_VOL(ch) (1 << (1 + (ch)))
@@ -1145,19 +1177,32 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
}
EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps);
-u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
+static unsigned int
+query_caps_hash(struct hda_codec *codec, hda_nid_t nid, u32 key,
+ unsigned int (*func)(struct hda_codec *, hda_nid_t))
{
struct hda_amp_info *info;
- info = get_alloc_amp_hash(codec, HDA_HASH_PINCAP_KEY(nid));
+ info = get_alloc_amp_hash(codec, key);
if (!info)
return 0;
if (!info->head.val) {
- info->amp_caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
info->head.val |= INFO_AMP_CAPS;
+ info->amp_caps = func(codec, nid);
}
return info->amp_caps;
}
+
+static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid)
+{
+ return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+}
+
+u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
+{
+ return query_caps_hash(codec, nid, HDA_HASH_PINCAP_KEY(nid),
+ read_pin_cap);
+}
EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps);
/*
@@ -1432,6 +1477,8 @@ _snd_hda_find_mixer_ctl(struct hda_codec *codec,
memset(&id, 0, sizeof(id));
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
id.index = idx;
+ if (snd_BUG_ON(strlen(name) >= sizeof(id.name)))
+ return NULL;
strcpy(id.name, name);
return snd_ctl_find_id(codec->bus->card, &id);
}
@@ -2242,28 +2289,22 @@ EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls);
int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
int direct, unsigned int verb, unsigned int parm)
{
- struct hda_bus *bus = codec->bus;
- unsigned int res;
- int err;
+ int err = snd_hda_codec_write(codec, nid, direct, verb, parm);
+ struct hda_cache_head *c;
+ u32 key;
- res = make_codec_cmd(codec, nid, direct, verb, parm);
- snd_hda_power_up(codec);
- mutex_lock(&bus->cmd_mutex);
- err = bus->ops.command(bus, res);
- if (!err) {
- struct hda_cache_head *c;
- u32 key;
- /* parm may contain the verb stuff for get/set amp */
- verb = verb | (parm >> 8);
- parm &= 0xff;
- key = build_cmd_cache_key(nid, verb);
- c = get_alloc_hash(&codec->cmd_cache, key);
- if (c)
- c->val = parm;
- }
- mutex_unlock(&bus->cmd_mutex);
- snd_hda_power_down(codec);
- return err;
+ if (err < 0)
+ return err;
+ /* parm may contain the verb stuff for get/set amp */
+ verb = verb | (parm >> 8);
+ parm &= 0xff;
+ key = build_cmd_cache_key(nid, verb);
+ mutex_lock(&codec->bus->cmd_mutex);
+ c = get_alloc_hash(&codec->cmd_cache, key);
+ if (c)
+ c->val = parm;
+ mutex_unlock(&codec->bus->cmd_mutex);
+ return 0;
}
EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache);
@@ -2321,7 +2362,8 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
if (wcaps & AC_WCAP_POWER) {
unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >>
AC_WCAP_TYPE_SHIFT;
- if (wid_type == AC_WID_PIN) {
+ if (power_state == AC_PWRST_D3 &&
+ wid_type == AC_WID_PIN) {
unsigned int pincap;
/*
* don't power down the widget if it controls
@@ -2333,7 +2375,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
nid, 0,
AC_VERB_GET_EAPD_BTLENABLE, 0);
eapd &= 0x02;
- if (power_state == AC_PWRST_D3 && eapd)
+ if (eapd)
continue;
}
}
@@ -2544,6 +2586,41 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
}
EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format);
+static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid)
+{
+ unsigned int val = 0;
+ if (nid != codec->afg &&
+ (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD))
+ val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
+ if (!val || val == -1)
+ val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
+ if (!val || val == -1)
+ return 0;
+ return val;
+}
+
+static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid)
+{
+ return query_caps_hash(codec, nid, HDA_HASH_PARPCM_KEY(nid),
+ get_pcm_param);
+}
+
+static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid)
+{
+ unsigned int streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
+ if (!streams || streams == -1)
+ streams = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM);
+ if (!streams || streams == -1)
+ return 0;
+ return streams;
+}
+
+static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid)
+{
+ return query_caps_hash(codec, nid, HDA_HASH_PARSTR_KEY(nid),
+ get_stream_param);
+}
+
/**
* snd_hda_query_supported_pcm - query the supported PCM rates and formats
* @codec: the HDA codec
@@ -2562,15 +2639,8 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
{
unsigned int i, val, wcaps;
- val = 0;
wcaps = get_wcaps(codec, nid);
- if (nid != codec->afg && (wcaps & AC_WCAP_FORMAT_OVRD)) {
- val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
- if (val == -1)
- return -EIO;
- }
- if (!val)
- val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
+ val = query_pcm_param(codec, nid);
if (ratesp) {
u32 rates = 0;
@@ -2592,15 +2662,9 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
u64 formats = 0;
unsigned int streams, bps;
- streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
- if (streams == -1)
+ streams = query_stream_param(codec, nid);
+ if (!streams)
return -EIO;
- if (!streams) {
- streams = snd_hda_param_read(codec, codec->afg,
- AC_PAR_STREAM);
- if (streams == -1)
- return -EIO;
- }
bps = 0;
if (streams & AC_SUPFMT_PCM) {
@@ -2674,17 +2738,9 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
int i;
unsigned int val = 0, rate, stream;
- if (nid != codec->afg &&
- (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) {
- val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
- if (val == -1)
- return 0;
- }
- if (!val) {
- val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM);
- if (val == -1)
- return 0;
- }
+ val = query_pcm_param(codec, nid);
+ if (!val)
+ return 0;
rate = format & 0xff00;
for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++)
@@ -2696,12 +2752,8 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
if (i >= AC_PAR_PCM_RATE_BITS)
return 0;
- stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
- if (stream == -1)
- return 0;
- if (!stream && nid != codec->afg)
- stream = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM);
- if (!stream || stream == -1)
+ stream = query_stream_param(codec, nid);
+ if (!stream)
return 0;
if (stream & AC_SUPFMT_PCM) {
@@ -3835,11 +3887,10 @@ EXPORT_SYMBOL_HDA(auto_pin_cfg_labels);
/**
* snd_hda_suspend - suspend the codecs
* @bus: the HDA bus
- * @state: suspsend state
*
* Returns 0 if successful.
*/
-int snd_hda_suspend(struct hda_bus *bus, pm_message_t state)
+int snd_hda_suspend(struct hda_bus *bus)
{
struct hda_codec *codec;
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 2fdecf4b0eb..cad79efaabc 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -574,6 +574,8 @@ struct hda_bus_ops {
/* attach a PCM stream */
int (*attach_pcm)(struct hda_bus *bus, struct hda_codec *codec,
struct hda_pcm *pcm);
+ /* reset bus for retry verb */
+ void (*bus_reset)(struct hda_bus *bus);
#ifdef CONFIG_SND_HDA_POWER_SAVE
/* notify power-up/down from codec to controller */
void (*pm_notify)(struct hda_bus *bus);
@@ -622,7 +624,13 @@ struct hda_bus {
/* misc op flags */
unsigned int needs_damn_long_delay :1;
+ unsigned int allow_bus_reset:1; /* allow bus reset at fatal error */
+ unsigned int sync_write:1; /* sync after verb write */
+ /* status for codec/controller */
unsigned int shutdown :1; /* being unloaded */
+ unsigned int rirb_error:1; /* error in codec communication */
+ unsigned int response_reset:1; /* controller was reset */
+ unsigned int in_reset:1; /* during reset operation */
};
/*
@@ -747,7 +755,8 @@ struct hda_codec {
/* detected preset */
const struct hda_codec_preset *preset;
struct module *owner;
- const char *name; /* codec name */
+ const char *vendor_name; /* codec vendor name */
+ const char *chip_name; /* codec chip name */
const char *modelname; /* model name for preset */
/* set by patch */
@@ -905,7 +914,7 @@ void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen);
* power management
*/
#ifdef CONFIG_PM
-int snd_hda_suspend(struct hda_bus *bus, pm_message_t state);
+int snd_hda_suspend(struct hda_bus *bus);
int snd_hda_resume(struct hda_bus *bus);
#endif
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index 1c57505c287..6812fbe80fa 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -242,7 +242,8 @@ CODEC_INFO_SHOW(subsystem_id);
CODEC_INFO_SHOW(revision_id);
CODEC_INFO_SHOW(afg);
CODEC_INFO_SHOW(mfg);
-CODEC_INFO_STR_SHOW(name);
+CODEC_INFO_STR_SHOW(vendor_name);
+CODEC_INFO_STR_SHOW(chip_name);
CODEC_INFO_STR_SHOW(modelname);
#define CODEC_INFO_STORE(type) \
@@ -275,7 +276,8 @@ static ssize_t type##_store(struct device *dev, \
CODEC_INFO_STORE(vendor_id);
CODEC_INFO_STORE(subsystem_id);
CODEC_INFO_STORE(revision_id);
-CODEC_INFO_STR_STORE(name);
+CODEC_INFO_STR_STORE(vendor_name);
+CODEC_INFO_STR_STORE(chip_name);
CODEC_INFO_STR_STORE(modelname);
#define CODEC_ACTION_STORE(type) \
@@ -499,7 +501,8 @@ static struct device_attribute codec_attrs[] = {
CODEC_ATTR_RW(revision_id),
CODEC_ATTR_RO(afg),
CODEC_ATTR_RO(mfg),
- CODEC_ATTR_RW(name),
+ CODEC_ATTR_RW(vendor_name),
+ CODEC_ATTR_RW(chip_name),
CODEC_ATTR_RW(modelname),
CODEC_ATTR_RW(init_verbs),
CODEC_ATTR_RW(hints),
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 3128e1a6bc6..4e9ea708027 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -128,21 +128,33 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
"{ULI, M5461}}");
MODULE_DESCRIPTION("Intel HDA driver");
+#ifdef CONFIG_SND_VERBOSE_PRINTK
+#define SFX /* nop */
+#else
#define SFX "hda-intel: "
-
+#endif
/*
* registers
*/
#define ICH6_REG_GCAP 0x00
+#define ICH6_GCAP_64OK (1 << 0) /* 64bit address support */
+#define ICH6_GCAP_NSDO (3 << 1) /* # of serial data out signals */
+#define ICH6_GCAP_BSS (31 << 3) /* # of bidirectional streams */
+#define ICH6_GCAP_ISS (15 << 8) /* # of input streams */
+#define ICH6_GCAP_OSS (15 << 12) /* # of output streams */
#define ICH6_REG_VMIN 0x02
#define ICH6_REG_VMAJ 0x03
#define ICH6_REG_OUTPAY 0x04
#define ICH6_REG_INPAY 0x06
#define ICH6_REG_GCTL 0x08
+#define ICH6_GCTL_RESET (1 << 0) /* controller reset */
+#define ICH6_GCTL_FCNTRL (1 << 1) /* flush control */
+#define ICH6_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */
#define ICH6_REG_WAKEEN 0x0c
#define ICH6_REG_STATESTS 0x0e
#define ICH6_REG_GSTS 0x10
+#define ICH6_GSTS_FSTS (1 << 1) /* flush status */
#define ICH6_REG_INTCTL 0x20
#define ICH6_REG_INTSTS 0x24
#define ICH6_REG_WALCLK 0x30
@@ -150,17 +162,27 @@ MODULE_DESCRIPTION("Intel HDA driver");
#define ICH6_REG_CORBLBASE 0x40
#define ICH6_REG_CORBUBASE 0x44
#define ICH6_REG_CORBWP 0x48
-#define ICH6_REG_CORBRP 0x4A
+#define ICH6_REG_CORBRP 0x4a
+#define ICH6_CORBRP_RST (1 << 15) /* read pointer reset */
#define ICH6_REG_CORBCTL 0x4c
+#define ICH6_CORBCTL_RUN (1 << 1) /* enable DMA */
+#define ICH6_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */
#define ICH6_REG_CORBSTS 0x4d
+#define ICH6_CORBSTS_CMEI (1 << 0) /* memory error indication */
#define ICH6_REG_CORBSIZE 0x4e
#define ICH6_REG_RIRBLBASE 0x50
#define ICH6_REG_RIRBUBASE 0x54
#define ICH6_REG_RIRBWP 0x58
+#define ICH6_RIRBWP_RST (1 << 15) /* write pointer reset */
#define ICH6_REG_RINTCNT 0x5a
#define ICH6_REG_RIRBCTL 0x5c
+#define ICH6_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */
+#define ICH6_RBCTL_DMA_EN (1 << 1) /* enable DMA */
+#define ICH6_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */
#define ICH6_REG_RIRBSTS 0x5d
+#define ICH6_RBSTS_IRQ (1 << 0) /* response irq */
+#define ICH6_RBSTS_OVERRUN (1 << 2) /* overrun irq */
#define ICH6_REG_RIRBSIZE 0x5e
#define ICH6_REG_IC 0x60
@@ -257,16 +279,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */
#define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */
-/* GCTL unsolicited response enable bit */
-#define ICH6_GCTL_UREN (1<<8)
-
-/* GCTL reset bit */
-#define ICH6_GCTL_RESET (1<<0)
-
-/* CORB/RIRB control, read/write pointer */
-#define ICH6_RBCTL_DMA_EN 0x02 /* enable DMA */
-#define ICH6_RBCTL_IRQ_EN 0x01 /* enable IRQ */
-#define ICH6_RBRWP_CLR 0x8000 /* read/write pointer clear */
/* below are so far hardcoded - should read registers in future */
#define ICH6_MAX_CORB_ENTRIES 256
#define ICH6_MAX_RIRB_ENTRIES 256
@@ -512,25 +524,25 @@ static void azx_init_cmd_io(struct azx *chip)
/* set the corb write pointer to 0 */
azx_writew(chip, CORBWP, 0);
/* reset the corb hw read pointer */
- azx_writew(chip, CORBRP, ICH6_RBRWP_CLR);
+ azx_writew(chip, CORBRP, ICH6_CORBRP_RST);
/* enable corb dma */
- azx_writeb(chip, CORBCTL, ICH6_RBCTL_DMA_EN);
+ azx_writeb(chip, CORBCTL, ICH6_CORBCTL_RUN);
/* RIRB set up */
chip->rirb.addr = chip->rb.addr + 2048;
chip->rirb.buf = (u32 *)(chip->rb.area + 2048);
+ chip->rirb.wp = chip->rirb.rp = chip->rirb.cmds = 0;
azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr);
azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr));
/* set the rirb size to 256 entries (ULI requires explicitly) */
azx_writeb(chip, RIRBSIZE, 0x02);
/* reset the rirb hw write pointer */
- azx_writew(chip, RIRBWP, ICH6_RBRWP_CLR);
+ azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST);
/* set N=1, get RIRB response interrupt for new entry */
azx_writew(chip, RINTCNT, 1);
/* enable rirb dma and response irq */
azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN);
- chip->rirb.rp = chip->rirb.cmds = 0;
}
static void azx_free_cmd_io(struct azx *chip)
@@ -606,6 +618,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus)
}
if (!chip->rirb.cmds) {
smp_rmb();
+ bus->rirb_error = 0;
return chip->rirb.res; /* the last value */
}
if (time_after(jiffies, timeout))
@@ -619,19 +632,21 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus)
}
if (chip->msi) {
- snd_printk(KERN_WARNING "hda_intel: No response from codec, "
+ snd_printk(KERN_WARNING SFX "No response from codec, "
"disabling MSI: last cmd=0x%08x\n", chip->last_cmd);
free_irq(chip->irq, chip);
chip->irq = -1;
pci_disable_msi(chip->pci);
chip->msi = 0;
- if (azx_acquire_irq(chip, 1) < 0)
+ if (azx_acquire_irq(chip, 1) < 0) {
+ bus->rirb_error = 1;
return -1;
+ }
goto again;
}
if (!chip->polling_mode) {
- snd_printk(KERN_WARNING "hda_intel: azx_get_response timeout, "
+ snd_printk(KERN_WARNING SFX "azx_get_response timeout, "
"switching to polling mode: last cmd=0x%08x\n",
chip->last_cmd);
chip->polling_mode = 1;
@@ -646,14 +661,23 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus)
return -1;
}
+ /* a fatal communication error; need either to reset or to fallback
+ * to the single_cmd mode
+ */
+ bus->rirb_error = 1;
+ if (bus->allow_bus_reset && !bus->response_reset && !bus->in_reset) {
+ bus->response_reset = 1;
+ return -1; /* give a chance to retry */
+ }
+
snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, "
"switching to single_cmd mode: last cmd=0x%08x\n",
chip->last_cmd);
- chip->rirb.rp = azx_readb(chip, RIRBWP);
- chip->rirb.cmds = 0;
- /* switch to single_cmd mode */
chip->single_cmd = 1;
+ bus->response_reset = 0;
+ /* re-initialize CORB/RIRB */
azx_free_cmd_io(chip);
+ azx_init_cmd_io(chip);
return -1;
}
@@ -667,12 +691,34 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus)
* I left the codes, however, for debugging/testing purposes.
*/
+/* receive a response */
+static int azx_single_wait_for_response(struct azx *chip)
+{
+ int timeout = 50;
+
+ while (timeout--) {
+ /* check IRV busy bit */
+ if (azx_readw(chip, IRS) & ICH6_IRS_VALID) {
+ /* reuse rirb.res as the response return value */
+ chip->rirb.res = azx_readl(chip, IR);
+ return 0;
+ }
+ udelay(1);
+ }
+ if (printk_ratelimit())
+ snd_printd(SFX "get_response timeout: IRS=0x%x\n",
+ azx_readw(chip, IRS));
+ chip->rirb.res = -1;
+ return -EIO;
+}
+
/* send a command */
static int azx_single_send_cmd(struct hda_bus *bus, u32 val)
{
struct azx *chip = bus->private_data;
int timeout = 50;
+ bus->rirb_error = 0;
while (timeout--) {
/* check ICB busy bit */
if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) {
@@ -682,7 +728,7 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val)
azx_writel(chip, IC, val);
azx_writew(chip, IRS, azx_readw(chip, IRS) |
ICH6_IRS_BUSY);
- return 0;
+ return azx_single_wait_for_response(chip);
}
udelay(1);
}
@@ -696,18 +742,7 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val)
static unsigned int azx_single_get_response(struct hda_bus *bus)
{
struct azx *chip = bus->private_data;
- int timeout = 50;
-
- while (timeout--) {
- /* check IRV busy bit */
- if (azx_readw(chip, IRS) & ICH6_IRS_VALID)
- return azx_readl(chip, IR);
- udelay(1);
- }
- if (printk_ratelimit())
- snd_printd(SFX "get_response timeout: IRS=0x%x\n",
- azx_readw(chip, IRS));
- return (unsigned int)-1;
+ return chip->rirb.res;
}
/*
@@ -775,17 +810,17 @@ static int azx_reset(struct azx *chip)
/* check to see if controller is ready */
if (!azx_readb(chip, GCTL)) {
- snd_printd("azx_reset: controller not ready!\n");
+ snd_printd(SFX "azx_reset: controller not ready!\n");
return -EBUSY;
}
/* Accept unsolicited responses */
- azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UREN);
+ azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UNSOL);
/* detect codecs */
if (!chip->codec_mask) {
chip->codec_mask = azx_readw(chip, STATESTS);
- snd_printdd("codec_mask = 0x%x\n", chip->codec_mask);
+ snd_printdd(SFX "codec_mask = 0x%x\n", chip->codec_mask);
}
return 0;
@@ -895,8 +930,7 @@ static void azx_init_chip(struct azx *chip)
azx_int_enable(chip);
/* initialize the codec command I/O */
- if (!chip->single_cmd)
- azx_init_cmd_io(chip);
+ azx_init_cmd_io(chip);
/* program the position buffer */
azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
@@ -953,12 +987,12 @@ static void azx_init_pci(struct azx *chip)
case AZX_DRIVER_SCH:
pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop);
if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) {
- pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, \
+ pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC,
snoop & (~INTEL_SCH_HDA_DEVC_NOSNOOP));
pci_read_config_word(chip->pci,
INTEL_SCH_HDA_DEVC, &snoop);
- snd_printdd("HDA snoop disabled, enabling ... %s\n",\
- (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) \
+ snd_printdd(SFX "HDA snoop disabled, enabling ... %s\n",
+ (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP)
? "Failed" : "OK");
}
break;
@@ -1012,7 +1046,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
/* clear rirb int */
status = azx_readb(chip, RIRBSTS);
if (status & RIRB_INT_MASK) {
- if (!chip->single_cmd && (status & RIRB_INT_RESPONSE))
+ if (status & RIRB_INT_RESPONSE)
azx_update_rirb(chip);
azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
}
@@ -1098,7 +1132,7 @@ static int azx_setup_periods(struct azx *chip,
pos_align;
pos_adj = frames_to_bytes(runtime, pos_adj);
if (pos_adj >= period_bytes) {
- snd_printk(KERN_WARNING "Too big adjustment %d\n",
+ snd_printk(KERN_WARNING SFX "Too big adjustment %d\n",
bdl_pos_adj[chip->dev_index]);
pos_adj = 0;
} else {
@@ -1122,7 +1156,7 @@ static int azx_setup_periods(struct azx *chip,
return 0;