aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorFlorian Schlichting <Florian.Schlichting@gmx.de>2006-03-15 08:05:19 -0500
committerJaroslav Kysela <perex@suse.cz>2006-03-22 04:38:50 -0500
commita23446c085faed6c1c90fba5cdd21d6990871750 (patch)
tree4d02131ba11c33fd5fa35c59ef61143b2a6c5d82 /sound
parent7c5706bb33687ce82f30d9ac06dd1bdf71b2262e (diff)
[ALSA] Fix NM256 hard lock up
Modules: NM256 driver Treat the nm256 mixer as a write-only device so as to avoid hangs on initialisation. Signed-off-by: Florian Schlichting <Florian.Schlichting@gmx.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/nm256/nm256.c120
1 files changed, 96 insertions, 24 deletions
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index 3a3ba6f547bc..cc297abc9d11 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -228,6 +228,7 @@ struct nm256 {
228 unsigned int use_cache: 1; /* use one big coef. table */ 228 unsigned int use_cache: 1; /* use one big coef. table */
229 unsigned int reset_workaround: 1; /* Workaround for some laptops to avoid freeze */ 229 unsigned int reset_workaround: 1; /* Workaround for some laptops to avoid freeze */
230 unsigned int reset_workaround_2: 1; /* Extended workaround for some other laptops to avoid freeze */ 230 unsigned int reset_workaround_2: 1; /* Extended workaround for some other laptops to avoid freeze */
231 unsigned int in_resume: 1;
231 232
232 int mixer_base; /* register offset of ac97 mixer */ 233 int mixer_base; /* register offset of ac97 mixer */
233 int mixer_status_offset; /* offset of mixer status reg. */ 234 int mixer_status_offset; /* offset of mixer status reg. */
@@ -242,6 +243,7 @@ struct nm256 {
242 struct nm256_stream streams[2]; 243 struct nm256_stream streams[2];
243 244
244 struct snd_ac97 *ac97; 245 struct snd_ac97 *ac97;
246 unsigned short *ac97_regs; /* register caches, only for valid regs */
245 247
246 struct snd_pcm *pcm; 248 struct snd_pcm *pcm;
247 249
@@ -1153,23 +1155,63 @@ snd_nm256_ac97_ready(struct nm256 *chip)
1153 return 0; 1155 return 0;
1154} 1156}
1155 1157
1158/*
1159 * Initial register values to be written to the AC97 mixer.
1160 * While most of these are identical to the reset values, we do this
1161 * so that we have most of the register contents cached--this avoids
1162 * reading from the mixer directly (which seems to be problematic,
1163 * probably due to ignorance).
1164 */
1165
1166struct initialValues {
1167 unsigned short reg;
1168 unsigned short value;
1169};
1170
1171static struct initialValues nm256_ac97_init_val[] =
1172{
1173 { AC97_MASTER, 0x8000 },
1174 { AC97_HEADPHONE, 0x8000 },
1175 { AC97_MASTER_MONO, 0x8000 },
1176 { AC97_PC_BEEP, 0x8000 },
1177 { AC97_PHONE, 0x8008 },
1178 { AC97_MIC, 0x8000 },
1179 { AC97_LINE, 0x8808 },
1180 { AC97_CD, 0x8808 },
1181 { AC97_VIDEO, 0x8808 },
1182 { AC97_AUX, 0x8808 },
1183 { AC97_PCM, 0x8808 },
1184 { AC97_REC_SEL, 0x0000 },
1185 { AC97_REC_GAIN, 0x0B0B },
1186 { AC97_GENERAL_PURPOSE, 0x0000 },
1187 { AC97_3D_CONTROL, 0x8000 },
1188 { AC97_VENDOR_ID1, 0x8384 },
1189 { AC97_VENDOR_ID2, 0x7609 },
1190};
1191
1192static int nm256_ac97_idx(unsigned short reg)
1193{
1194 int i;
1195 for (i = 0; i < ARRAY_SIZE(nm256_ac97_init_val); i++)
1196 if (nm256_ac97_init_val[i].reg == reg)
1197 return i;
1198 return -1;
1199}
1200
1156/* 1201/*
1202 * some nm256 easily crash when reading from mixer registers
1203 * thus we're treating it as a write-only mixer and cache the
1204 * written values
1157 */ 1205 */
1158static unsigned short 1206static unsigned short
1159snd_nm256_ac97_read(struct snd_ac97 *ac97, unsigned short reg) 1207snd_nm256_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
1160{ 1208{
1161 struct nm256 *chip = ac97->private_data; 1209 struct nm256 *chip = ac97->private_data;
1162 int res; 1210 int idx = nm256_ac97_idx(reg);
1163
1164 if (reg >= 128)
1165 return 0;
1166 1211
1167 if (! snd_nm256_ac97_ready(chip)) 1212 if (idx < 0)
1168 return 0; 1213 return 0;
1169 res = snd_nm256_readw(chip, chip->mixer_base + reg); 1214 return chip->ac97_regs[idx];
1170 /* Magic delay. Bleah yucky. */
1171 msleep(1);
1172 return res;
1173} 1215}
1174 1216
1175/* 1217/*
@@ -1180,8 +1222,12 @@ snd_nm256_ac97_write(struct snd_ac97 *ac97,
1180{ 1222{
1181 struct nm256 *chip = ac97->private_data; 1223 struct nm256 *chip = ac97->private_data;
1182 int tries = 2; 1224 int tries = 2;
1225 int idx = nm256_ac97_idx(reg);
1183 u32 base; 1226 u32 base;
1184 1227
1228 if (idx < 0)
1229 return;
1230
1185 base = chip->mixer_base; 1231 base = chip->mixer_base;
1186 1232
1187 snd_nm256_ac97_ready(chip); 1233 snd_nm256_ac97_ready(chip);
@@ -1190,12 +1236,32 @@ snd_nm256_ac97_write(struct snd_ac97 *ac97,
1190 while (tries-- > 0) { 1236 while (tries-- > 0) {
1191 snd_nm256_writew(chip, base + reg, val); 1237 snd_nm256_writew(chip, base + reg, val);
1192 msleep(1); /* a little delay here seems better.. */ 1238 msleep(1); /* a little delay here seems better.. */
1193 if (snd_nm256_ac97_ready(chip)) 1239 if (snd_nm256_ac97_ready(chip)) {
1240 /* successful write: set cache */
1241 chip->ac97_regs[idx] = val;
1194 return; 1242 return;
1243 }
1195 } 1244 }
1196 snd_printd("nm256: ac97 codec not ready..\n"); 1245 snd_printd("nm256: ac97 codec not ready..\n");
1197} 1246}
1198 1247
1248/* static resolution table */
1249static struct snd_ac97_res_table nm256_res_table[] = {
1250 { AC97_MASTER, 0x1f1f },
1251 { AC97_HEADPHONE, 0x1f1f },
1252 { AC97_MASTER_MONO, 0x001f },
1253 { AC97_PC_BEEP, 0x001f },
1254 { AC97_PHONE, 0x001f },
1255 { AC97_MIC, 0x001f },
1256 { AC97_LINE, 0x1f1f },
1257 { AC97_CD, 0x1f1f },
1258 { AC97_VIDEO, 0x1f1f },
1259 { AC97_AUX, 0x1f1f },
1260 { AC97_PCM, 0x1f1f },
1261 { AC97_REC_GAIN, 0x0f0f },
1262 { } /* terminator */
1263};
1264
1199/* initialize the ac97 into a known state */ 1265/* initialize the ac97 into a known state */
1200static void 1266static void
1201snd_nm256_ac97_reset(struct snd_ac97 *ac97) 1267snd_nm256_ac97_reset(struct snd_ac97 *ac97)
@@ -1213,6 +1279,16 @@ snd_nm256_ac97_reset(struct snd_ac97 *ac97)
1213 snd_nm256_writeb(chip, 0x6cc, 0x80); 1279 snd_nm256_writeb(chip, 0x6cc, 0x80);
1214 snd_nm256_writeb(chip, 0x6cc, 0x0); 1280 snd_nm256_writeb(chip, 0x6cc, 0x0);
1215 } 1281 }
1282 if (! chip->in_resume) {
1283 int i;
1284 for (i = 0; i < ARRAY_SIZE(nm256_ac97_init_val); i++) {
1285 /* preload the cache, so as to avoid even a single
1286 * read of the mixer regs
1287 */
1288 snd_nm256_ac97_write(ac97, nm256_ac97_init_val[i].reg,
1289 nm256_ac97_init_val[i].value);
1290 }
1291 }
1216} 1292}
1217 1293
1218/* create an ac97 mixer interface */ 1294/* create an ac97 mixer interface */
@@ -1221,32 +1297,25 @@ snd_nm256_mixer(struct nm256 *chip)
1221{ 1297{
1222 struct snd_ac97_bus *pbus; 1298 struct snd_ac97_bus *pbus;
1223 struct snd_ac97_template ac97; 1299 struct snd_ac97_template ac97;
1224 int i, err; 1300 int err;
1225 static struct snd_ac97_bus_ops ops = { 1301 static struct snd_ac97_bus_ops ops = {
1226 .reset = snd_nm256_ac97_reset, 1302 .reset = snd_nm256_ac97_reset,
1227 .write = snd_nm256_ac97_write, 1303 .write = snd_nm256_ac97_write,
1228 .read = snd_nm256_ac97_read, 1304 .read = snd_nm256_ac97_read,
1229 }; 1305 };
1230 /* looks like nm256 hangs up when unexpected registers are touched... */ 1306
1231 static int mixer_regs[] = { 1307 chip->ac97_regs = kcalloc(sizeof(short),
1232 AC97_MASTER, AC97_HEADPHONE, AC97_MASTER_MONO, 1308 ARRAY_SIZE(nm256_ac97_init_val), GFP_KERNEL);
1233 AC97_PC_BEEP, AC97_PHONE, AC97_MIC, AC97_LINE, AC97_CD, 1309 if (! chip->ac97_regs)
1234 AC97_VIDEO, AC97_AUX, AC97_PCM, AC97_REC_SEL, 1310 return -ENOMEM;
1235 AC97_REC_GAIN, AC97_GENERAL_PURPOSE, AC97_3D_CONTROL,
1236 /*AC97_EXTENDED_ID,*/
1237 AC97_VENDOR_ID1, AC97_VENDOR_ID2,
1238 -1
1239 };
1240 1311
1241 if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus)) < 0) 1312 if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus)) < 0)
1242 return err; 1313 return err;
1243 1314
1244 memset(&ac97, 0, sizeof(ac97)); 1315 memset(&ac97, 0, sizeof(ac97));
1245 ac97.scaps = AC97_SCAP_AUDIO; /* we support audio! */ 1316 ac97.scaps = AC97_SCAP_AUDIO; /* we support audio! */
1246 ac97.limited_regs = 1;
1247 for (i = 0; mixer_regs[i] >= 0; i++)
1248 set_bit(mixer_regs[i], ac97.reg_accessed);
1249 ac97.private_data = chip; 1317 ac97.private_data = chip;
1318 ac97.res_table = nm256_res_table;
1250 pbus->no_vra = 1; 1319 pbus->no_vra = 1;
1251 err = snd_ac97_mixer(pbus, &ac97, &chip->ac97); 1320 err = snd_ac97_mixer(pbus, &ac97, &chip->ac97);
1252 if (err < 0) 1321 if (err < 0)
@@ -1331,6 +1400,7 @@ static int nm256_resume(struct pci_dev *pci)
1331 int i; 1400 int i;
1332 1401
1333 /* Perform a full reset on the hardware */ 1402 /* Perform a full reset on the hardware */
1403 chip->in_resume = 1;
1334 pci_restore_state(pci); 1404 pci_restore_state(pci);
1335 pci_enable_device(pci); 1405 pci_enable_device(pci);
1336 snd_nm256_init_chip(chip); 1406 snd_nm256_init_chip(chip);
@@ -1348,6 +1418,7 @@ static int nm256_resume(struct pci_dev *pci)
1348 } 1418 }
1349 1419
1350 snd_power_change_state(card, SNDRV_CTL_POWER_D0); 1420 snd_power_change_state(card, SNDRV_CTL_POWER_D0);
1421 chip->in_resume = 0;
1351 return 0; 1422 return 0;
1352} 1423}
1353#endif /* CONFIG_PM */ 1424#endif /* CONFIG_PM */
@@ -1372,6 +1443,7 @@ static int snd_nm256_free(struct nm256 *chip)
1372 free_irq(chip->irq, chip); 1443 free_irq(chip->irq, chip);
1373 1444
1374 pci_disable_device(chip->pci); 1445 pci_disable_device(chip->pci);
1446 kfree(chip->ac97_regs);
1375 kfree(chip); 1447 kfree(chip);
1376 return 0; 1448 return 0;
1377} 1449}