aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorKrzysztof Helt <krzysztof.h1@wp.pl>2009-11-05 12:32:41 -0500
committerTakashi Iwai <tiwai@suse.de>2009-11-05 12:10:25 -0500
commitd114cd84a1c5ce42bb10cd3a2da57b2bbcef909b (patch)
tree32c7f37af0cc9ec55a37357723b7c4f055462830 /sound
parent9dcaa7b25f2c8f6a0485854cd3641f585a154072 (diff)
ALSA: cs4236: detect chip in one pass
The cs4236 was two step detection with call to the snd_wss_free() between two steps. The snd_wss_free() did not free a sound device created in the snd_wss_create(). This caused an OOPS during module removal as the same sound device was released twice. The same OOPS happened if the cs4236 module loading failed. Fix this by adapting the snd_cs4236_create() to correctly work with chips less capable then cs4236. The snd_cs4236_create() behaves the same as the snd_wss_create() if the chip is less capable than the cs4236. Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/isa/cs423x/cs4236.c13
-rw-r--r--sound/isa/cs423x/cs4236_lib.c50
-rw-r--r--sound/isa/wss/wss_lib.c3
3 files changed, 35 insertions, 31 deletions
diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c
index a076a6ce8071..93fa6720d197 100644
--- a/sound/isa/cs423x/cs4236.c
+++ b/sound/isa/cs423x/cs4236.c
@@ -394,21 +394,15 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
394 return -EBUSY; 394 return -EBUSY;
395 } 395 }
396 396
397 err = snd_wss_create(card, port[dev], cport[dev], 397 err = snd_cs4236_create(card, port[dev], cport[dev],
398 irq[dev], 398 irq[dev],
399 dma1[dev], dma2[dev], 399 dma1[dev], dma2[dev],
400 WSS_HW_DETECT3, 0, &chip); 400 WSS_HW_DETECT3, 0, &chip);
401 if (err < 0) 401 if (err < 0)
402 return err; 402 return err;
403
404 acard->chip = chip;
403 if (chip->hardware & WSS_HW_CS4236B_MASK) { 405 if (chip->hardware & WSS_HW_CS4236B_MASK) {
404 snd_wss_free(chip);
405 err = snd_cs4236_create(card,
406 port[dev], cport[dev],
407 irq[dev], dma1[dev], dma2[dev],
408 WSS_HW_DETECT, 0, &chip);
409 if (err < 0)
410 return err;
411 acard->chip = chip;
412 406
413 err = snd_cs4236_pcm(chip, 0, &pcm); 407 err = snd_cs4236_pcm(chip, 0, &pcm);
414 if (err < 0) 408 if (err < 0)
@@ -418,7 +412,6 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
418 if (err < 0) 412 if (err < 0)
419 return err; 413 return err;
420 } else { 414 } else {
421 acard->chip = chip;
422 err = snd_wss_pcm(chip, 0, &pcm); 415 err = snd_wss_pcm(chip, 0, &pcm);
423 if (err < 0) 416 if (err < 0)
424 return err; 417 return err;
diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c
index 38835f31298b..1b1ad1cad328 100644
--- a/sound/isa/cs423x/cs4236_lib.c
+++ b/sound/isa/cs423x/cs4236_lib.c
@@ -87,6 +87,7 @@
87#include <sound/core.h> 87#include <sound/core.h>
88#include <sound/wss.h> 88#include <sound/wss.h>
89#include <sound/asoundef.h> 89#include <sound/asoundef.h>
90#include <sound/initval.h>
90 91
91/* 92/*
92 * 93 *
@@ -264,7 +265,10 @@ static void snd_cs4236_resume(struct snd_wss *chip)
264} 265}
265 266
266#endif /* CONFIG_PM */ 267#endif /* CONFIG_PM */
267 268/*
269 * This function does no fail if the chip is not CS4236B or compatible.
270 * It just an equivalent to the snd_wss_create() then.
271 */
268int snd_cs4236_create(struct snd_card *card, 272int snd_cs4236_create(struct snd_card *card,
269 unsigned long port, 273 unsigned long port,
270 unsigned long cport, 274 unsigned long cport,
@@ -281,21 +285,17 @@ int snd_cs4236_create(struct snd_card *card,
281 *rchip = NULL; 285 *rchip = NULL;
282 if (hardware == WSS_HW_DETECT) 286 if (hardware == WSS_HW_DETECT)
283 hardware = WSS_HW_DETECT3; 287 hardware = WSS_HW_DETECT3;
284 if (cport < 0x100) { 288
285 snd_printk(KERN_ERR "please, specify control port "
286 "for CS4236+ chips\n");
287 return -ENODEV;
288 }
289 err = snd_wss_create(card, port, cport, 289 err = snd_wss_create(card, port, cport,
290 irq, dma1, dma2, hardware, hwshare, &chip); 290 irq, dma1, dma2, hardware, hwshare, &chip);
291 if (err < 0) 291 if (err < 0)
292 return err; 292 return err;
293 293
294 if (!(chip->hardware & WSS_HW_CS4236B_MASK)) { 294 if ((chip->hardware & WSS_HW_CS4236B_MASK) == 0) {
295 snd_printk(KERN_ERR "CS4236+: MODE3 and extended registers " 295 snd_printd("chip is not CS4236+, hardware=0x%x\n",
296 "not available, hardware=0x%x\n", chip->hardware); 296 chip->hardware);
297 snd_device_free(card, chip); 297 *rchip = chip;
298 return -ENODEV; 298 return 0;
299 } 299 }
300#if 0 300#if 0
301 { 301 {
@@ -308,9 +308,16 @@ int snd_cs4236_create(struct snd_card *card,
308 idx, snd_cs4236_ctrl_in(chip, idx)); 308 idx, snd_cs4236_ctrl_in(chip, idx));
309 } 309 }
310#endif 310#endif
311 if (cport < 0x100 || cport == SNDRV_AUTO_PORT) {
312 snd_printk(KERN_ERR "please, specify control port "
313 "for CS4236+ chips\n");
314 snd_device_free(card, chip);
315 return -ENODEV;
316 }
311 ver1 = snd_cs4236_ctrl_in(chip, 1); 317 ver1 = snd_cs4236_ctrl_in(chip, 1);
312 ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION); 318 ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION);
313 snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n", cport, ver1, ver2); 319 snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n",
320 cport, ver1, ver2);
314 if (ver1 != ver2) { 321 if (ver1 != ver2) {
315 snd_printk(KERN_ERR "CS4236+ chip detected, but " 322 snd_printk(KERN_ERR "CS4236+ chip detected, but "
316 "control port 0x%lx is not valid\n", cport); 323 "control port 0x%lx is not valid\n", cport);
@@ -321,13 +328,17 @@ int snd_cs4236_create(struct snd_card *card,
321 snd_cs4236_ctrl_out(chip, 2, 0xff); 328 snd_cs4236_ctrl_out(chip, 2, 0xff);
322 snd_cs4236_ctrl_out(chip, 3, 0x00); 329 snd_cs4236_ctrl_out(chip, 3, 0x00);
323 snd_cs4236_ctrl_out(chip, 4, 0x80); 330 snd_cs4236_ctrl_out(chip, 4, 0x80);
324 snd_cs4236_ctrl_out(chip, 5, ((IEC958_AES1_CON_PCM_CODER & 3) << 6) | IEC958_AES0_CON_EMPHASIS_NONE); 331 reg = ((IEC958_AES1_CON_PCM_CODER & 3) << 6) |
332 IEC958_AES0_CON_EMPHASIS_NONE;
333 snd_cs4236_ctrl_out(chip, 5, reg);
325 snd_cs4236_ctrl_out(chip, 6, IEC958_AES1_CON_PCM_CODER >> 2); 334 snd_cs4236_ctrl_out(chip, 6, IEC958_AES1_CON_PCM_CODER >> 2);
326 snd_cs4236_ctrl_out(chip, 7, 0x00); 335 snd_cs4236_ctrl_out(chip, 7, 0x00);
327 /* 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958 output */ 336 /*
328 /* is working with this setup, other hardware should have */ 337 * 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958
329 /* different signal paths and this value should be selectable */ 338 * output is working with this setup, other hardware should
330 /* in the future */ 339 * have different signal paths and this value should be
340 * selectable in the future
341 */
331 snd_cs4236_ctrl_out(chip, 8, 0x8c); 342 snd_cs4236_ctrl_out(chip, 8, 0x8c);
332 chip->rate_constraint = snd_cs4236_xrate; 343 chip->rate_constraint = snd_cs4236_xrate;
333 chip->set_playback_format = snd_cs4236_playback_format; 344 chip->set_playback_format = snd_cs4236_playback_format;
@@ -339,9 +350,10 @@ int snd_cs4236_create(struct snd_card *card,
339 350
340 /* initialize extended registers */ 351 /* initialize extended registers */
341 for (reg = 0; reg < sizeof(snd_cs4236_ext_map); reg++) 352 for (reg = 0; reg < sizeof(snd_cs4236_ext_map); reg++)
342 snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), snd_cs4236_ext_map[reg]); 353 snd_cs4236_ext_out(chip, CS4236_I23VAL(reg),
354 snd_cs4236_ext_map[reg]);
343 355
344 /* initialize compatible but more featured registers */ 356 /* initialize compatible but more featured registers */
345 snd_wss_out(chip, CS4231_LEFT_INPUT, 0x40); 357 snd_wss_out(chip, CS4231_LEFT_INPUT, 0x40);
346 snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x40); 358 snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x40);
347 snd_wss_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff); 359 snd_wss_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff);
diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c
index 2ba18978b419..705db0924375 100644
--- a/sound/isa/wss/wss_lib.c
+++ b/sound/isa/wss/wss_lib.c
@@ -1682,7 +1682,7 @@ static void snd_wss_resume(struct snd_wss *chip)
1682} 1682}
1683#endif /* CONFIG_PM */ 1683#endif /* CONFIG_PM */
1684 1684
1685int snd_wss_free(struct snd_wss *chip) 1685static int snd_wss_free(struct snd_wss *chip)
1686{ 1686{
1687 release_and_free_resource(chip->res_port); 1687 release_and_free_resource(chip->res_port);
1688 release_and_free_resource(chip->res_cport); 1688 release_and_free_resource(chip->res_cport);
@@ -1705,7 +1705,6 @@ int snd_wss_free(struct snd_wss *chip)
1705 kfree(chip); 1705 kfree(chip);
1706 return 0; 1706 return 0;
1707} 1707}
1708EXPORT_SYMBOL(snd_wss_free);
1709 1708
1710static int snd_wss_dev_free(struct snd_device *device) 1709static int snd_wss_dev_free(struct snd_device *device)
1711{ 1710{