diff options
author | Krzysztof Helt <krzysztof.h1@wp.pl> | 2009-11-05 12:32:41 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-11-05 12:10:25 -0500 |
commit | d114cd84a1c5ce42bb10cd3a2da57b2bbcef909b (patch) | |
tree | 32c7f37af0cc9ec55a37357723b7c4f055462830 /sound/isa/cs423x/cs4236_lib.c | |
parent | 9dcaa7b25f2c8f6a0485854cd3641f585a154072 (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/isa/cs423x/cs4236_lib.c')
-rw-r--r-- | sound/isa/cs423x/cs4236_lib.c | 50 |
1 files changed, 31 insertions, 19 deletions
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 | */ | ||
268 | int snd_cs4236_create(struct snd_card *card, | 272 | int 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); |