patch-2.3.30 linux/drivers/sound/cmpci.c
Next file: linux/drivers/sound/es1371.c
Previous file: linux/drivers/sound/Makefile
Back to the patch index
Back to the overall index
- Lines: 674
- Date:
Sat Nov 27 15:27:48 1999
- Orig file:
v2.3.29/linux/drivers/sound/cmpci.c
- Orig date:
Mon Nov 1 13:56:26 1999
diff -u --recursive --new-file v2.3.29/linux/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c
@@ -21,7 +21,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * Special thanks to David C. Niemi
+ * Special thanks to David C. Niemi, Jan Pfeifer
*
*
* Module command line parameters:
@@ -59,8 +59,43 @@
* read/write cannot be executed
* 20 09 99 0.13 merged the generic changes in sonicvibes since this
* diverged.
+ * 18.08.99 1.5 Only deallocate DMA buffer when unloading.
+ * 02.09.99 1.6 Enable SPDIF LOOP
+ * Change the mixer read back
+ * 21.09.99 2.33 Use RCS version aas driver version.
+ * Add support for modem, S/PDIF loop and 4 channels.
+ * (8738 only)
+ * Fix bug cause x11amp cannot play.
+ * $Log: cmpci.c,v $
+ * Revision 2.41 1999/10/27 02:00:05 cltien
+ * Now the fragsize for modem is activated by parameter.
+ *
+ * Revision 2.40 1999/10/26 23:38:26 cltien
+ * Remove debugging message in cm_write which may cause module counter not 0.
+ *
+ * Revision 2.39 1999/10/26 21:52:50 cltien
+ * I forgor too adjust mic recording volume, as it should be moved to 5MUTEMONO.
+ * Change the DYNAMIC macro to FIXEDDMA, which means static DMA buffer.
+ *
+ * Revision 2.38 1999/10/08 21:59:03 cltien
+ * Set FLINKON and reset FLINKOFF for modem.
+ *
+ * Revision 2.37 1999/09/28 02:57:04 cltien
+ * Add set_bus_master() to make sure bus master enabled.
+ *
+ * Revision 2.36 1999/09/22 14:15:03 cltien
+ * Use open_sem to avoid multiple access to open_mode.
+ * Use wakeup in IntrClose to activate process in waiting queue.
+ *
+ * Revision 2.35 1999/09/22 13:20:53 cltien
+ * Use open_mode to check if DAC in used. Also more check in IntrWrite and IntrClose. Now the modem can access DAC safely.
+ *
+ * Revision 2.34 1999/09/22 03:29:57 cltien
+ * Use module count to decide which one to access the dac.
+ *
+ *
*/
-
+
/*****************************************************************************/
#include <linux/config.h>
@@ -252,6 +287,7 @@
unsigned fragsize;
unsigned dmasize;
unsigned fragsamples;
+ unsigned dmasamples;
/* OSS stuff */
unsigned mapped:1;
unsigned ready:1;
@@ -276,6 +312,7 @@
/* --------------------------------------------------------------------- */
static struct cm_state *devs = NULL;
+static struct cm_state *devaudio = NULL;
static unsigned long wavetable_mem = 0;
/* --------------------------------------------------------------------- */
@@ -331,7 +368,7 @@
outl(addr, s->iobase + CODEC_CMI_CH0_FRAME1);
outw(count, s->iobase + CODEC_CMI_CH0_FRAME2);
outb(inb(s->iobase + CODEC_CMI_FUNCTRL0) & ~1, s->iobase + CODEC_CMI_FUNCTRL0);
- outb(inb(s->iobase + CODEC_CMI_FUNCTRL0 + 2) | 1, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+// outb(inb(s->iobase + CODEC_CMI_FUNCTRL0 + 2) | 1, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
}
static void set_dmaadc(struct cm_state *s, unsigned int addr, unsigned int count)
@@ -340,13 +377,16 @@
outl(addr, s->iobase + CODEC_CMI_CH1_FRAME1);
outw(count, s->iobase + CODEC_CMI_CH1_FRAME2);
outb(inb(s->iobase + CODEC_CMI_FUNCTRL0) | 2, s->iobase + CODEC_CMI_FUNCTRL0);
- outb(inb(s->iobase + CODEC_CMI_FUNCTRL0 + 2) | 2, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+// outb(inb(s->iobase + CODEC_CMI_FUNCTRL0 + 2) | 2, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
}
extern __inline__ unsigned get_dmadac(struct cm_state *s)
{
unsigned int curr_addr;
+ if (!s->dma_dac.dmasize || !(s->enable & CM_CENABLE_PE))
+ return 0;
+
curr_addr = inl(s->iobase + CODEC_CMI_CH0_FRAME1);
curr_addr -= virt_to_bus(s->dma_dac.rawbuf);
curr_addr = s->dma_dac.dmasize - curr_addr;
@@ -358,6 +398,9 @@
{
unsigned int curr_addr;
+ if (!s->dma_adc.dmasize || !(s->enable & CM_CENABLE_RE))
+ return 0;
+
curr_addr = inl(s->iobase + CODEC_CMI_CH1_FRAME1);
curr_addr -= virt_to_bus(s->dma_adc.rawbuf);
curr_addr = s->dma_adc.dmasize - curr_addr;
@@ -421,7 +464,7 @@
{ 22050, (16000 + 22050) / 2, (22050 + 32000) / 2, 2 },
{ 32000, (22050 + 32000) / 2, (32000 + 44100) / 2, 6 },
{ 44100, (32000 + 44100) / 2, (44100 + 48000) / 2, 3 },
- { 48000, 48000, 48000, 7 }
+ { 48000, (44100 + 48000) /2, 48000, 7 }
};
static void set_dac_rate(struct cm_state *s, unsigned rate)
@@ -485,10 +528,12 @@
unsigned long flags;
spin_lock_irqsave(&s->lock, flags);
+ /* disable channel */
+ outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
s->enable &= ~CM_CENABLE_RE;
/* disable interrupt */
outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) & ~2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
- /* disable channel and reset */
+ /* reset */
outb(s->enable | CM_CH1_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
udelay(10);
outb(s->enable & ~CM_CH1_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
@@ -500,10 +545,12 @@
unsigned long flags;
spin_lock_irqsave(&s->lock, flags);
+ /* disable channel */
s->enable &= ~CM_CENABLE_PE;
+ outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
/* disable interrupt */
outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) & ~1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
- /* disable channel and reset */
+ /* reset */
outb(s->enable | CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
udelay(10);
outb(s->enable & ~CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
@@ -516,10 +563,10 @@
spin_lock_irqsave(&s->lock, flags);
if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {
+ outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) | 1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
s->enable |= CM_CENABLE_PE;
outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
}
- outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) | 1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
spin_unlock_irqrestore(&s->lock, flags);
}
@@ -530,10 +577,10 @@
spin_lock_irqsave(&s->lock, flags);
if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
&& s->dma_adc.ready) {
+ outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) | 2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
s->enable |= CM_CENABLE_RE;
outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
}
- outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) | 2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
spin_unlock_irqrestore(&s->lock, flags);
}
@@ -593,10 +640,10 @@
return -ENOMEM;
db->buforder = order;
if ((virt_to_bus(db->rawbuf) ^ (virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1)) & ~0xffff)
- printk(KERN_DEBUG "cm: DMA buffer crosses 64k boundary: busaddr 0x%lx size %ld\n",
+ printk(KERN_DEBUG "cmpci: DMA buffer crosses 64k boundary: busaddr 0x%lx size %ld\n",
virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder);
if ((virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1) & ~0xffffff)
- printk(KERN_DEBUG "cm: DMA buffer beyond 16MB: busaddr 0x%lx size %ld\n",
+ printk(KERN_DEBUG "cmpci: DMA buffer beyond 16MB: busaddr 0x%lx size %ld\n",
virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder);
/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
@@ -623,17 +670,21 @@
db->fragsize = 1 << db->fragshift;
if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
db->numfrag = db->ossmaxfrags;
-#if 1
- /* to make fragsize >= 4096 */
- while (db->fragsize < 4096 && db->numfrag >= 4)
- {
- db->fragsize *= 2;
- db->fragshift++;
- db->numfrag /= 2;
+ /* to make fragsize >= 4096 */
+#if 0
+ if(s->modem)
+ {
+ while (db->fragsize < 4096 && db->numfrag >= 4)
+ {
+ db->fragsize *= 2;
+ db->fragshift++;
+ db->numfrag /= 2;
+ }
}
-#endif
+#endif
db->fragsamples = db->fragsize >> sample_shift[fmt];
db->dmasize = db->numfrag << db->fragshift;
+ db->dmasamples = db->dmasize >> sample_shift[fmt];
memset(db->rawbuf, (fmt & CM_CFMT_16BIT) ? 0 : 0x80, db->dmasize);
spin_lock_irqsave(&s->lock, flags);
if (rec) {
@@ -665,6 +716,7 @@
len -= x;
}
memset(buf + bptr, c, len);
+ outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
}
/* call with spinlock held! */
@@ -752,25 +804,26 @@
unsigned int intsrc, intstat;
/* fastpath out, to ease interrupt sharing */
- intsrc = inb(s->iobase + CODEC_CMI_INT_STATUS);
- if (!(intsrc & (CM_INT_CH0 | CM_INT_CH1)))
+ intsrc = inl(s->iobase + CODEC_CMI_INT_STATUS);
+ if (!(intsrc & 0x80000000))
return;
spin_lock(&s->lock);
intstat = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2);
- /* disable interrupt */
+ /* acknowledge interrupt */
if (intsrc & CM_INT_CH0)
+ {
outb(intstat & ~1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
+ udelay(10);
+ outb(intstat | 1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
+ }
if (intsrc & CM_INT_CH1)
+ {
outb(intstat & ~2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
+ udelay(10);
+ outb(intstat | 2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
+ }
cm_update_ptr(s);
-#ifdef SOUND_CONFIG_CMPCI_MIDI
cm_handle_midi(s);
-#endif
- /* enable interrupt */
- if (intsrc & CM_INT_CH0)
- outb(intstat | 1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
- if (intsrc & CM_INT_CH1)
- outb(intstat | 2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
spin_unlock(&s->lock);
}
@@ -788,7 +841,7 @@
/* --------------------------------------------------------------------- */
-static const char invalid_magic[] = KERN_CRIT "cm: invalid magic value\n";
+static const char invalid_magic[] = KERN_CRIT "cmpci: invalid magic value\n";
#ifdef CONFIG_SOUND_CMPCI /* support multiple chips */
#define VALIDATE_STATE(s)
@@ -808,6 +861,7 @@
#define MT_5MUTE 2
#define MT_4MUTEMONO 3
#define MT_6MUTE 4
+#define MT_5MUTEMONO 5
static const struct {
unsigned left;
@@ -818,7 +872,7 @@
} mixtable[SOUND_MIXER_NRDEVICES] = {
[SOUND_MIXER_CD] = { DSP_MIX_CDVOLIDX_L, DSP_MIX_CDVOLIDX_R, MT_5MUTE, 0x04, 0x02 },
[SOUND_MIXER_LINE] = { DSP_MIX_LINEVOLIDX_L, DSP_MIX_LINEVOLIDX_R, MT_5MUTE, 0x10, 0x08 },
- [SOUND_MIXER_MIC] = { DSP_MIX_MICVOLIDX, CODEC_CMI_MIXER2, MT_4MUTEMONO, 0x01, 0x01 },
+ [SOUND_MIXER_MIC] = { DSP_MIX_MICVOLIDX, DSP_MIX_MICVOLIDX, MT_5MUTEMONO, 0x01, 0x01 },
[SOUND_MIXER_SYNTH] = { DSP_MIX_FMVOLIDX_L, DSP_MIX_FMVOLIDX_R, MT_5MUTE, 0x40, 0x00 },
[SOUND_MIXER_VOLUME] = { DSP_MIX_MASTERVOLIDX_L, DSP_MIX_MASTERVOLIDX_R, MT_5MUTE, 0x00, 0x00 },
[SOUND_MIXER_PCM] = { DSP_MIX_VOICEVOLIDX_L, DSP_MIX_VOICEVOLIDX_R, MT_5MUTE, 0x00, 0x00 }
@@ -851,10 +905,16 @@
r = l;
break;
+ case MT_5MUTEMONO:
+ r = l;
+ rl = 100 - 3 * ((l >> 3) & 31);
+ rr = rl;
+ break;
+
case MT_5MUTE:
default:
- rl = 100 - 3 * (l & 31);
- rr = 100 - 3 * (r & 31);
+ rl = 100 - 3 * ((l >> 3) & 31);
+ rr = 100 - 3 * ((r >> 3) & 31);
break;
case MT_6MUTE:
@@ -992,7 +1052,7 @@
}
spin_lock_irqsave(&s->lock, flags);
wrmixer(s, DSP_MIX_ADCMIXIDX_L, j);
- wrmixer(s, DSP_MIX_ADCMIXIDX_R, (j & 1) | j>>1);
+ wrmixer(s, DSP_MIX_ADCMIXIDX_R, (j & 1) | (j>>1));
spin_unlock_irqrestore(&s->lock, flags);
return 0;
@@ -1041,6 +1101,14 @@
outb((inb(s->iobase + CODEC_CMI_MIXER2) & ~0x0e) | rr<<1, s->iobase + CODEC_CMI_MIXER2);
break;
+ case MT_5MUTEMONO:
+ r = l;
+ rl = l < 4 ? 0 : (l - 5) / 3;
+ rr = rl >> 2;
+ wrmixer(s, mixtable[i].left, rl<<3);
+ outb((inb(s->iobase + CODEC_CMI_MIXER2) & ~0x0e) | rr<<1, s->iobase + CODEC_CMI_MIXER2);
+ break;
+
case MT_5MUTE:
rl = l < 4 ? 0 : (l - 5) / 3;
rr = r < 4 ? 0 : (r - 5) / 3;
@@ -1154,10 +1222,10 @@
current->state = TASK_RUNNING;
return -EBUSY;
}
- tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac;
+ tmo = (count * HZ) / s->ratedac;
tmo >>= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK];
- if (!schedule_timeout(tmo + 1))
- printk(KERN_DEBUG "cm: dma timed out??\n");
+ if (!schedule_timeout(tmo ? : 1) && tmo)
+ printk(KERN_DEBUG "cmpci: dma timed out??\n");
}
remove_wait_queue(&s->dma_dac.wait, &wait);
current->state = TASK_RUNNING;
@@ -1204,7 +1272,18 @@
start_adc(s);
if (file->f_flags & O_NONBLOCK)
return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&s->dma_adc.wait);
+ if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) {
+ printk(KERN_DEBUG "cmpci: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+ s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
+ s->dma_adc.hwptr, s->dma_adc.swptr);
+ stop_adc(s);
+ spin_lock_irqsave(&s->lock, flags);
+ set_dmaadc(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.dmasamples);
+ /* program sample counts */
+ outw(s->dma_adc.fragsamples-1, s->iobase + CODEC_CMI_CH1_FRAME2 + 2);
+ s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
+ spin_unlock_irqrestore(&s->lock, flags);
+ }
if (signal_pending(current))
return ret ? ret : -ERESTARTSYS;
continue;
@@ -1264,7 +1343,18 @@
start_dac(s);
if (file->f_flags & O_NONBLOCK)
return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&s->dma_dac.wait);
+ if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) {
+ printk(KERN_DEBUG "cmpci: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+ s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count,
+ s->dma_dac.hwptr, s->dma_dac.swptr);
+ stop_dac(s);
+ spin_lock_irqsave(&s->lock, flags);
+ set_dmadac(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.dmasamples);
+ /* program sample counts */
+ outw(s->dma_dac.fragsamples-1, s->iobase + CODEC_CMI_CH0_FRAME2 + 2);
+ s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
+ spin_unlock_irqrestore(&s->lock, flags);
+ }
if (signal_pending(current))
return ret ? ret : -ERESTARTSYS;
continue;
@@ -1730,7 +1820,6 @@
NULL, /* lock */
};
-#ifdef CONFIG_SOUND_CMPCI_MIDI
/* --------------------------------------------------------------------- */
static ssize_t cm_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
@@ -1971,7 +2060,7 @@
}
tmo = (count * HZ) / 3100;
if (!schedule_timeout(tmo ? : 1) && tmo)
- printk(KERN_DEBUG "cm: midi timed out??\n");
+ printk(KERN_DEBUG "cmpci: midi timed out??\n");
}
remove_wait_queue(&s->midi.owait, &wait);
set_current_state(TASK_RUNNING);
@@ -2011,11 +2100,9 @@
NULL, /* revalidate */
NULL, /* lock */
};
-#endif
/* --------------------------------------------------------------------- */
-#ifdef CONFIG_SOUND_CMPCI_FM
static int cm_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
static const unsigned char op_offset[18] = {
@@ -2187,7 +2274,6 @@
NULL, /* revalidate */
NULL, /* lock */
};
-#endif /* CONFIG_SOUND_CMPCI_FM */
/* --------------------------------------------------------------------- */
@@ -2215,8 +2301,31 @@
};
#ifdef MODULE
-int __init init_module(void)
+static int spdif_loop = 0;
+static int four_ch = 0;
+static int rear_out = 0;
+MODULE_PARM(spdif_loop, "i");
+MODULE_PARM(four_ch, "i");
+MODULE_PARM(rear_out, "i");
+
+int __init init_module(void)
+#else
+#ifdef CONFIG_SOUND_CMPCI_SPDIFLOOP
+static int spdif_loop = 1;
#else
+static int spdif_loop = 0;
+#endif
+#ifdef CONFIG_SOUND_CMPCI_4CH
+static int four_ch = 1;
+#else
+static int four_ch = 0;
+#endif
+#ifdef CONFIG_SOUND_CMPCI_REAR
+static int rear_out = 1;
+#else
+static int read_out = 0;
+#endif
+
int __init init_cmpci(void)
#endif
{
@@ -2224,6 +2333,7 @@
struct pci_dev *pcidev = NULL;
mm_segment_t fs;
int i, val, index = 0;
+
struct {
unsigned short deviceid;
char *devicename;
@@ -2239,10 +2349,10 @@
if (!pci_present()) /* No PCI bus in this machine! */
#endif
return -ENODEV;
- printk(KERN_INFO "cm: version v1.1 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "cmpci: version v2.41-nomodem time " __TIME__ " " __DATE__ "\n");
#if 0
if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
- printk(KERN_INFO "cm: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
+ printk(KERN_INFO "cmpci: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
#endif
while (index < NR_DEVICE && pcidev == NULL && (
(pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, pcidev)) ||
@@ -2251,7 +2361,7 @@
if (pcidev->irq == 0)
continue;
if (!(s = kmalloc(sizeof(struct cm_state), GFP_KERNEL))) {
- printk(KERN_WARNING "cm: out of memory\n");
+ printk(KERN_WARNING "cmpci: out of memory\n");
continue;
}
/* search device name */
@@ -2272,65 +2382,60 @@
init_MUTEX(&s->open_sem);
s->magic = CM_MAGIC;
s->iobase = pcidev->resource[0].start;
-#ifdef CONFIG_SOUND_CMPCI_FM
s->iosynth = 0x388;
-#endif
-#ifdef CONFIG_SOUND_CMPCI_MIDI
s->iomidi = 0x330;
-#endif
if (s->iobase == 0)
continue;
s->irq = pcidev->irq;
if (check_region(s->iobase, CM_EXTENT_CODEC)) {
- printk(KERN_ERR "cm: io ports %#x-%#x in use\n", s->iobase, s->iobase+CM_EXTENT_CODEC-1);
+ printk(KERN_ERR "cmpci: io ports %#x-%#x in use\n", s->iobase, s->iobase+CM_EXTENT_CODEC-1);
goto err_region5;
}
request_region(s->iobase, CM_EXTENT_CODEC, "cmpci");
-#ifdef CONFIG_SOUND_CMPCI_MIDI
if (check_region(s->iomidi, CM_EXTENT_MIDI)) {
- printk(KERN_ERR "cm: io ports %#x-%#x in use\n", s->iomidi, s->iomidi+CM_EXTENT_MIDI-1);
- goto err_region4;
+ printk(KERN_WARNING "cmpci: io ports %#x-%#x in use, midi disabled.\n", s->iomidi, s->iomidi+CM_EXTENT_MIDI-1);
+ s->iomidi = 0;
+ }
+ else
+ {
+ request_region(s->iomidi, CM_EXTENT_MIDI, "cmpci Midi");
+ /* set IO based at 0x330 */
+ outb(inb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3) & ~0x60, s->iobase + CODEC_CMI_LEGACY_CTRL + 3);
}
- request_region(s->iomidi, CM_EXTENT_MIDI, "cmpci Midi");
- /* set IO based at 0x330 */
- outb(inb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3) & ~0x60, s->iobase + CODEC_CMI_LEGACY_CTRL + 3);
-#endif
-#ifdef CONFIG_SOUND_CMPCI_FM
if (check_region(s->iosynth, CM_EXTENT_SYNTH)) {
- printk(KERN_ERR "cm: io ports %#x-%#x in use\n", s->iosynth, s->iosynth+CM_EXTENT_SYNTH-1);
- goto err_region1;
+ printk(KERN_WARNING "cmpci: io ports %#x-%#x in use, synth disabled.\n", s->iosynth, s->iosynth+CM_EXTENT_SYNTH-1);
+ s->iosynth = 0;
+ }
+ else
+ {
+ request_region(s->iosynth, CM_EXTENT_SYNTH, "cmpci FM");
+ /* enable FM */
+ outb(inb(s->iobase + CODEC_CMI_MISC_CTRL + 2) | 8, s->iobase + CODEC_CMI_MISC_CTRL);
}
- request_region(s->iosynth, CM_EXTENT_SYNTH, "cmpci FM");
- /* enable FM */
- outb(inb(s->iobase + CODEC_CMI_MISC_CTRL + 2) | 8, s->iobase + CODEC_CMI_MISC_CTRL);
-#endif
/* initialize codec registers */
outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2); /* disable ints */
- outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* reset channels */
+ outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */
/* reset mixer */
wrmixer(s, DSP_MIX_DATARESETIDX, 0);
/* request irq */
if (request_irq(s->irq, cm_interrupt, SA_SHIRQ, "cmpci", s)) {
- printk(KERN_ERR "cm: irq %u in use\n", s->irq);
+ printk(KERN_ERR "cmpci: irq %u in use\n", s->irq);
goto err_irq;
}
- printk(KERN_INFO "cm: found %s adapter at io %#06x irq %u\n",
+ printk(KERN_INFO "cmpci: found %s adapter at io %#06x irq %u\n",
devicename, s->iobase, s->irq);
/* register devices */
if ((s->dev_audio = register_sound_dsp(&cm_audio_fops, -1)) < 0)
goto err_dev1;
if ((s->dev_mixer = register_sound_mixer(&cm_mixer_fops, -1)) < 0)
goto err_dev2;
-#ifdef CONFIG_SOUND_CMPCI_MIDI
- if ((s->dev_midi = register_sound_midi(&cm_midi_fops, -1)) < 0)
+ if (s->iomidi && (s->dev_midi = register_sound_midi(&cm_midi_fops, -1)) < 0)
goto err_dev3;
-#endif
-#ifdef CONFIG_SOUND_CMPCI_FM
- if ((s->dev_dmfm = register_sound_special(&cm_dmfm_fops, 15 /* ?? */)) < 0)
+ if (s->iosynth && (s->dev_dmfm = register_sound_special(&cm_dmfm_fops, 15 /* ?? */)) < 0)
goto err_dev4;
-#endif
+ pci_set_master(pcidev);
/* initialize the chips */
fs = get_fs();
set_fs(KERNEL_DS);
@@ -2344,6 +2449,38 @@
mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
}
set_fs(fs);
+ if (pcidev->device == PCI_DEVICE_ID_CMEDIA_CM8738)
+ {
+ /* enable SPDIF loop */
+ if (spdif_loop)
+ {
+ /* turn on spdif-in to spdif-out */
+ outb(inb(s->iobase + CODEC_CMI_FUNCTRL1) | 0x80, s->iobase + CODEC_CMI_FUNCTRL1);
+ printk(KERN_INFO "cmpci: Enable SPDIF loop\n");
+ }
+ else
+ outb(inb(s->iobase + CODEC_CMI_FUNCTRL1) & ~0x80, s->iobase + CODEC_CMI_FUNCTRL1);
+ /* enable 4 channels mode */
+ if (four_ch)
+ {
+ /* 4 channel mode (analog duplicate) */
+ outb(inb(s->iobase + CODEC_CMI_MISC_CTRL + 3) | 0x04, s->iobase + CODEC_CMI_MISC_CTRL + 3);
+ printk(KERN_INFO "cmpci: Enable 4 channels mode\n");
+ /* has separate rear-out jack ? */
+ if (rear_out)
+ {
+ /* has separate rear out jack */
+ outb(inb(s->iobase + CODEC_CMI_MIXER1) & ~0x20, s->iobase + CODEC_CMI_MIXER1);
+ }
+ else
+ {
+ outb(inb(s->iobase + CODEC_CMI_MIXER1) | 0x20, s->iobase + CODEC_CMI_MIXER1);
+ printk(KERN_INFO "cmpci: line-in routed as rear-out\n");
+ }
+ }
+ else
+ outb(inb(s->iobase + CODEC_CMI_MISC_CTRL + 3) & ~0x04, s->iobase + CODEC_CMI_MISC_CTRL + 3);
+ }
/* queue it for later freeing */
s->next = devs;
devs = s;
@@ -2357,16 +2494,14 @@
err_dev2:
unregister_sound_dsp(s->dev_audio);
err_dev1:
- printk(KERN_ERR "cm: cannot register misc device\n");
+ printk(KERN_ERR "cmpci: cannot register misc device\n");
free_irq(s->irq, s);
err_irq:
-#ifdef CONFIG_SOUND_CMPCI_FM
- release_region(s->iosynth, CM_EXTENT_SYNTH);
+ if(s->iosynth)
+ release_region(s->iosynth, CM_EXTENT_SYNTH);
err_region1:
-#endif
-#ifdef CONFIG_SOUND_CMPCI_MIDI
- release_region(s->iomidi, CM_EXTENT_MIDI);
-#endif
+ if(s->iomidi)
+ release_region(s->iomidi, CM_EXTENT_MIDI);
err_region4:
release_region(s->iobase, CM_EXTENT_CODEC);
err_region5:
@@ -2395,32 +2530,30 @@
devs = devs->next;
outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2); /* disable ints */
synchronize_irq();
- outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* reset channels */
+ outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */
free_irq(s->irq, s);
/* reset mixer */
wrmixer(s, DSP_MIX_DATARESETIDX, 0);
release_region(s->iobase, CM_EXTENT_CODEC);
-#ifdef CONFIG_SOUND_CMPCI_MIDI
- release_region(s->iomidi, CM_EXTENT_MIDI);
-#endif
-#ifdef CONFIG_SOUND_CMPCI_FM
- release_region(s->iosynth, CM_EXTENT_SYNTH);
-#endif
+ if(s->iomidi)
+ {
+ release_region(s->iomidi, CM_EXTENT_MIDI);
+ unregister_sound_midi(s->dev_midi);
+ }
+ if(s->iosynth)
+ {
+ release_region(s->iosynth, CM_EXTENT_SYNTH);
+ unregister_sound_special(s->dev_dmfm);
+ }
unregister_sound_dsp(s->dev_audio);
unregister_sound_mixer(s->dev_mixer);
-#ifdef CONFIG_SOUND_CMPCI_MIDI
- unregister_sound_midi(s->dev_midi);
-#endif
-#ifdef CONFIG_SOUND_CMPCI_FM
- unregister_sound_special(s->dev_dmfm);
-#endif
kfree_s(s, sizeof(struct cm_state));
}
if (wavetable_mem)
free_pages(wavetable_mem, 20-PAGE_SHIFT);
- printk(KERN_INFO "cm: unloading\n");
+ printk(KERN_INFO "cmpci: unloading\n");
}
#endif /* MODULE */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)