patch-2.2.4 linux/drivers/sbus/audio/cs4231.c

Next file: linux/drivers/sbus/audio/cs4231.h
Previous file: linux/drivers/sbus/audio/cs4215.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.3/linux/drivers/sbus/audio/cs4231.c linux/drivers/sbus/audio/cs4231.c
@@ -14,6 +14,7 @@
  * The APC DMA controller support unfortunately is not documented. Thanks, Sun
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -24,6 +25,7 @@
 #include <linux/delay.h>
 #include <linux/soundcard.h>
 #include <linux/version.h>
+#include <linux/ioport.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/system.h>
@@ -31,6 +33,10 @@
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/sbus.h>
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff && defined(CONFIG_PCI)
+#define EB4231_SUPPORT
+#include <asm/ebus.h>
+#endif
 
 #include <asm/audioio.h>
 #include "cs4231.h"
@@ -120,6 +126,7 @@
   tprintk(("enabling play\n"));
   save_flags(flags);
   cli();
+  
   cs4231_chip->regs->iar = 0x9;
   cs4231_chip->regs->idr |= PEN_ENABLE;
   restore_flags(flags);
@@ -261,14 +268,14 @@
   if (value != 0) {
     set_bits = cs4231_encoding_to_bits(drv, value);
     if (set_bits >= 0) {
-      cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x8;
-      tmp_bits = cs4231_chip->regs->idr;
-      cs4231_chip->regs->idr = CHANGE_ENCODING(tmp_bits, set_bits);
+        cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x8;
+        tmp_bits = cs4231_chip->regs->idr;
+        cs4231_chip->regs->idr = CHANGE_ENCODING(tmp_bits, set_bits);
     
-      CHIP_READY
+        CHIP_READY
 
-      cs4231_chip->perchip_info.play.encoding = value;
-      return 0;
+        cs4231_chip->perchip_info.play.encoding = value;
+        return 0;
     }
   }
   dprintk(("output enc failed\n"));
@@ -291,14 +298,14 @@
   if (value != 0) {
     set_bits = cs4231_encoding_to_bits(drv, value);
     if (set_bits >= 0) {
-      cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x1c;
-      tmp_bits = cs4231_chip->regs->idr;
-      cs4231_chip->regs->idr = CHANGE_ENCODING(tmp_bits, set_bits);
+        cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x1c;
+        tmp_bits = cs4231_chip->regs->idr;
+        cs4231_chip->regs->idr = CHANGE_ENCODING(tmp_bits, set_bits);
 
-      CHIP_READY
+        CHIP_READY
 
-      cs4231_chip->perchip_info.record.encoding = value;
-      return 0;
+        cs4231_chip->perchip_info.record.encoding = value;
+        return 0;
     }
   }
   dprintk(("input enc failed\n"));
@@ -321,14 +328,14 @@
   if (value != 0) {
     set_bits = cs4231_rate_to_bits(drv, value);
     if (set_bits >= 0) {
-      cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x8;
-      tmp_bits = cs4231_chip->regs->idr;
-      cs4231_chip->regs->idr = CHANGE_DFR(tmp_bits, set_bits);
+        cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x8;
+        tmp_bits = cs4231_chip->regs->idr;
+        cs4231_chip->regs->idr = CHANGE_DFR(tmp_bits, set_bits);
 
-      CHIP_READY
+        CHIP_READY
 
-      cs4231_chip->perchip_info.play.sample_rate = value;
-      return 0;
+        cs4231_chip->perchip_info.play.sample_rate = value;
+        return 0;
     }
   }
   dprintk(("output rate failed\n"));
@@ -351,14 +358,14 @@
   if (value != 0) {
     set_bits = cs4231_rate_to_bits(drv, value);
     if (set_bits >= 0) {
-      cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x1c;
-      tmp_bits = cs4231_chip->regs->idr;
-      cs4231_chip->regs->idr = CHANGE_DFR(tmp_bits, set_bits);
+        cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x1c;
+        tmp_bits = cs4231_chip->regs->idr;
+        cs4231_chip->regs->idr = CHANGE_DFR(tmp_bits, set_bits);
       
-      CHIP_READY
+        CHIP_READY
 
-      cs4231_chip->perchip_info.record.sample_rate = value;
-      return 0;
+        cs4231_chip->perchip_info.record.sample_rate = value;
+        return 0;
     }
   }
   dprintk(("input rate failed\n"));
@@ -383,14 +390,14 @@
   tmp_bits = cs4231_chip->regs->idr;
   switch (value) {
   case 1:
-    cs4231_chip->regs->idr = CS4231_MONO_ON(tmp_bits);
-    break;
+      cs4231_chip->regs->idr = CS4231_MONO_ON(tmp_bits);
+      break;
   case 2:
-    cs4231_chip->regs->idr = CS4231_STEREO_ON(tmp_bits);
-    break;
+      cs4231_chip->regs->idr = CS4231_STEREO_ON(tmp_bits);
+      break;
   default:
-    dprintk(("input chan failed\n"));
-    return -(EINVAL);
+      dprintk(("input chan failed\n"));
+      return -(EINVAL);
   }  
 
   CHIP_READY
@@ -417,14 +424,14 @@
   tmp_bits = cs4231_chip->regs->idr;
   switch (value) {
   case 1:
-    cs4231_chip->regs->idr = CS4231_MONO_ON(tmp_bits);
-    break;
+      cs4231_chip->regs->idr = CS4231_MONO_ON(tmp_bits);
+      break;
   case 2:
-    cs4231_chip->regs->idr = CS4231_STEREO_ON(tmp_bits);
-    break;
+      cs4231_chip->regs->idr = CS4231_STEREO_ON(tmp_bits);
+      break;
   default:
-    dprintk(("output chan failed\n"));
-    return -(EINVAL);
+      dprintk(("output chan failed\n"));
+      return -(EINVAL);
   }  
 
   CHIP_READY
@@ -477,7 +484,7 @@
   unsigned int x = 0;
 
   cs4231_chip->regs->iar = IAR_AUTOCAL_END;
-  while (cs4231_chip->regs->iar == IAR_NOT_READY && x <= CS_TIMEOUT) {
+  while (cs4231_chip->regs->idr == IAR_NOT_READY && x <= CS_TIMEOUT) {
     x++;
   }
 
@@ -494,17 +501,17 @@
   struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
   tprintk(("in cs4231_output_muted: %d\n", value));
   if (!value) {
-    cs4231_chip->regs->iar = 0x7;
-    cs4231_chip->regs->idr &= OUTCR_UNMUTE;
-    cs4231_chip->regs->iar = 0x6;
-    cs4231_chip->regs->idr &= OUTCR_UNMUTE;
-    cs4231_chip->perchip_info.output_muted = 0;
+      cs4231_chip->regs->iar = 0x7;
+      cs4231_chip->regs->idr &= OUTCR_UNMUTE;
+      cs4231_chip->regs->iar = 0x6;
+      cs4231_chip->regs->idr &= OUTCR_UNMUTE;
+      cs4231_chip->perchip_info.output_muted = 0;
   } else {
-    cs4231_chip->regs->iar = 0x7;
-    cs4231_chip->regs->idr |= OUTCR_MUTE;
-    cs4231_chip->regs->iar = 0x6;
-    cs4231_chip->regs->idr |= OUTCR_MUTE;
-    cs4231_chip->perchip_info.output_muted = 1;
+      cs4231_chip->regs->iar = 0x7;
+      cs4231_chip->regs->idr |= OUTCR_MUTE;
+      cs4231_chip->regs->iar = 0x6;
+      cs4231_chip->regs->idr |= OUTCR_MUTE;
+      cs4231_chip->perchip_info.output_muted = 1;
   }
   return 0;
 }
@@ -555,21 +562,21 @@
   cs4231_chip->regs->idr |= PINCR_HDPH_MUTE;
 
   if (value & AUDIO_SPEAKER) {
-    cs4231_chip->regs->iar = 0x1a;
-    cs4231_chip->regs->idr &= ~MONO_IOCR_MUTE;
-    retval |= AUDIO_SPEAKER;
+      cs4231_chip->regs->iar = 0x1a;
+      cs4231_chip->regs->idr &= ~MONO_IOCR_MUTE;
+      retval |= AUDIO_SPEAKER;
   }
 
   if (value & AUDIO_HEADPHONE) {
-   cs4231_chip->regs->iar = 0x0a;
-   cs4231_chip->regs->idr &= ~PINCR_HDPH_MUTE;
-   retval |= AUDIO_HEADPHONE;
+      cs4231_chip->regs->iar = 0x0a;
+      cs4231_chip->regs->idr &= ~PINCR_HDPH_MUTE;
+      retval |= AUDIO_HEADPHONE;
   }
 
   if (value & AUDIO_LINE_OUT) {
-    cs4231_chip->regs->iar = 0x0a;
-    cs4231_chip->regs->idr &= ~PINCR_LINE_MUTE;
-    retval |= AUDIO_LINE_OUT;
+      cs4231_chip->regs->iar = 0x0a;
+      cs4231_chip->regs->idr &= ~PINCR_LINE_MUTE;
+      retval |= AUDIO_LINE_OUT;
   }
   
   cs4231_chip->perchip_info.play.port = retval;
@@ -600,31 +607,31 @@
   /* This apparently applies only to APC ultras, not ebus ultras */
   if (!cs4231_chip->status & CS_STATUS_IS_ULTRA) {
     if (value & AUDIO_INTERNAL_CD_IN) {
-      cs4231_chip->regs->iar = 0x1;
-      cs4231_chip->regs->idr = CDROM_ENABLE(cs4231_chip->regs->idr);
-      cs4231_chip->regs->iar = 0x0;
-      cs4231_chip->regs->idr = CDROM_ENABLE(cs4231_chip->regs->idr);
-      retval = AUDIO_INTERNAL_CD_IN;
+        cs4231_chip->regs->iar = 0x1;
+        cs4231_chip->regs->idr = CDROM_ENABLE(cs4231_chip->regs->idr);
+        cs4231_chip->regs->iar = 0x0;
+        cs4231_chip->regs->idr = CDROM_ENABLE(cs4231_chip->regs->idr);
+        retval = AUDIO_INTERNAL_CD_IN;
     }
   }
   if ((value & AUDIO_LINE_IN)) {
-    cs4231_chip->regs->iar = 0x1;
-    cs4231_chip->regs->idr = LINE_ENABLE(cs4231_chip->regs->idr);
-    cs4231_chip->regs->iar = 0x0;
-    cs4231_chip->regs->idr = LINE_ENABLE(cs4231_chip->regs->idr);
-    retval = AUDIO_LINE_IN;
+      cs4231_chip->regs->iar = 0x1;
+      cs4231_chip->regs->idr = LINE_ENABLE(cs4231_chip->regs->idr);
+      cs4231_chip->regs->iar = 0x0;
+      cs4231_chip->regs->idr = LINE_ENABLE(cs4231_chip->regs->idr);
+      retval = AUDIO_LINE_IN;
   } else if (value & AUDIO_MICROPHONE) {
-    cs4231_chip->regs->iar = 0x1;
-    cs4231_chip->regs->idr = MIC_ENABLE(cs4231_chip->regs->idr);
-    cs4231_chip->regs->iar = 0x0;
-    cs4231_chip->regs->idr = MIC_ENABLE(cs4231_chip->regs->idr);
-    retval = AUDIO_MICROPHONE;
+      cs4231_chip->regs->iar = 0x1;
+      cs4231_chip->regs->idr = MIC_ENABLE(cs4231_chip->regs->idr);
+      cs4231_chip->regs->iar = 0x0;
+      cs4231_chip->regs->idr = MIC_ENABLE(cs4231_chip->regs->idr);
+      retval = AUDIO_MICROPHONE;
   } else if (value & AUDIO_ANALOG_LOOPBACK) {
-    cs4231_chip->regs->iar = 0x1;
-    cs4231_chip->regs->idr = OUTPUTLOOP_ENABLE(cs4231_chip->regs->idr);
-    cs4231_chip->regs->iar = 0x0;
-    cs4231_chip->regs->idr = OUTPUTLOOP_ENABLE(cs4231_chip->regs->idr);
-    retval = AUDIO_ANALOG_LOOPBACK;
+      cs4231_chip->regs->iar = 0x1;
+      cs4231_chip->regs->idr = OUTPUTLOOP_ENABLE(cs4231_chip->regs->idr);
+      cs4231_chip->regs->iar = 0x0;
+      cs4231_chip->regs->idr = OUTPUTLOOP_ENABLE(cs4231_chip->regs->idr);
+      retval = AUDIO_ANALOG_LOOPBACK;
   }
 
   cs4231_chip->perchip_info.record.port = retval;
@@ -654,9 +661,9 @@
 
   cs4231_chip->regs->iar = 0x0d;
   if (a >= CS4231_MON_MAX_ATEN) 
-    cs4231_chip->regs->idr = LOOPB_OFF;
+      cs4231_chip->regs->idr = LOOPB_OFF;
   else 
-    cs4231_chip->regs->idr = ((a << 2) | LOOPB_ON);
+      cs4231_chip->regs->idr = ((a << 2) | LOOPB_ON);
 
   if (value == AUDIO_MAX_GAIN) 
     cs4231_chip->perchip_info.monitor_gain = AUDIO_MAX_GAIN;
@@ -689,6 +696,32 @@
         return (int)cs4231_chip->perchip_info.record.error;
 }
 
+#ifdef EB4231_SUPPORT
+static int eb4231_get_output_samples(struct sparcaudio_driver *drv)
+{
+        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+        int count = 
+          cs4231_length_to_samplecount(&cs4231_chip->perchip_info.play, 
+                                       readl(&cs4231_chip->eb2p->dbcr));
+
+        return (cs4231_chip->perchip_info.play.samples - 
+                ((count > cs4231_chip->perchip_info.play.samples) 
+                 ? 0 : count));
+}
+
+static int eb4231_get_input_samples(struct sparcaudio_driver *drv)
+{
+        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+        int count = 
+          cs4231_length_to_samplecount(&cs4231_chip->perchip_info.record, 
+                                       readl(&cs4231_chip->eb2c->dbcr));
+
+        return (cs4231_chip->perchip_info.record.samples - 
+                ((count > cs4231_chip->perchip_info.record.samples) ?
+                0 : count));
+}
+#endif
+
 static int cs4231_get_output_samples(struct sparcaudio_driver *drv)
 {
         struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
@@ -890,13 +923,21 @@
 
   tprintk(("in cs4231_chip_reset\n"));
 
-  cs4231_chip->regs->dmacsr = CS_CHIP_RESET;
-  cs4231_chip->regs->dmacsr = 0x00;
-  cs4231_chip->regs->dmacsr |= CS_CDC_RESET;
+  if (cs4231_chip->status & CS_STATUS_IS_EBUS) {
+#ifdef EB4231_SUPPORT
+    writel(EBUS_DCSR_RESET, &cs4231_chip->eb2p->dcsr);
+    writel(EBUS_DCSR_RESET, &cs4231_chip->eb2c->dcsr);
+#endif
+  } else {
+    cs4231_chip->regs->dmacsr = APC_CHIP_RESET;
+    cs4231_chip->regs->dmacsr = 0x00;
+    cs4231_chip->regs->dmacsr |= APC_CDC_RESET;
   
-  udelay(20);
+    udelay(20);
   
-  cs4231_chip->regs->dmacsr &= ~(CS_CDC_RESET);
+    cs4231_chip->regs->dmacsr &= ~(APC_CDC_RESET);
+  }
+
   cs4231_chip->regs->iar |= IAR_AUTOCAL_BEGIN;
   
   CHIP_READY
@@ -928,9 +969,9 @@
   
   cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x11;
   if (cs4231_chip->status & CS_STATUS_REV_A)
-    cs4231_chip->regs->idr = (HPF_ON | XTALE_ON);
+      cs4231_chip->regs->idr = (HPF_ON | XTALE_ON);
   else
-    cs4231_chip->regs->idr = (HPF_ON);
+      cs4231_chip->regs->idr = HPF_ON;
   
   cs4231_chip->regs->iar = IAR_AUTOCAL_BEGIN | 0x1a;
   cs4231_chip->regs->idr = 0x00;
@@ -990,6 +1031,36 @@
   return count;
 }
 
+#ifdef EB4231_SUPPORT
+static void eb4231_getsamplecount(struct sparcaudio_driver *drv, unsigned int length, unsigned int direction)
+{
+  struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+  struct audio_prinfo *thisdir;
+  unsigned int count, nextcount, curcount;
+
+  if (direction == 1) /* record */ 
+    {
+      thisdir = &cs4231_chip->perchip_info.record;
+      curcount = 
+	cs4231_length_to_samplecount(thisdir, readl(&cs4231_chip->eb2c->dbcr));
+      nextcount = 
+	cs4231_length_to_samplecount(thisdir, 0/*cs4231_chip->regs->dmacnc*/);
+    }
+  else /* play */
+    {
+      thisdir = &cs4231_chip->perchip_info.play;
+      curcount = 
+	cs4231_length_to_samplecount(thisdir, readl(&cs4231_chip->eb2p->dbcr));
+      nextcount = 
+	cs4231_length_to_samplecount(thisdir, 0/*cs4231_chip->regs->dmapnc*/);
+    }
+  count = thisdir->samples;
+  length = cs4231_length_to_samplecount(thisdir, length);
+  /* normalize for where we are. */
+  thisdir->samples = ((count - nextcount) + (length - curcount));
+}
+#endif
+
 static void cs4231_getsamplecount(struct sparcaudio_driver *drv, unsigned int length, unsigned int direction)
 {
   struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
@@ -1060,14 +1131,18 @@
     /* stop capture here or midlevel? */
     cs4231_chip->perchip_info.record.open = 0;
     if (cs4231_chip->input_dma_handle) {
-      mmu_release_scsi_one((u32)((unsigned long)cs4231_chip->input_dma_handle),
+#if 0
+      mmu_release_scsi_one(cs4231_chip->input_dma_handle,
                            cs4231_chip->input_dma_size, drv->dev->my_bus);
+#endif
       cs4231_chip->input_dma_handle = 0;
       cs4231_chip->input_dma_size = 0;
     }
     if (cs4231_chip->input_next_dma_handle) {
-      mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->input_next_dma_handle),
+#if 0
+      mmu_release_scsi_one(cs4231_chip->input_next_dma_handle,
                            cs4231_chip->input_next_dma_size, drv->dev->my_bus);
+#endif
       cs4231_chip->input_next_dma_handle = 0;
       cs4231_chip->input_next_dma_size = 0;
     }
@@ -1077,15 +1152,19 @@
     cs4231_chip->perchip_info.play.active =
       cs4231_chip->perchip_info.play.open = 0;
     if (cs4231_chip->output_dma_handle) {
-      mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->output_dma_handle),
+#if 0
+      mmu_release_scsi_one(cs4231_chip->output_dma_handle,
                            cs4231_chip->output_dma_size, drv->dev->my_bus);
+#endif
       cs4231_chip->output_dma_handle = 0;
       cs4231_chip->output_dma_size = 0;
     }
     if (cs4231_chip->output_next_dma_handle) {
-      mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->output_next_dma_handle),
+#if 0
+      mmu_release_scsi_one(cs4231_chip->output_next_dma_handle,
                            cs4231_chip->output_next_dma_size, 
                            drv->dev->my_bus);
+#endif
       cs4231_chip->output_next_dma_handle = 0;
       cs4231_chip->output_next_dma_size = 0;
     }
@@ -1110,7 +1189,7 @@
     cs4231_chip->playlen = cs4231_chip->output_size;
 
   if (cs4231_chip->output_dma_handle) {
-    mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->output_dma_handle), 
+    mmu_release_scsi_one(cs4231_chip->output_dma_handle, 
                          cs4231_chip->output_dma_size, drv->dev->my_bus);
     cs4231_chip->output_dma_handle = 0;
     cs4231_chip->output_dma_size = 0;
@@ -1126,11 +1205,10 @@
 
   if ((cs4231_chip->output_ptr && cs4231_chip->output_size > 0) && 
       !(cs4231_chip->perchip_info.play.pause)) {
-    cs4231_chip->output_next_dma_handle = (u32 *) (unsigned long)
+    cs4231_chip->output_next_dma_handle =
       mmu_get_scsi_one((char *) cs4231_chip->output_ptr, 
                        cs4231_chip->output_size, drv->dev->my_bus);
-    cs4231_chip->regs->dmapnva = (u32) (unsigned long)
-      cs4231_chip->output_next_dma_handle;
+    cs4231_chip->regs->dmapnva = cs4231_chip->output_next_dma_handle;
     cs4231_chip->output_next_dma_size = cs4231_chip->regs->dmapnc = 
       cs4231_chip->output_size;
     cs4231_chip->output_size = 0;
@@ -1147,6 +1225,62 @@
   return;
 }
 
+#ifdef EB4231_SUPPORT
+static void eb4231_playintr(struct sparcaudio_driver *drv)
+{
+  struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+  int status = 0;
+  unsigned int dcsr;
+
+  dcsr = readl(&cs4231_chip->eb2p->dcsr);
+
+  printk("pintr\ncsr 0x%x acr 0x%x bcr %d\n", readl(&cs4231_chip->eb2p->dcsr), readl(&cs4231_chip->eb2p->dacr), readl(&cs4231_chip->eb2p->dbcr));
+  if (cs4231_chip->playlen == 0 && cs4231_chip->output_size > 0) 
+    cs4231_chip->playlen = cs4231_chip->output_size;
+
+  if (cs4231_chip->output_dma_handle) {
+    cs4231_chip->output_dma_handle = 0;
+    cs4231_chip->output_dma_size = 0;
+    cs4231_chip->playing_count--;
+    status++;
+  }
+
+#if 0
+  if (cs4231_chip->output_next_dma_handle) {
+    cs4231_chip->output_dma_handle = cs4231_chip->output_next_dma_handle;
+    cs4231_chip->output_dma_size = cs4231_chip->output_next_dma_size;
+    cs4231_chip->output_next_dma_size = 0;
+    cs4231_chip->output_next_dma_handle = 0;
+  }
+#endif
+
+  if ((cs4231_chip->output_ptr && cs4231_chip->output_size > 0) && 
+      !(cs4231_chip->perchip_info.play.pause)) {
+#if 0
+    if (dcsr & EBUS_DCSR_A_LOADED) {
+      cs4231_chip->output_next_dma_handle = virt_to_bus(cs4231_chip->output_ptr);
+      cs4231_chip->output_next_dma_size = cs4231_chip->output_size;
+    } else {
+#endif
+      cs4231_chip->output_dma_handle = virt_to_bus(cs4231_chip->output_ptr);
+      cs4231_chip->output_dma_size = cs4231_chip->output_size;
+#if 0
+    }
+#endif
+    writel(virt_to_bus(cs4231_chip->output_ptr), &cs4231_chip->eb2p->dacr);
+    writel(cs4231_chip->output_size, &cs4231_chip->eb2p->dbcr);
+    cs4231_chip->output_size = 0;
+    cs4231_chip->output_ptr = NULL;
+    cs4231_chip->playing_count++;
+    status+=2;
+  }
+
+  sparcaudio_output_done(drv, status);
+
+  return;
+}
+#endif
+
 static void cs4231_recclear(int fmt, char *dmabuf, int length)
 {
   switch (fmt) {
@@ -1174,7 +1308,7 @@
   } 
 
   if (cs4231_chip->input_dma_handle) {
-    mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->input_dma_handle),
+    mmu_release_scsi_one(cs4231_chip->input_dma_handle, 
                          cs4231_chip->input_dma_size, drv->dev->my_bus);
     cs4231_chip->input_dma_handle = 0;
     cs4231_chip->input_dma_size = 0;
@@ -1192,11 +1326,10 @@
       !(cs4231_chip->perchip_info.record.pause)) {
     cs4231_recclear(cs4231_chip->perchip_info.record.encoding, 
                     (char *)cs4231_chip->input_ptr, cs4231_chip->input_size);
-    cs4231_chip->input_next_dma_handle = (u32*) (unsigned long)
+    cs4231_chip->input_next_dma_handle =
       mmu_get_scsi_one((char *) cs4231_chip->input_ptr, 
                        cs4231_chip->input_size, drv->dev->my_bus);
-    cs4231_chip->regs->dmacnva = (u32) (unsigned long)
-      cs4231_chip->input_next_dma_handle;
+    cs4231_chip->regs->dmacnva = cs4231_chip->input_next_dma_handle;
     cs4231_chip->input_next_dma_size = cs4231_chip->regs->dmacnc = 
       cs4231_chip->input_size;
     cs4231_chip->input_size = 0;
@@ -1213,6 +1346,107 @@
   return 1;
 }
 
+#ifdef EB4231_SUPPORT
+static int eb4231_recintr(struct sparcaudio_driver *drv)
+{
+  struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+  int status = 0;
+
+  if (cs4231_chip->perchip_info.record.active == 0) {
+    dprintk(("going inactive\n"));
+    cs4231_disable_rec(drv);    
+  } 
+
+  if (cs4231_chip->input_dma_handle) {
+#if 0
+    mmu_release_scsi_one(cs4231_chip->input_dma_handle, 
+                         cs4231_chip->input_dma_size, drv->dev->my_bus);
+#endif
+    cs4231_chip->input_dma_handle = 0;
+    cs4231_chip->input_dma_size = 0;
+    cs4231_chip->recording_count--;
+    status++;
+  }
+  if (cs4231_chip->input_next_dma_handle) {
+    cs4231_chip->input_dma_handle = cs4231_chip->input_next_dma_handle;
+    cs4231_chip->input_dma_size = cs4231_chip->input_next_dma_size;
+    cs4231_chip->input_next_dma_size = 0;
+    cs4231_chip->input_next_dma_handle = 0;
+  }
+
+  if ((cs4231_chip->input_ptr && cs4231_chip->input_size > 0) && 
+      !(cs4231_chip->perchip_info.record.pause)) {
+    cs4231_recclear(cs4231_chip->perchip_info.record.encoding, 
+                    (char *)cs4231_chip->input_ptr, cs4231_chip->input_size);
+#if 0
+    cs4231_chip->input_next_dma_handle =
+      mmu_get_scsi_one((char *) cs4231_chip->input_ptr, 
+                       cs4231_chip->input_size, drv->dev->my_bus);
+    cs4231_chip->regs->dmacnva = cs4231_chip->input_next_dma_handle;
+    cs4231_chip->input_next_dma_size = cs4231_chip->regs->dmacnc = 
+      cs4231_chip->input_size;
+#else
+    cs4231_chip->input_next_dma_handle = cs4231_chip->eb2c->dacr = virt_to_bus(cs4231_chip->input_ptr);
+    cs4231_chip->input_next_dma_size = cs4231_chip->eb2c->dbcr = cs4231_chip->input_size;
+#endif
+    cs4231_chip->input_size = 0;
+    cs4231_chip->input_ptr = NULL;
+    cs4231_chip->recording_count++;
+    status += 2;
+  } else {
+#if 0
+    cs4231_chip->regs->dmacnva = 0;
+    cs4231_chip->regs->dmacnc = 0;
+#else
+    cs4231_chip->eb2c->dacr = 0;
+    cs4231_chip->eb2c->dbcr = 0;
+#endif
+  }
+
+  sparcaudio_input_done(drv, 1);
+
+  return 1;
+}
+#endif
+
+#ifdef EB4231_SUPPORT
+static void eb4231_start_output(struct sparcaudio_driver *drv, __u8 * buffer,
+                                unsigned long count)
+{
+  struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+  unsigned int dcsr;
+
+  dprintk(("in eb4231 start output act %d pau %d\n", cs4231_chip->perchip_info.play.active, cs4231_chip->perchip_info.play.pause));
+  cs4231_chip->output_ptr = buffer;
+  cs4231_chip->output_size = count;
+
+  if (cs4231_chip->perchip_info.play.active || 
+      (cs4231_chip->perchip_info.play.pause))
+    return;
+
+  cs4231_ready(drv);
+
+  cs4231_chip->perchip_info.play.active = 1;
+  cs4231_chip->playing_count = 0;
+
+  dcsr = readl(&cs4231_chip->eb2p->dcsr);
+  if (!(dcsr & EBUS_DCSR_EN_DMA)) {
+    dprintk(("about to go setup\n"));
+
+    dcsr = EB2_PLAY_SETUP;
+    writel(dcsr, (unsigned long)&cs4231_chip->eb2p->dcsr);
+    eb4231_playintr(drv);
+    dprintk(("enabling\n"));
+    cs4231_enable_play(drv);
+
+    cs4231_ready(drv);
+  } else {
+    dprintk(("playing next block\n"));
+    eb4231_playintr(drv);
+  }
+}
+#endif
+
 static void cs4231_start_output(struct sparcaudio_driver *drv, __u8 * buffer,
                                 unsigned long count)
 {
@@ -1231,14 +1465,14 @@
   cs4231_chip->perchip_info.play.active = 1;
   cs4231_chip->playing_count = 0;
 
-  if ((cs4231_chip->regs->dmacsr & CS_PPAUSE) || 
-      !(cs4231_chip->regs->dmacsr & PDMA_READY)) {
-    cs4231_chip->regs->dmacsr &= ~CS_XINT_PLAY;
-    cs4231_chip->regs->dmacsr &= ~CS_PPAUSE;
+  if ((cs4231_chip->regs->dmacsr & APC_PPAUSE) || 
+      !(cs4231_chip->regs->dmacsr & APC_PDMA_READY)) {
+    cs4231_chip->regs->dmacsr &= ~APC_XINT_PLAY;
+    cs4231_chip->regs->dmacsr &= ~APC_PPAUSE;
     
     cs4231_playintr(drv);
 
-    cs4231_chip->regs->dmacsr |= CS_PLAY_SETUP;
+    cs4231_chip->regs->dmacsr |= APC_PLAY_SETUP;
     cs4231_enable_play(drv);
 
     cs4231_ready(drv);
@@ -1246,6 +1480,28 @@
     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;
+
+  dprintk(("in cs4231_stop_output\n"));
+  dprintk(("csr 0x%x acr 0x%x bcr %d\n", readl(&cs4231_chip->eb2p->dcsr), readl(&cs4231_chip->eb2p->dacr), readl(&cs4231_chip->eb2p->dbcr)));
+  cs4231_chip->output_ptr = NULL;
+  cs4231_chip->output_size = 0;
+  if (cs4231_chip->output_dma_handle) {
+    cs4231_chip->output_dma_handle = 0;
+    cs4231_chip->output_dma_size = 0;
+  }
+#if 0
+  if (cs4231_chip->output_next_dma_handle) {
+    cs4231_chip->output_next_dma_handle = 0;
+    cs4231_chip->output_next_dma_size = 0;
+  }
+#endif
+}
+#endif
+
 static void cs4231_stop_output(struct sparcaudio_driver *drv)
 {
   struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
@@ -1254,13 +1510,13 @@
   cs4231_chip->output_ptr = NULL;
   cs4231_chip->output_size = 0;
   if (cs4231_chip->output_dma_handle) {
-    mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->output_dma_handle),
+    mmu_release_scsi_one(cs4231_chip->output_dma_handle,
                          cs4231_chip->output_dma_size, drv->dev->my_bus);
     cs4231_chip->output_dma_handle = 0;
     cs4231_chip->output_dma_size = 0;
   }
   if (cs4231_chip->output_next_dma_handle) {
-    mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->output_next_dma_handle),
+    mmu_release_scsi_one(cs4231_chip->output_next_dma_handle,
                          cs4231_chip->output_next_dma_size, drv->dev->my_bus);
     cs4231_chip->output_next_dma_handle = 0;
     cs4231_chip->output_next_dma_size = 0;
@@ -1272,10 +1528,10 @@
   struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
   int x = 0;
 
-  while (!(cs4231_chip->regs->dmacsr & CS_XINT_COVF) && x <= CS_TIMEOUT) {
+  while (!(cs4231_chip->regs->dmacsr & APC_XINT_COVF) && x <= CS_TIMEOUT) {
     x++;
   }
-  cs4231_chip->regs->dmacsr |= CS_XINT_CEMP;
+  cs4231_chip->regs->dmacsr |= APC_XINT_CEMP;
 }
 
 static void cs4231_start_input(struct sparcaudio_driver *drv, __u8 * buffer, 
@@ -1295,14 +1551,14 @@
   cs4231_chip->perchip_info.record.active = 1;
   cs4231_chip->recording_count = 0;
 
-  if ((cs4231_chip->regs->dmacsr & CS_CPAUSE) || 
-      !(cs4231_chip->regs->dmacsr & CDMA_READY)) {
-    cs4231_chip->regs->dmacsr &= ~CS_XINT_CAPT;
-    cs4231_chip->regs->dmacsr &= ~CS_CPAUSE;
+  if ((cs4231_chip->regs->dmacsr & APC_CPAUSE) || 
+      !(cs4231_chip->regs->dmacsr & APC_CDMA_READY)) {
+    cs4231_chip->regs->dmacsr &= ~APC_XINT_CAPT;
+    cs4231_chip->regs->dmacsr &= ~APC_CPAUSE;
 
     cs4231_recintr(drv);
 
-    cs4231_chip->regs->dmacsr |= CS_CAPT_SETUP;
+    cs4231_chip->regs->dmacsr |= APC_CAPT_SETUP;
     cs4231_enable_rec(drv);
 
     cs4231_ready(drv);
@@ -1315,18 +1571,18 @@
   struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
 
   cs4231_chip->perchip_info.record.active = 0;
-  cs4231_chip->regs->dmacsr |= (CS_CPAUSE);
+  cs4231_chip->regs->dmacsr |= (APC_CPAUSE);
 
   cs4231_chip->input_ptr = NULL;
   cs4231_chip->input_size = 0;
   if (cs4231_chip->input_dma_handle) {
-    mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->input_dma_handle),
+    mmu_release_scsi_one(cs4231_chip->input_dma_handle,
                          cs4231_chip->input_dma_size, drv->dev->my_bus);
     cs4231_chip->input_dma_handle = 0;
     cs4231_chip->input_dma_size = 0;
   }
   if (cs4231_chip->input_next_dma_handle) {
-    mmu_release_scsi_one((u32) ((unsigned long)cs4231_chip->input_next_dma_handle),
+    mmu_release_scsi_one(cs4231_chip->input_next_dma_handle,
                          cs4231_chip->input_next_dma_size, drv->dev->my_bus);
     cs4231_chip->input_next_dma_handle = 0;
     cs4231_chip->input_next_dma_size = 0;
@@ -1408,7 +1664,11 @@
   struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
 
   strncpy(audinfo->name, "SUNW,CS4231", sizeof(audinfo->name) - 1);
-  /* versions: SPARCstation 4/5=a, Ultra=b */
+  /* versions */
+  /* a: SPARCstation 4/5          b: Ultra 1/2 (electron)       */
+  /* c: Ultra 1/2 PCI? (positron) d: ppc                        */
+  /* e: x86                       f: Ultra Enterprise? (tazmo)  */
+  /* g: Ultra 30? (quark)         h: Ultra 5/10? (darwin)       */
   /* apparently Ultra 1, Ultra 2 don't have internal CD input */
   if (cs4231_chip->status & CS_STATUS_IS_ULTRA)
     strncpy(audinfo->version, "b", sizeof(audinfo->version) - 1);
@@ -1450,6 +1710,114 @@
   return retval;
 }
 
+#ifdef EB4231_SUPPORT
+/* ebus audio capture interrupt handler. */
+void eb4231_cinterrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+  struct sparcaudio_driver *drv = (struct sparcaudio_driver *)dev_id;
+  struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+  int dummy1, dummy2;
+  
+  printk("in eb4231_interrupt\n");
+
+  /* Clear the interrupt. */
+  dummy1 = readl(&cs4231_chip->eb2p->dcsr);
+  dummy2 = readl(&cs4231_chip->eb2c->dcsr);
+
+  printk("play csr 0x%x capt csr 0x%x\n", dummy1, dummy2);
+
+  cs4231_chip->eb2p->dcsr = dummy1;
+  cs4231_chip->eb2c->dcsr = dummy2;
+#if 0
+  if (dummy & APC_PLAY_INT) {
+    if (dummy & APC_XINT_PNVA) {
+      cs4231_chip->perchip_info.play.samples += 
+	cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.play), 
+				     cs4231_chip->playlen); 
+      eb4231_playintr(drv);
+    } 
+    /* Any other conditions we need worry about? */
+  }
+
+  if (dummy & APC_CAPT_INT) {
+    if (dummy & APC_XINT_CNVA) {
+      cs4231_chip->perchip_info.record.samples += 
+	cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.record), 
+				     cs4231_chip->reclen);
+      eb4231_recintr(drv);
+    }
+    /* Any other conditions we need worry about? */
+  }
+
+  
+  if (dummy & APC_XINT_CEMP) {
+    if (cs4231_chip->perchip_info.record.active == 0) {
+      /* Fix me */
+      cs4231_chip->perchip_info.record.active = 0;
+      cs4231_chip->perchip_info.record.error = 1;
+      eb4231_recintr(drv);
+    }
+  }
+
+  if (dummy & APC_XINT_EMPT) {
+    if (!cs4231_chip->output_next_dma_handle) {
+      cs4231_chip->regs->dmacsr |= (APC_PPAUSE);
+      cs4231_disable_play(drv);
+      cs4231_chip->perchip_info.play.error = 1;
+    }
+    cs4231_chip->perchip_info.play.active = 0;
+    eb4231_playintr(drv);
+
+    eb4231_getsamplecount(drv, cs4231_chip->playlen, 0);
+  }
+#endif
+}
+
+/* ebus audio play interrupt handler. */
+void eb4231_pinterrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+  struct sparcaudio_driver *drv = (struct sparcaudio_driver *)dev_id;
+  struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
+  unsigned int dummy;
+  
+  dprintk(("in eb4231_interrupt2\n"));
+
+  /* Clear the interrupt. */
+  dummy = readl(&cs4231_chip->eb2p->dcsr);
+  dprintk(("play csr 0x%x\n", dummy));
+
+  if (dummy & EBUS_DCSR_INT_PEND) {
+#if 0
+    if (!(dummy & EBUS_DCSR_NA_LOADED)) {
+#endif
+      cs4231_chip->perchip_info.play.samples += 
+        cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.play), 
+                                     cs4231_chip->playlen); 
+      eb4231_playintr(drv);
+#if 0
+    } 
+#endif
+  }
+
+  if (!(dummy & EBUS_DCSR_A_LOADED)) {
+#if 0
+    if (!cs4231_chip->output_next_dma_handle) {
+#endif
+      writel((dummy & ~EBUS_DCSR_EN_DMA), &cs4231_chip->eb2p->dcsr);
+      cs4231_disable_play(drv);
+      cs4231_chip->perchip_info.play.error = 1;
+#if 0
+    }
+#endif
+    cs4231_chip->perchip_info.play.active = 0;
+#if 0
+    eb4231_playintr(drv);
+#endif
+    eb4231_getsamplecount(drv, cs4231_chip->playlen, 0);
+  }
+
+}
+#endif
 
 /* Audio interrupt handler. */
 void cs4231_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -1458,7 +1826,7 @@
   struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
   __u32 dummy;
   
-  tprintk(("in cs4231_interrupt\n"));
+  dprintk(("in cs4231_interrupt\n"));
 
   /* Clear the interrupt. */
   dummy = cs4231_chip->regs->dmacsr;
@@ -1468,8 +1836,8 @@
    * if anything since we may be doing shared interrupts 
    */
 
-  if (dummy & CS_PLAY_INT) {
-    if (dummy & CS_XINT_PNVA) {
+  if (dummy & APC_PLAY_INT) {
+    if (dummy & APC_XINT_PNVA) {
       cs4231_chip->perchip_info.play.samples += 
 	cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.play), 
 				     cs4231_chip->playlen); 
@@ -1478,8 +1846,8 @@
     /* Any other conditions we need worry about? */
   }
 
-  if (dummy & CS_CAPT_INT) {
-    if (dummy & CS_XINT_CNVA) {
+  if (dummy & APC_CAPT_INT) {
+    if (dummy & APC_XINT_CNVA) {
       cs4231_chip->perchip_info.record.samples += 
 	cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.record), 
 				     cs4231_chip->reclen);
@@ -1489,7 +1857,7 @@
   }
 
   
-  if (dummy & CS_XINT_CEMP) {
+  if (dummy & APC_XINT_CEMP) {
     if (cs4231_chip->perchip_info.record.active == 0) {
       /* Fix me */
       cs4231_chip->perchip_info.record.active = 0;
@@ -1498,9 +1866,9 @@
     }
   }
 
-  if (dummy & CS_XINT_EMPT) {
+  if (dummy & APC_XINT_EMPT) {
     if (!cs4231_chip->output_next_dma_handle) {
-      cs4231_chip->regs->dmacsr |= (CS_PPAUSE);
+      cs4231_chip->regs->dmacsr |= (APC_PPAUSE);
       cs4231_disable_play(drv);
       cs4231_chip->perchip_info.play.error = 1;
     }
@@ -1510,7 +1878,7 @@
     cs4231_getsamplecount(drv, cs4231_chip->playlen, 0);
   }
 
-  if (dummy & CS_GENL_INT) {
+  if (dummy & APC_GENL_INT) {
     /* If we get here we must be sharing an interrupt, but I haven't code 
        to handle this right now */
   }
@@ -1576,6 +1944,67 @@
         cs4231_get_formats,
 };
 
+#ifdef EB4231_SUPPORT
+static struct sparcaudio_operations eb4231_ops = {
+	cs4231_open,
+	cs4231_release,
+	cs4231_ioctl,
+	eb4231_start_output,
+	eb4231_stop_output,
+	cs4231_start_input,
+        cs4231_stop_input,
+	cs4231_audio_getdev,
+        cs4231_set_output_volume,
+        cs4231_get_output_volume,
+        cs4231_set_input_volume,
+        cs4231_get_input_volume,
+        cs4231_set_monitor_volume,
+        cs4231_get_monitor_volume,
+	cs4231_set_output_balance,
+	cs4231_get_output_balance,
+        cs4231_set_input_balance,
+        cs4231_get_input_balance,
+        cs4231_set_output_channels,
+        cs4231_get_output_channels,
+        cs4231_set_input_channels,
+        cs4231_get_input_channels,
+        cs4231_set_output_precision,
+        cs4231_get_output_precision,
+        cs4231_set_input_precision,
+        cs4231_get_input_precision,
+        cs4231_set_output_port,
+        cs4231_get_output_port,
+        cs4231_set_input_port,
+        cs4231_get_input_port,
+        cs4231_set_output_encoding,
+        cs4231_get_output_encoding,
+        cs4231_set_input_encoding,
+        cs4231_get_input_encoding,
+        cs4231_set_output_rate,
+        cs4231_get_output_rate,
+        cs4231_set_input_rate,
+	cs4231_get_input_rate,
+	cs4231_audio_getdev_sunos,
+	cs4231_get_output_ports,
+	cs4231_get_input_ports,
+	cs4231_output_muted,
+	cs4231_get_output_muted,
+	cs4231_set_output_pause,
+	cs4231_get_output_pause,
+	cs4231_set_input_pause,
+	cs4231_get_input_pause,
+	cs4231_set_output_samples,
+	eb4231_get_output_samples,
+	cs4231_set_input_samples,
+	eb4231_get_input_samples,
+	cs4231_set_output_error,
+	cs4231_get_output_error,
+	cs4231_set_input_error,
+	cs4231_get_input_error,
+        cs4231_get_formats,
+};
+#endif
+
 /* Attach to an cs4231 chip given its PROM node. */
 static int cs4231_attach(struct sparcaudio_driver *drv, 
 			 struct linux_sbus_device *sdev)
@@ -1642,6 +2071,8 @@
 
   enable_irq(cs4231_chip->irq);
 
+  cs4231_chip->nirqs = 1;
+
   cs4231_enable_interrupts(drv);
 
   /* Reset the audio chip. */
@@ -1676,13 +2107,149 @@
 						  AUDIO_ANALOG_LOOPBACK);
 
   /* Announce the hardware to the user. */
-  printk(KERN_INFO "audio%d: cs4231%c at 0x%lx irq %d\n",
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100
+  printk(KERN_INFO "audio%d: cs4231%c at 0x%x irq %d\n",
          drv->index, (cs4231_chip->status & CS_STATUS_REV_A) ? 'a' : ' ', 
 	 (unsigned long)cs4231_chip->regs, cs4231_chip->irq);
+#else	 
+  printk(KERN_INFO "audio%d: cs4231%c at %p irq %s\n",
+         drv->index, (cs4231_chip->status & CS_STATUS_REV_A) ? 'a' : ' ', 
+	 cs4231_chip->regs, __irq_itoa(cs4231_chip->irq));
+#endif
+  
+  /* Success! */
+  return 0;
+}
+
+#ifdef EB4231_SUPPORT
+/* Attach to an cs4231 chip given its PROM node. */
+static int eb4231_attach(struct sparcaudio_driver *drv, 
+			 struct linux_ebus_device *edev)
+{
+  struct cs4231_chip *cs4231_chip;
+  int len, err, nregs;
+  struct linux_prom_registers regs[4];
+
+  /* Allocate our private information structure. */
+  drv->private = kmalloc(sizeof(struct cs4231_chip), GFP_KERNEL);
+  if (!drv->private)
+    return -ENOMEM;
+
+  /* Point at the information structure and initialize it. */
+  drv->ops = &eb4231_ops;
+  cs4231_chip = (struct cs4231_chip *)drv->private;
+  cs4231_chip->input_ptr = cs4231_chip->output_ptr = NULL;
+  cs4231_chip->input_size = cs4231_chip->output_size = 0;
+  cs4231_chip->status = 0;
+
+  len = prom_getproperty(edev->prom_node, "reg", (void *)regs, sizeof(regs));
+
+  if ((len % sizeof(regs[0])) != 0) {
+    printk("eb4231: Strange reg property size %d\n", len);
+    return -ENODEV;
+  }
+
+  nregs = len / sizeof(regs[0]);
+
+  /* Make sure we can map the registers first */
+  if (check_region(edev->base_address[0],
+                   sizeof(struct cs4231_regs))) {
+    printk("eb4231_attach: can't get region at %016lx\n",
+           edev->base_address[0]);
+    goto cleanup;
+  }
+  if (check_region(edev->base_address[1],
+                   sizeof(struct linux_ebus_dma))) {
+    printk("eb4231_attach: can't get region at %016lx\n",
+           edev->base_address[1]);
+    goto cleanup;
+  }
+  if (check_region(edev->base_address[2],
+                   sizeof(struct linux_ebus_dma))) {
+    printk("eb4231_attach: can't get region at %016lx\n",
+           edev->base_address[2]);
+    goto cleanup;
+  }
+
+  cs4231_chip->regs = (struct cs4231_regs *)edev->base_address[0];
+  cs4231_chip->eb2p = (struct linux_ebus_dma *)edev->base_address[1];
+  cs4231_chip->eb2c = (struct linux_ebus_dma *)edev->base_address[2];
+
+  request_region((unsigned long)cs4231_chip->regs, 
+                 sizeof(struct cs4231_regs), "cs4231 regs");
+  request_region((unsigned long)cs4231_chip->eb2c, 
+                 sizeof(struct linux_ebus_dma), "4231 capture DMA");
+  request_region((unsigned long)cs4231_chip->eb2p, 
+                 sizeof(struct linux_ebus_dma), "4231 playback DMA");
+
+  cs4231_chip->status |= CS_STATUS_IS_EBUS;
+
+  /* Attach the interrupt handler to the audio interrupt. */
+  cs4231_chip->irq = edev->irqs[0];
+  cs4231_chip->irq2 = edev->irqs[1];
+
+  request_irq(cs4231_chip->irq, eb4231_cinterrupt, SA_SHIRQ, "cs4231", drv);
+#if 0
+  enable_irq(cs4231_chip->irq);
+#endif
+
+  request_irq(cs4231_chip->irq2, eb4231_pinterrupt, SA_SHIRQ, "cs4231", drv);
+  enable_irq(cs4231_chip->irq2);
+
+  cs4231_chip->nirqs = 2;
+
+  cs4231_enable_interrupts(drv);
+
+  /* Reset the audio chip. */
+  cs4231_chip_reset(drv);
+
+  /* Register ourselves with the midlevel audio driver. */
+  err = register_sparcaudio_driver(drv, 1);
+
+  if (err < 0) {
+    printk(KERN_ERR "cs4231: unable to register\n");
+    cs4231_disable_interrupts(drv);
+    disable_irq(cs4231_chip->irq);
+    free_irq(cs4231_chip->irq, drv);
+    if (cs4231_chip->nirqs == 2) {
+      disable_irq(cs4231_chip->irq2);
+      free_irq(cs4231_chip->irq2, drv);
+    }
+    release_region((unsigned long)cs4231_chip->regs, 
+                   sizeof(struct cs4231_regs));
+    release_region((unsigned long)cs4231_chip->eb2c, 
+                   sizeof(struct linux_ebus_dma));
+    release_region((unsigned long)cs4231_chip->eb2p, 
+                   sizeof(struct linux_ebus_dma));
+  cleanup:
+    kfree(drv->private);
+    return -EIO;
+  }
+
+  cs4231_chip->perchip_info.play.active = 
+    cs4231_chip->perchip_info.play.pause = 0;
+
+  cs4231_chip->perchip_info.record.active = 
+    cs4231_chip->perchip_info.record.pause = 0;
+
+  cs4231_chip->perchip_info.play.avail_ports = (AUDIO_HEADPHONE |
+						AUDIO_SPEAKER |
+						AUDIO_LINE_OUT);
+
+  cs4231_chip->perchip_info.record.avail_ports = (AUDIO_INTERNAL_CD_IN |
+						  AUDIO_LINE_IN | 
+						  AUDIO_MICROPHONE |
+						  AUDIO_ANALOG_LOOPBACK);
+
+  /* Announce the hardware to the user. */
+  printk(KERN_INFO "audio%d: cs4231%c(eb2) at %p irq %s\n",
+         drv->index, (cs4231_chip->status & CS_STATUS_REV_A) ? 'a' : ' ', 
+	 cs4231_chip->regs, __irq_itoa(cs4231_chip->irq));
   
   /* Success! */
   return 0;
 }
+#endif
 
 /* Probe for the cs4231 chip and then attach the driver. */
 #ifdef MODULE
@@ -1691,13 +2258,17 @@
 __initfunc(int cs4231_init(void))
 #endif
 {
-  struct linux_sbus *bus;
+  struct linux_sbus *sbus;
   struct linux_sbus_device *sdev;
-  
+#ifdef EB4231_SUPPORT
+  struct linux_ebus *ebus;
+  struct linux_ebus_device *edev;
+#endif
+
   num_drivers = 0;
   
   /* Probe each SBUS for cs4231 chips. */
-  for_all_sbusdev(sdev,bus) {
+  for_all_sbusdev(sdev,sbus) {
     if (!strcmp(sdev->prom_name, "SUNW,CS4231")) {
       /* Don't go over the max number of drivers. */
       if (num_drivers >= MAX_DRIVERS)
@@ -1708,6 +2279,21 @@
     }
   }
   
+#ifdef EB4231_SUPPORT
+  for_each_ebus(ebus) {
+    for_each_ebusdev(edev, ebus) {
+      if (!strcmp(edev->prom_name, "SUNW,CS4231")) {
+        /* Don't go over the max number of drivers. */
+        if (num_drivers >= MAX_DRIVERS)
+          continue;
+      
+        if (eb4231_attach(&drivers[num_drivers], edev) == 0)
+          num_drivers++;
+      }
+    }
+  }
+#endif
+
   /* Only return success if we found some cs4231 chips. */
   return (num_drivers > 0) ? 0 : -EIO;
 }
@@ -1716,13 +2302,21 @@
 /* Detach from an cs4231 chip given the device structure. */
 static void cs4231_detach(struct sparcaudio_driver *drv)
 {
-        struct cs4231_chip *info = (struct cs4231_chip *)drv->private;
+        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
 
 	cs4231_disable_interrupts(drv);
         unregister_sparcaudio_driver(drv, 1);
-        disable_irq(info->irq);
-        free_irq(info->irq, drv);
-        sparc_free_io(info->regs, info->regs_size);
+        disable_irq(cs4231_chip->irq);
+        free_irq(cs4231_chip->irq, drv);
+        if (!(cs4231_chip->status & CS_STATUS_IS_EBUS)) {
+          sparc_free_io(cs4231_chip->regs, cs4231_chip->regs_size);
+        } else {
+#ifdef EB4231_SUPPORT
+          release_region(cs4231_chip->regs, sizeof(struct cs4231_regs));
+          release_region(cs4231_chip->eb2c, sizeof(struct linux_ebus_dma));
+          release_region(cs4231_chip->eb2p, sizeof(struct linux_ebus_dma));
+#endif
+        }
         kfree(drv->private);
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)