patch-2.3.14 linux/drivers/sound/esssolo1.c
Next file: linux/drivers/sound/lowlevel/awe_compat-fbsd.h
Previous file: linux/drivers/sound/es1371.c
Back to the patch index
Back to the overall index
- Lines: 678
- Date:
Thu Aug 12 12:21:48 1999
- Orig file:
v2.3.13/linux/drivers/sound/esssolo1.c
- Orig date:
Mon Aug 9 14:59:23 1999
diff -u --recursive --new-file v2.3.13/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c
@@ -39,13 +39,26 @@
* 15.06.99 0.4 Fix bad allocation bug.
* Thanks to Deti Fliegl <fliegl@in.tum.de>
* 28.06.99 0.5 Add pci_set_master
- *
+ * 12.08.99 0.6 Fix MIDI UART crashing the driver
+ * Changed mixer semantics from OSS documented
+ * behaviour to OSS "code behaviour".
+ * Recording might actually work now.
+ * The real DDMA controller address register is at PCI config
+ * 0x60, while the register at 0x18 is used as a placeholder
+ * register for BIOS address allocation. This register
+ * is supposed to be copied into 0x60, according
+ * to the Solo1 datasheet. When I do that, I can access
+ * the DDMA registers except the mask bit, which
+ * is stuck at 1. When I copy the contents of 0x18 +0x10
+ * to the DDMA base register, everything seems to work.
+ * The fun part is that the Windows Solo1 driver doesn't
+ * seem to do these tricks.
+ * Bugs remaining: plops and clicks when starting/stopping playback
*
*/
/*****************************************************************************/
-#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/string.h>
@@ -69,6 +82,10 @@
/* --------------------------------------------------------------------- */
+#undef OSS_DOCUMENTED_MIXER_SEMANTICS
+
+/* --------------------------------------------------------------------- */
+
#ifndef PCI_VENDOR_ID_ESS
#define PCI_VENDOR_ID_ESS 0x125d
#endif
@@ -78,9 +95,12 @@
#define SOLO1_MAGIC ((PCI_VENDOR_ID_ESS<<16)|PCI_DEVICE_ID_ESS_SOLO1)
+#define DDMABASE_OFFSET 0x10 /* chip bug workaround kludge */
+#define DDMABASE_EXTENT 16
+
#define IOBASE_EXTENT 16
#define SBBASE_EXTENT 16
-#define VCBASE_EXTENT 16
+#define VCBASE_EXTENT (DDMABASE_EXTENT+DDMABASE_OFFSET)
#define MPUBASE_EXTENT 4
#define GPBASE_EXTENT 4
@@ -98,16 +118,15 @@
/* --------------------------------------------------------------------- */
-#define DEBUGREC
-
-/* --------------------------------------------------------------------- */
-
struct solo1_state {
/* magic */
unsigned int magic;
- /* we keep sb cards in a linked list */
+ /* we keep the cards in a linked list */
struct solo1_state *next;
+
+ /* pcidev is needed to turn off the DDMA controller at driver shutdown */
+ struct pci_dev *pcidev;
/* soundcore stuff */
int dev_audio;
@@ -116,10 +135,10 @@
int dev_dmfm;
/* hardware resources */
- unsigned long iobase, sbbase, vcbase, mpubase, gpbase; /* long for SPARC */
+ unsigned long iobase, sbbase, vcbase, ddmabase, mpubase, gpbase; /* long for SPARC */
unsigned int irq;
- /* mixer registers; there is no HW readback */
+ /* mixer registers */
struct {
unsigned short vol[10];
unsigned int recsrc;
@@ -302,6 +321,8 @@
spin_lock_irqsave(&s->lock, flags);
if (!(s->ena & FMODE_WRITE) && (s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {
s->ena |= FMODE_WRITE;
+ write_mixer(s, 0x78, 0x12);
+ udelay(10);
write_mixer(s, 0x78, 0x13);
}
spin_unlock_irqrestore(&s->lock, flags);
@@ -326,47 +347,24 @@
&& s->dma_adc.ready) {
s->ena |= FMODE_READ;
write_ctrl(s, 0xb8, 0xf);
-#ifdef DEBUGREC
+#if 0
printk(KERN_DEBUG "solo1: DMAbuffer: 0x%08lx\n", (long)s->dma_adc.rawbuf);
printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x\n",
- inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
-#endif
- outb(0, s->vcbase+0xd); /* master reset */
-#ifdef DEBUGREC
- printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x (a. clr)\n",
- inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
-#endif
- outb(1, s->vcbase+0xf); /* mask */
-#ifdef DEBUGREC
- printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x (a. mask)\n",
- inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
-#endif
- outb(0x54/*0x14*/, s->vcbase+0xb); /* DMA_MODE_READ | DMA_MODE_AUTOINIT */
-#ifdef DEBUGREC
- printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x (a. wrmode)\n",
- inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
-#endif
- outl(virt_to_bus(s->dma_adc.rawbuf), s->vcbase);
-#ifdef DEBUGREC
- printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x (a. wrbase)\n",
- inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
-#endif
- outw(s->dma_adc.dmasize-1, s->vcbase+4);
-#ifdef DEBUGREC
- printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x (a. wrcnt)\n",
- inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
-#endif
- outb(0, s->vcbase+0xf);
-#ifdef DEBUGREC
- printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x (a. clrmask)\n",
- inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
+ inb(s->ddmabase+0xf), inw(s->ddmabase+4), inl(s->ddmabase), inb(s->ddmabase+8));
#endif
+ outb(0, s->ddmabase+0xd); /* master reset */
+ outb(1, s->ddmabase+0xf); /* mask */
+ outb(0x54/*0x14*/, s->ddmabase+0xb); /* DMA_MODE_READ | DMA_MODE_AUTOINIT */
+ outl(virt_to_bus(s->dma_adc.rawbuf), s->ddmabase);
+ outw(s->dma_adc.dmasize-1, s->ddmabase+4);
+ outb(0, s->ddmabase+0xf);
}
spin_unlock_irqrestore(&s->lock, flags);
-#ifdef DEBUGREC
- printk(KERN_DEBUG "solo1: start DMA: reg B8: 0x%02x DMAstat: 0x%02x DMAcnt: 0x%04x DMAmask: 0x%02x SBstat: 0x%02x\n",
- read_ctrl(s, 0xb8), inb(s->vcbase+8), inw(s->vcbase+4), inb(s->vcbase+0xf), inb(s->sbbase+0xc));
-
+#if 0
+ printk(KERN_DEBUG "solo1: start DMA: reg B8: 0x%02x SBstat: 0x%02x\n"
+ KERN_DEBUG "solo1: DMA: stat: 0x%02x cnt: 0x%04x mask: 0x%02x\n",
+ read_ctrl(s, 0xb8), inb(s->sbbase+0xc),
+ inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->ddmabase+0xf));
printk(KERN_DEBUG "solo1: A1: 0x%02x A2: 0x%02x A4: 0x%02x A5: 0x%02x A8: 0x%02x\n"
KERN_DEBUG "solo1: B1: 0x%02x B2: 0x%02x B4: 0x%02x B7: 0x%02x B8: 0x%02x B9: 0x%02x\n",
read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8),
@@ -456,16 +454,16 @@
va = virt_to_bus(s->dma_adc.rawbuf);
if ((va & ~((1<<24)-1)))
panic("solo1: buffer above 16M boundary");
- outb(0, s->vcbase+0xd); /* clear */
- outb(1, s->vcbase+0xf); /* mask */
- //outb(0, s->vcbase+8); /* enable (enable is active low!) */
- outb(0x54, s->vcbase+0xb); /* DMA_MODE_READ | DMA_MODE_AUTOINIT */
- outl(va, s->vcbase);
- outw(s->dma_adc.dmasize-1, s->vcbase+4);
+ outb(0, s->ddmabase+0xd); /* clear */
+ outb(1, s->ddmabase+0xf); /* mask */
+ /*outb(0, s->ddmabase+8);*/ /* enable (enable is active low!) */
+ outb(0x54, s->ddmabase+0xb); /* DMA_MODE_READ | DMA_MODE_AUTOINIT */
+ outl(va, s->ddmabase);
+ outw(s->dma_adc.dmasize-1, s->ddmabase+4);
c = - s->dma_adc.fragsamples;
write_ctrl(s, 0xa4, c);
write_ctrl(s, 0xa5, c >> 8);
- outb(0, s->vcbase+0xf);
+ outb(0, s->ddmabase+0xf);
s->dma_adc.ready = 1;
return 0;
}
@@ -513,12 +511,12 @@
/* update ADC pointer */
if (s->ena & FMODE_READ) {
- hwptr = (s->dma_adc.dmasize - 1 - inw(s->vcbase+4)) % s->dma_adc.dmasize;
+ hwptr = (s->dma_adc.dmasize - 1 - inw(s->ddmabase+4)) % s->dma_adc.dmasize;
diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
s->dma_adc.hwptr = hwptr;
s->dma_adc.total_bytes += diff;
s->dma_adc.count += diff;
-#ifdef DEBUGREC
+#if 0
printk(KERN_DEBUG "solo1: rd: hwptr %u swptr %u dmasize %u count %u\n",
s->dma_adc.hwptr, s->dma_adc.swptr, s->dma_adc.dmasize, s->dma_adc.count);
#endif
@@ -633,16 +631,28 @@
SOUND_MASK_MIC, SOUND_MASK_MIC, SOUND_MASK_CD, SOUND_MASK_VOLUME,
SOUND_MASK_MIC, 0, SOUND_MASK_LINE, 0
};
- static const unsigned char mixtable[SOUND_MIXER_NRDEVICES] = {
- [SOUND_MIXER_PCM] = 0x7c, /* voice */
- [SOUND_MIXER_SYNTH] = 0x36, /* FM */
- [SOUND_MIXER_CD] = 0x38, /* CD */
- [SOUND_MIXER_LINE] = 0x3e, /* Line */
- [SOUND_MIXER_LINE1] = 0x3a, /* AUX */
- [SOUND_MIXER_MIC] = 0x1a, /* Mic */
- [SOUND_MIXER_LINE2] = 0x6d /* Mono in */
+ static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {
+ [SOUND_MIXER_PCM] = 1, /* voice */
+ [SOUND_MIXER_SYNTH] = 2, /* FM */
+ [SOUND_MIXER_CD] = 3, /* CD */
+ [SOUND_MIXER_LINE] = 4, /* Line */
+ [SOUND_MIXER_LINE1] = 5, /* AUX */
+ [SOUND_MIXER_MIC] = 6, /* Mic */
+ [SOUND_MIXER_LINE2] = 7, /* Mono in */
+ [SOUND_MIXER_SPEAKER] = 8, /* Speaker */
+ [SOUND_MIXER_RECLEV] = 9, /* Recording level */
+ [SOUND_MIXER_VOLUME] = 10 /* Master Volume */
};
- unsigned char l, r, rl, rr;
+ static const unsigned char mixreg[] = {
+ 0x7c, /* voice */
+ 0x36, /* FM */
+ 0x38, /* CD */
+ 0x3e, /* Line */
+ 0x3a, /* AUX */
+ 0x1a, /* Mic */
+ 0x6d /* Mono in */
+ };
+ unsigned char l, r, rl, rr, vidx;
int i, val;
VALIDATE_STATE(s);
@@ -657,16 +667,6 @@
val = (read_mixer(s, 0x7d) & 0x08) ? 1 : 0;
return put_user(val, (int *)arg);
}
- if (cmd == SOUND_MIXER_PRIVATE1) {
- /* enable/disable/query mixer preamp */
- get_user_ret(val, (int *)arg, -EFAULT);
- if (val != -1) {
- val = val ? 0xff : 0xf7;
- write_mixer(s, 0x7d, (read_mixer(s, 0x7d) | 0x08) & val);
- }
- val = (read_mixer(s, 0x7d) & 0x08) ? 1 : 0;
- return put_user(val, (int *)arg);
- }
if (cmd == SOUND_MIXER_PRIVATE2) {
/* enable/disable/query spatializer */
get_user_ret(val, (int *)arg, -EFAULT);
@@ -720,36 +720,11 @@
case SOUND_MIXER_CAPS:
return put_user(SOUND_CAP_EXCL_INPUT, (int *)arg);
- case SOUND_MIXER_VOLUME:
- rl = read_mixer(s, 0x60);
- rr = read_mixer(s, 0x62);
- l = (rl * 3 + 11) / 2;
- if (rl & 0x40)
- l = 0;
- r = (rr * 3 + 11) / 2;
- if (rr & 0x40)
- r = 0;
- return put_user((((unsigned int)r) << 8) | l, (int *)arg);
-
- case SOUND_MIXER_SPEAKER:
- rl = read_mixer(s, 0x3c);
- l = (rl & 7) * 14 + 2;
- return put_user(l * 0x101, (int *)arg);
-
- case SOUND_MIXER_RECLEV:
- rl = read_ctrl(s, 0xb4);
- r = ((rl & 0xf) * 13 + 5) / 2;
- l = (((rl >> 4) & 0xf) * 13 + 5) / 2;
- return put_user((((unsigned int)r) << 8) | l, (int *)arg);
-
default:
i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i])
+ if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))
return -EINVAL;
- rl = read_mixer(s, mixtable[i]);
- r = ((rl & 0xf) * 13 + 5) / 2;
- l = (((rl >> 4) & 0xf) * 13 + 5) / 2;
- return put_user((((unsigned int)r) << 8) | l, (int *)arg);
+ return put_user(s->mix.vol[vidx-1], (int *)arg);
}
}
if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE))
@@ -757,21 +732,21 @@
s->mix.modcnt++;
switch (_IOC_NR(cmd)) {
case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-
- {
- static const unsigned char regs[] = {
- 0x1c, 0x1a, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x60, 0x62, 0x6d, 0x7c
- };
- int i;
-
- for (i = 0; i < sizeof(regs); i++)
- printk(KERN_DEBUG "solo1: mixer reg 0x%02x: 0x%02x\n",
- regs[i], read_mixer(s, regs[i]));
- printk(KERN_DEBUG "solo1: ctrl reg 0x%02x: 0x%02x\n",
- 0xb4, read_ctrl(s, 0xb4));
- }
-
- get_user_ret(val, (int *)arg, -EFAULT);
+#if 0
+ {
+ static const unsigned char regs[] = {
+ 0x1c, 0x1a, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x60, 0x62, 0x6d, 0x7c
+ };
+ int i;
+
+ for (i = 0; i < sizeof(regs); i++)
+ printk(KERN_DEBUG "solo1: mixer reg 0x%02x: 0x%02x\n",
+ regs[i], read_mixer(s, regs[i]));
+ printk(KERN_DEBUG "solo1: ctrl reg 0x%02x: 0x%02x\n",
+ 0xb4, read_ctrl(s, 0xb4));
+ }
+#endif
+ get_user_ret(val, (int *)arg, -EFAULT);
i = hweight32(val);
if (i == 0)
return 0;
@@ -810,7 +785,12 @@
}
write_mixer(s, 0x60, rl);
write_mixer(s, 0x62, rr);
- return put_user((((unsigned int)r) << 8) | l, (int *)arg);
+#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+ s->mix.vol[9] = ((unsigned int)r << 8) | l;
+#else
+ s->mix.vol[9] = val;
+#endif
+ return put_user(s->mix.vol[9], (int *)arg);
case SOUND_MIXER_SPEAKER:
get_user_ret(val, (int *)arg, -EFAULT);
@@ -822,7 +802,12 @@
rl = (l - 2) / 14;
l = rl * 14 + 2;
write_mixer(s, 0x3c, rl);
- return put_user(l * 0x101, (int *)arg);
+#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+ s->mix.vol[7] = l * 0x101;
+#else
+ s->mix.vol[7] = val;
+#endif
+ return put_user(s->mix.vol[7], (int *)arg);
case SOUND_MIXER_RECLEV:
get_user_ret(val, (int *)arg, -EFAULT);
@@ -841,11 +826,16 @@
r = (rl * 13 + 5) / 2;
l = (rr * 13 + 5) / 2;
write_ctrl(s, 0xb4, (rl << 4) | rr);
- return put_user((((unsigned int)r) << 8) | l, (int *)arg);
+#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+ s->mix.vol[8] = ((unsigned int)r << 8) | l;
+#else
+ s->mix.vol[8] = val;
+#endif
+ return put_user(s->mix.vol[8], (int *)arg);
default:
i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i])
+ if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))
return -EINVAL;
get_user_ret(val, (int *)arg, -EFAULT);
l = (val << 1) & 0x1fe;
@@ -862,8 +852,13 @@
rr = (r - 5) / 13;
r = (rl * 13 + 5) / 2;
l = (rr * 13 + 5) / 2;
- write_mixer(s, mixtable[i], (rl << 4) | rr);
- return put_user((((unsigned int)r) << 8) | l, (int *)arg);
+ write_mixer(s, mixreg[vidx-1], (rl << 4) | rr);
+#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
+ s->mix.vol[vidx-1] = ((unsigned int)r << 8) | l;
+#else
+ s->mix.vol[vidx-1] = val;
+#endif
+ return put_user(s->mix.vol[vidx-1], (int *)arg);
}
}
@@ -919,10 +914,8 @@
NULL, /* fsync */
NULL, /* fasync */
NULL, /* check_media_change */
-#if 0
NULL, /* revalidate */
NULL, /* lock */
-#endif
};
/* --------------------------------------------------------------------- */
@@ -931,7 +924,8 @@
{
DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
- int count, tmo;
+ int count;
+ unsigned tmo;
if (s->dma_dac.mapped)
return 0;
@@ -950,12 +944,12 @@
current->state = TASK_RUNNING;
return -EBUSY;
}
- tmo = (count * HZ) / s->rate;
+ tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->rate;
if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
tmo >>= 1;
if (s->channels > 1)
tmo >>= 1;
- if (!schedule_timeout(tmo ? : 1) && tmo)
+ if (!schedule_timeout(tmo + 1))
printk(KERN_DEBUG "solo1: dma timed out??\n");
}
remove_wait_queue(&s->dma_dac.wait, &wait);
@@ -996,7 +990,7 @@
cnt = count;
#ifdef DEBUGREC
printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x DMAstat: 0x%02x DMAcnt: 0x%04x SBstat: 0x%02x cnt: %u\n",
- read_ctrl(s, 0xb8), inb(s->vcbase+8), inw(s->vcbase+4), inb(s->sbbase+0xc), cnt);
+ read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc), cnt);
#endif
if (cnt <= 0) {
start_adc(s);
@@ -1007,12 +1001,10 @@
KERN_DEBUG "solo1_read: SBstat: 0x%02x cnt: %u\n",
read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8),
read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), read_ctrl(s, 0xb9),
- inl(s->vcbase), inw(s->vcbase+4), inb(s->vcbase+8), inb(s->vcbase+15), inb(s->sbbase+0xc), cnt);
+ inl(s->ddmabase), inw(s->ddmabase+4), inb(s->ddmabase+8), inb(s->ddmabase+15), inb(s->sbbase+0xc), cnt);
#endif
- if (inb(s->vcbase+15) & 1) {
+ if (inb(s->ddmabase+15) & 1)
printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n");
- return -EIO;
- }
if (file->f_flags & O_NONBLOCK)
return ret ? ret : -EAGAIN;
interruptible_sleep_on(&s->dma_adc.wait);
@@ -1023,7 +1015,7 @@
KERN_DEBUG "solo1_read: SBstat: 0x%02x cnt: %u\n",
read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8),
read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), read_ctrl(s, 0xb9),
- inl(s->vcbase), inw(s->vcbase+4), inb(s->vcbase+8), inb(s->vcbase+15), inb(s->sbbase+0xc), cnt);
+ inl(s->ddmabase), inw(s->ddmabase+4), inb(s->ddmabase+8), inb(s->ddmabase+15), inb(s->sbbase+0xc), cnt);
#endif
if (signal_pending(current))
return ret ? ret : -ERESTARTSYS;
@@ -1042,7 +1034,7 @@
start_adc(s);
#ifdef DEBUGREC
printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x DMAstat: 0x%02x DMAcnt: 0x%04x SBstat: 0x%02x\n",
- read_ctrl(s, 0xb8), inb(s->vcbase+8), inw(s->vcbase+4), inb(s->sbbase+0xc));
+ read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc));
#endif
}
return ret;
@@ -1304,7 +1296,7 @@
if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
return ret;
start_adc(s);
- if (inb(s->vcbase+15) & 1)
+ if (inb(s->ddmabase+15) & 1)
printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n");
} else
stop_adc(s);
@@ -1466,8 +1458,8 @@
}
if (file->f_mode & FMODE_READ) {
stop_adc(s);
- outb(1, s->vcbase+0xf); /* mask DMA channel */
- //outb(0, s->vcbase+0xd); /* DMA master clear */
+ outb(1, s->ddmabase+0xf); /* mask DMA channel */
+ outb(0, s->ddmabase+0xd); /* DMA master clear */
dealloc_dmabuf(&s->dma_adc);
}
s->open_mode &= ~(FMODE_READ | FMODE_WRITE);
@@ -1533,10 +1525,8 @@
NULL, /* fsync */
NULL, /* fasync */
NULL, /* check_media_change */
-#if 0
NULL, /* revalidate */
NULL, /* lock */
-#endif
};
/* --------------------------------------------------------------------- */
@@ -1550,7 +1540,7 @@
if (!(s->mpubase))
return;
wake = 0;
- while (inb(s->mpubase+1) & 0x80) {
+ while (!(inb(s->mpubase+1) & 0x80)) {
ch = inb(s->mpubase);
if (s->midi.icnt < MIDIINBUF) {
s->midi.ibuf[s->midi.iwr] = ch;
@@ -1562,7 +1552,7 @@
if (wake)
wake_up(&s->midi.iwait);
wake = 0;
- while ((inb(s->mpubase+1) & 0x40) && s->midi.ocnt > 0) {
+ while (!(inb(s->mpubase+1) & 0x40) && s->midi.ocnt > 0) {
outb(s->midi.obuf[s->midi.ord], s->mpubase);
s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF;
s->midi.ocnt--;
@@ -1577,22 +1567,12 @@
{
struct solo1_state *s = (struct solo1_state *)dev_id;
unsigned int intsrc;
-
- static unsigned lim = 0;
/* fastpath out, to ease interrupt sharing */
intsrc = inb(s->iobase+7); /* get interrupt source(s) */
if (!intsrc)
return;
(void)inb(s->sbbase+0xe); /* clear interrupt */
-#ifdef DEBUGREC
- if (intsrc & 0x10 && lim < 20) {
- lim++;
- printk(KERN_DEBUG "solo1: audio1int reg B8: 0x%02x DMAstat: 0x%02x DMAcnt: 0x%04x SBstat: 0x%02x\n",
- read_ctrl(s, 0xb8), inb(s->vcbase+8), inw(s->vcbase+4), inb(s->sbbase+0xc));
- }
- //printk(KERN_DEBUG "solo1: interrupt 0x%02x\n", intsrc);
-#endif
spin_lock(&s->lock);
/* clear audio interrupts first */
if (intsrc & 0x20)
@@ -1849,10 +1829,8 @@
NULL, /* fsync */
NULL, /* fasync */
NULL, /* check_media_change */
-#if 0
NULL, /* revalidate */
NULL, /* lock */
-#endif
};
/* --------------------------------------------------------------------- */
@@ -2025,10 +2003,8 @@
NULL, /* fsync */
NULL, /* fasync */
NULL, /* check_media_change */
-#if 0
NULL, /* revalidate */
NULL, /* lock */
-#endif
};
/* --------------------------------------------------------------------- */
@@ -2060,11 +2036,10 @@
struct pci_dev *pcidev = NULL;
mm_segment_t fs;
int i, val, index = 0;
- u16 ddmabase;
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "solo1: version v0.5 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "solo1: version v0.6 time " __TIME__ " " __DATE__ "\n");
while (index < NR_DEVICE &&
(pcidev = pci_find_device(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, pcidev))) {
if (pcidev->resource[0].start == 0 ||
@@ -2090,35 +2065,32 @@
init_waitqueue_head(&s->midi.owait);
init_MUTEX(&s->open_sem);
s->magic = SOLO1_MAGIC;
+ s->pcidev = pcidev;
s->iobase = pcidev->resource[0].start;
s->sbbase = pcidev->resource[1].start;
s->vcbase = pcidev->resource[2].start;
+ s->ddmabase = s->vcbase + DDMABASE_OFFSET;
s->mpubase = pcidev->resource[3].start;
s->gpbase = pcidev->resource[4].start;
s->irq = pcidev->irq;
if (check_region(s->iobase, IOBASE_EXTENT) ||
check_region(s->sbbase, SBBASE_EXTENT) ||
- check_region(s->vcbase, VCBASE_EXTENT) ||
+ check_region(s->ddmabase, DDMABASE_EXTENT) ||
check_region(s->mpubase, MPUBASE_EXTENT)) {
printk(KERN_ERR "solo1: io ports in use\n");
goto err_region;
}
request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1");
request_region(s->sbbase, SBBASE_EXTENT, "ESS Solo1");
- request_region(s->vcbase, VCBASE_EXTENT, "ESS Solo1");
+ request_region(s->ddmabase, DDMABASE_EXTENT, "ESS Solo1");
request_region(s->mpubase, MPUBASE_EXTENT, "ESS Solo1");
if (request_irq(s->irq, solo1_interrupt, SA_SHIRQ, "ESS Solo1", s)) {
printk(KERN_ERR "solo1: irq %u in use\n", s->irq);
goto err_irq;
}
/* initialize DDMA base address */
- /* use PCI config reg, and not vcbase, we need the bus view */
- pci_read_config_word(pcidev, 0x18, &ddmabase);
- pci_write_config_word(pcidev, 0x60, (ddmabase & (~0xf)) | 1);
-#ifdef DEBUGREC
- printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x\n",
- inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
-#endif
+ printk(KERN_DEBUG "solo1: ddma base address: 0x%lx\n", s->ddmabase);
+ pci_write_config_word(pcidev, 0x60, (s->ddmabase & (~0xf)) | 1);
/* set DMA policy to DDMA, IRQ emulation off (CLKRUN disabled for now) */
pci_write_config_dword(pcidev, 0x50, 0);
/* disable legacy audio address decode */
@@ -2147,21 +2119,9 @@
write_mixer(s, 0x52, 0);
write_mixer(s, 0x14, 0); /* DAC1 minimum volume */
write_mixer(s, 0x71, 0x20); /* enable new 0xA1 reg format */
-#ifdef DEBUGREC
- printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x\n",
- inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
-#endif
- outb(0, s->vcbase+0xd); /* DMA master clear */
-#ifdef DEBUGREC
- printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x\n",
- inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
-#endif
- outb(1, s->vcbase+0xf); /* mask channel */
-#ifdef DEBUGREC
- printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x\n",
- inb(s->vcbase+0xf), inw(s->vcbase+4), inl(s->vcbase), inb(s->vcbase+8));
-#endif
- //outb(0, s->vcbase+0x8); /* enable controller (enable is low active!!) */
+ outb(0, s->ddmabase+0xd); /* DMA master clear */
+ outb(1, s->ddmabase+0xf); /* mask channel */
+ /*outb(0, s->ddmabase+0x8);*/ /* enable controller (enable is low active!!) */
pci_set_master(pcidev); /* enable bus mastering */
@@ -2173,6 +2133,8 @@
val = initvol[i].vol;
mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
}
+ val = 1; /* enable mic preamp */
+ mixer_ioctl(s, SOUND_MIXER_PRIVATE1, (unsigned long)&val);
set_fs(fs);
/* queue it for later freeing */
s->next = devs;
@@ -2192,7 +2154,7 @@
err_irq:
release_region(s->iobase, IOBASE_EXTENT);
release_region(s->sbbase, SBBASE_EXTENT);
- release_region(s->vcbase, VCBASE_EXTENT);
+ release_region(s->ddmabase, DDMABASE_EXTENT);
release_region(s->mpubase, MPUBASE_EXTENT);
err_region:
kfree_s(s, sizeof(struct solo1_state));
@@ -2215,13 +2177,14 @@
devs = devs->next;
/* stop DMA controller */
outb(0, s->iobase+6);
- outb(0, s->vcbase+0xd); /* DMA master clear */
+ outb(0, s->ddmabase+0xd); /* DMA master clear */
outb(3, s->sbbase+6); /* reset sequencer and FIFO */
synchronize_irq();
+ pci_write_config_word(s->pcidev, 0x60, 0); /* turn off DDMA controller address space */
free_irq(s->irq, s);
release_region(s->iobase, IOBASE_EXTENT);
release_region(s->sbbase, SBBASE_EXTENT);
- release_region(s->vcbase, VCBASE_EXTENT);
+ release_region(s->ddmabase, DDMABASE_EXTENT);
release_region(s->mpubase, MPUBASE_EXTENT);
unregister_sound_dsp(s->dev_audio);
unregister_sound_mixer(s->dev_mixer);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)