patch-2.2.11 linux/drivers/sbus/audio/cs4231.c
Next file: linux/drivers/sbus/audio/cs4231.h
Previous file: linux/drivers/sbus/audio/audio.c
Back to the patch index
Back to the overall index
- Lines: 227
- Date:
Mon Aug 9 12:05:13 1999
- Orig file:
v2.2.10/linux/drivers/sbus/audio/cs4231.c
- Orig date:
Wed Apr 28 08:47:39 1999
diff -u --recursive --new-file v2.2.10/linux/drivers/sbus/audio/cs4231.c linux/drivers/sbus/audio/cs4231.c
@@ -1,7 +1,9 @@
/*
* drivers/sbus/audio/cs4231.c
*
- * Copyright 1996, 1997, 1998 Derrick J Brashear (shadow@andrew.cmu.edu)
+ * Copyright 1996, 1997, 1998, 1999 Derrick J Brashear (shadow@andrew.cmu.edu)
+ * The 4231/ebus support was written by David Miller, who didn't bother
+ * crediting himself here, so I will.
*
* Based on the AMD7930 driver:
* Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
@@ -11,7 +13,7 @@
*
* This was culled from the Crystal docs on the 4231a, and the addendum they
* faxed me on the 4231.
- * The APC DMA controller support unfortunately is not documented. Thanks, Sun
+ * The APC DMA controller support unfortunately is not documented. Thanks, Sun.
*/
#include <linux/config.h>
@@ -69,15 +71,17 @@
static int cs4231_play_gain(struct sparcaudio_driver *drv, int value,
unsigned char balance);
static void cs4231_ready(struct sparcaudio_driver *drv);
-static void cs4231_playintr(struct sparcaudio_driver *drv);
+static void cs4231_playintr(struct sparcaudio_driver *drv, int);
static int cs4231_recintr(struct sparcaudio_driver *drv);
static int cs4231_output_muted(struct sparcaudio_driver *drv, int value);
static void cs4231_pollinput(struct sparcaudio_driver *drv);
-static void eb4231_pollinput(struct sparcaudio_driver *drv);
static int cs4231_length_to_samplecount(struct audio_prinfo *thisdir,
unsigned int length);
static void cs4231_getsamplecount(struct sparcaudio_driver *drv,
unsigned int length, unsigned int value);
+#ifdef EB4231_SUPPORT
+static void eb4231_pollinput(struct sparcaudio_driver *drv);
+#endif
#define CHIP_READY udelay(100); cs4231_ready(drv); udelay(1000);
@@ -1228,11 +1232,20 @@
MOD_DEC_USE_COUNT;
}
-static void cs4231_playintr(struct sparcaudio_driver *drv)
+static void cs4231_playintr(struct sparcaudio_driver *drv, int push)
{
struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
int status = 0;
+ if (!push) {
+ if (!cs4231_chip->perchip_info.play.active) {
+ cs4231_chip->regs->dmapnva = cs4231_chip->output_next_dma_handle;
+ cs4231_chip->regs->dmapnc = cs4231_chip->output_next_dma_size;
+ }
+ sparcaudio_output_done(drv, 0);
+ return;
+ }
+
if (cs4231_chip->playlen == 0 && cs4231_chip->output_size > 0)
cs4231_chip->playlen = cs4231_chip->output_size;
@@ -1421,7 +1434,7 @@
status += 2;
}
- sparcaudio_input_done(drv, 1);
+ sparcaudio_input_done(drv, status);
return 1;
}
@@ -1489,21 +1502,20 @@
cs4231_chip->regs->dmacsr &= ~APC_XINT_PLAY;
cs4231_chip->regs->dmacsr &= ~APC_PPAUSE;
- cs4231_playintr(drv);
+ cs4231_playintr(drv, cs4231_chip->regs->dmapnva == 0 ? 1 : 0);
cs4231_chip->regs->dmacsr |= APC_PLAY_SETUP;
cs4231_enable_play(drv);
cs4231_ready(drv);
- } else
- cs4231_playintr(drv);
+ }
}
#ifdef EB4231_SUPPORT
static void eb4231_stop_output(struct sparcaudio_driver *drv)
{
struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
- int dcsr;
+ unsigned int dcsr;
dprintk(("eb4231_stop_output: dcsr 0x%x dacr 0x%x dbcr %d\n",
readl(&cs4231_chip->eb2p->dcsr),
@@ -1635,6 +1647,68 @@
cs4231_pollinput(drv);
}
+#ifdef EB4231_SUPPORT
+static void eb4231_start_input(struct sparcaudio_driver *drv, __u8 * buffer,
+ unsigned long count)
+{
+ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+ unsigned int dcsr;
+
+ cs4231_chip->input_ptr = buffer;
+ cs4231_chip->input_size = count;
+
+ if (cs4231_chip->perchip_info.record.active ||
+ (cs4231_chip->perchip_info.record.pause))
+ return;
+
+ cs4231_ready(drv);
+
+ cs4231_chip->perchip_info.record.active = 1;
+ cs4231_chip->recording_count = 0;
+
+ dcsr = readl(&cs4231_chip->eb2c->dcsr);
+ if (!(dcsr & EBUS_DCSR_EN_DMA)) {
+ writel(EBUS_DCSR_RESET, &(cs4231_chip->eb2c->dcsr));
+ writel(EBUS_DCSR_BURST_SZ_16, &(cs4231_chip->eb2c->dcsr));
+
+ eb4231_recintr(drv);
+
+ writel(EBUS_DCSR_BURST_SZ_16 |
+ (EBUS_DCSR_EN_DMA | EBUS_DCSR_INT_EN | EBUS_DCSR_EN_CNT | EBUS_DCSR_EN_NEXT),
+ &(cs4231_chip->eb2c->dcsr));
+
+ cs4231_enable_rec(drv);
+ cs4231_ready(drv);
+ } else
+ eb4231_recintr(drv);
+}
+
+static void eb4231_stop_input(struct sparcaudio_driver *drv)
+{
+ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+ unsigned int dcsr;
+
+ cs4231_chip->perchip_info.record.active = 0;
+
+ cs4231_chip->input_ptr = NULL;
+ cs4231_chip->input_size = 0;
+ if (cs4231_chip->input_dma_handle) {
+ cs4231_chip->input_dma_handle = 0;
+ cs4231_chip->input_dma_size = 0;
+ }
+ if (cs4231_chip->input_next_dma_handle) {
+ cs4231_chip->input_next_dma_handle = 0;
+ cs4231_chip->input_next_dma_size = 0;
+ }
+
+ dcsr = readl(&(cs4231_chip->eb2c->dcsr));
+ if (dcsr & EBUS_DCSR_EN_DMA)
+ writel(dcsr & ~EBUS_DCSR_EN_DMA, &(cs4231_chip->eb2c->dcsr));
+
+ cs4231_disable_rec(drv);
+}
+#endif
+
static int cs4231_set_output_pause(struct sparcaudio_driver *drv, int value)
{
struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
@@ -1763,13 +1837,25 @@
struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
int dummy;
- /* Read status. */
- dummy = readl(&cs4231_chip->eb2c->dcsr);
+ /* Clear the interrupt. */
+ dummy = readl(&(cs4231_chip->eb2c->dcsr));
+ writel(dummy, &(cs4231_chip->eb2c->dcsr));
- cs4231_chip->perchip_info.record.samples +=
- cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.record),
- cs4231_chip->reclen);
- eb4231_recintr(drv);
+ if ((dummy & EBUS_DCSR_TC) != 0
+ /*&& (dummy & EBUS_DCSR_A_LOADED) != 0*/) {
+ cs4231_chip->perchip_info.record.samples +=
+ cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.record),
+ cs4231_chip->reclen);
+ eb4231_recintr(drv);
+ }
+
+ if ((dummy & EBUS_DCSR_A_LOADED) == 0) {
+ cs4231_chip->perchip_info.record.active = 0;
+ eb4231_recintr(drv);
+#if 1
+ eb4231_getsamplecount(drv, cs4231_chip->reclen, 1);
+#endif
+ }
}
/* ebus audio play interrupt handler. */
@@ -1827,7 +1913,8 @@
cs4231_chip->perchip_info.play.samples +=
cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.play),
cs4231_chip->playlen);
- cs4231_playintr(drv);
+ if (!(dummy & APC_XINT_EMPT))
+ cs4231_playintr(drv, 1);
}
/* Any other conditions we need worry about? */
}
@@ -1859,7 +1946,7 @@
cs4231_chip->perchip_info.play.error = 1;
}
cs4231_chip->perchip_info.play.active = 0;
- cs4231_playintr(drv);
+ cs4231_playintr(drv, 0);
cs4231_getsamplecount(drv, cs4231_chip->playlen, 0);
}
@@ -1937,8 +2024,8 @@
cs4231_ioctl,
eb4231_start_output,
eb4231_stop_output,
- cs4231_start_input,
- cs4231_stop_input,
+ eb4231_start_input,
+ eb4231_stop_input,
cs4231_audio_getdev,
cs4231_set_output_volume,
cs4231_get_output_volume,
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)