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

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)