X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=sound%2Fsparc%2Fdbri.c;h=63bef0aadf1e13dd11a4da275ddbd390a398981d;hb=6ab3d5624e172c553004ecc862bfeac16d9d68b7;hp=941c7b1e7ebb959ed49e1077aa2dad14b99c4bdb;hpb=31151ba2cef171344beac254e65bd7e00138bb0d;p=powerpc.git diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 941c7b1e7e..63bef0aadf 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -1,6 +1,6 @@ /* * Driver for DBRI sound chip found on Sparcs. - * Copyright (C) 2004 Martin Habets (mhabets@users.sourceforge.net) + * Copyright (C) 2004, 2005 Martin Habets (mhabets@users.sourceforge.net) * * Based entirely upon drivers/sbus/audio/dbri.c which is: * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de) @@ -43,6 +43,12 @@ * audio devices. But the SUN HW group decided against it, at least on my * LX the speakerbox connector has at least 1 pin missing and 1 wrongly * connected. + * + * I've tried to stick to the following function naming conventions: + * snd_* ALSA stuff + * cs4215_* CS4215 codec specific stuff + * dbri_* DBRI high-level stuff + * other DBRI low-level stuff */ #include @@ -86,8 +92,8 @@ MODULE_PARM_DESC(enable, "Enable Sun DBRI soundcard."); #define D_USR (1<<4) #define D_DESC (1<<5) -static int dbri_debug = 0; -module_param(dbri_debug, int, 0444); +static int dbri_debug; +module_param(dbri_debug, int, 0644); MODULE_PARM_DESC(dbri_debug, "Debug value for Sun DBRI soundcard."); #ifdef DBRI_DEBUG @@ -293,8 +299,8 @@ struct dbri_desc { }; /* Per stream (playback or record) information */ -typedef struct dbri_streaminfo { - snd_pcm_substream_t *substream; +struct dbri_streaminfo { + struct snd_pcm_substream *substream; u32 dvma_buffer; /* Device view of Alsa DMA buffer */ int left; /* # of bytes left in DMA buffer */ int size; /* Size of DMA buffer */ @@ -303,12 +309,12 @@ typedef struct dbri_streaminfo { int left_gain; /* mixer elements */ int right_gain; int balance; -} dbri_streaminfo_t; +}; /* This structure holds the information for both chips (DBRI & CS4215) */ -typedef struct snd_dbri { - snd_card_t *card; /* ALSA card */ - snd_pcm_t *pcm; +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 */ @@ -320,7 +326,8 @@ typedef struct snd_dbri { void __iomem *regs; /* dbri HW regs */ int dbri_version; /* 'e' and up is OK */ int dbri_irqp; /* intr queue pointer */ - int wait_seen; + 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]; @@ -334,10 +341,7 @@ typedef struct snd_dbri { struct dbri_streaminfo stream_info[DBRI_NO_STREAMS]; struct snd_dbri *next; -} snd_dbri_t; - -/* Needed for the ALSA macros to work */ -#define chip_t snd_dbri_t +}; #define DBRI_MAX_VOLUME 63 /* Output volume */ #define DBRI_MAX_GAIN 15 /* Input gain */ @@ -589,7 +593,7 @@ typedef struct snd_dbri { /* Return a pointer to dbri_streaminfo */ #define DBRI_STREAM(dbri, substream) &dbri->stream_info[DBRI_STREAMNO(substream)] -static snd_dbri_t *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. @@ -625,16 +629,13 @@ static __u32 reverse_bytes(__u32 b, int len) Commands are sent to the DBRI by building a list of them in memory, then writing the address of the first list item to DBRI register 8. -The list is terminated with a WAIT command, which can generate a -CPU interrupt if required. +The list is terminated with a WAIT command, which generates a +CPU interrupt to signal completion. Since the DBRI can run in parallel with the CPU, several means of -synchronization present themselves. The original scheme (Rudolf's) -was to set a flag when we "cmdlock"ed the DBRI, clear the flag when -an interrupt signaled completion, and wait on a wait_queue if a routine -attempted to cmdlock while the flag was set. The problems arose when -we tried to cmdlock from inside an interrupt handler, which might -cause scheduling in an interrupt (if we waited), etc, etc +synchronization present themselves. The method implemented here is close +to the original scheme (Rudolf's), and uses 2 counters (wait_send and +wait_ackd) to synchronize the command buffer between the CPU and the DBRI. A more sophisticated scheme might involve a circular command buffer or an array of command buffers. A routine could fill one with @@ -642,76 +643,81 @@ commands and link it onto a list. When a interrupt signaled completion of the current command buffer, look on the list for the next one. -I've decided to implement something much simpler - after each command, -the CPU waits for the DBRI to finish the command by polling the P bit -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 pointer into dbri->dma->cmd -in return. After the commands have been writen, dbri_cmdsend() is -called with the final pointer value. +in return. dbri_cmdlock() will block if the previous commands have not +been completed yet. After this the commands can be written to the buffer, +and dbri_cmdsend() is called with the final pointer value to send them +to the DBRI. */ -enum dbri_lock_t { NoGetLock, GetLock }; +static void dbri_process_interrupt_buffer(struct snd_dbri * dbri); + +enum dbri_lock { NoGetLock, GetLock }; +#define MAXLOOPS 10 -static volatile s32 *dbri_cmdlock(snd_dbri_t * dbri, enum dbri_lock_t get) +static volatile s32 *dbri_cmdlock(struct snd_dbri * dbri, enum dbri_lock get) { + int maxloops = MAXLOOPS; + #ifndef SMP if ((get == GetLock) && spin_is_locked(&dbri->lock)) { printk(KERN_ERR "DBRI: cmdlock called while in spinlock."); } #endif + /* 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", + dbri->wait_send); + } else { + dprintk(D_CMD, "Chip completed command buffer (%d)\n", + MAXLOOPS - maxloops - 1); + } + /*if (get == GetLock) spin_lock(&dbri->lock); */ return &dbri->dma->cmd[0]; } -static void dbri_process_interrupt_buffer(snd_dbri_t *); - -static void dbri_cmdsend(snd_dbri_t * dbri, volatile s32 * cmd) +static void dbri_cmdsend(struct snd_dbri * dbri, volatile s32 * cmd) { - int MAXLOOPS = 1000000; - int maxloops = MAXLOOPS; 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); } if ((cmd - &dbri->dma->cmd[0]) >= DBRI_NO_CMDS - 1) { - printk("DBRI: Command buffer overflow! (bug in driver)\n"); + printk(KERN_ERR "DBRI: Command buffer overflow! (bug in driver)\n"); /* Ignore the last part. */ cmd = &dbri->dma->cmd[DBRI_NO_CMDS - 3]; } + dbri->wait_send++; + dbri->wait_send &= 0xffff; /* restrict it to a 16 bit counter. */ *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); - *(cmd++) = DBRI_CMD(D_WAIT, 1, 0); - dbri->wait_seen = 0; + *(cmd++) = DBRI_CMD(D_WAIT, 1, dbri->wait_send); + + /* Set command pointer and signal it is valid. */ sbus_writel(dbri->dma_dvma, dbri->regs + REG8); - while ((--maxloops) > 0 && (sbus_readl(dbri->regs + REG0) & D_P)) - barrier(); - if (maxloops == 0) { - printk(KERN_ERR "DBRI: Chip never completed command buffer\n"); - dprintk(D_CMD, "DBRI: Chip never completed command buffer\n"); - } else { - while ((--maxloops) > 0 && (!dbri->wait_seen)) - dbri_process_interrupt_buffer(dbri); - if (maxloops == 0) { - printk(KERN_ERR "DBRI: Chip never acked WAIT\n"); - dprintk(D_CMD, "DBRI: Chip never acked WAIT\n"); - } else { - dprintk(D_CMD, "Chip completed command " - "buffer (%d)\n", MAXLOOPS - maxloops); - } - } + reg = sbus_readl(dbri->regs + REG0); + reg |= D_P; + sbus_writel(reg, dbri->regs + REG0); /*spin_unlock(&dbri->lock); */ } /* Lock must be held when calling this */ -static void dbri_reset(snd_dbri_t * dbri) +static void dbri_reset(struct snd_dbri * dbri) { int i; @@ -726,7 +732,7 @@ static void dbri_reset(snd_dbri_t * dbri) } /* Lock must not be held before calling this */ -static void dbri_initialize(snd_dbri_t * dbri) +static void dbri_initialize(struct snd_dbri * dbri) { volatile s32 *cmd; u32 dma_addr, tmp; @@ -757,10 +763,11 @@ static void dbri_initialize(snd_dbri_t * dbri) for (n = 0; n < DBRI_NO_PIPES; n++) dbri->pipes[n].desc = dbri->pipes[n].first_desc = -1; - /* We should query the openprom to see what burst sizes this - * SBus supports. For now, just disable all SBus bursts */ + /* 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_S | D_E); + tmp |= D_G | D_E; + tmp &= ~D_S; sbus_writel(tmp, dbri->regs + REG0); /* @@ -788,7 +795,7 @@ list ordering, among other things. The transmit and receive functions here interface closely with the transmit and receive interrupt code. */ -static int pipe_active(snd_dbri_t * dbri, int pipe) +static int pipe_active(struct snd_dbri * dbri, int pipe) { return ((pipe >= 0) && (dbri->pipes[pipe].desc != -1)); } @@ -798,20 +805,20 @@ static int pipe_active(snd_dbri_t * dbri, int pipe) * Called on an in-use pipe to clear anything being transmitted or received * Lock must be held before calling this. */ -static void reset_pipe(snd_dbri_t * dbri, int pipe) +static void reset_pipe(struct snd_dbri * dbri, int pipe) { int sdp; int desc; volatile int *cmd; if (pipe < 0 || pipe > 31) { - printk("DBRI: reset_pipe called with illegal pipe number\n"); + printk(KERN_ERR "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"); + printk(KERN_ERR "DBRI: reset_pipe called on uninitialized pipe\n"); return; } @@ -831,15 +838,15 @@ static void reset_pipe(snd_dbri_t * dbri, int pipe) } /* FIXME: direction as an argument? */ -static void setup_pipe(snd_dbri_t * dbri, int pipe, int sdp) +static void setup_pipe(struct snd_dbri * dbri, int pipe, int sdp) { if (pipe < 0 || pipe > 31) { - printk("DBRI: setup_pipe called with illegal pipe number\n"); + printk(KERN_ERR "DBRI: setup_pipe called with illegal pipe number\n"); return; } if ((sdp & 0xf800) != sdp) { - printk("DBRI: setup_pipe called with strange SDP value\n"); + printk(KERN_ERR "DBRI: setup_pipe called with strange SDP value\n"); /* sdp &= 0xf800; */ } @@ -862,7 +869,7 @@ static void setup_pipe(snd_dbri_t * dbri, int pipe, int sdp) } /* FIXME: direction not needed */ -static void link_time_slot(snd_dbri_t * dbri, int pipe, +static void link_time_slot(struct snd_dbri * dbri, int pipe, enum in_or_out direction, int basepipe, int length, int cycle) { @@ -872,13 +879,13 @@ static void link_time_slot(snd_dbri_t * dbri, int pipe, int nextpipe; if (pipe < 0 || pipe > 31 || basepipe < 0 || basepipe > 31) { - printk - ("DBRI: link_time_slot called with illegal pipe number\n"); + 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) { - printk("DBRI: link_time_slot called on uninitialized pipe\n"); + printk(KERN_ERR "DBRI: link_time_slot called on uninitialized pipe\n"); return; } @@ -952,7 +959,7 @@ static void link_time_slot(snd_dbri_t * dbri, int pipe, dbri_cmdsend(dbri, cmd); } -static void unlink_time_slot(snd_dbri_t * dbri, int pipe, +static void unlink_time_slot(struct snd_dbri * dbri, int pipe, enum in_or_out direction, int prevpipe, int nextpipe) { @@ -960,8 +967,8 @@ static void unlink_time_slot(snd_dbri_t * dbri, int pipe, int val; if (pipe < 0 || pipe > 31 || prevpipe < 0 || prevpipe > 31) { - printk - ("DBRI: unlink_time_slot called with illegal pipe number\n"); + printk(KERN_ERR + "DBRI: unlink_time_slot called with illegal pipe number\n"); return; } @@ -996,27 +1003,27 @@ static void unlink_time_slot(snd_dbri_t * dbri, int pipe, * in the low-order 8 bits, filled either MSB-first or LSB-first, * depending on the settings passed to setup_pipe() */ -static void xmit_fixed(snd_dbri_t * dbri, int pipe, unsigned int data) +static void xmit_fixed(struct snd_dbri * dbri, int pipe, unsigned int data) { volatile s32 *cmd; if (pipe < 16 || pipe > 31) { - printk("DBRI: xmit_fixed: Illegal pipe number\n"); + printk(KERN_ERR "DBRI: xmit_fixed: Illegal pipe number\n"); return; } if (D_SDP_MODE(dbri->pipes[pipe].sdp) == 0) { - printk("DBRI: xmit_fixed: Uninitialized pipe %d\n", pipe); + printk(KERN_ERR "DBRI: xmit_fixed: Uninitialized pipe %d\n", pipe); return; } if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) { - printk("DBRI: xmit_fixed: Non-fixed pipe %d\n", pipe); + printk(KERN_ERR "DBRI: xmit_fixed: Non-fixed pipe %d\n", pipe); return; } if (!(dbri->pipes[pipe].sdp & D_SDP_TO_SER)) { - printk("DBRI: xmit_fixed: Called on receive pipe %d\n", pipe); + printk(KERN_ERR "DBRI: xmit_fixed: Called on receive pipe %d\n", pipe); return; } @@ -1033,20 +1040,20 @@ static void xmit_fixed(snd_dbri_t * dbri, int pipe, unsigned int data) dbri_cmdsend(dbri, cmd); } -static void recv_fixed(snd_dbri_t * dbri, int pipe, volatile __u32 * ptr) +static void recv_fixed(struct snd_dbri * dbri, int pipe, volatile __u32 * ptr) { if (pipe < 16 || pipe > 31) { - printk("DBRI: recv_fixed called with illegal pipe number\n"); + printk(KERN_ERR "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 %d\n", pipe); + printk(KERN_ERR "DBRI: recv_fixed called on non-fixed pipe %d\n", pipe); return; } if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) { - printk("DBRI: recv_fixed called on transmit pipe %d\n", pipe); + printk(KERN_ERR "DBRI: recv_fixed called on transmit pipe %d\n", pipe); return; } @@ -1065,9 +1072,9 @@ static void recv_fixed(snd_dbri_t * dbri, int pipe, volatile __u32 * ptr) * data buffers. Buffers too large for a single descriptor will * be spread across multiple descriptors. */ -static int setup_descs(snd_dbri_t * dbri, int streamno, unsigned int period) +static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period) { - dbri_streaminfo_t *info = &dbri->stream_info[streamno]; + struct dbri_streaminfo *info = &dbri->stream_info[streamno]; __u32 dvma_buffer; int desc = 0; int len; @@ -1075,12 +1082,12 @@ static int setup_descs(snd_dbri_t * dbri, int streamno, unsigned int period) int last_desc = -1; if (info->pipe < 0 || info->pipe > 15) { - printk("DBRI: setup_descs: Illegal pipe number\n"); + printk(KERN_ERR "DBRI: setup_descs: Illegal pipe number\n"); return -2; } if (dbri->pipes[info->pipe].sdp == 0) { - printk("DBRI: setup_descs: Uninitialized pipe %d\n", + printk(KERN_ERR "DBRI: setup_descs: Uninitialized pipe %d\n", info->pipe); return -2; } @@ -1090,20 +1097,20 @@ static int setup_descs(snd_dbri_t * dbri, int streamno, unsigned int period) if (streamno == DBRI_PLAY) { if (!(dbri->pipes[info->pipe].sdp & D_SDP_TO_SER)) { - printk("DBRI: setup_descs: Called on receive pipe %d\n", + printk(KERN_ERR "DBRI: setup_descs: Called on receive pipe %d\n", info->pipe); return -2; } } else { if (dbri->pipes[info->pipe].sdp & D_SDP_TO_SER) { - printk - ("DBRI: setup_descs: Called on transmit pipe %d\n", + printk(KERN_ERR + "DBRI: setup_descs: Called on transmit pipe %d\n", info->pipe); return -2; } /* Should be able to queue multiple buffers to receive on a pipe */ if (pipe_active(dbri, info->pipe)) { - printk("DBRI: recv_on_pipe: Called on active pipe %d\n", + printk(KERN_ERR "DBRI: recv_on_pipe: Called on active pipe %d\n", info->pipe); return -2; } @@ -1120,7 +1127,7 @@ static int setup_descs(snd_dbri_t * dbri, int streamno, unsigned int period) break; } if (desc == DBRI_NO_DESCS) { - printk("DBRI: setup_descs: No descriptors\n"); + printk(KERN_ERR "DBRI: setup_descs: No descriptors\n"); return -1; } @@ -1165,7 +1172,7 @@ static int setup_descs(snd_dbri_t * dbri, int streamno, unsigned int period) } if (first_desc == -1 || last_desc == -1) { - printk("DBRI: setup_descs: Not enough descriptors available\n"); + printk(KERN_ERR "DBRI: setup_descs: Not enough descriptors available\n"); return -1; } @@ -1200,7 +1207,7 @@ multiplexed serial interface which the DBRI can operate in either master enum master_or_slave { CHImaster, CHIslave }; -static void reset_chi(snd_dbri_t * dbri, enum master_or_slave master_or_slave, +static void reset_chi(struct snd_dbri * dbri, enum master_or_slave master_or_slave, int bits_per_frame) { volatile s32 *cmd; @@ -1270,7 +1277,7 @@ static void reset_chi(snd_dbri_t * dbri, enum master_or_slave master_or_slave, int divisor = 12288 / clockrate; if (divisor > 255 || divisor * clockrate != 12288) - printk("DBRI: illegal bits_per_frame in setup_chi\n"); + printk(KERN_ERR "DBRI: illegal bits_per_frame in setup_chi\n"); *(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(divisor) | D_CHI_FD | D_CHI_BPF(bits_per_frame)); @@ -1301,7 +1308,7 @@ In the standard SPARC audio configuration, the CS4215 codec is attached to the DBRI via the CHI interface and few of the DBRI's PIO pins. */ -static void cs4215_setup_pipes(snd_dbri_t * dbri) +static void cs4215_setup_pipes(struct snd_dbri * dbri) { /* * Data mode: @@ -1362,7 +1369,7 @@ static int cs4215_init_data(struct cs4215 *mm) return 0; } -static void cs4215_setdata(snd_dbri_t * dbri, int muted) +static void cs4215_setdata(struct snd_dbri * dbri, int muted) { if (muted) { dbri->mm.data[0] |= 63; @@ -1371,7 +1378,7 @@ static void cs4215_setdata(snd_dbri_t * dbri, int muted) dbri->mm.data[3] &= ~15; } else { /* Start by setting the playback attenuation. */ - dbri_streaminfo_t *info = &dbri->stream_info[DBRI_PLAY]; + struct dbri_streaminfo *info = &dbri->stream_info[DBRI_PLAY]; int left_gain = info->left_gain % 64; int right_gain = info->right_gain % 64; @@ -1402,7 +1409,7 @@ static void cs4215_setdata(snd_dbri_t * dbri, int muted) /* * Set the CS4215 to data mode. */ -static void cs4215_open(snd_dbri_t * dbri) +static void cs4215_open(struct snd_dbri * dbri) { int data_width; u32 tmp; @@ -1464,7 +1471,7 @@ static void cs4215_open(snd_dbri_t * dbri) /* * Send the control information (i.e. audio format) */ -static int cs4215_setctrl(snd_dbri_t * dbri) +static int cs4215_setctrl(struct snd_dbri * dbri) { int i, val; u32 tmp; @@ -1474,7 +1481,6 @@ static int cs4215_setctrl(snd_dbri_t * dbri) /* Temporarily mute outputs, and wait 1/8000 sec (125 us) * to make sure this takes. This avoids clicking noises. */ - cs4215_setdata(dbri, 1); udelay(125); @@ -1530,8 +1536,8 @@ static int cs4215_setctrl(snd_dbri_t * dbri) tmp |= D_C; /* Enable CHI */ sbus_writel(tmp, dbri->regs + REG0); - for (i = 64; ((dbri->mm.status & 0xe4) != 0x20); --i) { - udelay(125); + for (i = 10; ((dbri->mm.status & 0xe4) != 0x20); --i) { + msleep_interruptible(1); } if (i == 0) { dprintk(D_MM, "CS4215 didn't respond to CLB (0x%02x)\n", @@ -1564,7 +1570,7 @@ static int cs4215_setctrl(snd_dbri_t * dbri) * As part of the process we resend the settings for the data * timeslots as well. */ -static int cs4215_prepare(snd_dbri_t * dbri, unsigned int rate, +static int cs4215_prepare(struct snd_dbri * dbri, unsigned int rate, snd_pcm_format_t format, unsigned int channels) { int freq_idx; @@ -1622,7 +1628,7 @@ static int cs4215_prepare(snd_dbri_t * dbri, unsigned int rate, /* * */ -static int cs4215_init(snd_dbri_t * dbri) +static int cs4215_init(struct snd_dbri * dbri) { u32 reg2 = sbus_readl(dbri->regs + REG2); dprintk(D_MM, "cs4215_init: reg2=0x%x\n", reg2); @@ -1678,8 +1684,8 @@ buffer and calls dbri_process_one_interrupt() for each interrupt word. Complicated interrupts are handled by dedicated functions (which appear first in this file). Any pending interrupts can be serviced by calling dbri_process_interrupt_buffer(), which works even if the CPU's -interrupts are disabled. This function is used by dbri_cmdsend() -to make sure we're synced up with the chip after each command sequence, +interrupts are disabled. This function is used by dbri_cmdlock() +to make sure we're synced up with the chip before each command sequence, even if we're running cli'ed. */ @@ -1691,8 +1697,8 @@ even if we're running cli'ed. */ static void xmit_descs(unsigned long data) { - snd_dbri_t *dbri = (snd_dbri_t *) data; - dbri_streaminfo_t *info; + struct snd_dbri *dbri = (struct snd_dbri *) data; + struct dbri_streaminfo *info; volatile s32 *cmd; unsigned long flags; int first_td; @@ -1758,23 +1764,25 @@ play: spin_unlock_irqrestore(&dbri->lock, flags); } -DECLARE_TASKLET(xmit_descs_task, xmit_descs, 0); +static DECLARE_TASKLET(xmit_descs_task, xmit_descs, 0); /* transmission_complete_intr() * * Called by main interrupt handler when DBRI signals transmission complete * on a pipe (interrupt triggered by the B bit in a transmit descriptor). * - * Walks through the pipe's list of transmit buffer descriptors, releasing - * each one's DMA buffer (if present), flagging the descriptor available, - * and signaling its callback routine (if present), before proceeding - * to the next one. Stops when the first descriptor is found without + * Walks through the pipe's list of transmit buffer descriptors and marks + * them as available. Stops when the first descriptor is found without * TBC (Transmit Buffer Complete) set, or we've run through them all. + * + * The DMA buffers are not released, but re-used. Since the transmit buffer + * descriptors are not clobbered, they can be re-submitted as is. This is + * done by the xmit_descs() tasklet above since that could take longer. */ -static void transmission_complete_intr(snd_dbri_t * dbri, int pipe) +static void transmission_complete_intr(struct snd_dbri * dbri, int pipe) { - dbri_streaminfo_t *info; + struct dbri_streaminfo *info; int td; int status; @@ -1822,9 +1830,9 @@ static void transmission_complete_intr(snd_dbri_t * dbri, int pipe) snd_pcm_period_elapsed(info->substream); } -static void reception_complete_intr(snd_dbri_t * dbri, int pipe) +static void reception_complete_intr(struct snd_dbri * dbri, int pipe) { - dbri_streaminfo_t *info; + struct dbri_streaminfo *info; int rd = dbri->pipes[pipe].desc; s32 status; @@ -1866,7 +1874,7 @@ static void reception_complete_intr(snd_dbri_t * dbri, int pipe) snd_pcm_period_elapsed(info->substream); } -static void dbri_process_one_interrupt(snd_dbri_t * dbri, int x) +static void dbri_process_one_interrupt(struct snd_dbri * dbri, int x) { int val = D_INTR_GETVAL(x); int channel = D_INTR_GETCHAN(x); @@ -1885,7 +1893,11 @@ static void dbri_process_one_interrupt(snd_dbri_t * dbri, int x) } if (channel == D_INTR_CMD && command == D_WAIT) { - dbri->wait_seen++; + dbri->wait_ackd = val; + if (dbri->wait_send != val) { + printk(KERN_ERR "Processing wait command %d when %d was send.\n", + val, dbri->wait_send); + } return; } @@ -1938,7 +1950,7 @@ static void dbri_process_one_interrupt(snd_dbri_t * dbri, int x) * order is important since we might recurse back into this function * and need to make sure the pointer has been advanced first. */ -static void dbri_process_interrupt_buffer(snd_dbri_t * dbri) +static void dbri_process_interrupt_buffer(struct snd_dbri * dbri) { s32 x; @@ -1957,7 +1969,7 @@ static void dbri_process_interrupt_buffer(snd_dbri_t * dbri) static irqreturn_t snd_dbri_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - snd_dbri_t *dbri = dev_id; + struct snd_dbri *dbri = dev_id; static int errcnt = 0; int x; @@ -1994,8 +2006,7 @@ static irqreturn_t snd_dbri_interrupt(int irq, void *dev_id, * The only one I've seen is MRR, which will be triggered * if you let a transmit pipe underrun, then try to CDP it. * - * If these things persist, we should probably reset - * and re-init the chip. + * If these things persist, we reset the chip. */ if ((++errcnt) % 10 == 0) { dprintk(D_INT, "Interrupt errors exceeded.\n"); @@ -2019,7 +2030,7 @@ static irqreturn_t snd_dbri_interrupt(int irq, void *dev_id, /**************************************************************************** PCM Interface ****************************************************************************/ -static snd_pcm_hardware_t snd_dbri_pcm_hw = { +static struct snd_pcm_hardware snd_dbri_pcm_hw = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | @@ -2040,11 +2051,11 @@ static snd_pcm_hardware_t snd_dbri_pcm_hw = { .periods_max = 1024, }; -static int snd_dbri_open(snd_pcm_substream_t * substream) +static int snd_dbri_open(struct snd_pcm_substream *substream) { - snd_dbri_t *dbri = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; - dbri_streaminfo_t *info = DBRI_STREAM(dbri, substream); + struct snd_dbri *dbri = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream); unsigned long flags; dprintk(D_USR, "open audio output.\n"); @@ -2063,10 +2074,10 @@ static int snd_dbri_open(snd_pcm_substream_t * substream) return 0; } -static int snd_dbri_close(snd_pcm_substream_t * substream) +static int snd_dbri_close(struct snd_pcm_substream *substream) { - snd_dbri_t *dbri = snd_pcm_substream_chip(substream); - dbri_streaminfo_t *info = DBRI_STREAM(dbri, substream); + struct snd_dbri *dbri = snd_pcm_substream_chip(substream); + struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream); dprintk(D_USR, "close audio output.\n"); info->substream = NULL; @@ -2076,12 +2087,12 @@ static int snd_dbri_close(snd_pcm_substream_t * substream) return 0; } -static int snd_dbri_hw_params(snd_pcm_substream_t * substream, - snd_pcm_hw_params_t * hw_params) +static int snd_dbri_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) { - snd_pcm_runtime_t *runtime = substream->runtime; - snd_dbri_t *dbri = snd_pcm_substream_chip(substream); - dbri_streaminfo_t *info = DBRI_STREAM(dbri, substream); + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_dbri *dbri = snd_pcm_substream_chip(substream); + struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream); int direction; int ret; @@ -2094,7 +2105,7 @@ static int snd_dbri_hw_params(snd_pcm_substream_t * substream, if ((ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) { - snd_printk(KERN_ERR "malloc_pages failed with %d\n", ret); + printk(KERN_ERR "malloc_pages failed with %d\n", ret); return ret; } @@ -2118,10 +2129,10 @@ static int snd_dbri_hw_params(snd_pcm_substream_t * substream, return 0; } -static int snd_dbri_hw_free(snd_pcm_substream_t * substream) +static int snd_dbri_hw_free(struct snd_pcm_substream *substream) { - snd_dbri_t *dbri = snd_pcm_substream_chip(substream); - dbri_streaminfo_t *info = DBRI_STREAM(dbri, substream); + struct snd_dbri *dbri = snd_pcm_substream_chip(substream); + struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream); int direction; dprintk(D_USR, "hw_free.\n"); @@ -2142,11 +2153,11 @@ static int snd_dbri_hw_free(snd_pcm_substream_t * substream) return snd_pcm_lib_free_pages(substream); } -static int snd_dbri_prepare(snd_pcm_substream_t * substream) +static int snd_dbri_prepare(struct snd_pcm_substream *substream) { - snd_dbri_t *dbri = snd_pcm_substream_chip(substream); - dbri_streaminfo_t *info = DBRI_STREAM(dbri, substream); - snd_pcm_runtime_t *runtime = substream->runtime; + struct snd_dbri *dbri = snd_pcm_substream_chip(substream); + struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream); + struct snd_pcm_runtime *runtime = substream->runtime; int ret; info->size = snd_pcm_lib_buffer_bytes(substream); @@ -2173,10 +2184,10 @@ static int snd_dbri_prepare(snd_pcm_substream_t * substream) return ret; } -static int snd_dbri_trigger(snd_pcm_substream_t * substream, int cmd) +static int snd_dbri_trigger(struct snd_pcm_substream *substream, int cmd) { - snd_dbri_t *dbri = snd_pcm_substream_chip(substream); - dbri_streaminfo_t *info = DBRI_STREAM(dbri, substream); + struct snd_dbri *dbri = snd_pcm_substream_chip(substream); + struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream); int ret = 0; switch (cmd) { @@ -2200,10 +2211,10 @@ static int snd_dbri_trigger(snd_pcm_substream_t * substream, int cmd) return ret; } -static snd_pcm_uframes_t snd_dbri_pointer(snd_pcm_substream_t * substream) +static snd_pcm_uframes_t snd_dbri_pointer(struct snd_pcm_substream *substream) { - snd_dbri_t *dbri = snd_pcm_substream_chip(substream); - dbri_streaminfo_t *info = DBRI_STREAM(dbri, substream); + struct snd_dbri *dbri = snd_pcm_substream_chip(substream); + struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream); snd_pcm_uframes_t ret; ret = bytes_to_frames(substream->runtime, info->offset) @@ -2213,7 +2224,7 @@ static snd_pcm_uframes_t snd_dbri_pointer(snd_pcm_substream_t * substream) return ret; } -static snd_pcm_ops_t snd_dbri_ops = { +static struct snd_pcm_ops snd_dbri_ops = { .open = snd_dbri_open, .close = snd_dbri_close, .ioctl = snd_pcm_lib_ioctl, @@ -2224,9 +2235,9 @@ static snd_pcm_ops_t snd_dbri_ops = { .pointer = snd_dbri_pointer, }; -static int __devinit snd_dbri_pcm(snd_dbri_t * dbri) +static int __devinit snd_dbri_pcm(struct snd_dbri * dbri) { - snd_pcm_t *pcm; + struct snd_pcm *pcm; int err; if ((err = snd_pcm_new(dbri->card, @@ -2259,8 +2270,8 @@ static int __devinit snd_dbri_pcm(snd_dbri_t * dbri) Mixer interface *****************************************************************************/ -static int snd_cs4215_info_volume(snd_kcontrol_t * kcontrol, - snd_ctl_elem_info_t * uinfo) +static int snd_cs4215_info_volume(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; @@ -2273,11 +2284,11 @@ static int snd_cs4215_info_volume(snd_kcontrol_t * kcontrol, return 0; } -static int snd_cs4215_get_volume(snd_kcontrol_t * kcontrol, - snd_ctl_elem_value_t * ucontrol) +static int snd_cs4215_get_volume(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - snd_dbri_t *dbri = snd_kcontrol_chip(kcontrol); - dbri_streaminfo_t *info; + struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol); + struct dbri_streaminfo *info; snd_assert(dbri != NULL, return -EINVAL); info = &dbri->stream_info[kcontrol->private_value]; snd_assert(info != NULL, return -EINVAL); @@ -2287,11 +2298,11 @@ static int snd_cs4215_get_volume(snd_kcontrol_t * kcontrol, return 0; } -static int snd_cs4215_put_volume(snd_kcontrol_t * kcontrol, - snd_ctl_elem_value_t * ucontrol) +static int snd_cs4215_put_volume(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - snd_dbri_t *dbri = snd_kcontrol_chip(kcontrol); - dbri_streaminfo_t *info = &dbri->stream_info[kcontrol->private_value]; + struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol); + struct dbri_streaminfo *info = &dbri->stream_info[kcontrol->private_value]; unsigned long flags; int changed = 0; @@ -2318,8 +2329,8 @@ static int snd_cs4215_put_volume(snd_kcontrol_t * kcontrol, return changed; } -static int snd_cs4215_info_single(snd_kcontrol_t * kcontrol, - snd_ctl_elem_info_t * uinfo) +static int snd_cs4215_info_single(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { int mask = (kcontrol->private_value >> 16) & 0xff; @@ -2331,10 +2342,10 @@ static int snd_cs4215_info_single(snd_kcontrol_t * kcontrol, return 0; } -static int snd_cs4215_get_single(snd_kcontrol_t * kcontrol, - snd_ctl_elem_value_t * ucontrol) +static int snd_cs4215_get_single(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - snd_dbri_t *dbri = snd_kcontrol_chip(kcontrol); + struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol); int elem = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; @@ -2356,10 +2367,10 @@ static int snd_cs4215_get_single(snd_kcontrol_t * kcontrol, return 0; } -static int snd_cs4215_put_single(snd_kcontrol_t * kcontrol, - snd_ctl_elem_value_t * ucontrol) +static int snd_cs4215_put_single(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - snd_dbri_t *dbri = snd_kcontrol_chip(kcontrol); + struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol); unsigned long flags; int elem = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; @@ -2414,7 +2425,7 @@ static int snd_cs4215_put_single(snd_kcontrol_t * kcontrol, .get = snd_cs4215_get_single, .put = snd_cs4215_put_single, \ .private_value = entry | (shift << 8) | (mask << 16) | (invert << 24) }, -static snd_kcontrol_new_t dbri_controls[] __devinitdata = { +static struct snd_kcontrol_new dbri_controls[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Playback Volume", @@ -2441,11 +2452,11 @@ static snd_kcontrol_new_t dbri_controls[] __devinitdata = { CS4215_SINGLE("Mic boost", 4, 4, 1, 1) }; -#define NUM_CS4215_CONTROLS (sizeof(dbri_controls)/sizeof(snd_kcontrol_new_t)) +#define NUM_CS4215_CONTROLS (sizeof(dbri_controls)/sizeof(struct snd_kcontrol_new)) -static int __init snd_dbri_mixer(snd_dbri_t * dbri) +static int __init snd_dbri_mixer(struct snd_dbri * dbri) { - snd_card_t *card; + struct snd_card *card; int idx, err; snd_assert(dbri != NULL && dbri->card != NULL, return -EINVAL); @@ -2455,8 +2466,7 @@ static int __init snd_dbri_mixer(snd_dbri_t * dbri) for (idx = 0; idx < NUM_CS4215_CONTROLS; idx++) { if ((err = snd_ctl_add(card, - snd_ctl_new1(&dbri_controls[idx], - dbri))) < 0) + snd_ctl_new1(&dbri_controls[idx], dbri))) < 0) return err; } @@ -2472,9 +2482,9 @@ static int __init snd_dbri_mixer(snd_dbri_t * dbri) /**************************************************************************** /proc interface ****************************************************************************/ -static void dbri_regs_read(snd_info_entry_t * entry, snd_info_buffer_t * buffer) +static void dbri_regs_read(struct snd_info_entry * entry, struct snd_info_buffer *buffer) { - snd_dbri_t *dbri = entry->private_data; + struct snd_dbri *dbri = entry->private_data; snd_iprintf(buffer, "REG0: 0x%x\n", sbus_readl(dbri->regs + REG0)); snd_iprintf(buffer, "REG2: 0x%x\n", sbus_readl(dbri->regs + REG2)); @@ -2483,15 +2493,13 @@ static void dbri_regs_read(snd_info_entry_t * entry, snd_info_buffer_t * buffer) } #ifdef DBRI_DEBUG -static void dbri_debug_read(snd_info_entry_t * entry, - snd_info_buffer_t * buffer) +static void dbri_debug_read(struct snd_info_entry * entry, + struct snd_info_buffer *buffer) { - snd_dbri_t *dbri = entry->private_data; + struct snd_dbri *dbri = entry->private_data; int pipe; snd_iprintf(buffer, "debug=%d\n", dbri_debug); - snd_iprintf(buffer, "CHI pipe in=%d, out=%d\n", - dbri->chi_in_pipe, dbri->chi_out_pipe); for (pipe = 0; pipe < 32; pipe++) { if (pipe_active(dbri, pipe)) { struct dbri_pipe *pptr = &dbri->pipes[pipe]; @@ -2506,34 +2514,20 @@ static void dbri_debug_read(snd_info_entry_t * entry, } } } - -static void dbri_debug_write(snd_info_entry_t * entry, - snd_info_buffer_t * buffer) -{ - char line[80]; - int i; - - if (snd_info_get_line(buffer, line, 80) == 0) { - sscanf(line, "%d\n", &i); - dbri_debug = i & 0x3f; - } -} #endif -void snd_dbri_proc(snd_dbri_t * dbri) +void snd_dbri_proc(struct snd_dbri * dbri) { - snd_info_entry_t *entry; - int err; + struct snd_info_entry *entry; - 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 | S_IWUSR; /* Writable for root */ - entry->c.text.write_size = 256; - entry->c.text.write = dbri_debug_write; + 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 } @@ -2542,13 +2536,13 @@ void snd_dbri_proc(snd_dbri_t * dbri) **************************** Initialization ******************************** **************************************************************************** */ -static void snd_dbri_free(snd_dbri_t * dbri); +static void snd_dbri_free(struct snd_dbri * dbri); -static int __init snd_dbri_create(snd_card_t * card, +static int __init snd_dbri_create(struct snd_card *card, struct sbus_dev *sdev, struct linux_prom_irqs *irq, int dev) { - snd_dbri_t *dbri = card->private_data; + struct snd_dbri *dbri = card->private_data; int err; spin_lock_init(&dbri->lock); @@ -2599,7 +2593,7 @@ static int __init snd_dbri_create(snd_card_t * card, return 0; } -static void snd_dbri_free(snd_dbri_t * dbri) +static void snd_dbri_free(struct snd_dbri * dbri) { dprintk(D_GEN, "snd_dbri_free\n"); dbri_reset(dbri); @@ -2617,10 +2611,10 @@ static void snd_dbri_free(snd_dbri_t * dbri) static int __init dbri_attach(int prom_node, struct sbus_dev *sdev) { - snd_dbri_t *dbri; + struct snd_dbri *dbri; struct linux_prom_irqs irq; struct resource *rp; - snd_card_t *card; + struct snd_card *card; static int dev = 0; int err; @@ -2637,46 +2631,41 @@ static int __init dbri_attach(int prom_node, struct sbus_dev *sdev) return -ENOENT; } - prom_getproperty(prom_node, "intr", (char *)&irq, sizeof(irq)); + err = prom_getproperty(prom_node, "intr", (char *)&irq, sizeof(irq)); + if (err < 0) { + printk(KERN_ERR "DBRI-%d: Firmware node lacks IRQ property.\n", dev); + return -ENODEV; + } card = snd_card_new(index[dev], id[dev], THIS_MODULE, - sizeof(snd_dbri_t)); + sizeof(struct snd_dbri)); if (card == NULL) return -ENOMEM; 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); return err; } - dbri = (snd_dbri_t *) card->private_data; - if ((err = snd_dbri_pcm(dbri)) < 0) { - snd_dbri_free(dbri); - snd_card_free(card); - return err; - } + dbri = card->private_data; + if ((err = snd_dbri_pcm(dbri)) < 0) + goto _err; - if ((err = snd_dbri_mixer(dbri)) < 0) { - snd_dbri_free(dbri); - snd_card_free(card); - return err; - } + if ((err = snd_dbri_mixer(dbri)) < 0) + goto _err; /* /proc file handling */ snd_dbri_proc(dbri); - if ((err = snd_card_register(card)) < 0) { - snd_dbri_free(dbri); - snd_card_free(card); - return 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, @@ -2684,6 +2673,11 @@ static int __init dbri_attach(int prom_node, struct sbus_dev *sdev) dev++; return 0; + + _err: + snd_dbri_free(dbri); + snd_card_free(card); + return err; } /* Probe for the dbri chip and then attach the driver. */ @@ -2712,11 +2706,11 @@ static int __init dbri_init(void) static void __exit dbri_exit(void) { - snd_dbri_t *this = dbri_list; + struct snd_dbri *this = dbri_list; while (this != NULL) { - snd_dbri_t *next = this->next; - snd_card_t *card = this->card; + struct snd_dbri *next = this->next; + struct snd_card *card = this->card; snd_dbri_free(this); snd_card_free(card);