[ALSA] sparc dbri: simplifed linking time slot function
[safe/jmp/linux-2.6] / sound / sparc / dbri.c
index 012c636..5696f79 100644 (file)
@@ -34,7 +34,7 @@
  * (the second one is a monitor/tee pipe, valid only for serial input).
  *
  * The mmcodec is connected via the CHI bus and needs the data & some
- * parameters (volume, balance, output selection) timemultiplexed in 8 byte
+ * parameters (volume, output selection) timemultiplexed in 8 byte
  * chunks. It also has a control mode, which serves for audio format setting.
  *
  * Looking at the CS4215 data sheet it is easy to set up 2 or 4 codecs on
@@ -46,7 +46,7 @@
  *
  * I've tried to stick to the following function naming conventions:
  * snd_*       ALSA stuff
- * cs4215_*    CS4215 codec specfic stuff
+ * cs4215_*    CS4215 codec specific stuff
  * dbri_*      DBRI high-level stuff
  * other       DBRI low-level stuff
  */
@@ -92,7 +92,7 @@ MODULE_PARM_DESC(enable, "Enable Sun DBRI soundcard.");
 #define D_USR  (1<<4)
 #define D_DESC (1<<5)
 
-static int dbri_debug = 0;
+static int dbri_debug;
 module_param(dbri_debug, int, 0644);
 MODULE_PARM_DESC(dbri_debug, "Debug value for Sun DBRI soundcard.");
 
@@ -104,17 +104,15 @@ static char *cmds[] = {
 
 #define dprintk(a, x...) if(dbri_debug & a) printk(KERN_DEBUG x)
 
-#define DBRI_CMD(cmd, intr, value) ((cmd << 28) |                      \
-                                   (1 << 27) | \
-                                   value)
 #else
 #define dprintk(a, x...)
 
-#define DBRI_CMD(cmd, intr, value) ((cmd << 28) |                      \
-                                   (intr << 27) | \
-                                   value)
 #endif                         /* DBRI_DEBUG */
 
+#define DBRI_CMD(cmd, intr, value) ((cmd << 28) |      \
+                                   (intr << 27) |      \
+                                   value)
+
 /***************************************************************************
        CS4215 specific definitions and structures
 ****************************************************************************/
@@ -240,28 +238,21 @@ static struct {
 #define REG9   0x24UL          /* Interrupt Queue Pointer */
 
 #define DBRI_NO_CMDS   64
-#define DBRI_NO_INTS   1       /* Note: the value of this define was
-                                * originally 2.  The ringbuffer to store
-                                * interrupts in dma is currently broken.
-                                * This is a temporary fix until the ringbuffer
-                                * is fixed.
-                                */
 #define DBRI_INT_BLK   64
 #define DBRI_NO_DESCS  64
 #define DBRI_NO_PIPES  32
-
-#define DBRI_MM_ONB    1
-#define DBRI_MM_SB     2
+#define DBRI_MAX_PIPE  (DBRI_NO_PIPES - 1)
 
 #define DBRI_REC       0
 #define DBRI_PLAY      1
 #define DBRI_NO_STREAMS        2
 
 /* One transmit/receive descriptor */
+/* When ba != 0 descriptor is used */
 struct dbri_mem {
        volatile __u32 word1;
-       volatile __u32 ba;      /* Transmit/Receive Buffer Address */
-       volatile __u32 nda;     /* Next Descriptor Address */
+       __u32 ba;       /* Transmit/Receive Buffer Address */
+       __u32 nda;      /* Next Descriptor Address */
        volatile __u32 word4;
 };
 
@@ -270,7 +261,7 @@ struct dbri_mem {
  */
 struct dbri_dma {
        volatile s32 cmd[DBRI_NO_CMDS]; /* Place for commands       */
-       volatile s32 intr[DBRI_NO_INTS * DBRI_INT_BLK]; /* Interrupt field  */
+       volatile s32 intr[DBRI_INT_BLK];        /* Interrupt field  */
        struct dbri_mem desc[DBRI_NO_DESCS];    /* Xmit/receive descriptors */
 };
 
@@ -282,22 +273,13 @@ enum in_or_out { PIPEinput, PIPEoutput };
 
 struct dbri_pipe {
        u32 sdp;                /* SDP command word */
-       enum in_or_out direction;
        int nextpipe;           /* Next pipe in linked list */
-       int prevpipe;
-       int cycle;              /* Offset of timeslot (bits) */
        int length;             /* Length of timeslot (bits) */
        int first_desc;         /* Index of first descriptor */
        int desc;               /* Index of active descriptor */
        volatile __u32 *recv_fixed_ptr; /* Ptr to receive fixed data */
 };
 
-struct dbri_desc {
-       int inuse;              /* Boolean flag */
-       int next;               /* Index of next desc, or -1 */
-       unsigned int len;
-};
-
 /* Per stream (playback or record) information */
 struct dbri_streaminfo {
        struct snd_pcm_substream *substream;
@@ -308,32 +290,27 @@ struct dbri_streaminfo {
        int pipe;               /* Data pipe used                 */
        int left_gain;          /* mixer elements                 */
        int right_gain;
-       int balance;
 };
 
 /* This structure holds the information for both chips (DBRI & CS4215) */
 struct snd_dbri {
        struct snd_card *card;  /* ALSA card */
-       struct snd_pcm *pcm;
 
        int regs_size, irq;     /* Needed for unload */
        struct sbus_dev *sdev;  /* SBUS device info */
        spinlock_t lock;
 
-       volatile struct dbri_dma *dma;  /* Pointer to our DMA block */
+       struct dbri_dma *dma;   /* Pointer to our DMA block */
        u32 dma_dvma;           /* DBRI visible DMA address */
 
        void __iomem *regs;     /* dbri HW regs */
-       int dbri_version;       /* 'e' and up is OK */
        int dbri_irqp;          /* intr queue pointer */
        int wait_send;          /* sequence of command buffers send */
        int wait_ackd;          /* sequence of command buffers acknowledged */
 
        struct dbri_pipe pipes[DBRI_NO_PIPES];  /* DBRI's 32 data pipes */
-       struct dbri_desc descs[DBRI_NO_DESCS];
+       int next_desc[DBRI_NO_DESCS];           /* Index of next desc, or -1 */
 
-       int chi_in_pipe;
-       int chi_out_pipe;
        int chi_bpf;
 
        struct cs4215 mm;       /* mmcodec special info */
@@ -345,8 +322,6 @@ struct snd_dbri {
 
 #define DBRI_MAX_VOLUME                63      /* Output volume */
 #define DBRI_MAX_GAIN          15      /* Input gain */
-#define DBRI_RIGHT_BALANCE     255
-#define DBRI_MID_BALANCE       (DBRI_RIGHT_BALANCE >> 1)
 
 /* DBRI Reg0 - Status Control Register - defines. (Page 17) */
 #define D_P            (1<<15) /* Program command & queue pointer valid */
@@ -593,7 +568,7 @@ struct snd_dbri {
 /* Return a pointer to dbri_streaminfo */
 #define DBRI_STREAM(dbri, substream)   &dbri->stream_info[DBRI_STREAMNO(substream)]
 
-static struct snd_dbri *dbri_list = NULL;      /* All DBRI devices */
+static struct snd_dbri *dbri_list;     /* All DBRI devices */
 
 /*
  * Short data pipes transmit LSB first. The CS4215 receives MSB first. Grrr.
@@ -670,10 +645,6 @@ static volatile s32 *dbri_cmdlock(struct snd_dbri * dbri, enum dbri_lock get)
        /* Delay if previous commands are still being processed */
        while ((--maxloops) > 0 && (dbri->wait_send != dbri->wait_ackd)) {
                msleep_interruptible(1);
-               /* If dbri_cmdlock() got called from inside the
-                * interrupt handler, this will do the processing.
-                */
-               dbri_process_interrupt_buffer(dbri);
        }
        if (maxloops == 0) {
                printk(KERN_ERR "DBRI: Chip never completed command buffer %d\n",
@@ -690,7 +661,6 @@ static volatile s32 *dbri_cmdlock(struct snd_dbri * dbri, enum dbri_lock get)
 static void dbri_cmdsend(struct snd_dbri * dbri, volatile s32 * cmd)
 {
        volatile s32 *ptr;
-       u32     reg;
 
        for (ptr = &dbri->dma->cmd[0]; ptr < cmd; ptr++) {
                dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr);
@@ -709,9 +679,6 @@ static void dbri_cmdsend(struct snd_dbri * dbri, volatile s32 * cmd)
 
        /* Set command pointer and signal it is valid. */
        sbus_writel(dbri->dma_dvma, dbri->regs + REG8);
-       reg = sbus_readl(dbri->regs + REG0);
-       reg |= D_P;
-       sbus_writel(reg, dbri->regs + REG0);
 
        /*spin_unlock(&dbri->lock); */
 }
@@ -720,6 +687,7 @@ static void dbri_cmdsend(struct snd_dbri * dbri, volatile s32 * cmd)
 static void dbri_reset(struct snd_dbri * dbri)
 {
        int i;
+       u32 tmp;
 
        dprintk(D_GEN, "reset 0:%x 2:%x 8:%x 9:%x\n",
                sbus_readl(dbri->regs + REG0),
@@ -729,13 +697,20 @@ static void dbri_reset(struct snd_dbri * dbri)
        sbus_writel(D_R, dbri->regs + REG0);    /* Soft Reset */
        for (i = 0; (sbus_readl(dbri->regs + REG0) & D_R) && i < 64; i++)
                udelay(10);
+
+       /* A brute approach - DBRI falls back to working burst size by itself
+        * On SS20 D_S does not work, so do not try so high. */
+       tmp = sbus_readl(dbri->regs + REG0);
+       tmp |= D_G | D_E;
+       tmp &= ~D_S;
+       sbus_writel(tmp, dbri->regs + REG0);
 }
 
 /* Lock must not be held before calling this */
 static void dbri_initialize(struct snd_dbri * dbri)
 {
        volatile s32 *cmd;
-       u32 dma_addr, tmp;
+       u32 dma_addr;
        unsigned long flags;
        int n;
 
@@ -747,33 +722,19 @@ static void dbri_initialize(struct snd_dbri * dbri)
        dprintk(D_GEN, "init: cmd: %p, int: %p\n",
                &dbri->dma->cmd[0], &dbri->dma->intr[0]);
 
+       /* Initialize pipes */
+       for (n = 0; n < DBRI_NO_PIPES; n++)
+               dbri->pipes[n].desc = dbri->pipes[n].first_desc = -1;
+
        /*
         * Initialize the interrupt ringbuffer.
         */
-       for (n = 0; n < DBRI_NO_INTS - 1; n++) {
-               dma_addr = dbri->dma_dvma;
-               dma_addr += dbri_dma_off(intr, ((n + 1) & DBRI_INT_BLK));
-               dbri->dma->intr[n * DBRI_INT_BLK] = dma_addr;
-       }
        dma_addr = dbri->dma_dvma + dbri_dma_off(intr, 0);
-       dbri->dma->intr[n * DBRI_INT_BLK] = dma_addr;
+       dbri->dma->intr[0] = dma_addr;
        dbri->dbri_irqp = 1;
-
-       /* Initialize pipes */
-       for (n = 0; n < DBRI_NO_PIPES; n++)
-               dbri->pipes[n].desc = dbri->pipes[n].first_desc = -1;
-
-       /* A brute approach - DBRI falls back to working burst size by itself
-        * On SS20 D_S does not work, so do not try so high. */
-       tmp = sbus_readl(dbri->regs + REG0);
-       tmp |= D_G | D_E;
-       tmp &= ~D_S;
-       sbus_writel(tmp, dbri->regs + REG0);
-
        /*
         * Set up the interrupt queue
         */
-       dma_addr = dbri->dma_dvma + dbri_dma_off(intr, 0);
        *(cmd++) = DBRI_CMD(D_IIQ, 0, 0);
        *(cmd++) = dma_addr;
 
@@ -811,7 +772,7 @@ static void reset_pipe(struct snd_dbri * dbri, int pipe)
        int desc;
        volatile int *cmd;
 
-       if (pipe < 0 || pipe > 31) {
+       if (pipe < 0 || pipe > DBRI_MAX_PIPE) {
                printk(KERN_ERR "DBRI: reset_pipe called with illegal pipe number\n");
                return;
        }
@@ -829,18 +790,17 @@ static void reset_pipe(struct snd_dbri * dbri, int pipe)
 
        desc = dbri->pipes[pipe].first_desc;
        while (desc != -1) {
-               dbri->descs[desc].inuse = 0;
-               desc = dbri->descs[desc].next;
+               dbri->dma->desc[desc].nda = dbri->dma->desc[desc].ba = 0;
+               desc = dbri->next_desc[desc];
        }
 
        dbri->pipes[pipe].desc = -1;
        dbri->pipes[pipe].first_desc = -1;
 }
 
-/* FIXME: direction as an argument? */
 static void setup_pipe(struct snd_dbri * dbri, int pipe, int sdp)
 {
-       if (pipe < 0 || pipe > 31) {
+       if (pipe < 0 || pipe > DBRI_MAX_PIPE) {
                printk(KERN_ERR "DBRI: setup_pipe called with illegal pipe number\n");
                return;
        }
@@ -860,100 +820,59 @@ static void setup_pipe(struct snd_dbri * dbri, int pipe, int sdp)
        dbri->pipes[pipe].sdp = sdp;
        dbri->pipes[pipe].desc = -1;
        dbri->pipes[pipe].first_desc = -1;
-       if (sdp & D_SDP_TO_SER)
-               dbri->pipes[pipe].direction = PIPEoutput;
-       else
-               dbri->pipes[pipe].direction = PIPEinput;
 
        reset_pipe(dbri, pipe);
 }
 
-/* FIXME: direction not needed */
 static void link_time_slot(struct snd_dbri * dbri, int pipe,
-                          enum in_or_out direction, int basepipe,
+                          int prevpipe, int nextpipe,
                           int length, int cycle)
 {
        volatile s32 *cmd;
        int val;
-       int prevpipe;
-       int nextpipe;
 
-       if (pipe < 0 || pipe > 31 || basepipe < 0 || basepipe > 31) {
+       if (pipe < 0 || pipe > DBRI_MAX_PIPE 
+                       || prevpipe < 0 || prevpipe > DBRI_MAX_PIPE
+                       || nextpipe < 0 || nextpipe > DBRI_MAX_PIPE) {
                printk(KERN_ERR 
                    "DBRI: link_time_slot called with illegal pipe number\n");
                return;
        }
 
-       if (dbri->pipes[pipe].sdp == 0 || dbri->pipes[basepipe].sdp == 0) {
+       if (dbri->pipes[pipe].sdp == 0 
+                       || dbri->pipes[prevpipe].sdp == 0
+                       || dbri->pipes[nextpipe].sdp == 0) {
                printk(KERN_ERR "DBRI: link_time_slot called on uninitialized pipe\n");
                return;
        }
 
-       /* Deal with CHI special case:
-        * "If transmission on edges 0 or 1 is desired, then cycle n
-        *  (where n = # of bit times per frame...) must be used."
-        *                  - DBRI data sheet, page 11
-        */
-       if (basepipe == 16 && direction == PIPEoutput && cycle == 0)
-               cycle = dbri->chi_bpf;
-
-       if (basepipe == pipe) {
-               prevpipe = pipe;
-               nextpipe = pipe;
-       } else {
-               /* We're not initializing a new linked list (basepipe != pipe),
-                * so run through the linked list and find where this pipe
-                * should be sloted in, based on its cycle.  CHI confuses
-                * things a bit, since it has a single anchor for both its
-                * transmit and receive lists.
-                */
-               if (basepipe == 16) {
-                       if (direction == PIPEinput) {
-                               prevpipe = dbri->chi_in_pipe;
-                       } else {
-                               prevpipe = dbri->chi_out_pipe;
-                       }
-               } else {
-                       prevpipe = basepipe;
-               }
-
-               nextpipe = dbri->pipes[prevpipe].nextpipe;
-
-               while (dbri->pipes[nextpipe].cycle < cycle
-                      && dbri->pipes[nextpipe].nextpipe != basepipe) {
-                       prevpipe = nextpipe;
-                       nextpipe = dbri->pipes[nextpipe].nextpipe;
-               }
-       }
-
-       if (prevpipe == 16) {
-               if (direction == PIPEinput) {
-                       dbri->chi_in_pipe = pipe;
-               } else {
-                       dbri->chi_out_pipe = pipe;
-               }
-       } else {
-               dbri->pipes[prevpipe].nextpipe = pipe;
-       }
+       dbri->pipes[prevpipe].nextpipe = pipe;
 
        dbri->pipes[pipe].nextpipe = nextpipe;
-       dbri->pipes[pipe].cycle = cycle;
        dbri->pipes[pipe].length = length;
 
        cmd = dbri_cmdlock(dbri, NoGetLock);
 
-       if (direction == PIPEinput) {
-               val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(prevpipe) | pipe;
+       if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) {
+               /* Deal with CHI special case:
+                * "If transmission on edges 0 or 1 is desired, then cycle n
+                *  (where n = # of bit times per frame...) must be used."
+                *                  - DBRI data sheet, page 11
+                */
+               if (prevpipe == 16 && cycle == 0)
+                       cycle = dbri->chi_bpf;
+
+               val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(prevpipe) | pipe;
                *(cmd++) = DBRI_CMD(D_DTS, 0, val);
+               *(cmd++) = 0;
                *(cmd++) =
                    D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);
-               *(cmd++) = 0;
        } else {
-               val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(prevpipe) | pipe;
+               val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(prevpipe) | pipe;
                *(cmd++) = DBRI_CMD(D_DTS, 0, val);
-               *(cmd++) = 0;
                *(cmd++) =
                    D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);
+               *(cmd++) = 0;
        }
 
        dbri_cmdsend(dbri, cmd);
@@ -966,7 +885,8 @@ static void unlink_time_slot(struct snd_dbri * dbri, int pipe,
        volatile s32 *cmd;
        int val;
 
-       if (pipe < 0 || pipe > 31 || prevpipe < 0 || prevpipe > 31) {
+       if (pipe < 0 || pipe > DBRI_MAX_PIPE 
+                       || prevpipe < 0 || prevpipe > DBRI_MAX_PIPE) {
                printk(KERN_ERR 
                    "DBRI: unlink_time_slot called with illegal pipe number\n");
                return;
@@ -1007,7 +927,7 @@ static void xmit_fixed(struct snd_dbri * dbri, int pipe, unsigned int data)
 {
        volatile s32 *cmd;
 
-       if (pipe < 16 || pipe > 31) {
+       if (pipe < 16 || pipe > DBRI_MAX_PIPE) {
                printk(KERN_ERR "DBRI: xmit_fixed: Illegal pipe number\n");
                return;
        }
@@ -1042,7 +962,7 @@ static void xmit_fixed(struct snd_dbri * dbri, int pipe, unsigned int data)
 
 static void recv_fixed(struct snd_dbri * dbri, int pipe, volatile __u32 * ptr)
 {
-       if (pipe < 16 || pipe > 31) {
+       if (pipe < 16 || pipe > DBRI_MAX_PIPE) {
                printk(KERN_ERR "DBRI: recv_fixed called with illegal pipe number\n");
                return;
        }
@@ -1123,7 +1043,7 @@ static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period
                int mylen;
 
                for (; desc < DBRI_NO_DESCS; desc++) {
-                       if (!dbri->descs[desc].inuse)
+                       if (!dbri->dma->desc[desc].ba)
                                break;
                }
                if (desc == DBRI_NO_DESCS) {
@@ -1140,19 +1060,16 @@ static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period
                        mylen = period;
                }
 
-               dbri->descs[desc].inuse = 1;
-               dbri->descs[desc].next = -1;
+               dbri->next_desc[desc] = -1;
                dbri->dma->desc[desc].ba = dvma_buffer;
                dbri->dma->desc[desc].nda = 0;
 
                if (streamno == DBRI_PLAY) {
-                       dbri->descs[desc].len = mylen;
                        dbri->dma->desc[desc].word1 = DBRI_TD_CNT(mylen);
                        dbri->dma->desc[desc].word4 = 0;
                        if (first_desc != -1)
                                dbri->dma->desc[desc].word1 |= DBRI_TD_M;
                } else {
-                       dbri->descs[desc].len = 0;
                        dbri->dma->desc[desc].word1 = 0;
                        dbri->dma->desc[desc].word4 =
                            DBRI_RD_B | DBRI_RD_BCNT(mylen);
@@ -1161,7 +1078,7 @@ static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period
                if (first_desc == -1) {
                        first_desc = desc;
                } else {
-                       dbri->descs[last_desc].next = desc;
+                       dbri->next_desc[last_desc] = desc;
                        dbri->dma->desc[last_desc].nda =
                            dbri->dma_dvma + dbri_dma_off(desc, desc);
                }
@@ -1184,7 +1101,7 @@ static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period
        dbri->pipes[info->pipe].first_desc = first_desc;
        dbri->pipes[info->pipe].desc = first_desc;
 
-       for (desc = first_desc; desc != -1; desc = dbri->descs[desc].next) {
+       for (desc = first_desc; desc != -1; desc = dbri->next_desc[desc]) {
                dprintk(D_DESC, "DESC %d: %08x %08x %08x %08x\n",
                        desc,
                        dbri->dma->desc[desc].word1,
@@ -1220,20 +1137,14 @@ static void reset_chi(struct snd_dbri * dbri, enum master_or_slave master_or_sla
 
                /* Set CHI Anchor: Pipe 16 */
 
-               val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(16) | D_PIPE(16);
+               val = D_DTS_VO | D_DTS_VI | D_DTS_INS 
+                       | D_DTS_PRVIN(16) | D_PIPE(16) | D_DTS_PRVOUT(16);
                *(cmd++) = DBRI_CMD(D_DTS, 0, val);
                *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16);
-               *(cmd++) = 0;
-
-               val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(16) | D_PIPE(16);
-               *(cmd++) = DBRI_CMD(D_DTS, 0, val);
-               *(cmd++) = 0;
                *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16);
 
                dbri->pipes[16].sdp = 1;
                dbri->pipes[16].nextpipe = 16;
-               dbri->chi_in_pipe = 16;
-               dbri->chi_out_pipe = 16;
 
 #if 0
                chi_initialized++;
@@ -1241,21 +1152,17 @@ static void reset_chi(struct snd_dbri * dbri, enum master_or_slave master_or_sla
        } else {
                int pipe;
 
-               for (pipe = dbri->chi_in_pipe;
-                    pipe != 16; pipe = dbri->pipes[pipe].nextpipe) {
-                       unlink_time_slot(dbri, pipe, PIPEinput,
-                                        16, dbri->pipes[pipe].nextpipe);
-               }
-               for (pipe = dbri->chi_out_pipe;
-                    pipe != 16; pipe = dbri->pipes[pipe].nextpipe) {
-                       unlink_time_slot(dbri, pipe, PIPEoutput,
-                                        16, dbri->pipes[pipe].nextpipe);
-               }
-
-               dbri->chi_in_pipe = 16;
-               dbri->chi_out_pipe = 16;
-
-               cmd = dbri_cmdlock(dbri, GetLock);
+               for (pipe = 0; pipe < DBRI_NO_PIPES; pipe++ )
+                       if ( pipe != 16 ) {
+                               if (dbri->pipes[pipe].sdp & D_SDP_TO_SER)
+                                       unlink_time_slot(dbri, pipe, PIPEoutput,
+                                                        16, dbri->pipes[pipe].nextpipe);
+                               else
+                                       unlink_time_slot(dbri, pipe, PIPEinput,
+                                                        16, dbri->pipes[pipe].nextpipe);
+                       }
+  
+               cmd = dbri_cmdlock(dbri, GetLock);
        }
 
        if (master_or_slave == CHIslave) {
@@ -1379,16 +1286,8 @@ static void cs4215_setdata(struct snd_dbri * dbri, int muted)
        } else {
                /* Start by setting the playback attenuation. */
                struct dbri_streaminfo *info = &dbri->stream_info[DBRI_PLAY];
-               int left_gain = info->left_gain % 64;
-               int right_gain = info->right_gain % 64;
-
-               if (info->balance < DBRI_MID_BALANCE) {
-                       right_gain *= info->balance;
-                       right_gain /= DBRI_MID_BALANCE;
-               } else {
-                       left_gain *= DBRI_RIGHT_BALANCE - info->balance;
-                       left_gain /= DBRI_MID_BALANCE;
-               }
+               int left_gain = info->left_gain & 0x3f;
+               int right_gain = info->right_gain & 0x3f;
 
                dbri->mm.data[0] &= ~0x3f;      /* Reset the volume bits */
                dbri->mm.data[1] &= ~0x3f;
@@ -1397,8 +1296,8 @@ static void cs4215_setdata(struct snd_dbri * dbri, int muted)
 
                /* Now set the recording gain. */
                info = &dbri->stream_info[DBRI_REC];
-               left_gain = info->left_gain % 16;
-               right_gain = info->right_gain % 16;
+               left_gain = info->left_gain & 0xf;
+               right_gain = info->right_gain & 0xf;
                dbri->mm.data[2] |= CS4215_LG(left_gain);
                dbri->mm.data[3] |= CS4215_RG(right_gain);
        }
@@ -1455,10 +1354,10 @@ static void cs4215_open(struct snd_dbri * dbri)
         */
        data_width = dbri->mm.channels * dbri->mm.precision;
 
-       link_time_slot(dbri, 20, PIPEoutput, 16, 32, dbri->mm.offset + 32);
-       link_time_slot(dbri, 4, PIPEoutput, 16, data_width, dbri->mm.offset);
-       link_time_slot(dbri, 6, PIPEinput, 16, data_width, dbri->mm.offset);
-       link_time_slot(dbri, 21, PIPEinput, 16, 16, dbri->mm.offset + 40);
+       link_time_slot(dbri, 4, 16, 16, data_width, dbri->mm.offset);
+       link_time_slot(dbri, 20, 4, 16, 32, dbri->mm.offset + 32);
+       link_time_slot(dbri, 6, 16, 16, data_width, dbri->mm.offset);
+       link_time_slot(dbri, 21, 6, 16, 16, dbri->mm.offset + 40);
 
        /* FIXME: enable CHI after _setdata? */
        tmp = sbus_readl(dbri->regs + REG0);
@@ -1524,9 +1423,9 @@ static int cs4215_setctrl(struct snd_dbri * dbri)
         * Pipe 19: Receive timeslot 7 (version). 
         */
 
-       link_time_slot(dbri, 17, PIPEoutput, 16, 32, dbri->mm.offset);
-       link_time_slot(dbri, 18, PIPEinput, 16, 8, dbri->mm.offset);
-       link_time_slot(dbri, 19, PIPEinput, 16, 8, dbri->mm.offset + 48);
+       link_time_slot(dbri, 17, 16, 16, 32, dbri->mm.offset);
+       link_time_slot(dbri, 18, 16, 16, 8, dbri->mm.offset);
+       link_time_slot(dbri, 19, 18, 16, 8, dbri->mm.offset + 48);
 
        /* Wait for the chip to echo back CLB (Control Latch Bit) as zero */
        dbri->mm.ctrl[0] &= ~CS4215_CLB;
@@ -1785,6 +1684,7 @@ static void transmission_complete_intr(struct snd_dbri * dbri, int pipe)
        struct dbri_streaminfo *info;
        int td;
        int status;
+       int len;
 
        info = &dbri->stream_info[DBRI_PLAY];
 
@@ -1803,11 +1703,12 @@ static void transmission_complete_intr(struct snd_dbri * dbri, int pipe)
                dprintk(D_INT, "TD %d, status 0x%02x\n", td, status);
 
                dbri->dma->desc[td].word4 = 0;  /* Reset it for next time. */
-               info->offset += dbri->descs[td].len;
-               info->left -= dbri->descs[td].len;
+               len = DBRI_RD_CNT(dbri->dma->desc[td].word1);
+               info->offset += len;
+               info->left -= len;
 
                /* On the last TD, transmit them all again. */
-               if (dbri->descs[td].next == -1) {
+               if (dbri->next_desc[td] == -1) {
                        if (info->left > 0) {
                                printk(KERN_WARNING
                                       "%d bytes left after last transfer.\n",
@@ -1817,7 +1718,7 @@ static void transmission_complete_intr(struct snd_dbri * dbri, int pipe)
                        tasklet_schedule(&xmit_descs_task);
                }
 
-               td = dbri->descs[td].next;
+               td = dbri->next_desc[td];
                dbri->pipes[pipe].desc = td;
        }
 
@@ -1841,8 +1742,8 @@ static void reception_complete_intr(struct snd_dbri * dbri, int pipe)
                return;
        }
 
-       dbri->descs[rd].inuse = 0;
-       dbri->pipes[pipe].desc = dbri->descs[rd].next;
+       dbri->dma->desc[rd].ba = 0;
+       dbri->pipes[pipe].desc = dbri->next_desc[rd];
        status = dbri->dma->desc[rd].word1;
        dbri->dma->desc[rd].word1 = 0;  /* Reset it for next time. */
 
@@ -1856,7 +1757,7 @@ static void reception_complete_intr(struct snd_dbri * dbri, int pipe)
                rd, DBRI_RD_STATUS(status), DBRI_RD_CNT(status));
 
        /* On the last TD, transmit them all again. */
-       if (dbri->descs[rd].next == -1) {
+       if (dbri->next_desc[rd] == -1) {
                if (info->left > info->size) {
                        printk(KERN_WARNING
                               "%d bytes recorded in %d size buffer.\n",
@@ -1957,10 +1858,8 @@ static void dbri_process_interrupt_buffer(struct snd_dbri * dbri)
        while ((x = dbri->dma->intr[dbri->dbri_irqp]) != 0) {
                dbri->dma->intr[dbri->dbri_irqp] = 0;
                dbri->dbri_irqp++;
-               if (dbri->dbri_irqp == (DBRI_NO_INTS * DBRI_INT_BLK))
+               if (dbri->dbri_irqp == DBRI_INT_BLK)
                        dbri->dbri_irqp = 1;
-               else if ((dbri->dbri_irqp & (DBRI_INT_BLK - 1)) == 0)
-                       dbri->dbri_irqp++;
 
                dbri_process_one_interrupt(dbri, x);
        }
@@ -2254,7 +2153,6 @@ static int __devinit snd_dbri_pcm(struct snd_dbri * dbri)
        pcm->private_data = dbri;
        pcm->info_flags = 0;
        strcpy(pcm->name, dbri->card->shortname);
-       dbri->pcm = pcm;
 
        if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm,
                        SNDRV_DMA_TYPE_CONTINUOUS,
@@ -2473,7 +2371,6 @@ static int __init snd_dbri_mixer(struct snd_dbri * dbri)
        for (idx = DBRI_REC; idx < DBRI_NO_STREAMS; idx++) {
                dbri->stream_info[idx].left_gain = 0;
                dbri->stream_info[idx].right_gain = 0;
-               dbri->stream_info[idx].balance = DBRI_MID_BALANCE;
        }
 
        return 0;
@@ -2505,12 +2402,11 @@ static void dbri_debug_read(struct snd_info_entry * entry,
                        struct dbri_pipe *pptr = &dbri->pipes[pipe];
                        snd_iprintf(buffer,
                                    "Pipe %d: %s SDP=0x%x desc=%d, "
-                                   "len=%d @ %d prev: %d next %d\n",
+                                   "len=%d next %d\n",
                                    pipe,
-                                   (pptr->direction ==
-                                    PIPEinput ? "input" : "output"), pptr->sdp,
-                                   pptr->desc, pptr->length, pptr->cycle,
-                                   pptr->prevpipe, pptr->nextpipe);
+                                  ((pptr->sdp & D_SDP_TO_SER) ? "output" : "input"),
+                                   pptr->sdp, pptr->desc,
+                                   pptr->length, pptr->nextpipe);
                }
        }
 }
@@ -2519,15 +2415,15 @@ static void dbri_debug_read(struct snd_info_entry * entry,
 void snd_dbri_proc(struct snd_dbri * dbri)
 {
        struct snd_info_entry *entry;
-       int err;
 
-       err = snd_card_proc_new(dbri->card, "regs", &entry);
-       snd_info_set_text_ops(entry, dbri, 1024, dbri_regs_read);
+       if (! snd_card_proc_new(dbri->card, "regs", &entry))
+               snd_info_set_text_ops(entry, dbri, dbri_regs_read);
 
 #ifdef DBRI_DEBUG
-       err = snd_card_proc_new(dbri->card, "debug", &entry);
-       snd_info_set_text_ops(entry, dbri, 4096, dbri_debug_read);
-       entry->mode = S_IFREG | S_IRUGO;        /* Readable only. */
+       if (! snd_card_proc_new(dbri->card, "debug", &entry)) {
+               snd_info_set_text_ops(entry, dbri, dbri_debug_read);
+               entry->mode = S_IFREG | S_IRUGO;        /* Readable only. */
+       }
 #endif
 }
 
@@ -2549,7 +2445,6 @@ static int __init snd_dbri_create(struct snd_card *card,
        dbri->card = card;
        dbri->sdev = sdev;
        dbri->irq = irq->pri;
-       dbri->dbri_version = sdev->prom_name[9];
 
        dbri->dma = sbus_alloc_consistent(sdev, sizeof(struct dbri_dma),
                                          &dbri->dma_dvma);
@@ -2569,7 +2464,7 @@ static int __init snd_dbri_create(struct snd_card *card,
                return -EIO;
        }
 
-       err = request_irq(dbri->irq, snd_dbri_interrupt, SA_SHIRQ,
+       err = request_irq(dbri->irq, snd_dbri_interrupt, IRQF_SHARED,
                          "DBRI audio", dbri);
        if (err) {
                printk(KERN_ERR "DBRI: Can't get irq %d\n", dbri->irq);
@@ -2645,9 +2540,9 @@ static int __init dbri_attach(int prom_node, struct sbus_dev *sdev)
        strcpy(card->driver, "DBRI");
        strcpy(card->shortname, "Sun DBRI");
        rp = &sdev->resource[0];
-       sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %s",
+       sprintf(card->longname, "%s at 0x%02lx:0x%016Lx, irq %d",
                card->shortname,
-               rp->flags & 0xffL, rp->start, __irq_itoa(irq.pri));
+               rp->flags & 0xffL, (unsigned long long)rp->start, irq.pri);
 
        if ((err = snd_dbri_create(card, sdev, &irq, dev)) < 0) {
                snd_card_free(card);
@@ -2664,15 +2559,12 @@ static int __init dbri_attach(int prom_node, struct sbus_dev *sdev)
        /* /proc file handling */
        snd_dbri_proc(dbri);
 
-       if ((err = snd_card_set_generic_dev(card)) < 0)
-               goto _err;
-
        if ((err = snd_card_register(card)) < 0)
                goto _err;
 
        printk(KERN_INFO "audio%d at %p (irq %d) is DBRI(%c)+CS4215(%d)\n",
               dev, dbri->regs,
-              dbri->irq, dbri->dbri_version, dbri->mm.version);
+              dbri->irq, sdev->prom_name[9], dbri->mm.version);
        dev++;
 
        return 0;