On Sun, Nov 01, 2009 at 12:47:38PM +0100, Krzysztof Helt wrote:
From: Krzysztof Helt krzysztof.h1@wp.pl
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
<snip>
@@ -281,83 +285,88 @@ int snd_cs4236_create(struct snd_card *card, *rchip = NULL; if (hardware == WSS_HW_DETECT) hardware = WSS_HW_DETECT3;
- if (cport < 0x100) {
snd_printk(KERN_ERR "please, specify control port "
"for CS4236+ chips\n");
return -ENODEV;
- }
- err = snd_wss_create(card, port, cport, irq, dma1, dma2, hardware, hwshare, &chip); if (err < 0) return err;
- if (!(chip->hardware & WSS_HW_CS4236B_MASK)) {
snd_printk(KERN_ERR "CS4236+: MODE3 and extended registers "
"not available, hardware=0x%x\n", chip->hardware);
snd_device_free(card, chip);
return -ENODEV;
- }
- if (chip->hardware & WSS_HW_CS4236B_MASK) {
#if 0
- {
int idx;
for (idx = 0; idx < 8; idx++)
snd_printk(KERN_DEBUG "CD%i = 0x%x\n",
idx, inb(chip->cport + idx));
for (idx = 0; idx < 9; idx++)
snd_printk(KERN_DEBUG "C%i = 0x%x\n",
idx, snd_cs4236_ctrl_in(chip, idx));
- }
{
int idx;
for (idx = 0; idx < 8; idx++)
snd_printk(KERN_DEBUG "CD%i = 0x%x\n",
idx, inb(chip->cport + idx));
for (idx = 0; idx < 9; idx++)
snd_printk(KERN_DEBUG "C%i = 0x%x\n",
idx, snd_cs4236_ctrl_in(chip, idx));
}
#endif
- ver1 = snd_cs4236_ctrl_in(chip, 1);
- ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION);
- snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n", cport, ver1, ver2);
- if (ver1 != ver2) {
snd_printk(KERN_ERR "CS4236+ chip detected, but "
"control port 0x%lx is not valid\n", cport);
snd_device_free(card, chip);
return -ENODEV;
- }
- snd_cs4236_ctrl_out(chip, 0, 0x00);
- snd_cs4236_ctrl_out(chip, 2, 0xff);
- snd_cs4236_ctrl_out(chip, 3, 0x00);
- snd_cs4236_ctrl_out(chip, 4, 0x80);
- snd_cs4236_ctrl_out(chip, 5, ((IEC958_AES1_CON_PCM_CODER & 3) << 6) | IEC958_AES0_CON_EMPHASIS_NONE);
- snd_cs4236_ctrl_out(chip, 6, IEC958_AES1_CON_PCM_CODER >> 2);
- snd_cs4236_ctrl_out(chip, 7, 0x00);
- /* 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958 output */
- /* is working with this setup, other hardware should have */
- /* different signal paths and this value should be selectable */
- /* in the future */
- snd_cs4236_ctrl_out(chip, 8, 0x8c);
- chip->rate_constraint = snd_cs4236_xrate;
- chip->set_playback_format = snd_cs4236_playback_format;
- chip->set_capture_format = snd_cs4236_capture_format;
if (cport < 0x100 || cport == SNDRV_AUTO_PORT) {
snd_printk(KERN_ERR "please, specify control port "
"for CS4236+ chips\n");
Missing a call to snd_device_free() here.
return -ENODEV;
}