patch-2.2.4 linux/drivers/sbus/audio/dbri.c
Next file: linux/drivers/sbus/audio/dbri.h
Previous file: linux/drivers/sbus/audio/cs4231.h
Back to the patch index
Back to the overall index
- Lines: 2220
- Date:
Mon Mar 15 16:11:30 1999
- Orig file:
v2.2.3/linux/drivers/sbus/audio/dbri.c
- Orig date:
Thu Nov 19 09:56:28 1998
diff -u --recursive --new-file v2.2.3/linux/drivers/sbus/audio/dbri.c linux/drivers/sbus/audio/dbri.c
@@ -2,11 +2,10 @@
* drivers/sbus/audio/dbri.c
*
* Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de)
- * The SparcLinux interface was adopted from the CS4231 driver.
+ * Copyright (C) 1998, 1999 Brent Baccala (baccala@freesoft.org)
*
* This is the lowlevel driver for the DBRI & MMCODEC duo used for ISDN & AUDIO
* on Sun SPARCstation 10, 20, LX and Voyager models.
- * NOTE: This driver only supports audio for now, there is NO SUPPORT for ISDN.
*
* - DBRI: AT&T T5900FX Dual Basic Rates ISDN Interface. It is a 32 channel
* data time multiplexer with ISDN support (aka T7259)
@@ -59,6 +58,7 @@
#include <asm/io.h>
#include <asm/delay.h>
#include <asm/sbus.h>
+#include <asm/pgtable.h>
#include <asm/audioio.h>
#include "dbri.h"
@@ -69,7 +69,7 @@
#include "../../isdn/hisax/foreign.h"
#endif
-/* #define DBRI_DEBUG */
+#define DBRI_DEBUG
#ifdef DBRI_DEBUG
@@ -80,14 +80,17 @@
#define D_MM (1<<3)
#define D_USR (1<<4)
-static int dbri_debug = D_GEN|D_INT|D_CMD|D_MM|D_USR;
+/* static int dbri_debug = D_GEN|D_INT|D_CMD|D_MM|D_USR; */
+static int dbri_debug = 0;
+MODULE_PARM(dbri_debug, "i");
+
static char *cmds[] = {
"WAIT", "PAUSE", "JUMP", "IIQ", "REX", "SDP", "CDP", "DTS",
"SSP", "CHI", "NT", "TE", "CDEC", "TEST", "CDM", "RESRV"
};
/* Bit hunting */
-#define dumpcmd {int i; for(i=0; i<n; i++) printk("DBRI: %x\n", dbri->cmd[i]); }
+#define dumpcmd {int i; for(i=0; i<n; i++) printk("DBRI: %x\n", dbri->dma->cmd[i]); }
#define DBRI_CMD(cmd, intr, value) ((cmd << 28) | (1 << 27) | value)
@@ -103,14 +106,16 @@
#define MAX_DRIVERS 2 /* Increase this if need more than 2 DBRI's */
-#define WAIT_INTR1 0xbe
-#define WAIT_INTR2 0xbf
-
static struct sparcaudio_driver drivers[MAX_DRIVERS];
-static char drv_name[] = "DBRI/audio";
-static int num_drivers;
+static int num_drivers = 0;
+
+
+/*
+****************************************************************************
+************** DBRI initialization and command synchronization *************
+****************************************************************************
+*/
-static void * output_callback_arg;
/*
* Commands are sent to the DBRI by building a list of them in memory,
@@ -137,35 +142,46 @@
* in DBRI register 0. I've tried to implement this in such a way
* that might make implementing a more sophisticated scheme easier.
*
- * Every time a routine wants to write commands to the DBRI, it
- * must first call dbri_cmdlock() and get an initial index into dbri->cmd
- * (currently always 0) in return. After the commands have been
- * write (index incremented after each one), dbri_cmdsend() is called
- * with the final index value.
+ * Every time a routine wants to write commands to the DBRI, it must
+ * first call dbri_cmdlock() and get an initial pointer into dbri->dma->cmd
+ * in return. After the commands have been writen, dbri_cmdsend() is
+ * called with the final pointer value.
*/
-static int dbri_cmdlock(struct dbri *dbri)
+static int dbri_locked = 0; /* XXX not SMP safe! XXX */
+
+static volatile int * dbri_cmdlock(struct dbri *dbri)
{
- return 0;
+ if (dbri_locked) {
+ printk("DBRI: Command buffer locked! (bug in driver)\n");
+ }
+ dbri_locked ++;
+ return dbri->dma->cmd;
}
-static void dbri_cmdsend(struct dbri *dbri, int n)
+static void dbri_cmdsend(struct dbri *dbri, volatile int * cmd)
{
int maxloops = 1000000;
- dbri->cmd[n++] = DBRI_CMD(D_WAIT, 0, WAIT_INTR1);
- dbri->regs->reg8 = (int)dbri->cmd;
-
- while (maxloops > 0 && (dbri->regs->reg0 & D_P));
+ dbri_locked --;
+ if (dbri_locked != 0) {
+ printk("DBRI: Command buffer improperly locked! (bug in driver)\n");
+ } else if ((cmd - dbri->dma->cmd) >= DBRI_NO_CMDS-1) {
+ printk("DBRI: Command buffer overflow! (bug in driver)\n");
+ } else {
+ *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
+ *(cmd++) = DBRI_CMD(D_WAIT, 0, 0);
+ dbri->regs->reg8 = (int)dbri->dma_dvma->cmd;
+ while ((maxloops--) > 0 && (dbri->regs->reg0 & D_P));
+ }
if (maxloops == 0) {
- printk("DBRI: Maxloops exceeded in dbri_cmdsend\n");
+ printk("DBRI: Chip never completed command buffer\n");
}
}
-static void dbri_reset(struct sparcaudio_driver *drv)
+static void dbri_reset(struct dbri *dbri)
{
- struct dbri *dbri = (struct dbri *)drv->private;
int i;
dprintk(D_GEN, ("DBRI: reset 0:%x 2:%x 8:%x 9:%x\n",
@@ -177,75 +193,662 @@
udelay(10);
}
-static void dbri_detach(struct sparcaudio_driver *drv)
+static void dbri_detach(struct dbri *dbri)
{
- struct dbri *info = (struct dbri *)drv->private;
-
- dbri_reset(drv);
- unregister_sparcaudio_driver(drv, 1);
- free_irq(info->irq, drv);
- sparc_free_io(info->regs, info->regs_size);
- kfree(drv->private);
+ dbri_reset(dbri);
+ free_irq(dbri->irq, dbri);
+ sparc_free_io(dbri->regs, dbri->regs_size);
+ /* Should we release the DMA structure dbri->dma here? */
+ kfree(dbri);
}
-static void dbri_initialize(struct sparcaudio_driver *drv)
+static void dbri_initialize(struct dbri *dbri)
{
- struct dbri *dbri = (struct dbri *)drv->private;
- int n;
+ int n;
+ volatile int *cmd;
- dbri_reset(drv);
- dbri->wait = NULL;
+ dbri_reset(dbri);
dprintk(D_GEN, ("DBRI: init: cmd: %x, int: %x\n",
- (int)dbri->cmd, (int)dbri->intr));
+ (int)dbri->dma->cmd, (int)dbri->dma->intr));
/*
* Initialize the interrupt ringbuffer.
*/
for(n = 0; n < DBRI_NO_INTS-1; n++)
- dbri->intr[n * DBRI_INT_BLK] =
- (int)(&dbri->intr[(n+1)*DBRI_INT_BLK]);
- dbri->intr[n * DBRI_INT_BLK] = (int)(dbri->intr);
+ dbri->dma->intr[n * DBRI_INT_BLK] =
+ (int)(&dbri->dma_dvma->intr[(n+1)*DBRI_INT_BLK]);
+ dbri->dma->intr[n * DBRI_INT_BLK] = (int)(dbri->dma_dvma->intr);
dbri->dbri_irqp = 1;
-#ifdef USE_SBUS_BURSTS
- /* Enable 4-word, 8-word, and 16-word SBus Bursts */
- dbri->regs->reg0 |= (D_G|D_S|D_E);
-#else
- /* Disable 4-word, 8-word, and 16-word SBus Bursts */
+ /* We should query the openprom to see what burst sizes this
+ * SBus supports. For now, just disable all SBus bursts */
dbri->regs->reg0 &= ~(D_G|D_S|D_E);
-#endif
/*
* Set up the interrupt queue
*/
- n = dbri_cmdlock(dbri);
+ cmd = dbri_cmdlock(dbri);
- dbri->cmd[n++] = DBRI_CMD(D_IIQ, 0, 0);
- dbri->cmd[n++] = (int)(dbri->intr);
+ *(cmd++) = DBRI_CMD(D_IIQ, 0, 0);
+ *(cmd++) = (int)(dbri->dma_dvma->intr);
- dbri_cmdsend(dbri, n);
+ dbri_cmdsend(dbri, cmd);
}
+/*
+****************************************************************************
+*************************** DBRI interrupt handler *************************
+****************************************************************************
+*/
+
/*
* Short data pipes transmit LSB first. The CS4215 receives MSB first. Grrr.
- * So we have to reverse the bits. Note: only 1, 2 or 4 bytes are supported.
+ * So we have to reverse the bits. Note: not all bit lengths are supported
*/
static __u32 reverse_bytes(__u32 b, int len)
{
switch(len) {
- case 4: b = ((b & 0xffff0000) >> 16) | ((b & 0x0000ffff) << 16);
- case 2: b = ((b & 0xff00ff00) >> 8) | ((b & 0x00ff00ff) << 8);
- case 1: b = ((b & 0xf0f0f0f0) >> 4) | ((b & 0x0f0f0f0f) << 4);
- b = ((b & 0xcccccccc) >> 2) | ((b & 0x33333333) << 2);
- b = ((b & 0xaaaaaaaa) >> 1) | ((b & 0x55555555) << 1);
+ case 32:
+ b = ((b & 0xffff0000) >> 16) | ((b & 0x0000ffff) << 16);
+ case 16:
+ b = ((b & 0xff00ff00) >> 8) | ((b & 0x00ff00ff) << 8);
+ case 8:
+ b = ((b & 0xf0f0f0f0) >> 4) | ((b & 0x0f0f0f0f) << 4);
+ case 4:
+ b = ((b & 0xcccccccc) >> 2) | ((b & 0x33333333) << 2);
+ case 2:
+ b = ((b & 0xaaaaaaaa) >> 1) | ((b & 0x55555555) << 1);
+ case 1:
+ break;
+ default:
+ printk("DBRI reverse_bytes: unsupported length\n");
}
return b;
}
+/* transmission_complete_intr()
+ *
+ * Called by main interrupt handler when DBRI signals transmission complete
+ * on a pipe.
+ *
+ * Walks through the pipe's list of transmit buffer descriptors, releasing
+ * each one's DMA buffer (if present) and signaling its callback routine
+ * (if present), before flaging the descriptor available and proceeding
+ * to the next one.
+ *
+ * Assumes that only the last in a chain of descriptors will have FINT
+ * sent to signal an interrupt, so that the chain will be completely
+ * transmitted by the time we get here, and there's no need to save
+ * any of the descriptors. In particular, use of the DBRI's CDP command
+ * is precluded, but I've not been able to get CDP working reliably anyway.
+ */
+
+static void transmission_complete_intr(struct dbri *dbri, int pipe)
+{
+ int td = dbri->pipes[pipe].desc;
+ int status;
+ void *buffer;
+ void (*callback)(void *, int);
+
+ dbri->pipes[pipe].desc = -1;
+
+ for (; td >= 0; td = dbri->descs[td].next) {
+
+ if (td >= DBRI_NO_DESCS) {
+ printk("DBRI: invalid td on pipe %d\n", pipe);
+ return;
+ }
+
+ status = dbri->dma->desc[td].word4;
+
+ buffer = dbri->descs[td].buffer;
+ if (buffer) {
+ mmu_release_scsi_one(sbus_dvma_addr(buffer),
+ dbri->descs[td].len,
+ dbri->sdev->my_bus);
+ }
+
+ callback = dbri->descs[td].output_callback;
+ if (callback != NULL) {
+ callback(dbri->descs[td].output_callback_arg,
+ DBRI_TD_STATUS(status) & 0xe);
+ }
+
+ dbri->descs[td].inuse = 0;
+ }
+}
+
+static void reception_complete_intr(struct dbri *dbri, int pipe)
+{
+ int rd = dbri->pipes[pipe].desc;
+ int status;
+ void *buffer;
+ void (*callback)(void *, int, unsigned int);
+
+ if (rd < 0 || rd >= DBRI_NO_DESCS) {
+ printk("DBRI: invalid rd on pipe %d\n", pipe);
+ return;
+ }
+
+ dbri->descs[rd].inuse = 0;
+ dbri->pipes[pipe].desc = -1;
+ status = dbri->dma->desc[rd].word1;
+
+ buffer = dbri->descs[rd].buffer;
+ if (buffer) {
+ mmu_release_scsi_one(sbus_dvma_addr(buffer),
+ dbri->descs[rd].len,
+ dbri->sdev->my_bus);
+ }
+
+ callback = dbri->descs[rd].input_callback;
+ if (callback != NULL) {
+ callback(dbri->descs[rd].input_callback_arg,
+ DBRI_RD_STATUS(status),
+ DBRI_RD_CNT(status)-2);
+ }
+}
+
+static void dbri_intr(int irq, void *opaque, struct pt_regs *regs)
+{
+ struct dbri *dbri = (struct dbri *)opaque;
+ int x;
+
+ /*
+ * Read it, so the interrupt goes away.
+ */
+ x = dbri->regs->reg1;
+
+ if ( x & (D_MRR|D_MLE|D_LBG|D_MBE) ) {
+ /*
+ * What should I do here ?
+ */
+ if(x & D_MRR) printk("DBRI: Multiple Error Ack on SBus\n");
+ if(x & D_MLE) printk("DBRI: Multiple Late Error on SBus\n");
+ if(x & D_LBG) printk("DBRI: Lost Bus Grant on SBus\n");
+ if(x & D_MBE) printk("DBRI: Burst Error on SBus\n");
+ }
+
+ if (!(x & D_IR)) /* Not for us */
+ return;
+
+ x = dbri->dma->intr[dbri->dbri_irqp];
+ while (x != 0) {
+ int val = D_INTR_GETVAL(x);
+ int channel = D_INTR_GETCHAN(x);
+
+ dbri->dma->intr[dbri->dbri_irqp] = 0;
+
+ if(D_INTR_GETCHAN(x) == D_INTR_CMD) {
+ dprintk(D_INT,("DBRI: INTR: Command: %-5s Value:%d\n",
+ cmds[D_INTR_GETCMD(x)], D_INTR_GETVAL(x)));
+ } else {
+ dprintk(D_INT,("DBRI: INTR: Chan:%d Code:%d Val:%#x\n",
+ D_INTR_GETCHAN(x), D_INTR_GETCODE(x),
+ D_INTR_GETRVAL(x)));
+ }
+
+ if (D_INTR_GETCODE(x) == D_INTR_SBRI) {
+
+ /* SBRI - BRI status change */
+
+ int liu_states[] = {1, 0, 8, 3, 4, 5, 6, 7};
+ dbri->liu_state = liu_states[val & 0x7];
+ if (dbri->liu_callback)
+ dbri->liu_callback(dbri->liu_callback_arg);
+ }
+
+ if (D_INTR_GETCODE(x) == D_INTR_BRDY) {
+ reception_complete_intr(dbri, channel);
+ }
+
+ if (D_INTR_GETCODE(x) == D_INTR_XCMP) {
+ transmission_complete_intr(dbri, channel);
+ }
+
+ if (D_INTR_GETCODE(x) == D_INTR_FXDT) {
+
+ /* FXDT - Fixed data change */
+
+ if (dbri->pipes[D_INTR_GETCHAN(x)].sdp & D_SDP_MSB) {
+ val = reverse_bytes(val, dbri->pipes[channel].length);
+ }
+
+ if (dbri->pipes[D_INTR_GETCHAN(x)].recv_fixed_ptr) {
+ * dbri->pipes[channel].recv_fixed_ptr = val;
+ }
+ }
+
+
+ dbri->dbri_irqp++;
+ if (dbri->dbri_irqp == (DBRI_NO_INTS * DBRI_INT_BLK))
+ dbri->dbri_irqp = 1;
+ else if ((dbri->dbri_irqp & (DBRI_INT_BLK-1)) == 0)
+ dbri->dbri_irqp++;
+ x = dbri->dma->intr[dbri->dbri_irqp];
+ }
+}
+
+
+/*
+****************************************************************************
+************************** DBRI data pipe management ***********************
+****************************************************************************
+*/
+
+
+/* reset_pipe(dbri, pipe)
+ *
+ * Called on an in-use pipe to clear anything being transmitted or received
+ */
+
+static void reset_pipe(struct dbri *dbri, int pipe)
+{
+ int sdp;
+ volatile int *cmd;
+
+ if (pipe < 0 || pipe > 31) {
+ printk("DBRI: reset_pipe called with illegal pipe number\n");
+ return;
+ }
+
+ sdp = dbri->pipes[pipe].sdp;
+ if (sdp == 0) {
+ printk("DBRI: reset_pipe called on uninitialized pipe\n");
+ return;
+ }
+
+ cmd = dbri_cmdlock(dbri);
+ *(cmd++) = DBRI_CMD(D_SDP, 0, sdp | D_SDP_C | D_SDP_P);
+ *(cmd++) = 0;
+ dbri_cmdsend(dbri, cmd);
+
+ dbri->pipes[pipe].desc = -1;
+}
+
+static void setup_pipe(struct dbri *dbri, int pipe, int sdp)
+{
+ if (pipe < 0 || pipe > 31) {
+ printk("DBRI: setup_pipe called with illegal pipe number\n");
+ return;
+ }
+
+ if ((sdp & 0xf800) != sdp) {
+ printk("DBRI: setup_pipe called with strange SDP value\n");
+ /* sdp &= 0xf800; */
+ }
+
+ sdp |= D_PIPE(pipe);
+ dbri->pipes[pipe].sdp = sdp;
+
+ reset_pipe(dbri, pipe);
+}
+
+enum master_or_slave { CHImaster, CHIslave };
+
+static void reset_chi(struct dbri *dbri, enum master_or_slave master_or_slave,
+ int bits_per_frame)
+{
+ volatile int *cmd;
+ int val;
+
+ cmd = dbri_cmdlock(dbri);
+
+ /* Set CHI Anchor: Pipe 16 */
+
+ val = D_DTS_VI | D_DTS_VO | D_DTS_INS |
+ D_DTS_PRVIN(D_P_16) | D_DTS_PRVOUT(D_P_16) | D_PIPE(D_P_16);
+ *(cmd++) = DBRI_CMD(D_DTS, 0, val);
+ *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(D_P_16);
+ *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(D_P_16);
+
+ dbri->pipes[16].sdp = 1;
+ dbri->pipes[16].nextpipe = 16;
+
+ if (master_or_slave == CHIslave) {
+ /* Setup DBRI for CHI Slave - receive clock, frame sync (FS)
+ *
+ * CHICM = 0 (slave mode, 8 kHz frame rate)
+ * IR = give immediate CHI status interrupt
+ * EN = give CHI status interrupt upon change
+ */
+ *(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(0)
+ | D_CHI_IR | D_CHI_EN);
+ } else {
+ /* Setup DBRI for CHI Master - generate clock, FS
+ *
+ * BPF = bits per 8 kHz frame
+ * 12.288 MHz / CHICM_divisor = clock rate
+ * FD = 1 - drive CHIFS on rising edge of CHICK
+ */
+
+ int clockrate = bits_per_frame * 8;
+ int divisor = 12288 / clockrate;
+
+ if (divisor > 255 || divisor * clockrate != 12288) {
+ printk("DBRI: illegal bits_per_frame in setup_chi\n");
+ }
+
+ *(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(divisor) | D_CHI_FD
+ | D_CHI_IR | D_CHI_EN
+ | D_CHI_BPF(bits_per_frame));
+ }
+
+ /* CHI Data Mode
+ *
+ * RCE = 0 - receive on falling edge of CHICK
+ * XCE = 1 - transmit on rising edge of CHICK
+ * XEN = 1 - enable transmitter
+ * REN = 1 - enable receiver
+ */
+
+ *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
+
+ *(cmd++) = DBRI_CMD(D_CDM, 0, D_CDM_XCE|D_CDM_XEN|D_CDM_REN);
+
+ dbri_cmdsend(dbri, cmd);
+}
+
+enum in_or_out { PIPEinput, PIPEoutput };
+
+static void link_time_slot(struct dbri *dbri, int pipe,
+ enum in_or_out direction, int prevpipe,
+ int length, int cycle)
+{
+ volatile int *cmd;
+ int val;
+ int nextpipe;
+
+ if (pipe < 0 || pipe > 31 || prevpipe < 0 || prevpipe > 31) {
+ printk("DBRI: link_time_slot called with illegal pipe number\n");
+ return;
+ }
+
+ if (dbri->pipes[pipe].sdp == 0 || dbri->pipes[prevpipe].sdp == 0) {
+ printk("DBRI: link_time_slot called on uninitialized pipe\n");
+ return;
+ }
+
+ if (pipe == prevpipe) {
+ nextpipe = pipe;
+ } else {
+ nextpipe = dbri->pipes[prevpipe].nextpipe;
+ }
+
+ dbri->pipes[pipe].nextpipe = nextpipe;
+ dbri->pipes[pipe].cycle = cycle;
+ dbri->pipes[pipe].length = length;
+
+ cmd = dbri_cmdlock(dbri);
+
+ if (direction == PIPEinput) {
+ val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(prevpipe) | pipe;
+ *(cmd++) = DBRI_CMD(D_DTS, 0, val);
+ *(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;
+ *(cmd++) = DBRI_CMD(D_DTS, 0, val);
+ *(cmd++) = 0;
+ *(cmd++) = D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);
+ }
+
+ dbri_cmdsend(dbri, cmd);
+}
+
+static void xmit_fixed(struct dbri *dbri, int pipe, unsigned int data)
+{
+ volatile int *cmd;
+
+ if (pipe < 16 || pipe > 31) {
+ printk("DBRI: xmit_fixed called with illegal pipe number\n");
+ return;
+ }
+
+ if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) {
+ printk("DBRI: xmit_fixed called on non-fixed pipe\n");
+ return;
+ }
+
+ if (! dbri->pipes[pipe].sdp & D_SDP_TO_SER) {
+ printk("DBRI: xmit_fixed called on receive pipe\n");
+ return;
+ }
+
+ /* DBRI short pipes always transmit LSB first */
+
+ if (dbri->pipes[pipe].sdp & D_SDP_MSB) {
+ data = reverse_bytes(data, dbri->pipes[pipe].length);
+ }
+
+ cmd = dbri_cmdlock(dbri);
+
+ *(cmd++) = DBRI_CMD(D_SSP, 0, pipe);
+ *(cmd++) = data;
+
+ dbri_cmdsend(dbri, cmd);
+}
+
+/* recv_fixed()
+ *
+ * Receive data on a "fixed" pipe - i.e, one whose contents are not
+ * expected to change much, and which we don't need to read constantly
+ * into a buffer. The DBRI only interrupts us when the data changes.
+ * Only short pipes (numbers 16-31) can be used in fixed data mode.
+ *
+ * Pass this function a pointer to a 32-bit field, no matter how large
+ * the actual time slot is. The interrupt handler takes care of bit
+ * ordering and alignment. An 8-bit time slot will always end up
+ * in the low-order 8 bits, filled either MSB-first or LSB-first,
+ * depending on the settings passed to setup_pipe()
+ */
+
+static void recv_fixed(struct dbri *dbri, int pipe, __u32 *ptr)
+{
+ if (pipe < 16 || pipe > 31) {
+ printk("DBRI: recv_fixed called with illegal pipe number\n");
+ return;
+ }
+
+ if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) {
+ printk("DBRI: recv_fixed called on non-fixed pipe\n");
+ return;
+ }
+
+ if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) {
+ printk("DBRI: recv_fixed called on transmit pipe\n");
+ return;
+ }
+
+ dbri->pipes[pipe].recv_fixed_ptr = ptr;
+}
+
+
+static void xmit_on_pipe(struct dbri *dbri, int pipe,
+ void * buffer, unsigned int len,
+ void (*callback)(void *, int), void * callback_arg)
+{
+ volatile int *cmd;
+ int td = 0;
+ int first_td = -1;
+ int last_td;
+ __u32 dvma_buffer;
+
+ if (pipe < 0 || pipe > 15) {
+ printk("DBRI: xmit_on_pipe called with illegal pipe number\n");
+ return;
+ }
+
+ if (dbri->pipes[pipe].sdp == 0) {
+ printk("DBRI: xmit_on_pipe called on uninitialized pipe\n");
+ return;
+ }
+
+ if (! dbri->pipes[pipe].sdp & D_SDP_TO_SER) {
+ printk("DBRI: xmit_on_pipe called on receive pipe\n");
+ return;
+ }
+
+ /* XXX Fix this XXX
+ * Should be able to queue multiple buffers to send on a pipe
+ */
+
+ if (dbri->pipes[pipe].desc != -1) {
+ printk("DBRI: xmit_on_pipe called on active pipe\n");
+ return;
+ }
+
+ dvma_buffer = mmu_get_scsi_one(buffer, len, dbri->sdev->my_bus);
+
+ while (len > 0) {
+ int mylen;
+
+ for (td; td < DBRI_NO_DESCS; td ++) {
+ if (! dbri->descs[td].inuse) break;
+ }
+ if (td == DBRI_NO_DESCS) {
+ break;
+ }
+
+ if (len > (1 << 13) - 1) {
+ mylen = (1 << 13) - 1;
+ } else {
+ mylen = len;
+ }
+
+ dbri->descs[td].inuse = 1;
+ dbri->descs[td].next = -1;
+ dbri->descs[td].buffer = NULL;
+ dbri->descs[td].output_callback = NULL;
+ dbri->descs[td].input_callback = NULL;
+
+ dbri->dma->desc[td].word1 = DBRI_TD_CNT(mylen);
+ dbri->dma->desc[td].ba = dvma_buffer;
+ dbri->dma->desc[td].nda = 0;
+ dbri->dma->desc[td].word4 = 0;
+
+ if (first_td == -1) {
+ first_td = td;
+ } else {
+ dbri->descs[last_td].next = td;
+ dbri->dma->desc[last_td].nda =
+ (int) & dbri->dma_dvma->desc[td];
+ }
+
+ last_td = td;
+ dvma_buffer += mylen;
+ len -= mylen;
+ }
+
+ if (first_td == -1) {
+ printk("xmit_on_pipe: No descriptors available\n");
+ return;
+ }
+
+ if (len > 0) {
+ printk("xmit_on_pipe: Insufficient descriptors; data truncated\n");
+ }
+
+ dbri->dma->desc[last_td].word1 |= DBRI_TD_I | DBRI_TD_F | DBRI_TD_B;
+
+ dbri->descs[last_td].buffer = buffer;
+ dbri->descs[last_td].len = len;
+ dbri->descs[last_td].output_callback = callback;
+ dbri->descs[last_td].output_callback_arg = callback_arg;
+
+ dbri->pipes[pipe].desc = first_td;
+
+ cmd = dbri_cmdlock(dbri);
+
+ *(cmd++) = DBRI_CMD(D_SDP, 0, dbri->pipes[pipe].sdp | D_SDP_P | D_SDP_C);
+ *(cmd++) = (int) & dbri->dma_dvma->desc[first_td];
+
+ dbri_cmdsend(dbri, cmd);
+}
+
+static void recv_on_pipe(struct dbri *dbri, int pipe,
+ void * buffer, unsigned int len,
+ void (*callback)(void *, int, unsigned int),
+ void * callback_arg)
+{
+ volatile int *cmd;
+ int rd;
+
+ if (pipe < 0 || pipe > 15) {
+ printk("DBRI: recv_on_pipe called with illegal pipe number\n");
+ return;
+ }
+
+ if (dbri->pipes[pipe].sdp == 0) {
+ printk("DBRI: recv_on_pipe called on uninitialized pipe\n");
+ return;
+ }
+
+ if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) {
+ printk("DBRI: recv_on_pipe called on transmit pipe\n");
+ return;
+ }
+
+ /* XXX Fix this XXX
+ * Should be able to queue multiple buffers to send on a pipe
+ */
+
+ if (dbri->pipes[pipe].desc != -1) {
+ printk("DBRI: recv_on_pipe called on active pipe\n");
+ return;
+ }
+
+ /* XXX Fix this XXX
+ * Use multiple descriptors, if needed, to fit in all the data
+ */
+
+ if (len > (1 << 13) - 1) {
+ printk("recv_on_pipe called with len=%d; truncated\n", len);
+ len = (1 << 13) - 1;
+ }
+
+ /* Make sure buffer size is multiple of four */
+ len &= ~3;
+
+ for (rd = 0; rd < DBRI_NO_DESCS; rd ++) {
+ if (! dbri->descs[rd].inuse) break;
+ }
+ if (rd == DBRI_NO_DESCS) {
+ printk("DBRI xmit_on_pipe: No descriptors available\n");
+ return;
+ }
+
+ dbri->dma->desc[rd].word1 = 0;
+ dbri->dma->desc[rd].ba = mmu_get_scsi_one(buffer, len,
+ dbri->sdev->my_bus);
+ dbri->dma->desc[rd].nda = 0;
+ dbri->dma->desc[rd].word4 = DBRI_RD_B | DBRI_RD_BCNT(len);
+
+ dbri->descs[rd].buffer = buffer;
+ dbri->descs[rd].len = len;
+ dbri->descs[rd].input_callback = callback;
+ dbri->descs[rd].input_callback_arg = callback_arg;
+
+ dbri->pipes[pipe].desc = rd;
+
+ cmd = dbri_cmdlock(dbri);
+
+ *(cmd++) = DBRI_CMD(D_SDP, 0, dbri->pipes[pipe].sdp | D_SDP_P);
+ *(cmd++) = (int) & dbri->dma_dvma->desc[rd];
+
+ dbri_cmdsend(dbri, cmd);
+}
+
+
+/*
+****************************************************************************
+*********************** CS4215 audio codec management **********************
+****************************************************************************
+*/
static void mmcodec_default(struct cs4215 *mm)
@@ -266,7 +869,7 @@
* Control Time Slot 1-4
* 0: Default I/O voltage scale
* 1: 8 bit ulaw, 8kHz, mono, high pass filter disabled
- * 2: Serial enable, CHI master, 1 CHI device (64bit), clock 1
+ * 2: Serial enable, CHI master, 128 bits per frame, clock 1
* 3: Tests disabled
*/
mm->ctrl[0] = CS4215_RSRVD_1;
@@ -278,10 +881,6 @@
static void mmcodec_init_data(struct dbri *dbri)
{
- int val, n;
-
- n = dbri_cmdlock(dbri);
-
/*
* Data mode:
* Pipe 4: Send timeslots 1-4 (audio data)
@@ -295,80 +894,27 @@
* bits. The CS4215, it seems, observes TSIN (the delayed signal)
* even if it's the CHI master. Don't ask me...
*/
-
-
- /* Pipe 4: SDP */
- val = D_SDP_MEM|D_SDP_TO_SER|D_SDP_C|D_SDP_P|D_SDP_MSB|D_PIPE(D_P_4);
- dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
- dbri->cmd[n++] = 0;
-
-
- /* Pipe 17: SDP */
- val = D_SDP_FIXED|D_SDP_TO_SER|D_SDP_C|D_PIPE(D_P_17);
- dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
- dbri->cmd[n++] = 0; /* Fixed data */
-
- /* Pipe 17: SSP */
- dbri->cmd[n++] = DBRI_CMD(D_SSP, 0, D_PIPE(D_P_17));
- dbri->cmd[n++] = reverse_bytes(*(int *)dbri->mm.data, 4);
-
-
- /* Pipe 6: SDP */
- val=D_SDP_MEM|D_SDP_FROM_SER|D_SDP_C|D_SDP_P|D_SDP_MSB|D_PIPE(D_P_6);
- dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
- dbri->cmd[n++] = 0;
-
-
- /* Pipe 20: SDP */
- val = D_SDP_FIXED|D_SDP_FROM_SER|D_SDP_CHANGE|D_SDP_C|D_PIPE(D_P_20);
- dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
- dbri->cmd[n++] = 0; /* Fixed data */
-
- dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 0, 0);
+ /* Switch CS4215 to data mode - set PIO3 to 1 */
+ dbri->regs->reg2 = D_ENPIO | D_PIO1 | D_PIO3 |
+ (dbri->mm.onboard ? D_PIO0 : D_PIO2);
+ reset_chi(dbri, CHIslave, 0);
- /* Pipe 4: DTS */
- val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_16) | D_PIPE(D_P_4);
- dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
- dbri->cmd[n++] = 0;
-#if 0
- /* Full blown, four time slots, 16 bit stereo */
- dbri->cmd[n++] = D_TS_LEN(32) | D_TS_CYCLE(8)| D_TS_NEXT(D_P_16);
-#else
- /* Single time slot, 8 bit mono */
- dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(8)| D_TS_NEXT(D_P_16);
-#endif
+ setup_pipe(dbri, 4, D_SDP_MEM | D_SDP_TO_SER | D_SDP_MSB);
+ setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB);
+ setup_pipe(dbri, 6, D_SDP_MEM | D_SDP_FROM_SER | D_SDP_MSB);
+ setup_pipe(dbri, 20, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);
- /* Pipe 17: DTS */
- val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_4) | D_PIPE(D_P_17);
- dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
- dbri->cmd[n++] = 0;
- dbri->cmd[n++] = D_TS_LEN(32) | D_TS_CYCLE(40) | D_TS_NEXT(D_P_16);
-
- /* Pipe 6: DTS */
- val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_16) | D_PIPE(D_P_6);
- dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
-#if 0
- /* Full blown, four time slots, 16 bit stereo */
- dbri->cmd[n++] = D_TS_LEN(32) | D_TS_CYCLE(8)| D_TS_NEXT(D_P_16);
-#else
- /* Single time slot, 8 bit mono */
- dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(8)| D_TS_NEXT(D_P_16);
-#endif
- dbri->cmd[n++] = 0;
-
- /* Pipe 20: DTS */
- val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_6) | D_PIPE(D_P_20);
- dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
- dbri->cmd[n++] = D_TS_LEN(16) | D_TS_CYCLE(48) | D_TS_NEXT(D_P_16);
- dbri->cmd[n++] = 0;
+ /* Pipes 4 and 6 - Single time slot, 8 bit mono */
- /* CHI: Slave mode; enable interrupts */
- dbri->cmd[n++] = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(0) | D_CHI_IR | D_CHI_EN);
+ link_time_slot(dbri, 17, PIPEoutput, 16, 32, 32);
+ link_time_slot(dbri, 4, PIPEoutput, 17, 8, 128);
+ link_time_slot(dbri, 6, PIPEinput, 16, 8, 0);
+ link_time_slot(dbri, 20, PIPEinput, 6, 16, 40);
- dbri_cmdsend(dbri, n);
+ xmit_fixed(dbri, 17, *(int *)dbri->mm.data);
}
@@ -377,7 +923,7 @@
*/
static void mmcodec_setctrl(struct dbri *dbri)
{
- int n, val;
+ int i, val;
/*
* Enable Control mode: Set DBRI's PIO3 (4215's D/~C) to 0, then wait
@@ -398,15 +944,15 @@
* into Data mode and put the DBRI into slave mode. Various timing
* requirements must be observed along the way.
*
- * Oh, and one more thing - when the DBRI is master (and only when
- * the DBRI is master), the addressing of the CS4215's time slots
- * is offset by eight bits, so we add eight to all the "cycle"
- * values in the Define Time Slot (DTS) commands. This is done in
- * hardware by a TI 248 that delays the DBRI->4215 frame sync signal
- * by eight clock cycles. Anybody know why?
+ * Oh, and one more thing, on a SPARCStation 20 (and maybe
+ * others?), the addressing of the CS4215's time slots is
+ * offset by eight bits, so we add eight to all the "cycle"
+ * values in the Define Time Slot (DTS) commands. This is
+ * done in hardware by a TI 248 that delays the DBRI->4215
+ * frame sync signal by eight clock cycles. Anybody know why?
*/
- n = dbri_cmdlock(dbri);
+ reset_chi(dbri, CHImaster, 128);
/*
* Control mode:
@@ -415,472 +961,325 @@
* Pipe 19: Receive timeslot 7 (version).
*/
- /* Set CHI Anchor: Pipe 16. This should take care of the rest. */
- val = D_DTS_VI | D_DTS_VO | D_DTS_INS |
- D_DTS_PRVIN(D_P_16) | D_DTS_PRVOUT(D_P_16) | D_PIPE(D_P_16);
- dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
- dbri->cmd[n++] = D_TS_ANCHOR | D_TS_NEXT(D_P_16);
- dbri->cmd[n++] = D_TS_ANCHOR | D_TS_NEXT(D_P_16);
-
-
- /* Setup the pipes first */
- val = D_SDP_FIXED|D_SDP_TO_SER|D_SDP_P|D_SDP_C|D_PIPE(D_P_17);
- dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
- dbri->cmd[n++] = 0;
-
- val = D_SDP_FIXED|D_SDP_CHANGE|D_SDP_C|D_PIPE(D_P_18);
- dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
- dbri->cmd[n++] = 0;
-
- val = D_SDP_FIXED|D_SDP_CHANGE|D_SDP_C|D_PIPE(D_P_19);
- dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
- dbri->cmd[n++] = 0;
+ setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB);
+ setup_pipe(dbri, 18, D_SDP_FIXED | D_SDP_CHANGE | D_SDP_MSB);
+ setup_pipe(dbri, 19, D_SDP_FIXED | D_SDP_CHANGE | D_SDP_MSB);
+
+ link_time_slot(dbri, 17, PIPEoutput, 16, 32, 128);
+ link_time_slot(dbri, 18, PIPEinput, 16, 8, 0);
+ link_time_slot(dbri, 19, PIPEinput, 18, 8, 48);
+
+ recv_fixed(dbri, 18, & dbri->mm.status);
+ recv_fixed(dbri, 19, & dbri->mm.version);
+
+ /* Wait for the chip to echo back CLB (Control Latch Bit) as zero */
- /* Fill in the data to send */
dbri->mm.ctrl[0] &= ~CS4215_CLB;
- dbri->cmd[n++] = DBRI_CMD(D_SSP, 0, D_PIPE(D_P_17));
- dbri->cmd[n++] = reverse_bytes(*(int *)dbri->mm.ctrl, 4);
+ xmit_fixed(dbri, 17, *(int *)dbri->mm.ctrl);
- dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 0, 0);
+ i = 1000000;
+ while ((! dbri->mm.status & CS4215_CLB) && i--);
+ if (i == 0) {
+ printk("CS4215 didn't respond to CLB\n");
+ return;
+ }
+ /* Terminate CS4215 control mode - data sheet says
+ * "Set CLB=1 and send two more frames of valid control info"
+ */
+ dbri->mm.ctrl[0] |= CS4215_CLB;
+ xmit_fixed(dbri, 17, *(int *)dbri->mm.ctrl);
- /* Link the timeslots */
+ /* Two frames of control info @ 8kHz frame rate = 250 us delay */
+ udelay(250);
+}
- /* Pipe 17 - CS4215 Status, Data Format, Serial Control, Test - output
- * time slots 1, 2, 3 and 4 - 32 bits
- */
+static int mmcodec_init(struct sparcaudio_driver *drv)
+{
+ struct dbri *dbri = (struct dbri *)drv->private;
+ int reg2 = dbri->regs->reg2;
- val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_16) | D_PIPE(D_P_17);
- dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
- dbri->cmd[n++] = 0;
- dbri->cmd[n++] = D_TS_LEN(32) | D_TS_CYCLE(8) | D_TS_NEXT(D_P_16);
- /* Pipe 18 - CS4215 Status and Data Format - input
- * time slots 1 & 2 - 16 bits
- */
+ /* Look for the cs4215 chips */
+ if(reg2 & D_PIO2) {
+ dprintk(D_MM, ("DBRI: Onboard CS4215 detected\n"));
+ dbri->mm.onboard = 1;
+ }
+ if(reg2 & D_PIO0) {
+ dprintk(D_MM, ("DBRI: Speakerbox detected\n"));
+ dbri->mm.onboard = 0;
+ }
+
- val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_16) | D_PIPE(D_P_18);
- dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
- dbri->cmd[n++] = D_TS_LEN(16) | D_TS_CYCLE(8) | D_TS_NEXT(D_P_16);
- dbri->cmd[n++] = 0;
+ /* Using the Speakerbox, if both are attached. */
+ if((reg2 & D_PIO2) && (reg2 & D_PIO0)) {
+ printk("DBRI: Using speakerbox / ignoring onboard mmcodec.\n");
+ dbri->regs->reg2 = D_ENPIO2;
+ dbri->mm.onboard = 0;
+ }
+ if( !(reg2 & (D_PIO0|D_PIO2)) ) {
+ printk("DBRI: no mmcodec found.\n");
+ return -EIO;
+ }
- /* Pipe 19 - CS4215 Revision - time slot 7, eight bits - input
- */
- val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_18) | D_PIPE(D_P_19);
- dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
- dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(56) | D_TS_NEXT(D_P_16);
- dbri->cmd[n++] = 0;
+ /* Now talk to our baby */
+ dbri->regs->reg0 |= D_C; /* Enable CHI */
+ mmcodec_default(&dbri->mm);
- /* Setup DBRI for CHI Master
- *
- * BPF = 128 (128 bits per 8 kHz frame = 1.024 MHz clock rate)
- * CHICM = 12 (12.288 MHz / 24 = 1.024 MHz clock rate)
- * FD = 1 - drive CHIFS on rising edge of CHICK
- *
- * RCE = 0 - receive on falling edge of CHICK
- * XCE = 1 - transmit on rising edge of CHICK
- */
- dbri->cmd[n++] = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(12) | D_CHI_FD |
- D_CHI_IR | D_CHI_EN | D_CHI_BPF(128));
- dbri->cmd[n++] = DBRI_CMD(D_CDM, 0, D_CDM_XCE|D_CDM_XEN|D_CDM_REN);
- dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 0, 0);
+ dbri->mm.version = 0xff;
+ mmcodec_setctrl(dbri);
+ if(dbri->mm.version == 0xff)
+ return -EIO;
- /* Wait for the command to complete */
- dbri_cmdsend(dbri, n);
+ mmcodec_init_data(dbri);
- /* Switch CS4215 to data mode - data sheet says
- * "Set CLB=1 and send two more frames of valid control info"
- */
- n = dbri_cmdlock(dbri);
+ return 0;
+}
- dbri->mm.ctrl[0] |= CS4215_CLB;
- dbri->cmd[n++] = DBRI_CMD(D_SSP, 0, D_PIPE(D_P_17));
- dbri->cmd[n++] = reverse_bytes(*(int *)dbri->mm.ctrl, 4);
- dbri_cmdsend(dbri, n);
+/*
+****************************************************************************
+******************** Interface with sparcaudio midlevel ********************
+****************************************************************************
+*/
- /* Two frames of control info @ 8kHz frame rate = 250 us delay */
- udelay(250);
- n = dbri_cmdlock(dbri);
+static int dbri_open(struct inode * inode, struct file * file,
+ struct sparcaudio_driver *drv)
+{
+ struct dbri *dbri = (struct dbri *)drv->private;
- /* Now switch back to data mode */
- /* Reset CHI Anchor: Stop Send/Receive */
- val = D_DTS_VI | D_DTS_VO | D_DTS_INS |
- D_DTS_PRVIN(D_P_16) | D_DTS_PRVOUT(D_P_16) | D_PIPE(D_P_16);
- dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
- dbri->cmd[n++] = D_TS_ANCHOR | D_TS_NEXT(D_P_16);
- dbri->cmd[n++] = D_TS_ANCHOR | D_TS_NEXT(D_P_16);
+ MOD_INC_USE_COUNT;
+ return 0;
+}
- /* Setup DBRI for CHI Slave */
- dbri->cmd[n++] = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(0));
- /* dbri->cmd[n++] = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(0) | D_CHI_IR | D_CHI_EN); */
- dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 0, 0x16);
+static void dbri_release(struct inode * inode, struct file * file,
+ struct sparcaudio_driver *drv)
+{
+ MOD_DEC_USE_COUNT;
+}
+static int dbri_ioctl(struct inode * inode, struct file * file,
+ unsigned int x, unsigned long y,
+ struct sparcaudio_driver *drv)
+{
+ return 0;
+}
- /* Wait for command to complete */
- dbri_cmdsend(dbri, n);
+static void dbri_audio_output_callback(void * callback_arg, int status)
+{
+ struct sparcaudio_driver *drv = callback_arg;
- /* Switch CS4215 to data mode - set PIO3 to 1 */
- dbri->regs->reg2 = D_ENPIO | D_PIO1 | D_PIO3 |
- (dbri->mm.onboard ? D_PIO0 : D_PIO2);
+ sparcaudio_output_done(drv, 1);
}
-static int mmcodec_init(struct sparcaudio_driver *drv)
+static void dbri_start_output(struct sparcaudio_driver *drv,
+ __u8 * buffer, unsigned long count)
{
struct dbri *dbri = (struct dbri *)drv->private;
- int reg2 = dbri->regs->reg2;
-
- /* Look for the cs4215 chips */
- if(reg2 & D_PIO2) {
- dprintk(D_MM, ("DBRI: Onboard CS4215 detected\n"));
- dbri->mm.onboard = 1;
- }
- if(reg2 & D_PIO0) {
- dprintk(D_MM, ("DBRI: Speakerbox detected\n"));
- dbri->mm.onboard = 0;
- }
-
+ /* Pipe 4 is audio transmit */
+ xmit_on_pipe(dbri, 4, buffer, count, &dbri_audio_output_callback, drv);
+}
- /* Using the Speakerbox, if both are attached. */
- if((reg2 & D_PIO2) && (reg2 & D_PIO0)) {
- printk("DBRI: Using speakerbox / ignoring onboard mmcodec.\n");
- dbri->regs->reg2 = D_ENPIO2;
- dbri->mm.onboard = 0;
- }
- if( !(reg2 & (D_PIO0|D_PIO2)) ) {
- printk("DBRI: no mmcodec found.\n");
- return -EIO;
- }
+static void dbri_stop_output(struct sparcaudio_driver *drv)
+{
+ struct dbri *dbri = (struct dbri *)drv->private;
+ reset_pipe(dbri, 4);
+}
- /* Now talk to our baby */
- dbri->regs->reg0 |= D_C; /* Enable CHI */
+static void dbri_start_input(struct sparcaudio_driver *drv,
+ __u8 * buffer, unsigned long len)
+{
+}
- mmcodec_default(&dbri->mm);
+static void dbri_stop_input(struct sparcaudio_driver *drv)
+{
+}
- dbri->mm.version = 0xff;
- mmcodec_setctrl(dbri);
- if(dbri->mm.version == 0xff)
- return -EIO;
+static void dbri_audio_getdev(struct sparcaudio_driver *drv,
+ audio_device_t *devptr)
+{
+}
- mmcodec_init_data(dbri);
+static int dbri_set_output_volume(struct sparcaudio_driver *drv, int volume)
+{
+ return 0;
+}
- return 0;
+static int dbri_get_output_volume(struct sparcaudio_driver *drv)
+{
+ return 0;
}
-void dbri_isdn_init(struct dbri *dbri)
+static int dbri_set_input_volume(struct sparcaudio_driver *drv, int volume)
{
- int n, val;
+ return 0;
+}
- /* Pipe 0: Receive D channel
- * Pipe 8: Receive B1 channel
- * Pipe 9: Receive B2 channel
- * Pipe 1: Transmit D channel
- * Pipe 10: Transmit B1 channel
- * Pipe 11: Transmit B2 channel
- */
+static int dbri_get_input_volume(struct sparcaudio_driver *drv)
+{
+ return 0;
+}
- n = dbri_cmdlock(dbri);
+static int dbri_set_monitor_volume(struct sparcaudio_driver *drv, int volume)
+{
+ return 0;
+}
- /* Pipe 0: SDP */
- val = D_SDP_HDLC|D_SDP_FROM_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_0);
- dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
- dbri->cmd[n++] = 0;
-
- /* Pipe 8: SDP */
- val = D_SDP_HDLC|D_SDP_FROM_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_8);
- dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
- dbri->cmd[n++] = 0;
-
- /* Pipe 9: SDP */
- val = D_SDP_HDLC|D_SDP_FROM_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_9);
- dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
- dbri->cmd[n++] = 0;
-
- /* Pipe 1: SDP */
- val = D_SDP_HDLC_D|D_SDP_TO_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_1);
- dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
- dbri->cmd[n++] = 0;
-
- /* Pipe 10: SDP */
- val = D_SDP_HDLC|D_SDP_TO_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_10);
- dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
- dbri->cmd[n++] = 0;
-
- /* Pipe 11: SDP */
- val = D_SDP_HDLC|D_SDP_TO_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_11);
- dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
- dbri->cmd[n++] = 0;
-
-
- dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 0, 0);
-
- /* Pipe 0: DTS */
- val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_0) | D_PIPE(D_P_0);
- dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
- dbri->cmd[n++] = D_TS_LEN(2) | D_TS_CYCLE(17)| D_TS_NEXT(D_P_0);
- dbri->cmd[n++] = 0;
-
- /* Pipe 8: DTS */
- val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_0) | D_PIPE(D_P_8);
- dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
- dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(0)| D_TS_NEXT(D_P_0);
- dbri->cmd[n++] = 0;
-
- /* Pipe 9: DTS */
- val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_8) | D_PIPE(D_P_9);
- dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
- dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(8)| D_TS_NEXT(D_P_0);
- dbri->cmd[n++] = 0;
-
- /* Pipe 1: DTS */
- val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_1) | D_PIPE(D_P_1);
- dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
- dbri->cmd[n++] = 0;
- dbri->cmd[n++] = D_TS_LEN(2) | D_TS_CYCLE(17)| D_TS_NEXT(D_P_1);
-
- /* Pipe 10: DTS */
- val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_1) | D_PIPE(D_P_10);
- dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
- dbri->cmd[n++] = 0;
- dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(0)| D_TS_NEXT(D_P_1);
-
- /* Pipe 11: DTS */
- val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_10) | D_PIPE(D_P_11);
- dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
- dbri->cmd[n++] = 0;
- dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(8)| D_TS_NEXT(D_P_1);
+static int dbri_get_monitor_volume(struct sparcaudio_driver *drv)
+{
+ return 0;
+}
+static int dbri_set_output_balance(struct sparcaudio_driver *drv, int balance)
+{
+ return 0;
+}
- /* Wait for command to complete */
- dbri_cmdsend(dbri, n);
+static int dbri_get_output_balance(struct sparcaudio_driver *drv)
+{
+ return 0;
}
-void dbri_intr(int irq, void *dev_id, struct pt_regs *regs)
+static int dbri_set_input_balance(struct sparcaudio_driver *drv, int balance)
{
- struct sparcaudio_driver *drv = (struct sparcaudio_driver *)dev_id;
- struct dbri *dbri = (struct dbri *)drv->private;
- int x, val;
- static int numint = 0;
-
- /*
- * Read it, so the interrupt goes away.
- */
- x = dbri->regs->reg1;
-#if 0
- if(numint++ > 20) {
- dbri->regs->reg0 = D_R; /* Soft Reset */
- numint = 0;
- printk("Soft reset\n");
- }
-#endif
+ return 0;
+}
- if ( x & (D_MRR|D_MLE|D_LBG|D_MBE) ) {
- /*
- * What should I do here ?
- */
- if(x & D_MRR) printk("DBRI: Multiple Error Ack on SBus\n");
- if(x & D_MLE) printk("DBRI: Multiple Late Error on SBus\n");
- if(x & D_LBG) printk("DBRI: Lost Bus Grant on SBus\n");
- if(x & D_MBE) printk("DBRI: Burst Error on SBus\n");
- }
+static int dbri_get_input_balance(struct sparcaudio_driver *drv)
+{
+ return 0;
+}
- if (!(x & D_IR)) /* Not for us */
- return;
+static int dbri_set_output_channels(struct sparcaudio_driver *drv, int chan)
+{
+ return 0;
+}
- x = dbri->intr[dbri->dbri_irqp];
- while (x != 0) {
- dbri->intr[dbri->dbri_irqp] = 0;
+static int dbri_get_output_channels(struct sparcaudio_driver *drv)
+{
+ return 0;
+}
- if(D_INTR_GETCHAN(x) == D_INTR_CMD) {
- dprintk(D_INT,("DBRI: INTR: Command: %-5s Value:%d\n",
- cmds[D_INTR_GETCMD(x)], D_INTR_GETVAL(x)));
- } else {
- dprintk(D_INT,("DBRI: INTR: Chan:%d Code:%d Val:%#x\n",
- D_INTR_GETCHAN(x), D_INTR_GETCODE(x),
- D_INTR_GETRVAL(x)));
- }
+static int dbri_set_input_channels(struct sparcaudio_driver *drv, int chan)
+{
+ return 0;
+}
- val = D_INTR_GETVAL(x);
+static int dbri_get_input_channels(struct sparcaudio_driver *drv)
+{
+ return 0;
+}
- if (D_INTR_GETCODE(x) == D_INTR_SBRI) {
- int liu_states[] = {1, 0, 8, 3, 4, 5, 6, 7};
- dbri->liu_state = liu_states[val & 0x7];
- if (dbri->liu_callback)
- dbri->liu_callback(dbri->liu_callback_arg);
- }
+static int dbri_set_output_precision(struct sparcaudio_driver *drv, int prec)
+{
+ return 8;
+}
- switch(D_INTR_GETCHAN(x)) {
- case D_INTR_CMD:
-#if 0
- if(D_INTR_GETCMD(x) == D_WAIT)
- if(val == WAIT_INTR1) {
- dbri_cmdlocked = 0;
- wake_up(&dbri->wait);
- }
- if(val == WAIT_INTR2)
- wake_up(&dbri->int_wait);
-#endif
- break;
+static int dbri_get_output_precision(struct sparcaudio_driver *drv)
+{
+ return 8;
+}
- case D_P_0:
- /* Pipe 0 - D channel receive */
- if (D_INTR_GETCODE(x) == D_INTR_BRDY &&
- dbri->D.input_callback) {
- dbri->D.input_callback(dbri->D.input_callback_arg,
- DBRI_RD_STATUS(dbri->D.rd.flags),
- DBRI_RD_CNT(dbri->D.rd.flags)-2);
- }
- break;
-
- case D_P_1:
- /* Pipe 1 - D channel transmit */
- if (D_INTR_GETCODE(x) == D_INTR_XCMP &&
- dbri->D.output_callback) {
- dbri->D.output_callback(dbri->D.output_callback_arg,
- DBRI_TD_STATUS(dbri->D.rd.flags)&0xe);
- }
- break;
-
- case D_P_4:
- /* Pipe 4 - audio transmit */
- if (D_INTR_GETCODE(x) == D_INTR_XCMP) {
- sparcaudio_output_done(output_callback_arg, 1);
- }
- break;
-
- case D_P_8:
- /* Pipe 8 - B1 channel receive */
- if (D_INTR_GETCODE(x) == D_INTR_BRDY &&
- dbri->B[0].input_callback) {
- dbri->B[0].input_callback(dbri->B[0].input_callback_arg,
- DBRI_RD_STATUS(dbri->B[0].rd.flags),
- DBRI_RD_CNT(dbri->B[0].rd.flags)-2);
- }
- break;
-
- case D_P_9:
- /* Pipe 9 - B2 channel receive */
- if (D_INTR_GETCODE(x) == D_INTR_BRDY &&
- dbri->B[1].input_callback) {
- dbri->B[1].input_callback(dbri->B[1].input_callback_arg,
- DBRI_RD_STATUS(dbri->B[1].rd.flags),
- DBRI_RD_CNT(dbri->B[1].rd.flags)-2);
- }
- break;
-
- case D_P_10:
- /* Pipe 10 - B1 channel transmit */
- if (D_INTR_GETCODE(x) == D_INTR_XCMP &&
- dbri->B[0].output_callback) {
- dbri->B[0].output_callback(dbri->B[0].output_callback_arg,
- DBRI_TD_STATUS(dbri->B[0].rd.flags)&0xfe);
- }
- break;
-
- case D_P_11:
- /* Pipe 11 - B2 channel transmit */
- if (D_INTR_GETCODE(x) == D_INTR_XCMP &&
- dbri->B[1].output_callback) {
- dbri->B[1].output_callback(dbri->B[1].output_callback_arg,
- DBRI_TD_STATUS(dbri->B[1].rd.flags)&0xfe);
- }
- break;
-
- case D_P_18:
- /* Pipe 18 - receive CS4215 status */
- if(val != 0) {
- x = reverse_bytes(val,2)&CS4215_12_MASK;
- printk("Comparing int: %x with hi(%x)\n", x, *(int *)dbri->mm.ctrl);
- if(x == (*(int *)dbri->mm.ctrl >> 16)) {
- printk("Comp ok\n");
- wake_up(&dbri->int_wait);
- }
- }
- break;
- case D_P_19:
- /* Pipe 19 - receive CS4215 version */
- if(val != 0) {
- dbri->mm.version =
- reverse_bytes(val, 1) & 0xf;
- }
- break;
- }
+static int dbri_set_input_precision(struct sparcaudio_driver *drv, int prec)
+{
+ return 8;
+}
- dbri->dbri_irqp++;
- if (dbri->dbri_irqp == (DBRI_NO_INTS * DBRI_INT_BLK))
- dbri->dbri_irqp = 1;
- else if ((dbri->dbri_irqp & (DBRI_INT_BLK-1)) == 0)
- dbri->dbri_irqp++;
- x = dbri->intr[dbri->dbri_irqp];
- }
+static int dbri_get_input_precision(struct sparcaudio_driver *drv)
+{
+ return 8;
+}
+
+static int dbri_set_output_port(struct sparcaudio_driver *drv, int port)
+{
+ return 0;
}
+static int dbri_get_output_port(struct sparcaudio_driver *drv)
+{
+ return 0;
+}
-/*
-****************************************************************************
-******************** Interface with sparcaudio midlevel ********************
-****************************************************************************
-*/
+static int dbri_set_input_port(struct sparcaudio_driver *drv, int port)
+{
+ return 0;
+}
+static int dbri_get_input_port(struct sparcaudio_driver *drv)
+{
+ return 0;
+}
-static void dummy()
+static int dbri_set_output_encoding(struct sparcaudio_driver *drv, int enc)
{
+ return 0;
}
-static int dbri_open(struct inode * inode, struct file * file,
- struct sparcaudio_driver *drv)
+static int dbri_get_output_encoding(struct sparcaudio_driver *drv)
{
- struct dbri *dbri = (struct dbri *)drv->private;
+ return 0;
+}
- MOD_INC_USE_COUNT;
+static int dbri_set_input_encoding(struct sparcaudio_driver *drv, int enc)
+{
+ return 0;
+}
- return 0;
+static int dbri_get_input_encoding(struct sparcaudio_driver *drv)
+{
+ return 0;
}
-static void dbri_release(struct inode * inode, struct file * file,
- struct sparcaudio_driver *drv)
+static int dbri_set_output_rate(struct sparcaudio_driver *drv, int rate)
{
- MOD_DEC_USE_COUNT;
+ return 0;
}
-static void dbri_start_output(struct sparcaudio_driver *drv,
- __u8 * buffer, unsigned long count)
+static int dbri_get_output_rate(struct sparcaudio_driver *drv)
{
- struct dbri *dbri = (struct dbri *)drv->private;
- int val, n;
+ return 0;
+}
- if (count > (1 << 14) - 1) {
- printk("dbri_start_output called with count=%d; truncated", count);
- count = (1 << 14) - 1;
- }
+static int dbri_set_input_rate(struct sparcaudio_driver *drv, int rate)
+{
+ return 0;
+}
- n = dbri_cmdlock(dbri);
+static int dbri_get_input_rate(struct sparcaudio_driver *drv)
+{
+ return 0;
+}
- dbri->mm.td.flags = DBRI_TD_F | DBRI_TD_B | DBRI_TD_D | DBRI_TD_CNT(count);
- dbri->mm.td.ba = (__u32) buffer;
- dbri->mm.td.nda = 0;
- dbri->mm.td.status = 0;
+static int dbri_sunaudio_getdev_sunos(struct sparcaudio_driver *drv)
+{
+ return 0;
+}
- /* Pipe 4 is audio transmit */
- val = D_SDP_MEM|D_SDP_TO_SER|D_SDP_P|D_SDP_MSB|D_PIPE(D_P_4);
- dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
- dbri->cmd[n++] = (__u32)&dbri->mm.td;
+static int dbri_get_output_ports(struct sparcaudio_driver *drv)
+{
+ return 0;
+}
- output_callback_arg = drv;
+static int dbri_get_input_ports(struct sparcaudio_driver *drv)
+{
+ return 0;
+}
- dbri_cmdsend(dbri, n);
+static int dbri_set_output_muted(struct sparcaudio_driver *drv, int mute)
+{
+ return 0;
}
-static void dbri_stop_output(struct sparcaudio_driver *drv)
+static int dbri_get_output_muted(struct sparcaudio_driver *drv)
{
- struct dbri *dbri = (struct dbri *)drv->private;
+ return 0;
}
@@ -888,60 +1287,89 @@
static struct sparcaudio_operations dbri_ops = {
dbri_open,
dbri_release,
- dummy, /* dbri_ioctl, */
+ dbri_ioctl,
dbri_start_output,
dbri_stop_output,
- dummy, /* dbri_start_input, */
- dummy, /* dbri_stop_input, */
- dummy, /* dbri_audio_getdev, */
- dummy, /* dbri_set_output_volume, */
- dummy, /* dbri_get_output_volume, */
- dummy, /* dbri_set_input_volume, */
- dummy, /* dbri_get_input_volume, */
- dummy, /* dbri_set_monitor_volume, */
- dummy, /* dbri_get_monitor_volume, */
- dummy, /* dbri_set_output_balance */
- dummy, /* dbri_get_output_balance, */
- dummy, /* dbri_set_input_balance */
- dummy, /* dbri_get_input_balance, */
- dummy, /* dbri_set_output_channels */
- dummy, /* dbri_get_output_channels, */
- dummy, /* dbri_set_input_channels */
- dummy, /* dbri_get_input_channels, */
- dummy, /* dbri_set_output_precision */
- dummy, /* dbri_get_output_precision, */
- dummy, /* dbri_set_input_precision */
- dummy, /* dbri_get_input_precision, */
- dummy, /* dbri_set_output_port */
- dummy, /* dbri_get_output_port, */
- dummy, /* dbri_set_input_port */
- dummy, /* dbri_get_input_port, */
- dummy, /* dbri_set_output_encoding */
- dummy, /* dbri_get_output_encoding, */
- dummy, /* dbri_set_input_encoding */
- dummy, /* dbri_get_input_encoding, */
- dummy, /* dbri_set_output_rate */
- dummy, /* dbri_get_output_rate, */
- dummy, /* dbri_set_input_rate */
- dummy, /* dbri_get_input_rate, */
- dummy, /* dbri_sunaudio_getdev_sunos, */
- dummy, /* dbri_get_output_ports, */
- dummy, /* dbri_get_input_ports, */
- dummy, /* dbri_set_output_muted */
- dummy, /* dbri_get_output_muted, */
+ dbri_start_input,
+ dbri_stop_input,
+ dbri_audio_getdev,
+ dbri_set_output_volume,
+ dbri_get_output_volume,
+ dbri_set_input_volume,
+ dbri_get_input_volume,
+ dbri_set_monitor_volume,
+ dbri_get_monitor_volume,
+ dbri_set_output_balance,
+ dbri_get_output_balance,
+ dbri_set_input_balance,
+ dbri_get_input_balance,
+ dbri_set_output_channels,
+ dbri_get_output_channels,
+ dbri_set_input_channels,
+ dbri_get_input_channels,
+ dbri_set_output_precision,
+ dbri_get_output_precision,
+ dbri_set_input_precision,
+ dbri_get_input_precision,
+ dbri_set_output_port,
+ dbri_get_output_port,
+ dbri_set_input_port,
+ dbri_get_input_port,
+ dbri_set_output_encoding,
+ dbri_get_output_encoding,
+ dbri_set_input_encoding,
+ dbri_get_input_encoding,
+ dbri_set_output_rate,
+ dbri_get_output_rate,
+ dbri_set_input_rate,
+ dbri_get_input_rate,
+ dbri_sunaudio_getdev_sunos,
+ dbri_get_output_ports,
+ dbri_get_input_ports,
+ dbri_set_output_muted,
+ dbri_get_output_muted,
};
+
/*
****************************************************************************
************************** ISDN (Hisax) Interface **************************
****************************************************************************
*/
+
+void dbri_isdn_init(struct dbri *dbri)
+{
+ /* Pipe 0: Receive D channel
+ * Pipe 8: Receive B1 channel
+ * Pipe 9: Receive B2 channel
+ * Pipe 1: Transmit D channel
+ * Pipe 10: Transmit B1 channel
+ * Pipe 11: Transmit B2 channel
+ */
+
+ setup_pipe(dbri, 0, D_SDP_HDLC | D_SDP_FROM_SER | D_SDP_LSB);
+ setup_pipe(dbri, 8, D_SDP_HDLC | D_SDP_FROM_SER | D_SDP_LSB);
+ setup_pipe(dbri, 9, D_SDP_HDLC | D_SDP_FROM_SER | D_SDP_LSB);
+
+ setup_pipe(dbri, 1, D_SDP_HDLC_D | D_SDP_TO_SER | D_SDP_LSB);
+ setup_pipe(dbri,10, D_SDP_HDLC | D_SDP_TO_SER | D_SDP_LSB);
+ setup_pipe(dbri,11, D_SDP_HDLC | D_SDP_TO_SER | D_SDP_LSB);
+
+ link_time_slot(dbri, 0, PIPEinput, 0, 2, 17);
+ link_time_slot(dbri, 8, PIPEinput, 8, 8, 0);
+ link_time_slot(dbri, 9, PIPEinput, 9, 8, 8);
+
+ link_time_slot(dbri, 1, PIPEoutput, 1, 2, 17);
+ link_time_slot(dbri, 10, PIPEoutput, 1, 8, 0);
+ link_time_slot(dbri, 11, PIPEoutput, 10, 8, 8);
+}
+
int dbri_get_irqnum(int dev)
{
struct dbri *dbri;
- if (dev > num_drivers) {
+ if (dev >= num_drivers) {
return(0);
}
@@ -955,7 +1383,7 @@
{
struct dbri *dbri;
- if (dev > num_drivers) {
+ if (dev >= num_drivers) {
return(0);
}
@@ -964,11 +1392,13 @@
return dbri->liu_state;
}
+void dbri_liu_activate(int dev, int priority);
+
void dbri_liu_init(int dev, void (*callback)(void *), void *callback_arg)
{
struct dbri *dbri;
- if (dev > num_drivers) {
+ if (dev >= num_drivers) {
return;
}
@@ -979,26 +1409,28 @@
dbri->liu_callback_arg = callback_arg;
dbri_isdn_init(dbri);
+ dbri_liu_activate(dev, 0);
}
void dbri_liu_activate(int dev, int priority)
{
struct dbri *dbri;
- int n, val;
+ int val;
+ volatile int *cmd;
- if (dev > num_drivers) {
+ if (dev >= num_drivers) {
return;
}
dbri = (struct dbri *) drivers[dev].private;
- n = dbri_cmdlock(dbri);
+ cmd = dbri_cmdlock(dbri);
/* Turn on the ISDN TE interface and request activation */
val = D_NT_IRM_IMM | D_NT_IRM_EN | D_NT_ACT;
- dbri->cmd[n++] = DBRI_CMD(D_TE, 0, val);
+ *(cmd++) = DBRI_CMD(D_TE, 0, val);
- dbri_cmdsend(dbri, n);
+ dbri_cmdsend(dbri, cmd);
/* Activate the interface */
dbri->regs->reg0 |= D_T;
@@ -1008,7 +1440,7 @@
{
struct dbri *dbri;
- if (dev > num_drivers) {
+ if (dev >= num_drivers) {
return;
}
@@ -1022,37 +1454,15 @@
void (*callback)(void *, int), void *callback_arg)
{
struct dbri *dbri;
- int n, val;
- if (dev > num_drivers) {
+ if (dev >= num_drivers) {
return;
}
dbri = (struct dbri *) drivers[dev].private;
- if (count > (1 << 14) - 1) {
- printk("dbri_dxmit called with count=%d; truncated", count);
- count = (1 << 14) - 1;
- }
-
- n = dbri_cmdlock(dbri);
-
- /* XXX - Shouldn't I check to make sure D.td isn't is use? */
-
- dbri->D.td.flags = DBRI_TD_F | DBRI_TD_B | DBRI_TD_CNT(count) | DBRI_TD_I;
- dbri->D.td.ba = (__u32) buffer;
- dbri->D.td.nda = 0;
- dbri->D.td.status = 0;
-
- /* Pipe 1 is D channel transmit */
- val = D_SDP_HDLC_D|D_SDP_TO_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_1);
- dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
- dbri->cmd[n++] = (__u32)&dbri->D.td;
-
- dbri->D.output_callback = callback;
- dbri->D.output_callback_arg = callback_arg;
-
- dbri_cmdsend(dbri, n);
+ /* Pipe 1 is D channel transmit */
+ xmit_on_pipe(dbri, 1, buffer, count, callback, callback_arg);
}
void dbri_drecv(int dev, __u8 *buffer, unsigned int size,
@@ -1060,106 +1470,63 @@
void *callback_arg)
{
struct dbri *dbri;
- int n, val;
- if (dev > num_drivers) {
+ if (dev >= num_drivers) {
return;
}
dbri = (struct dbri *) drivers[dev].private;
- if (size > (1 << 14) - 1) {
- printk("dbri_drecv called with size=%d; truncated", size);
- size = (1 << 14) - 1;
- }
-
- /* Make sure size is a multiple of four */
- size &= ~3;
-
- n = dbri_cmdlock(dbri);
-
- /* XXX - Shouldn't I check to make sure D.rd isn't is use? */
-
- dbri->D.rd.flags = 0;
- dbri->D.rd.ba = (__u32) buffer;
- dbri->D.rd.nda = 0;
- dbri->D.rd.status = DBRI_RD_B | DBRI_RD_BCNT(size);
-
- /* Pipe 0 is D channel receive */
- val = D_SDP_HDLC|D_SDP_FROM_SER|D_SDP_C|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_0);
- dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
- dbri->cmd[n++] = (__u32)&dbri->D.rd;
-
- dbri_cmdsend(dbri, n);
-
- dbri->D.input_callback = callback;
- dbri->D.input_callback_arg = callback_arg;
+ /* Pipe 0 is D channel receive */
+ recv_on_pipe(dbri, 0, buffer, size, callback, callback_arg);
}
int dbri_bopen(int dev, unsigned int chan,
int hdlcmode, u_char xmit_idle_char)
{
struct dbri *dbri;
- int n, val;
+ int val;
- if (dev > num_drivers || chan > 1) {
+ if (dev >= num_drivers || chan > 1) {
return -1;
}
dbri = (struct dbri *) drivers[dev].private;
- if (hdlcmode) {
-
- return -1;
-
- /* Pipe 8/9: receive B1/B2 channel */
- dbri->B[chan].recvSDP = D_SDP_HDLC|D_SDP_FROM_SER|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_8+chan);
-
- /* Pipe 10/11: transmit B1/B2 channel */
- dbri->B[chan].xmitSDP = D_SDP_HDLC|D_SDP_TO_SER|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_10+chan);
+ if (hdlcmode) {
- } else { /* !hdlcmode means transparent */
-
- /* Pipe 8/9: receive B1/B2 channel */
- dbri->B[chan].recvSDP = D_SDP_MEM|D_SDP_FROM_SER|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_8+chan);
-
- /* Pipe 10/11: transmit B1/B2 channel */
- dbri->B[chan].xmitSDP = D_SDP_MEM|D_SDP_TO_SER|D_SDP_P|D_SDP_LSB|D_PIPE(D_P_10+chan);
-
- }
+ /* return -1; */
- n = dbri_cmdlock(dbri);
+ /* Pipe 8/9: receive B1/B2 channel */
+ setup_pipe(dbri, 8+chan, D_SDP_HDLC | D_SDP_FROM_SER|D_SDP_LSB);
- /* Pipe 8/9: receive B1/B2 channel */
- val = dbri->B[chan].recvSDP | D_SDP_C;
- dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
- dbri->cmd[n++] = 0;
+ /* Pipe 10/11: transmit B1/B2 channel */
+ setup_pipe(dbri,10+chan, D_SDP_HDLC | D_SDP_TO_SER | D_SDP_LSB);
- /* Pipe 10/11: transmit B1/B2 channel */
- val = dbri->B[chan].xmitSDP | D_SDP_C;
- dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
- dbri->cmd[n++] = 0;
+ } else { /* !hdlcmode means transparent */
- dbri->B[chan].output_callback = NULL;
- dbri->B[chan].input_callback = NULL;
+ /* Pipe 8/9: receive B1/B2 channel */
+ setup_pipe(dbri, 8+chan, D_SDP_MEM | D_SDP_FROM_SER|D_SDP_LSB);
- dbri_cmdsend(dbri, n);
+ /* Pipe 10/11: transmit B1/B2 channel */
+ setup_pipe(dbri,10+chan, D_SDP_MEM | D_SDP_TO_SER | D_SDP_LSB);
- return 0;
+ }
+ return 0;
}
void dbri_bclose(int dev, unsigned int chan)
{
struct dbri *dbri;
- if (dev > num_drivers || chan > 1) {
+ if (dev >= num_drivers || chan > 1) {
return;
}
dbri = (struct dbri *) drivers[dev].private;
- dbri->B[chan].output_callback = NULL;
- dbri->B[chan].input_callback = NULL;
+ reset_pipe(dbri, 8+chan);
+ reset_pipe(dbri, 10+chan);
}
void dbri_bxmit(int dev, unsigned int chan,
@@ -1168,37 +1535,15 @@
void *callback_arg)
{
struct dbri *dbri;
- int n, val;
- if (dev > num_drivers || chan > 1) {
+ if (dev >= num_drivers || chan > 1) {
return;
}
dbri = (struct dbri *) drivers[dev].private;
- if (count > (1 << 14) - 1) {
- printk("dbri_bxmit called with count=%ld; truncated", count);
- count = (1 << 14) - 1;
- }
-
- n = dbri_cmdlock(dbri);
-
- /* XXX - Shouldn't I check to make sure td isn't is use? */
-
- dbri->B[chan].td.flags = DBRI_TD_F | DBRI_TD_B | DBRI_TD_CNT(count);
- dbri->B[chan].td.ba = (__u32) buffer;
- dbri->B[chan].td.nda = 0;
- dbri->B[chan].td.status = 0;
-
- /* Pipe 10/11 is B1/B2 channel transmit */
- val = dbri->B[chan].xmitSDP;
- dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
- dbri->cmd[n++] = (__u32)&dbri->B[chan].td;
-
- dbri->B[chan].output_callback = callback;
- dbri->B[chan].output_callback_arg = callback_arg;
-
- dbri_cmdsend(dbri, n);
+ /* Pipe 10/11 is B1/B2 channel transmit */
+ xmit_on_pipe(dbri, 10+chan, buffer, count, callback, callback_arg);
}
void dbri_brecv(int dev, unsigned int chan,
@@ -1207,40 +1552,15 @@
void *callback_arg)
{
struct dbri *dbri;
- int n, val;
- if (dev > num_drivers || chan > 1) {
+ if (dev >= num_drivers || chan > 1) {
return;
}
dbri = (struct dbri *) drivers[dev].private;
- if (size > (1 << 14) - 1) {
- printk("dbri_brecv called with size=%ld; truncated", size);
- size = (1 << 14) - 1;
- }
-
- /* Make sure size is a multiple of four */
- size &= ~3;
-
- n = dbri_cmdlock(dbri);
-
- /* XXX - Shouldn't I check to make sure RD isn't is use? */
-
- dbri->B[chan].rd.flags = 0;
- dbri->B[chan].rd.ba = (__u32) buffer;
- dbri->B[chan].rd.nda = 0;
- dbri->B[chan].rd.status = DBRI_RD_B | DBRI_RD_BCNT(size);
-
- /* Pipe 8/9 is B1/B2 channel receive */
- val = dbri->B[chan].recvSDP;
- dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
- dbri->cmd[n++] = (__u32)&dbri->B[chan].rd;
-
- dbri_cmdsend(dbri, n);
-
- dbri->B[chan].input_callback = callback;
- dbri->B[chan].input_callback_arg = callback_arg;
+ /* Pipe 8/9 is B1/B2 channel receive */
+ recv_on_pipe(dbri, 8+chan, buffer, size, callback, callback_arg);
}
#if defined(DBRI_ISDN) || defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff
@@ -1271,6 +1591,7 @@
{
struct dbri *dbri;
struct linux_prom_irqs irq;
+ __u32 dma_dvma;
int err;
if (sdev->prom_name[9] < 'e') {
@@ -1287,7 +1608,13 @@
memset(dbri, 0, sizeof(*dbri));
+ /* sparc_dvma_malloc() will halt the kernel if the malloc fails */
+ dbri->dma = sparc_dvma_malloc (sizeof (struct dbri_dma),
+ "DBRI DMA Cmd Block", &dma_dvma);
+ dbri->dma_dvma = (struct dbri_dma *) dma_dvma;
+
dbri->dbri_version = sdev->prom_name[9];
+ dbri->sdev = sdev;
/* Map the registers into memory. */
prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0],
@@ -1295,7 +1622,7 @@
dbri->regs_size = sdev->reg_addrs[0].reg_size;
dbri->regs = sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0,
sdev->reg_addrs[0].reg_size,
- drv_name, sdev->reg_addrs[0].which_io, 0);
+ "DBRI Registers", sdev->reg_addrs[0].which_io, 0);
if (!dbri->regs) {
printk(KERN_ERR "DBRI: could not allocate registers\n");
kfree(drv->private);
@@ -1305,7 +1632,8 @@
prom_getproperty(sdev->prom_node, "intr", (char *)&irq, sizeof(irq));
dbri->irq = irq.pri;
- err = request_irq(dbri->irq, dbri_intr, SA_SHIRQ, "DBRI/audio", drv);
+ err = request_irq(dbri->irq, dbri_intr, SA_SHIRQ,
+ "DBRI audio/ISDN", dbri);
if (err) {
printk(KERN_ERR "DBRI: Can't get irq %d\n", dbri->irq);
sparc_free_io(dbri->regs, dbri->regs_size);
@@ -1313,23 +1641,20 @@
return err;
}
+ dbri_initialize(dbri);
+ err = mmcodec_init(drv);
+ if(err) {
+ dbri_detach(dbri);
+ return err;
+ }
+
/* Register ourselves with the midlevel audio driver. */
err = register_sparcaudio_driver(drv,1);
if (err) {
printk(KERN_ERR "DBRI: unable to register audio\n");
- free_irq(dbri->irq, drv);
- sparc_free_io(dbri->regs, dbri->regs_size);
- kfree(drv->private);
- return err;
- }
-
- dbri_initialize(drv);
- err = mmcodec_init(drv);
- if(err) {
- dbri_detach(drv);
+ dbri_detach(dbri);
return err;
}
-
dbri->perchip_info.play.active = dbri->perchip_info.play.pause = 0;
dbri->perchip_info.record.active = dbri->perchip_info.record.pause = 0;
@@ -1380,7 +1705,8 @@
register int i;
for (i = 0; i < num_drivers; i++) {
- dbri_detach(&drivers[i]);
+ dbri_detach((struct dbri *) drivers[i].private);
+ unregister_sparcaudio_driver(& drivers[i], 1);
num_drivers--;
}
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)