summaryrefslogtreecommitdiffstats
path: root/sound/oss/vwsnd.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/oss/vwsnd.c
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'sound/oss/vwsnd.c')
-rw-r--r--sound/oss/vwsnd.c3486
1 files changed, 3486 insertions, 0 deletions
diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c
new file mode 100644
index 000000000000..265423054caf
--- /dev/null
+++ b/sound/oss/vwsnd.c
@@ -0,0 +1,3486 @@
+/*
+ * Sound driver for Silicon Graphics 320 and 540 Visual Workstations'
+ * onboard audio. See notes in Documentation/sound/oss/vwsnd .
+ *
+ * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#undef VWSND_DEBUG /* define for debugging */
+
+/*
+ * XXX to do -
+ *
+ * External sync.
+ * Rename swbuf, hwbuf, u&i, hwptr&swptr to something rational.
+ * Bug - if select() called before read(), pcm_setup() not called.
+ * Bug - output doesn't stop soon enough if process killed.
+ */
+
+/*
+ * Things to test -
+ *
+ * Will readv/writev work? Write a test.
+ *
+ * insmod/rmmod 100 million times.
+ *
+ * Run I/O until int ptrs wrap around (roughly 6.2 hours @ DAT
+ * rate).
+ *
+ * Concurrent threads banging on mixer simultaneously, both UP
+ * and SMP kernels. Especially, watch for thread A changing
+ * OUTSRC while thread B changes gain -- both write to the same
+ * ad1843 register.
+ *
+ * What happens if a client opens /dev/audio then forks?
+ * Do two procs have /dev/audio open? Test.
+ *
+ * Pump audio through the CD, MIC and line inputs and verify that
+ * they mix/mute into the output.
+ *
+ * Apps:
+ * amp
+ * mpg123
+ * x11amp
+ * mxv
+ * kmedia
+ * esound
+ * need more input apps
+ *
+ * Run tests while bombarding with signals. setitimer(2) will do it... */
+
+/*
+ * This driver is organized in nine sections.
+ * The nine sections are:
+ *
+ * debug stuff
+ * low level lithium access
+ * high level lithium access
+ * AD1843 access
+ * PCM I/O
+ * audio driver
+ * mixer driver
+ * probe/attach/unload
+ * initialization and loadable kernel module interface
+ *
+ * That is roughly the order of increasing abstraction, so forward
+ * dependencies are minimal.
+ */
+
+/*
+ * Locking Notes
+ *
+ * INC_USE_COUNT and DEC_USE_COUNT keep track of the number of
+ * open descriptors to this driver. They store it in vwsnd_use_count.
+ * The global device list, vwsnd_dev_list, is immutable when the IN_USE
+ * is true.
+ *
+ * devc->open_lock is a semaphore that is used to enforce the
+ * single reader/single writer rule for /dev/audio. The rule is
+ * that each device may have at most one reader and one writer.
+ * Open will block until the previous client has closed the
+ * device, unless O_NONBLOCK is specified.
+ *
+ * The semaphore devc->io_sema serializes PCM I/O syscalls. This
+ * is unnecessary in Linux 2.2, because the kernel lock
+ * serializes read, write, and ioctl globally, but it's there,
+ * ready for the brave, new post-kernel-lock world.
+ *
+ * Locking between interrupt and baselevel is handled by the
+ * "lock" spinlock in vwsnd_port (one lock each for read and
+ * write). Each half holds the lock just long enough to see what
+ * area it owns and update its pointers. See pcm_output() and
+ * pcm_input() for most of the gory stuff.
+ *
+ * devc->mix_sema serializes all mixer ioctls. This is also
+ * redundant because of the kernel lock.
+ *
+ * The lowest level lock is lith->lithium_lock. It is a
+ * spinlock which is held during the two-register tango of
+ * reading/writing an AD1843 register. See
+ * li_{read,write}_ad1843_reg().
+ */
+
+/*
+ * Sample Format Notes
+ *
+ * Lithium's DMA engine has two formats: 16-bit 2's complement
+ * and 8-bit unsigned . 16-bit transfers the data unmodified, 2
+ * bytes per sample. 8-bit unsigned transfers 1 byte per sample
+ * and XORs each byte with 0x80. Lithium can input or output
+ * either mono or stereo in either format.
+ *
+ * The AD1843 has four formats: 16-bit 2's complement, 8-bit
+ * unsigned, 8-bit mu-Law and 8-bit A-Law.
+ *
+ * This driver supports five formats: AFMT_S8, AFMT_U8,
+ * AFMT_MU_LAW, AFMT_A_LAW, and AFMT_S16_LE.
+ *
+ * For AFMT_U8 output, we keep the AD1843 in 16-bit mode, and
+ * rely on Lithium's XOR to translate between U8 and S8.
+ *
+ * For AFMT_S8, AFMT_MU_LAW and AFMT_A_LAW output, we have to XOR
+ * the 0x80 bit in software to compensate for Lithium's XOR.
+ * This happens in pcm_copy_{in,out}().
+ *
+ * Changes:
+ * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
+ * Added some __init/__exit
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <asm/semaphore.h>
+#include <asm/mach-visws/cobalt.h>
+
+#include "sound_config.h"
+
+/*****************************************************************************/
+/* debug stuff */
+
+#ifdef VWSND_DEBUG
+
+static int shut_up = 1;
+
+/*
+ * dbgassert - called when an assertion fails.
+ */
+
+static void dbgassert(const char *fcn, int line, const char *expr)
+{
+ if (in_interrupt())
+ panic("ASSERTION FAILED IN INTERRUPT, %s:%s:%d %s\n",
+ __FILE__, fcn, line, expr);
+ else {
+ int x;
+ printk(KERN_ERR "ASSERTION FAILED, %s:%s:%d %s\n",
+ __FILE__, fcn, line, expr);
+ x = * (volatile int *) 0; /* force proc to exit */
+ }
+}
+
+/*
+ * Bunch of useful debug macros:
+ *
+ * ASSERT - print unless e nonzero (panic if in interrupt)
+ * DBGDO - include arbitrary code if debugging
+ * DBGX - debug print raw (w/o function name)
+ * DBGP - debug print w/ function name
+ * DBGE - debug print function entry
+ * DBGC - debug print function call
+ * DBGR - debug print function return
+ * DBGXV - debug print raw when verbose
+ * DBGPV - debug print when verbose
+ * DBGEV - debug print function entry when verbose
+ * DBGRV - debug print function return when verbose
+ */
+
+#define ASSERT(e) ((e) ? (void) 0 : dbgassert(__FUNCTION__, __LINE__, #e))
+#define DBGDO(x) x
+#define DBGX(fmt, args...) (in_interrupt() ? 0 : printk(KERN_ERR fmt, ##args))
+#define DBGP(fmt, args...) (DBGX("%s: " fmt, __FUNCTION__ , ##args))
+#define DBGE(fmt, args...) (DBGX("%s" fmt, __FUNCTION__ , ##args))
+#define DBGC(rtn) (DBGP("calling %s\n", rtn))
+#define DBGR() (DBGP("returning\n"))
+#define DBGXV(fmt, args...) (shut_up ? 0 : DBGX(fmt, ##args))
+#define DBGPV(fmt, args...) (shut_up ? 0 : DBGP(fmt, ##args))
+#define DBGEV(fmt, args...) (shut_up ? 0 : DBGE(fmt, ##args))
+#define DBGCV(rtn) (shut_up ? 0 : DBGC(rtn))
+#define DBGRV() (shut_up ? 0 : DBGR())
+
+#else /* !VWSND_DEBUG */
+
+#define ASSERT(e) ((void) 0)
+#define DBGDO(x) /* don't */
+#define DBGX(fmt, args...) ((void) 0)
+#define DBGP(fmt, args...) ((void) 0)
+#define DBGE(fmt, args...) ((void) 0)
+#define DBGC(rtn) ((void) 0)
+#define DBGR() ((void) 0)
+#define DBGPV(fmt, args...) ((void) 0)
+#define DBGXV(fmt, args...) ((void) 0)
+#define DBGEV(fmt, args...) ((void) 0)
+#define DBGCV(rtn) ((void) 0)
+#define DBGRV() ((void) 0)
+
+#endif /* !VWSND_DEBUG */
+
+/*****************************************************************************/
+/* low level lithium access */
+
+/*
+ * We need to talk to Lithium registers on three pages. Here are
+ * the pages' offsets from the base address (0xFF001000).
+ */
+
+enum {
+ LI_PAGE0_OFFSET = 0x01000 - 0x1000, /* FF001000 */
+ LI_PAGE1_OFFSET = 0x0F000 - 0x1000, /* FF00F000 */
+ LI_PAGE2_OFFSET = 0x10000 - 0x1000, /* FF010000 */
+};
+
+/* low-level lithium data */
+
+typedef struct lithium {
+ void * page0; /* virtual addresses */
+ void * page1;
+ void * page2;
+ spinlock_t lock; /* protects codec and UST/MSC access */
+} lithium_t;
+
+/*
+ * li_create initializes the lithium_t structure and sets up vm mappings
+ * to access the registers.
+ * Returns 0 on success, -errno on failure.
+ */
+
+static int __init li_create(lithium_t *lith, unsigned long baseaddr)
+{
+ static void li_destroy(lithium_t *);
+
+ spin_lock_init(&lith->lock);
+ lith->page0 = ioremap_nocache(baseaddr + LI_PAGE0_OFFSET, PAGE_SIZE);
+ lith->page1 = ioremap_nocache(baseaddr + LI_PAGE1_OFFSET, PAGE_SIZE);
+ lith->page2 = ioremap_nocache(baseaddr + LI_PAGE2_OFFSET, PAGE_SIZE);
+ if (!lith->page0 || !lith->page1 || !lith->page2) {
+ li_destroy(lith);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/*
+ * li_destroy destroys the lithium_t structure and vm mappings.
+ */
+
+static void li_destroy(lithium_t *lith)
+{
+ if (lith->page0) {
+ iounmap(lith->page0);
+ lith->page0 = NULL;
+ }
+ if (lith->page1) {
+ iounmap(lith->page1);
+ lith->page1 = NULL;
+ }
+ if (lith->page2) {
+ iounmap(lith->page2);
+ lith->page2 = NULL;
+ }
+}
+
+/*
+ * basic register accessors - read/write long/byte
+ */
+
+static __inline__ unsigned long li_readl(lithium_t *lith, int off)
+{
+ return * (volatile unsigned long *) (lith->page0 + off);
+}
+
+static __inline__ unsigned char li_readb(lithium_t *lith, int off)
+{
+ return * (volatile unsigned char *) (lith->page0 + off);
+}
+
+static __inline__ void li_writel(lithium_t *lith, int off, unsigned long val)
+{
+ * (volatile unsigned long *) (lith->page0 + off) = val;
+}
+
+static __inline__ void li_writeb(lithium_t *lith, int off, unsigned char val)
+{
+ * (volatile unsigned char *) (lith->page0 + off) = val;
+}
+
+/*****************************************************************************/
+/* High Level Lithium Access */
+
+/*
+ * Lithium DMA Notes
+ *
+ * Lithium has two dedicated DMA channels for audio. They are known
+ * as comm1 and comm2 (communication areas 1 and 2). Comm1 is for
+ * input, and comm2 is for output. Each is controlled by three
+ * registers: BASE (base address), CFG (config) and CCTL
+ * (config/control).
+ *
+ * Each DMA channel points to a physically contiguous ring buffer in
+ * main memory of up to 8 Kbytes. (This driver always uses 8 Kb.)
+ * There are three pointers into the ring buffer: read, write, and
+ * trigger. The pointers are 8 bits each. Each pointer points to
+ * 32-byte "chunks" of data. The DMA engine moves 32 bytes at a time,
+ * so there is no finer-granularity control.
+ *
+ * In comm1, the hardware updates the write ptr, and software updates
+ * the read ptr. In comm2, it's the opposite: hardware updates the
+ * read ptr, and software updates the write ptr. I designate the
+ * hardware-updated ptr as the hwptr, and the software-updated ptr as
+ * the swptr.
+ *
+ * The trigger ptr and trigger mask are used to trigger interrupts.
+ * From the Lithium spec, section 5.6.8, revision of 12/15/1998:
+ *
+ * Trigger Mask Value
+ *
+ * A three bit wide field that represents a power of two mask
+ * that is used whenever the trigger pointer is compared to its
+ * respective read or write pointer. A value of zero here
+ * implies a mask of 0xFF and a value of seven implies a mask
+ * 0x01. This value can be used to sub-divide the ring buffer
+ * into pie sections so that interrupts monitor the progress of
+ * hardware from section to section.
+ *
+ * My interpretation of that is, whenever the hw ptr is updated, it is
+ * compared with the trigger ptr, and the result is masked by the
+ * trigger mask. (Actually, by the complement of the trigger mask.)
+ * If the result is zero, an interrupt is triggered. I.e., interrupt
+ * if ((hwptr & ~mask) == (trptr & ~mask)). The mask is formed from
+ * the trigger register value as mask = (1 << (8 - tmreg)) - 1.
+ *
+ * In yet different words, setting tmreg to 0 causes an interrupt after
+ * every 256 DMA chunks (8192 bytes) or once per traversal of the
+ * ring buffer. Setting it to 7 caues an interrupt every 2 DMA chunks
+ * (64 bytes) or 128 times per traversal of the ring buffer.
+ */
+
+/* Lithium register offsets and bit definitions */
+
+#define LI_HOST_CONTROLLER 0x000
+# define LI_HC_RESET 0x00008000
+# define LI_HC_LINK_ENABLE 0x00004000
+# define LI_HC_LINK_FAILURE 0x00000004
+# define LI_HC_LINK_CODEC 0x00000002
+# define LI_HC_LINK_READY 0x00000001
+
+#define LI_INTR_STATUS 0x010
+#define LI_INTR_MASK 0x014
+# define LI_INTR_LINK_ERR 0x00008000
+# define LI_INTR_COMM2_TRIG 0x00000008
+# define LI_INTR_COMM2_UNDERFLOW 0x00000004
+# define LI_INTR_COMM1_TRIG 0x00000002
+# define LI_INTR_COMM1_OVERFLOW 0x00000001
+
+#define LI_CODEC_COMMAND 0x018
+# define LI_CC_BUSY 0x00008000
+# define LI_CC_DIR 0x00000080
+# define LI_CC_DIR_RD LI_CC_DIR
+# define LI_CC_DIR_WR (!LI_CC_DIR)
+# define LI_CC_ADDR_MASK 0x0000007F
+
+#define LI_CODEC_DATA 0x01C
+
+#define LI_COMM1_BASE 0x100
+#define LI_COMM1_CTL 0x104
+# define LI_CCTL_RESET 0x80000000
+# define LI_CCTL_SIZE 0x70000000
+# define LI_CCTL_DMA_ENABLE 0x08000000
+# define LI_CCTL_TMASK 0x07000000 /* trigger mask */
+# define LI_CCTL_TPTR 0x00FF0000 /* trigger pointer */
+# define LI_CCTL_RPTR 0x0000FF00
+# define LI_CCTL_WPTR 0x000000FF
+#define LI_COMM1_CFG 0x108
+# define LI_CCFG_LOCK 0x00008000
+# define LI_CCFG_SLOT 0x00000070
+# define LI_CCFG_DIRECTION 0x00000008
+# define LI_CCFG_DIR_IN (!LI_CCFG_DIRECTION)
+# define LI_CCFG_DIR_OUT LI_CCFG_DIRECTION
+# define LI_CCFG_MODE 0x00000004
+# define LI_CCFG_MODE_MONO (!LI_CCFG_MODE)
+# define LI_CCFG_MODE_STEREO LI_CCFG_MODE
+# define LI_CCFG_FORMAT 0x00000003
+# define LI_CCFG_FMT_8BIT 0x00000000
+# define LI_CCFG_FMT_16BIT 0x00000001
+#define LI_COMM2_BASE 0x10C
+#define LI_COMM2_CTL 0x110
+ /* bit definitions are the same as LI_COMM1_CTL */
+#define LI_COMM2_CFG 0x114
+ /* bit definitions are the same as LI_COMM1_CFG */
+
+#define LI_UST_LOW 0x200 /* 64-bit Unadjusted System Time is */
+#define LI_UST_HIGH 0x204 /* microseconds since boot */
+
+#define LI_AUDIO1_UST 0x300 /* UST-MSC pairs */
+#define LI_AUDIO1_MSC 0x304 /* MSC (Media Stream Counter) */
+#define LI_AUDIO2_UST 0x308 /* counts samples actually */
+#define LI_AUDIO2_MSC 0x30C /* processed as of time UST */
+
+/*
+ * Lithium's DMA engine operates on chunks of 32 bytes. We call that
+ * a DMACHUNK.
+ */
+
+#define DMACHUNK_SHIFT 5
+#define DMACHUNK_SIZE (1 << DMACHUNK_SHIFT)
+#define BYTES_TO_CHUNKS(bytes) ((bytes) >> DMACHUNK_SHIFT)
+#define CHUNKS_TO_BYTES(chunks) ((chunks) << DMACHUNK_SHIFT)
+
+/*
+ * Two convenient macros to shift bitfields into/out of position.
+ *
+ * Observe that (mask & -mask) is (1 << low_set_bit_of(mask)).
+ * As long as mask is constant, we trust the compiler will change the
+ * multipy and divide into shifts.
+ */
+
+#define SHIFT_FIELD(val, mask) (((val) * ((mask) & -(mask))) & (mask))
+#define UNSHIFT_FIELD(val, mask) (((val) & (mask)) / ((mask) & -(mask)))
+
+/*
+ * dma_chan_desc is invariant information about a Lithium
+ * DMA channel. There are two instances, li_comm1 and li_comm2.
+ *
+ * Note that the CCTL register fields are write ptr and read ptr, but what
+ * we care about are which pointer is updated by software and which by
+ * hardware.
+ */
+
+typedef struct dma_chan_desc {
+ int basereg;
+ int cfgreg;
+ int ctlreg;
+ int hwptrreg;
+ int swptrreg;
+ int ustreg;
+ int mscreg;
+ unsigned long swptrmask;
+ int ad1843_slot;
+ int direction; /* LI_CCTL_DIR_IN/OUT */
+} dma_chan_desc_t;
+
+static const dma_chan_desc_t li_comm1 = {
+ LI_COMM1_BASE, /* base register offset */
+ LI_COMM1_CFG, /* config register offset */
+ LI_COMM1_CTL, /* control register offset */
+ LI_COMM1_CTL + 0, /* hw ptr reg offset (write ptr) */
+ LI_COMM1_CTL + 1, /* sw ptr reg offset (read ptr) */
+ LI_AUDIO1_UST, /* ust reg offset */
+ LI_AUDIO1_MSC, /* msc reg offset */
+ LI_CCTL_RPTR, /* sw ptr bitmask in ctlval */
+ 2, /* ad1843 serial slot */
+ LI_CCFG_DIR_IN /* direction */
+};
+
+static const dma_chan_desc_t li_comm2 = {
+ LI_COMM2_BASE, /* base register offset */
+ LI_COMM2_CFG, /* config register offset */
+ LI_COMM2_CTL, /* control register offset */
+ LI_COMM2_CTL + 1, /* hw ptr reg offset (read ptr) */
+ LI_COMM2_CTL + 0, /* sw ptr reg offset (writr ptr) */
+ LI_AUDIO2_UST, /* ust reg offset */
+ LI_AUDIO2_MSC, /* msc reg offset */
+ LI_CCTL_WPTR, /* sw ptr bitmask in ctlval */
+ 2, /* ad1843 serial slot */
+ LI_CCFG_DIR_OUT /* direction */
+};
+
+/*
+ * dma_chan is variable information about a Lithium DMA channel.
+ *
+ * The desc field points to invariant information.
+ * The lith field points to a lithium_t which is passed
+ * to li_read* and li_write* to access the registers.
+ * The *val fields shadow the lithium registers' contents.
+ */
+
+typedef struct dma_chan {
+ const dma_chan_desc_t *desc;
+ lithium_t *lith;
+ unsigned long baseval;
+ unsigned long cfgval;
+ unsigned long ctlval;
+} dma_chan_t;
+
+/*
+ * ustmsc is a UST/MSC pair (Unadjusted System Time/Media Stream Counter).
+ * UST is time in microseconds since the system booted, and MSC is a
+ * counter that increments with every audio sample.
+ */
+
+typedef struct ustmsc {
+ unsigned long long ust;
+ unsigned long msc;
+} ustmsc_t;
+
+/*
+ * li_ad1843_wait waits until lithium says the AD1843 register
+ * exchange is not busy. Returns 0 on success, -EBUSY on timeout.
+ *
+ * Locking: must be called with lithium_lock held.
+ */
+
+static int li_ad1843_wait(lithium_t *lith)
+{
+ unsigned long later = jiffies + 2;
+ while (li_readl(lith, LI_CODEC_COMMAND) & LI_CC_BUSY)
+ if (time_after_eq(jiffies, later))
+ return -EBUSY;
+ return 0;
+}
+
+/*
+ * li_read_ad1843_reg returns the current contents of a 16 bit AD1843 register.
+ *
+ * Returns unsigned register value on success, -errno on failure.
+ */
+
+static int li_read_ad1843_reg(lithium_t *lith, int reg)
+{
+ int val;
+
+ ASSERT(!in_interrupt());
+ spin_lock(&lith->lock);
+ {
+ val = li_ad1843_wait(lith);
+ if (val == 0) {
+ li_writel(lith, LI_CODEC_COMMAND, LI_CC_DIR_RD | reg);
+ val = li_ad1843_wait(lith);
+ }
+ if (val == 0)
+ val = li_readl(lith, LI_CODEC_DATA);
+ }
+ spin_unlock(&lith->lock);
+
+ DBGXV("li_read_ad1843_reg(lith=0x%p, reg=%d) returns 0x%04x\n",
+ lith, reg, val);
+
+ return val;
+}
+
+/*
+ * li_write_ad1843_reg writes the specified value to a 16 bit AD1843 register.
+ */
+
+static void li_write_ad1843_reg(lithium_t *lith, int reg, int newval)
+{
+ spin_lock(&lith->lock);
+ {
+ if (li_ad1843_wait(lith) == 0) {
+ li_writel(lith, LI_CODEC_DATA, newval);
+ li_writel(lith, LI_CODEC_COMMAND, LI_CC_DIR_WR | reg);
+ }
+ }
+ spin_unlock(&lith->lock);
+}
+
+/*
+ * li_setup_dma calculates all the register settings for DMA in a particular
+ * mode. It takes too many arguments.
+ */
+
+static void li_setup_dma(dma_chan_t *chan,
+ const dma_chan_desc_t *desc,
+ lithium_t *lith,
+ unsigned long buffer_paddr,
+ int bufshift,
+ int fragshift,
+ int channels,
+ int sampsize)
+{
+ unsigned long mode, format;
+ unsigned long size, tmask;
+
+ DBGEV("(chan=0x%p, desc=0x%p, lith=0x%p, buffer_paddr=0x%lx, "
+ "bufshift=%d, fragshift=%d, channels=%d, sampsize=%d)\n",
+ chan, desc, lith, buffer_paddr,
+ bufshift, fragshift, channels, sampsize);
+
+ /* Reset the channel first. */
+
+ li_writel(lith, desc->ctlreg, LI_CCTL_RESET);
+
+ ASSERT(channels == 1 || channels == 2);
+ if (channels == 2)
+ mode = LI_CCFG_MODE_STEREO;
+ else
+ mode = LI_CCFG_MODE_MONO;
+ ASSERT(sampsize == 1 || sampsize == 2);
+ if (sampsize == 2)
+ format = LI_CCFG_FMT_16BIT;
+ else
+ format = LI_CCFG_FMT_8BIT;
+ chan->desc = desc;
+ chan->lith = lith;
+
+ /*
+ * Lithium DMA address register takes a 40-bit physical
+ * address, right-shifted by 8 so it fits in 32 bits. Bit 37
+ * must be set -- it enables cache coherence.
+ */
+
+ ASSERT(!(buffer_paddr & 0xFF));
+ chan->baseval = (buffer_paddr >> 8) | 1 << (37 - 8);
+
+ chan->cfgval = (!LI_CCFG_LOCK |
+ SHIFT_FIELD(desc->ad1843_slot, LI_CCFG_SLOT) |
+ desc->direction |
+ mode |
+ format);
+
+ size = bufshift - 6;
+ tmask = 13 - fragshift; /* See Lithium DMA Notes above. */
+ ASSERT(size >= 2 && size <= 7);
+ ASSERT(tmask >= 1 && tmask <= 7);
+ chan->ctlval = (!LI_CCTL_RESET |
+ SHIFT_FIELD(size, LI_CCTL_SIZE) |
+ !LI_CCTL_DMA_ENABLE |
+ SHIFT_FIELD(tmask, LI_CCTL_TMASK) |
+ SHIFT_FIELD(0, LI_CCTL_TPTR));
+
+ DBGPV("basereg 0x%x = 0x%lx\n", desc->basereg, chan->baseval);
+ DBGPV("cfgreg 0x%x = 0x%lx\n", desc->cfgreg, chan->cfgval);
+ DBGPV("ctlreg 0x%x = 0x%lx\n", desc->ctlreg, chan->ctlval);
+
+ li_writel(lith, desc->basereg, chan->baseval);
+ li_writel(lith, desc->cfgreg, chan->cfgval);
+ li_writel(lith, desc->ctlreg, chan->ctlval);
+
+ DBGRV();
+}
+
+static void li_shutdown_dma(dma_chan_t *chan)
+{
+ lithium_t *lith = chan->lith;
+ void * lith1 = lith->page1;
+
+ DBGEV("(chan=0x%p)\n", chan);
+
+ chan->ctlval &= ~LI_CCTL_DMA_ENABLE;
+ DBGPV("ctlreg 0x%x = 0x%lx\n", chan->desc->ctlreg, chan->ctlval);
+ li_writel(lith, chan->desc->ctlreg, chan->ctlval);
+
+ /*
+ * Offset 0x500 on Lithium page 1 is an undocumented,
+ * unsupported register that holds the zero sample value.
+ * Lithium is supposed to output zero samples when DMA is
+ * inactive, and repeat the last sample when DMA underflows.
+ * But it has a bug, where, after underflow occurs, the zero
+ * sample is not reset.
+ *
+ * I expect this to break in a future rev of Lithium.
+ */
+
+ if (lith1 && chan->desc->direction == LI_CCFG_DIR_OUT)
+ * (volatile unsigned long *) (lith1 + 0x500) = 0;
+}
+
+/*
+ * li_activate_dma always starts dma at the beginning of the buffer.
+ *
+ * N.B., these may be called from interrupt.
+ */
+
+static __inline__ void li_activate_dma(dma_chan_t *chan)
+{
+ chan->ctlval |= LI_CCTL_DMA_ENABLE;
+ DBGPV("ctlval = 0x%lx\n", chan->ctlval);
+ li_writel(chan->lith, chan->desc->ctlreg, chan->ctlval);
+}
+
+static void li_deactivate_dma(dma_chan_t *chan)
+{
+ lithium_t *lith = chan->lith;
+ void * lith2 = lith->page2;
+
+ chan->ctlval &= ~(LI_CCTL_DMA_ENABLE | LI_CCTL_RPTR | LI_CCTL_WPTR);
+ DBGPV("ctlval = 0x%lx\n", chan->ctlval);
+ DBGPV("ctlreg 0x%x = 0x%lx\n", chan->desc->ctlreg, chan->ctlval);
+ li_writel(lith, chan->desc->ctlreg, chan->ctlval);
+
+ /*
+ * Offsets 0x98 and 0x9C on Lithium page 2 are undocumented,
+ * unsupported registers that are internal copies of the DMA
+ * read and write pointers. Because of a Lithium bug, these
+ * registers aren't zeroed correctly when DMA is shut off. So
+ * we whack them directly.
+ *
+ * I expect this to break in a future rev of Lithium.
+ */
+
+ if (lith2 && chan->desc->direction == LI_CCFG_DIR_OUT) {
+ * (volatile unsigned long *) (lith2 + 0x98) = 0;
+ * (volatile unsigned long *) (lith2 + 0x9C) = 0;
+ }
+}
+
+/*
+ * read/write the ring buffer pointers. These routines' arguments and results
+ * are byte offsets from the beginning of the ring buffer.
+ */
+
+static __inline__ int li_read_swptr(dma_chan_t *chan)
+{
+ const unsigned long mask = chan->desc->swptrmask;
+
+ return CHUNKS_TO_BYTES(UNSHIFT_FIELD(chan->ctlval, mask));
+}
+
+static __inline__ int li_read_hwptr(dma_chan_t *chan)
+{
+ return CHUNKS_TO_BYTES(li_readb(chan->lith, chan->desc->hwptrreg));
+}
+
+static __inline__ void li_write_swptr(dma_chan_t *chan, int val)
+{
+ const unsigned long mask = chan->desc->swptrmask;
+
+ ASSERT(!(val & ~CHUNKS_TO_BYTES(0xFF)));
+ val = BYTES_TO_CHUNKS(val);
+ chan->ctlval = (chan->ctlval & ~mask) | SHIFT_FIELD(val, mask);
+ li_writeb(chan->lith, chan->desc->swptrreg, val);
+}
+
+/* li_read_USTMSC() returns a UST/MSC pair for the given channel. */
+
+static void li_read_USTMSC(dma_chan_t *chan, ustmsc_t *ustmsc)
+{
+ lithium_t *lith = chan->lith;
+ const dma_chan_desc_t *desc = chan->desc;
+ unsigned long now_low, now_high0, now_high1, chan_ust;
+
+ spin_lock(&lith->lock);
+ {
+ /*
+ * retry until we do all five reads without the
+ * high word changing. (High word increments
+ * every 2^32 microseconds, i.e., not often)
+ */
+ do {
+ now_high0 = li_readl(lith, LI_UST_HIGH);
+ now_low = li_readl(lith, LI_UST_LOW);
+
+ /*
+ * Lithium guarantees these two reads will be
+ * atomic -- ust will not increment after msc
+ * is read.
+ */
+
+ ustmsc->msc = li_readl(lith, desc->mscreg);
+ chan_ust = li_readl(lith, desc->ustreg);
+
+ now_high1 = li_readl(lith, LI_UST_HIGH);
+ } while (now_high0 != now_high1);
+ }
+ spin_unlock(&lith->lock);
+ ustmsc->ust = ((unsigned long long) now_high0 << 32 | chan_ust);
+}
+
+static void li_enable_interrupts(lithium_t *lith, unsigned int mask)
+{
+ DBGEV("(lith=0x%p, mask=0x%x)\n", lith, mask);
+
+ /* clear any already-pending interrupts. */
+
+ li_writel(lith, LI_INTR_STATUS, mask);
+
+ /* enable the interrupts. */
+
+ mask |= li_readl(lith, LI_INTR_MASK);
+ li_writel(lith, LI_INTR_MASK, mask);
+}
+
+static void li_disable_interrupts(lithium_t *lith, unsigned int mask)
+{
+ unsigned int keepmask;
+
+ DBGEV("(lith=0x%p, mask=0x%x)\n", lith, mask);
+
+ /* disable the interrupts */
+
+ keepmask = li_readl(lith, LI_INTR_MASK) & ~mask;
+ li_writel(lith, LI_INTR_MASK, keepmask);
+
+ /* clear any pending interrupts. */
+
+ li_writel(lith, LI_INTR_STATUS, mask);
+}
+
+/* Get the interrupt status and clear all pending interrupts. */
+
+static unsigned int li_get_clear_intr_status(lithium_t *lith)
+{
+ unsigned int status;
+
+ status = li_readl(lith, LI_INTR_STATUS);
+ li_writel(lith, LI_INTR_STATUS, ~0);
+ return status & li_readl(lith, LI_INTR_MASK);
+}
+
+static int li_init(lithium_t *lith)
+{
+ /* 1. System power supplies stabilize. */
+
+ /* 2. Assert the ~RESET signal. */
+
+ li_writel(lith, LI_HOST_CONTROLLER, LI_HC_RESET);
+ udelay(1);
+
+ /* 3. Deassert the ~RESET signal and enter a wait period to allow
+ the AD1843 internal clocks and the external crystal oscillator
+ to stabilize. */
+
+ li_writel(lith, LI_HOST_CONTROLLER, LI_HC_LINK_ENABLE);
+ udelay(1);
+
+ return 0;
+}
+
+/*****************************************************************************/
+/* AD1843 access */
+
+/*
+ * AD1843 bitfield definitions. All are named as in the AD1843 data
+ * sheet, with ad1843_ prepended and individual bit numbers removed.
+ *
+ * E.g., bits LSS0 through LSS2 become ad1843_LSS.
+ *
+ * Only the bitfields we need are defined.
+ */
+
+typedef struct ad1843_bitfield {
+ char reg;
+ char lo_bit;
+ char nbits;
+} ad1843_bitfield_t;
+
+static const ad1843_bitfield_t
+ ad1843_PDNO = { 0, 14, 1 }, /* Converter Power-Down Flag */
+ ad1843_INIT = { 0, 15, 1 }, /* Clock Initialization Flag */
+ ad1843_RIG = { 2, 0, 4 }, /* Right ADC Input Gain */
+ ad1843_RMGE = { 2, 4, 1 }, /* Right ADC Mic Gain Enable */
+ ad1843_RSS = { 2, 5, 3 }, /* Right ADC Source Select */
+ ad1843_LIG = { 2, 8, 4 }, /* Left ADC Input Gain */
+ ad1843_LMGE = { 2, 12, 1 }, /* Left ADC Mic Gain Enable */
+ ad1843_LSS = { 2, 13, 3 }, /* Left ADC Source Select */
+ ad1843_RX1M = { 4, 0, 5 }, /* Right Aux 1 Mix Gain/Atten */
+ ad1843_RX1MM = { 4, 7, 1 }, /* Right Aux 1 Mix Mute */
+ ad1843_LX1M = { 4, 8, 5 }, /* Left Aux 1 Mix Gain/Atten */
+ ad1843_LX1MM = { 4, 15, 1 }, /* Left Aux 1 Mix Mute */
+ ad1843_RX2M = { 5, 0, 5 }, /* Right Aux 2 Mix Gain/Atten */
+ ad1843_RX2MM = { 5, 7, 1 }, /* Right Aux 2 Mix Mute */
+ ad1843_LX2M = { 5, 8, 5 }, /* Left Aux 2 Mix Gain/Atten */
+ ad1843_LX2MM = { 5, 15, 1 }, /* Left Aux 2 Mix Mute */
+ ad1843_RMCM = { 7, 0, 5 }, /* Right Mic Mix Gain/Atten */
+ ad1843_RMCMM = { 7, 7, 1 }, /* Right Mic Mix Mute */
+ ad1843_LMCM = { 7, 8, 5 }, /* Left Mic Mix Gain/Atten */
+ ad1843_LMCMM = { 7, 15, 1 }, /* Left Mic Mix Mute */
+ ad1843_HPOS = { 8, 4, 1 }, /* Headphone Output Voltage Swing */
+ ad1843_HPOM = { 8, 5, 1 }, /* Headphone Output Mute */
+ ad1843_RDA1G = { 9, 0, 6 }, /* Right DAC1 Analog/Digital Gain */
+ ad1843_RDA1GM = { 9, 7, 1 }, /* Right DAC1 Analog Mute */
+ ad1843_LDA1G = { 9, 8, 6 }, /* Left DAC1 Analog/Digital Gain */
+ ad1843_LDA1GM = { 9, 15, 1 }, /* Left DAC1 Analog Mute */
+ ad1843_RDA1AM = { 11, 7, 1 }, /* Right DAC1 Digital Mute */
+ ad1843_LDA1AM = { 11, 15, 1 }, /* Left DAC1 Digital Mute */
+ ad1843_ADLC = { 15, 0, 2 }, /* ADC Left Sample Rate Source */
+ ad1843_ADRC = { 15, 2, 2 }, /* ADC Right Sample Rate Source */
+ ad1843_DA1C = { 15, 8, 2 }, /* DAC1 Sample Rate Source */
+ ad1843_C1C = { 17, 0, 16 }, /* Clock 1 Sample Rate Select */
+ ad1843_C2C = { 20, 0, 16 }, /* Clock 1 Sample Rate Select */
+ ad1843_DAADL = { 25, 4, 2 }, /* Digital ADC Left Source Select */
+ ad1843_DAADR = { 25, 6, 2 }, /* Digital ADC Right Source Select */
+ ad1843_DRSFLT = { 25, 15, 1 }, /* Digital Reampler Filter Mode */
+ ad1843_ADLF = { 26, 0, 2 }, /* ADC Left Channel Data Format */
+ ad1843_ADRF = { 26, 2, 2 }, /* ADC Right Channel Data Format */
+ ad1843_ADTLK = { 26, 4, 1 }, /* ADC Transmit Lock Mode Select */
+ ad1843_SCF = { 26, 7, 1 }, /* SCLK Frequency Select */
+ ad1843_DA1F = { 26, 8, 2 }, /* DAC1 Data Format Select */
+ ad1843_DA1SM = { 26, 14, 1 }, /* DAC1 Stereo/Mono Mode Select */
+ ad1843_ADLEN = { 27, 0, 1 }, /* ADC Left Channel Enable */
+ ad1843_ADREN = { 27, 1, 1 }, /* ADC Right Channel Enable */
+ ad1843_AAMEN = { 27, 4, 1 }, /* Analog to Analog Mix Enable */
+ ad1843_ANAEN = { 27, 7, 1 }, /* Analog Channel Enable */
+ ad1843_DA1EN = { 27, 8, 1 }, /* DAC1 Enable */
+ ad1843_DA2EN = { 27, 9, 1 }, /* DAC2 Enable */
+ ad1843_C1EN = { 28, 11, 1 }, /* Clock Generator 1 Enable */
+ ad1843_C2EN = { 28, 12, 1 }, /* Clock Generator 2 Enable */
+ ad1843_PDNI = { 28, 15, 1 }; /* Converter Power Down */
+
+/*
+ * The various registers of the AD1843 use three different formats for
+ * specifying gain. The ad1843_gain structure parameterizes the
+ * formats.
+ */
+
+typedef struct ad1843_gain {
+
+ int negative; /* nonzero if gain is negative. */
+ const ad1843_bitfield_t *lfield;
+ const ad1843_bitfield_t *rfield;
+
+} ad1843_gain_t;
+
+static const ad1843_gain_t ad1843_gain_RECLEV
+ = { 0, &ad1843_LIG, &ad1843_RIG };
+static const ad1843_gain_t ad1843_gain_LINE
+ = { 1, &ad1843_LX1M, &ad1843_RX1M };
+static const ad1843_gain_t ad1843_gain_CD
+ = { 1, &ad1843_LX2M, &ad1843_RX2M };
+static const ad1843_gain_t ad1843_gain_MIC
+ = { 1, &ad1843_LMCM, &ad1843_RMCM };
+static const ad1843_gain_t ad1843_gain_PCM
+ = { 1, &ad1843_LDA1G, &ad1843_RDA1G };
+
+/* read the current value of an AD1843 bitfield. */
+
+static int ad1843_read_bits(lithium_t *lith, const ad1843_bitfield_t *field)
+{
+ int w = li_read_ad1843_reg(lith, field->reg);
+ int val = w >> field->lo_bit & ((1 << field->nbits) - 1);
+
+ DBGXV("ad1843_read_bits(lith=0x%p, field->{%d %d %d}) returns 0x%x\n",
+ lith, field->reg, field->lo_bit, field->nbits, val);
+
+ return val;
+}
+
+/*
+ * write a new value to an AD1843 bitfield and return the old value.
+ */
+
+static int ad1843_write_bits(lithium_t *lith,
+ const ad1843_bitfield_t *field,
+ int newval)
+{
+ int w = li_read_ad1843_reg(lith, field->reg);
+ int mask = ((1 << field->nbits) - 1) << field->lo_bit;
+ int oldval = (w & mask) >> field->lo_bit;
+ int newbits = (newval << field->lo_bit) & mask;
+ w = (w & ~mask) | newbits;
+ (void) li_write_ad1843_reg(lith, field->reg, w);
+
+ DBGXV("ad1843_write_bits(lith=0x%p, field->{%d %d %d}, val=0x%x) "
+ "returns 0x%x\n",
+ lith, field->reg, field->lo_bit, field->nbits, newval,
+ oldval);
+
+ return oldval;
+}
+
+/*
+ * ad1843_read_multi reads multiple bitfields from the same AD1843
+ * register. It uses a single read cycle to do it. (Reading the
+ * ad1843 requires 256 bit times at 12.288 MHz, or nearly 20
+ * microseconds.)
+ *
+ * Called ike this.
+ *
+ * ad1843_read_multi(lith, nfields,
+ * &ad1843_FIELD1, &val1,
+ * &ad1843_FIELD2, &val2, ...);
+ */
+
+static void ad1843_read_multi(lithium_t *lith, int argcount, ...)
+{
+ va_list ap;
+ const ad1843_bitfield_t *fp;
+ int w = 0, mask, *value, reg = -1;
+
+ va_start(ap, argcount);
+ while (--argcount >= 0) {
+ fp = va_arg(ap, const ad1843_bitfield_t *);
+ value = va_arg(ap, int *);
+ if (reg == -1) {
+ reg = fp->reg;
+ w = li_read_ad1843_reg(lith, reg);
+ }
+ ASSERT(reg == fp->reg);
+ mask = (1 << fp->nbits) - 1;
+ *value = w >> fp->lo_bit & mask;
+ }
+ va_end(ap);
+}
+
+/*
+ * ad1843_write_multi stores multiple bitfields into the same AD1843
+ * register. It uses one read and one write cycle to do it.
+ *
+ * Called like this.
+ *
+ * ad1843_write_multi(lith, nfields,
+ * &ad1843_FIELD1, val1,
+ * &ad1843_FIELF2, val2, ...);
+ */
+
+static void ad1843_write_multi(lithium_t *lith, int argcount, ...)
+{
+ va_list ap;
+ int reg;
+ const ad1843_bitfield_t *fp;
+ int value;
+ int w, m, mask, bits;
+
+ mask = 0;
+ bits = 0;
+ reg = -1;
+
+ va_start(ap, argcount);
+ while (--argcount >= 0) {
+ fp = va_arg(ap, const ad1843_bitfield_t *);
+ value = va_arg(ap, int);
+ if (reg == -1)
+ reg = fp->reg;
+ ASSERT(fp->reg == reg);
+ m = ((1 << fp->nbits) - 1) << fp->lo_bit;
+ mask |= m;
+ bits |= (value << fp->lo_bit) & m;
+ }
+ va_end(ap);
+ ASSERT(!(bits & ~mask));
+ if (~mask & 0xFFFF)
+ w = li_read_ad1843_reg(lith, reg);
+ else
+ w = 0;
+ w = (w & ~mask) | bits;
+ (void) li_write_ad1843_reg(lith, reg, w);
+}
+
+/*
+ * ad1843_get_gain reads the specified register and extracts the gain value
+ * using the supplied gain type. It returns the gain in OSS format.
+ */
+
+static int ad1843_get_gain(lithium_t *lith, const ad1843_gain_t *gp)
+{
+ int lg, rg;
+ unsigned short mask = (1 << gp->lfield->nbits) - 1;
+
+ ad1843_read_multi(lith, 2, gp->lfield, &lg, gp->rfield, &rg);
+ if (gp->negative) {</