diff options
author | Takashi Iwai <tiwai@suse.de> | 2008-11-06 11:11:10 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2008-11-06 11:29:48 -0500 |
commit | 6ce4a3bc1b93e8ca50b142b00dd73bfdb5c4a172 (patch) | |
tree | d6adcd686919c9107d638966aee06bb63ee8d5fd /sound/pci/hda/hda_intel.c | |
parent | 33fa35ed0d7e8996cc68cc2ffc21f12b38fa03c1 (diff) |
ALSA: hda - Make codec-probing more robust
When an error occurs during the codec probing, typically accessing to an
non-existing codec slot, the controller chip gets often screwed up and
can no longer communicate with the codecs.
This patch adds a preparation phase just to probe codec addresses before
actually creating codec instances. If any error occurs during this
probing phase, the driver resets the controller to recover.
This will (hopefully) fix the famous "single_cmd" errors.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/hda_intel.c')
-rw-r--r-- | sound/pci/hda/hda_intel.c | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index bf8e6f94aebc..f3c447cf67f8 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -392,6 +392,7 @@ struct azx { | |||
392 | unsigned int msi :1; | 392 | unsigned int msi :1; |
393 | unsigned int irq_pending_warned :1; | 393 | unsigned int irq_pending_warned :1; |
394 | unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */ | 394 | unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */ |
395 | unsigned int probing :1; /* codec probing phase */ | ||
395 | 396 | ||
396 | /* for debugging */ | 397 | /* for debugging */ |
397 | unsigned int last_cmd; /* last issued command (to sync) */ | 398 | unsigned int last_cmd; /* last issued command (to sync) */ |
@@ -624,6 +625,14 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) | |||
624 | goto again; | 625 | goto again; |
625 | } | 626 | } |
626 | 627 | ||
628 | if (chip->probing) { | ||
629 | /* If this critical timeout happens during the codec probing | ||
630 | * phase, this is likely an access to a non-existing codec | ||
631 | * slot. Better to return an error and reset the system. | ||
632 | */ | ||
633 | return -1; | ||
634 | } | ||
635 | |||
627 | snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, " | 636 | snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, " |
628 | "switching to single_cmd mode: last cmd=0x%08x\n", | 637 | "switching to single_cmd mode: last cmd=0x%08x\n", |
629 | chip->last_cmd); | 638 | chip->last_cmd); |
@@ -1175,8 +1184,28 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) | |||
1175 | return 0; | 1184 | return 0; |
1176 | } | 1185 | } |
1177 | 1186 | ||
1187 | /* | ||
1188 | * Probe the given codec address | ||
1189 | */ | ||
1190 | static int probe_codec(struct azx *chip, int addr) | ||
1191 | { | ||
1192 | unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | | ||
1193 | (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; | ||
1194 | unsigned int res; | ||
1195 | |||
1196 | chip->probing = 1; | ||
1197 | azx_send_cmd(chip->bus, cmd); | ||
1198 | res = azx_get_response(chip->bus); | ||
1199 | chip->probing = 0; | ||
1200 | if (res == -1) | ||
1201 | return -EIO; | ||
1202 | snd_printdd("hda_intel: codec #%d probed OK\n", addr); | ||
1203 | return 0; | ||
1204 | } | ||
1205 | |||
1178 | static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, | 1206 | static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, |
1179 | struct hda_pcm *cpcm); | 1207 | struct hda_pcm *cpcm); |
1208 | static void azx_stop_chip(struct azx *chip); | ||
1180 | 1209 | ||
1181 | /* | 1210 | /* |
1182 | * Codec initialization | 1211 | * Codec initialization |
@@ -1216,6 +1245,32 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, | |||
1216 | max_slots = azx_max_codecs[chip->driver_type]; | 1245 | max_slots = azx_max_codecs[chip->driver_type]; |
1217 | if (!max_slots) | 1246 | if (!max_slots) |
1218 | max_slots = AZX_MAX_CODECS; | 1247 | max_slots = AZX_MAX_CODECS; |
1248 | |||
1249 | /* First try to probe all given codec slots */ | ||
1250 | for (c = 0; c < max_slots; c++) { | ||
1251 | if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { | ||
1252 | if (probe_codec(chip, c) < 0) { | ||
1253 | /* Some BIOSen give you wrong codec addresses | ||
1254 | * that don't exist | ||
1255 | */ | ||
1256 | snd_printk(KERN_WARNING | ||
1257 | "hda_intel: Codec #%d probe error; " | ||
1258 | "disabling it...\n", c); | ||
1259 | chip->codec_mask &= ~(1 << c); | ||
1260 | /* More badly, accessing to a non-existing | ||
1261 | * codec often screws up the controller chip, | ||
1262 | * and distrubs the further communications. | ||
1263 | * Thus if an error occurs during probing, | ||
1264 | * better to reset the controller chip to | ||
1265 | * get back to the sanity state. | ||
1266 | */ | ||
1267 | azx_stop_chip(chip); | ||
1268 | azx_init_chip(chip); | ||
1269 | } | ||
1270 | } | ||
1271 | } | ||
1272 | |||
1273 | /* Then create codec instances */ | ||
1219 | for (c = 0; c < max_slots; c++) { | 1274 | for (c = 0; c < max_slots; c++) { |
1220 | if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { | 1275 | if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { |
1221 | struct hda_codec *codec; | 1276 | struct hda_codec *codec; |