summaryrefslogtreecommitdiffstats
path: root/sound/isa/wss
diff options
context:
space:
mode:
authorKrzysztof Helt <krzysztof.h1@wp.pl>2008-07-31 21:10:47 +0200
committerJaroslav Kysela <perex@perex.cz>2008-08-06 15:40:02 +0200
commit760fc6b838d8c783c363e8bdb3714bd92a8945c4 (patch)
treebe50fd4d3e3c3d561d62a369066f9ea62d348fbc /sound/isa/wss
parentALSA: wss_lib: use wss pcm code instead of ad1848 one (diff)
downloadlinux-760fc6b838d8c783c363e8bdb3714bd92a8945c4.tar.xz
linux-760fc6b838d8c783c363e8bdb3714bd92a8945c4.zip
ALSA: wss_lib: use wss detection code instead of ad1848 one
Use the wss detection code and kill the ad1848 library. The library is fully assimilated into the new wss library. This required reworking of the AD1848 family code so the code is changed to correctly detect chips from the AD1848 and CS4231 families. I have tested it on following cards: Gallant SC-6600 (codec: AD1848, driver: snd-sc6600) SoundScape VIVO/90 (codec: AD1845, driver: snd-sscape) SG Waverider (codec: CS4231A, driver: Rene Herman's snd-galaxy) Opti930 (codec: built-in - CS4231 compatible, driver: snd-opti93x) Opti931 (codec: built-in - CS4231 compatible, driver: snd-opti93x) Gallant SC-70P (chip/codec: CS4237B, driver: snd-cs4236) Audio Plus 3D (chip/codec: CMI8330A, driver: snd-cmi8330) Dell Latitude CP (chip/codec: cs4236, driver snd-cs4232) Sound playback and recording works on all these cards. Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl> Reviewed-by: Rene Herman <rene.herman@gmail.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/isa/wss')
-rw-r--r--sound/isa/wss/wss_lib.c150
1 files changed, 120 insertions, 30 deletions
diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c
index 57d1e8ee6bbb..a5602f515f49 100644
--- a/sound/isa/wss/wss_lib.c
+++ b/sound/isa/wss/wss_lib.c
@@ -1073,7 +1073,11 @@ irqreturn_t snd_wss_interrupt(int irq, void *dev_id)
struct snd_wss *chip = dev_id;
unsigned char status;
- status = snd_wss_in(chip, CS4231_IRQ_STATUS);
+ if (chip->hardware & WSS_HW_AD1848_MASK)
+ /* pretend it was the only possible irq for AD1848 */
+ status = CS4231_PLAYBACK_IRQ;
+ else
+ status = snd_wss_in(chip, CS4231_IRQ_STATUS);
if (status & CS4231_TIMER_IRQ) {
if (chip->timer)
snd_timer_interrupt(chip->timer, chip->timer->sticks);
@@ -1105,7 +1109,11 @@ irqreturn_t snd_wss_interrupt(int irq, void *dev_id)
}
spin_lock(&chip->reg_lock);
- snd_wss_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0);
+ status = ~CS4231_ALL_IRQS | ~status;
+ if (chip->hardware & WSS_HW_AD1848_MASK)
+ wss_outb(chip, CS4231P(STATUS), 0);
+ else
+ snd_wss_outm(chip, CS4231_IRQ_STATUS, status, 0);
spin_unlock(&chip->reg_lock);
return IRQ_HANDLED;
}
@@ -1137,36 +1145,112 @@ static snd_pcm_uframes_t snd_wss_capture_pointer(struct snd_pcm_substream *subst
*/
-static int snd_wss_probe(struct snd_wss *chip)
+static int snd_ad1848_probe(struct snd_wss *chip)
{
unsigned long flags;
- int i, id, rev;
- unsigned char *ptr;
- unsigned int hw;
+ int i, id, rev, ad1847;
-#if 0
- snd_wss_debug(chip);
-#endif
id = 0;
- for (i = 0; i < 50; i++) {
+ ad1847 = 0;
+ for (i = 0; i < 1000; i++) {
mb();
- if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
- udelay(2000);
+ if (inb(chip->port + CS4231P(REGSEL)) & CS4231_INIT)
+ msleep(1);
else {
spin_lock_irqsave(&chip->reg_lock, flags);
- snd_wss_out(chip, CS4231_MISC_INFO, CS4231_MODE2);
- id = snd_wss_in(chip, CS4231_MISC_INFO) & 0x0f;
+ snd_wss_out(chip, CS4231_MISC_INFO, 0x00);
+ snd_wss_out(chip, CS4231_LEFT_INPUT, 0xaa);
+ snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x45);
+ rev = snd_wss_in(chip, CS4231_RIGHT_INPUT);
+ if (rev == 0x65) {
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ id = 1;
+ ad1847 = 1;
+ break;
+ }
+ if (snd_wss_in(chip, CS4231_LEFT_INPUT) == 0xaa &&
+ rev == 0x45) {
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ id = 1;
+ break;
+ }
spin_unlock_irqrestore(&chip->reg_lock, flags);
- if (id == 0x0a)
- break; /* this is valid value */
}
}
- snd_printdd("wss: port = 0x%lx, id = 0x%x\n", chip->port, id);
- if (id != 0x0a)
+ if (id != 1)
return -ENODEV; /* no valid device found */
+ id = 0;
+ if (chip->hardware == WSS_HW_DETECT)
+ id = ad1847 ? WSS_HW_AD1847 : WSS_HW_AD1848;
+
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ inb(chip->port + CS4231P(STATUS)); /* clear any pendings IRQ */
+ outb(0, chip->port + CS4231P(STATUS));
+ mb();
+ if (id == WSS_HW_AD1848) {
+ /* check if there are more than 16 registers */
+ rev = snd_wss_in(chip, CS4231_MISC_INFO);
+ snd_wss_out(chip, CS4231_MISC_INFO, 0x40);
+ for (i = 0; i < 16; ++i) {
+ if (snd_wss_in(chip, i) != snd_wss_in(chip, i + 16)) {
+ id = WSS_HW_CMI8330;
+ break;
+ }
+ }
+ snd_wss_out(chip, CS4231_MISC_INFO, 0x00);
+ if (id != WSS_HW_CMI8330 && (rev & 0x80))
+ id = WSS_HW_CS4248;
+ if (id == WSS_HW_CMI8330 && (rev & 0x0f) != 0x0a)
+ id = 0;
+ }
+ if (id == WSS_HW_CMI8330) {
+ /* verify it is not CS4231 by changing the version register */
+ /* on CMI8330 it is volume control register and can be set 0 */
+ snd_wss_out(chip, CS4231_MISC_INFO, CS4231_MODE2);
+ snd_wss_dout(chip, CS4231_VERSION, 0x00);
+ rev = snd_wss_in(chip, CS4231_VERSION) & 0xe7;
+ if (rev)
+ id = 0;
+ snd_wss_out(chip, CS4231_MISC_INFO, 0);
+ }
+ if (id)
+ chip->hardware = id;
+
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ return 0; /* all things are ok.. */
+}
+
+static int snd_wss_probe(struct snd_wss *chip)
+{
+ unsigned long flags;
+ int i, id, rev, regnum;
+ unsigned char *ptr;
+ unsigned int hw;
+
+ id = snd_ad1848_probe(chip);
+ if (id < 0)
+ return id;
hw = chip->hardware;
if ((hw & WSS_HW_TYPE_MASK) == WSS_HW_DETECT) {
+ for (i = 0; i < 50; i++) {
+ mb();
+ if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
+ msleep(2);
+ else {
+ spin_lock_irqsave(&chip->reg_lock, flags);
+ snd_wss_out(chip, CS4231_MISC_INFO,
+ CS4231_MODE2);
+ id = snd_wss_in(chip, CS4231_MISC_INFO) & 0x0f;
+ spin_unlock_irqrestore(&chip->reg_lock, flags);
+ if (id == 0x0a)
+ break; /* this is valid value */
+ }
+ }
+ snd_printdd("wss: port = 0x%lx, id = 0x%x\n", chip->port, id);
+ if (id != 0x0a)
+ return -ENODEV; /* no valid device found */
+
rev = snd_wss_in(chip, CS4231_VERSION) & 0xe7;
snd_printdd("CS4231: VERSION (I25) = 0x%x\n", rev);
if (rev == 0x80) {
@@ -1197,7 +1281,8 @@ static int snd_wss_probe(struct snd_wss *chip)
mb();
spin_unlock_irqrestore(&chip->reg_lock, flags);
- chip->image[CS4231_MISC_INFO] = CS4231_MODE2;
+ if (!(chip->hardware & WSS_HW_AD1848_MASK))
+ chip->image[CS4231_MISC_INFO] = CS4231_MODE2;
switch (chip->hardware) {
case WSS_HW_INTERWAVE:
chip->image[CS4231_MISC_INFO] = CS4231_IW_MODE3;
@@ -1223,9 +1308,10 @@ static int snd_wss_probe(struct snd_wss *chip)
chip->hardware == WSS_HW_INTERWAVE ? 0xc2 : 0x01;
}
ptr = (unsigned char *) &chip->image;
+ regnum = (chip->hardware & WSS_HW_AD1848_MASK) ? 16 : 32;
snd_wss_mce_down(chip);
spin_lock_irqsave(&chip->reg_lock, flags);
- for (i = 0; i < 32; i++) /* ok.. fill all CS4231 registers */
+ for (i = 0; i < regnum; i++) /* ok.. fill all registers */
snd_wss_out(chip, i, *ptr++);
spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_wss_mce_up(chip);
@@ -1635,6 +1721,10 @@ static int snd_wss_new(struct snd_card *card,
else
memcpy(&chip->image, &snd_wss_original_image,
sizeof(snd_wss_original_image));
+ if (chip->hardware & WSS_HW_AD1848_MASK) {
+ chip->image[CS4231_PIN_CTRL] = 0;
+ chip->image[CS4231_TEST_INIT] = 0;
+ }
*rchip = chip;
return 0;
@@ -1662,7 +1752,7 @@ int snd_wss_create(struct snd_card *card,
chip->dma1 = -1;
chip->dma2 = -1;
- chip->res_port = request_region(port, 4, "CS4231");
+ chip->res_port = request_region(port, 4, "WSS");
if (!chip->res_port) {
snd_printk(KERN_ERR "wss: can't grab port 0x%lx\n", port);
snd_wss_free(chip);
@@ -1681,20 +1771,20 @@ int snd_wss_create(struct snd_card *card,
chip->cport = cport;
if (!(hwshare & WSS_HWSHARE_IRQ))
if (request_irq(irq, snd_wss_interrupt, IRQF_DISABLED,
- "CS4231", (void *) chip)) {
+ "WSS", (void *) chip)) {
snd_printk(KERN_ERR "wss: can't grab IRQ %d\n", irq);
snd_wss_free(chip);
return -EBUSY;
}
chip->irq = irq;
- if (!(hwshare & WSS_HWSHARE_DMA1) && request_dma(dma1, "CS4231 - 1")) {
+ if (!(hwshare & WSS_HWSHARE_DMA1) && request_dma(dma1, "WSS - 1")) {
snd_printk(KERN_ERR "wss: can't grab DMA1 %d\n", dma1);
snd_wss_free(chip);
return -EBUSY;
}
chip->dma1 = dma1;
if (!(hwshare & WSS_HWSHARE_DMA2) && dma1 != dma2 &&
- dma2 >= 0 && request_dma(dma2, "CS4231 - 2")) {
+ dma2 >= 0 && request_dma(dma2, "WSS - 2")) {
snd_printk(KERN_ERR "wss: can't grab DMA2 %d\n", dma2);
snd_wss_free(chip);
return -EBUSY;
@@ -1705,6 +1795,12 @@ int snd_wss_create(struct snd_card *card,
} else
chip->dma2 = dma2;
+ if (hardware == WSS_HW_THINKPAD) {
+ chip->thinkpad_flag = 1;
+ chip->hardware = WSS_HW_DETECT; /* reset */
+ snd_wss_thinkpad_twiddle(chip, 1);
+ }
+
/* global setup */
if (snd_wss_probe(chip) < 0) {
snd_wss_free(chip);
@@ -1775,12 +1871,6 @@ int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_wss_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_wss_capture_ops);
- /* temporary */
- if (chip->hardware & WSS_HW_AD1848_MASK) {
- chip->rate_constraint = snd_wss_xrate;
- chip->set_playback_format = snd_wss_playback_format;
- chip->set_capture_format = snd_wss_capture_format;
- }
/* global setup */
pcm->private_data = chip;
pcm->info_flags = 0;