aboutsummaryrefslogtreecommitdiffstats
path: root/sound/isa/cs423x/cs4236_lib.c
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/isa/cs423x/cs4236_lib.c
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/isa/cs423x/cs4236_lib.c')
-rw-r--r--sound/isa/cs423x/cs4236_lib.c50
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 */
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);