From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Date: Mon, 26 Mar 2007 20:52:33 -0300 From: Marcelo Tosatti To: Adrian Bunk , Dan Malek Subject: Re: [RFC: 2.6 patch] powerpc: remove the unused HTDMSOUND driver Message-ID: <20070326235233.GA11472@dmt> References: <20070325145838.GM16477@stusta.de> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii In-Reply-To: <20070325145838.GM16477@stusta.de> Cc: linux-kernel@vger.kernel.org, linuxppc-dev@ozlabs.org, paulus@samba.org, linuxppc-embedded@ozlabs.org, Andrew Morton List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Dan, Shall this driver be removed? On Sun, Mar 25, 2007 at 04:58:38PM +0200, Adrian Bunk wrote: > Recently, someone fixed a syntax error in the HTDMSOUND driver > introduced 4 years ago. > > Unfortunately not by trying to compile this driver for his hardware but > by code inspection - which seems to be a strong indication that there > are no users left for this OSS sound driver. > > This patch therefore removes it. > > Signed-off-by: Adrian Bunk > > --- > > This patch was already sent on: > - 7 Mar 2007 > > arch/ppc/8xx_io/Kconfig | 4 > arch/ppc/8xx_io/Makefile | 1 > arch/ppc/8xx_io/cs4218.h | 166 - > arch/ppc/8xx_io/cs4218_tdm.c | 2833 -------------------------------- > arch/ppc/platforms/rpxclassic.h | 4 > arch/ppc/platforms/rpxhiox.h | 41 > arch/ppc/platforms/rpxlite.h | 4 > arch/ppc/syslib/m8xx_setup.c | 2 > 8 files changed, 1 insertion(+), 3054 deletions(-) > > --- linux-2.6.21-rc2-mm1/arch/ppc/8xx_io/Kconfig.old 2007-03-06 06:47:04.000000000 +0100 > +++ linux-2.6.21-rc2-mm1/arch/ppc/8xx_io/Kconfig 2007-03-06 06:47:16.000000000 +0100 > @@ -74,10 +74,6 @@ > Allocate large buffers for MPC8xx Ethernet. Increases throughput > and decreases the likelihood of dropped packets, but costs memory. > > -config HTDMSOUND > - bool "Embedded Planet HIOX Audio" > - depends on SOUND=y > - > # This doesn't really belong here, but it is convenient to ask > # 8xx specific questions. > comment "Generic MPC8xx Options" > --- linux-2.6.21-rc2-mm1/arch/ppc/8xx_io/Makefile.old 2007-03-06 06:47:23.000000000 +0100 > +++ linux-2.6.21-rc2-mm1/arch/ppc/8xx_io/Makefile 2007-03-06 06:47:30.000000000 +0100 > @@ -7,4 +7,3 @@ > obj-$(CONFIG_FEC_ENET) += fec.o > obj-$(CONFIG_SCC_ENET) += enet.o > obj-$(CONFIG_UCODE_PATCH) += micropatch.o > -obj-$(CONFIG_HTDMSOUND) += cs4218_tdm.o > --- linux-2.6.21-rc2-mm1/arch/ppc/platforms/rpxlite.h.old 2007-03-06 06:49:05.000000000 +0100 > +++ linux-2.6.21-rc2-mm1/arch/ppc/platforms/rpxlite.h 2007-03-06 06:49:41.000000000 +0100 > @@ -57,10 +57,6 @@ > #define BCSR1_PCVCTL6 ((uint)0x00020000) > #define BCSR1_PCVCTL7 ((uint)0x00010000) > > -#if defined(CONFIG_HTDMSOUND) > -#include > -#endif > - > /* define IO_BASE for pcmcia */ > #define _IO_BASE 0x80000000 > #define _IO_BASE_SIZE 0x1000 > --- linux-2.6.21-rc2-mm1/arch/ppc/platforms/rpxclassic.h.old 2007-03-06 06:49:51.000000000 +0100 > +++ linux-2.6.21-rc2-mm1/arch/ppc/platforms/rpxclassic.h 2007-03-06 06:49:56.000000000 +0100 > @@ -69,10 +69,6 @@ > #define BCSR2_QSPACESEL ((uint)0x00004000) > #define BCSR2_FETHLEDMODE ((uint)0x00000800) /* CLLF */ > > -#if defined(CONFIG_HTDMSOUND) > -#include > -#endif > - > /* define IO_BASE for pcmcia, CLLF only */ > #if !defined(CONFIG_PCI) > #define _IO_BASE 0x80000000 > --- linux-2.6.21-rc2-mm1/arch/ppc/syslib/m8xx_setup.c.old 2007-03-06 06:50:43.000000000 +0100 > +++ linux-2.6.21-rc2-mm1/arch/ppc/syslib/m8xx_setup.c 2007-03-06 06:50:59.000000000 +0100 > @@ -413,7 +413,7 @@ > io_block_mapping(_IO_BASE,_IO_BASE,_IO_BASE_SIZE, _PAGE_IO); > #endif > #endif > -#if defined(CONFIG_HTDMSOUND) || defined(CONFIG_RPXTOUCH) || defined(CONFIG_FB_RPX) > +#if defined(CONFIG_RPXTOUCH) || defined(CONFIG_FB_RPX) > io_block_mapping(HIOX_CSR_ADDR, HIOX_CSR_ADDR, HIOX_CSR_SIZE, _PAGE_IO); > #endif > #ifdef CONFIG_FADS > --- linux-2.6.21-rc2-mm1/arch/ppc/platforms/rpxhiox.h 2007-02-04 19:44:54.000000000 +0100 > +++ /dev/null 2006-09-19 00:45:31.000000000 +0200 > @@ -1,41 +0,0 @@ > -/* > - * The Embedded Planet HIOX expansion card definitions. > - * There were a few different versions of these cards, but only > - * the one that escaped real production is defined here. > - * > - * Copyright (c) 2000 Dan Malek (dmalek@jlc.net) > - */ > -#ifndef __MACH_RPX_HIOX_DEFS > -#define __MACH_RPX_HIOX_DEFS > - > -#define HIOX_CSR_ADDR ((uint)0xfac00000) > -#define HIOX_CSR_SIZE ((uint)(4 * 1024)) > -#define HIOX_CSR0_ADDR HIOX_CSR_ADDR > -#define HIOX_CSR4_ADDR ((uint)0xfac00004) > - > -#define HIOX_CSR0_DEFAULT ((uint)0x380f3c00) > -#define HIOX_CSR0_ENSCC2 ((uint)0x80000000) > -#define HIOX_CSR0_ENSMC2 ((uint)0x04000000) > -#define HIOX_CSR0_ENVDOCLK ((uint)0x02000000) > -#define HIOX_CSR0_VDORST_HL ((uint)0x01000000) > -#define HIOX_CSR0_RS232SEL ((uint)0x0000c000) > -#define HIOX_CSR0_SCC3SEL ((uint)0x0000c000) > -#define HIOX_CSR0_SMC1SEL ((uint)0x00008000) > -#define HIOX_CSR0_SCC1SEL ((uint)0x00004000) > -#define HIOX_CSR0_ENTOUCH ((uint)0x00000080) > -#define HIOX_CSR0_PDOWN100 ((uint)0x00000060) > -#define HIOX_CSR0_PDOWN10 ((uint)0x00000040) > -#define HIOX_CSR0_PDOWN1 ((uint)0x00000020) > -#define HIOX_CSR0_TSELSPI ((uint)0x00000010) > -#define HIOX_CSR0_TIRQSTAT ((uint)0x00000008) > -#define HIOX_CSR4_DEFAULT ((uint)0x00000000) > -#define HIOX_CSR4_ENTIRQ2 ((uint)0x20000000) > -#define HIOX_CSR4_ENTIRQ3 ((uint)0x10000000) > -#define HIOX_CSR4_ENAUDIO ((uint)0x00000080) > -#define HIOX_CSR4_RSTAUDIO ((uint)0x00000040) /* 0 == reset */ > -#define HIOX_CSR4_AUDCLKHI ((uint)0x00000020) > -#define HIOX_CSR4_AUDSPISEL ((uint)0x00000010) > -#define HIOX_CSR4_AUDIRQSTAT ((uint)0x00000008) > -#define HIOX_CSR4_AUDCLKSEL ((uint)0x00000007) > - > -#endif > --- linux-2.6.21-rc2-mm1/arch/ppc/8xx_io/cs4218.h 2007-02-04 19:44:54.000000000 +0100 > +++ /dev/null 2006-09-19 00:45:31.000000000 +0200 > @@ -1,166 +0,0 @@ > -#ifndef _cs4218_h_ > -/* > - * Hacked version of linux/drivers/sound/dmasound/dmasound.h > - * > - * > - * Minor numbers for the sound driver. > - * > - * Unfortunately Creative called the codec chip of SB as a DSP. For this > - * reason the /dev/dsp is reserved for digitized audio use. There is a > - * device for true DSP processors but it will be called something else. > - * In v3.0 it's /dev/sndproc but this could be a temporary solution. > - */ > -#define _cs4218_h_ > - > -#include > - > -#define SND_NDEVS 256 /* Number of supported devices */ > -#define SND_DEV_CTL 0 /* Control port /dev/mixer */ > -#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM > - synthesizer and MIDI output) */ > -#define SND_DEV_MIDIN 2 /* Raw midi access */ > -#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */ > -#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */ > -#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */ > -#define SND_DEV_STATUS 6 /* /dev/sndstat */ > -/* #7 not in use now. Was in 2.4. Free for use after v3.0. */ > -#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */ > -#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */ > -#define SND_DEV_PSS SND_DEV_SNDPROC > - > -/* switch on various prinks */ > -#define DEBUG_DMASOUND 1 > - > -#define MAX_AUDIO_DEV 5 > -#define MAX_MIXER_DEV 4 > -#define MAX_SYNTH_DEV 3 > -#define MAX_MIDI_DEV 6 > -#define MAX_TIMER_DEV 3 > - > -#define MAX_CATCH_RADIUS 10 > - > -#define le2be16(x) (((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff)) > -#define le2be16dbl(x) (((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff)) > - > -#define IOCTL_IN(arg, ret) \ > - do { int error = get_user(ret, (int *)(arg)); \ > - if (error) return error; \ > - } while (0) > -#define IOCTL_OUT(arg, ret) ioctl_return((int *)(arg), ret) > - > -static inline int ioctl_return(int *addr, int value) > -{ > - return value < 0 ? value : put_user(value, addr); > -} > - > -#define HAS_RECORD > - > - /* > - * Initialization > - */ > - > -/* description of the set-up applies to either hard or soft settings */ > - > -typedef struct { > - int format; /* AFMT_* */ > - int stereo; /* 0 = mono, 1 = stereo */ > - int size; /* 8/16 bit*/ > - int speed; /* speed */ > -} SETTINGS; > - > - /* > - * Machine definitions > - */ > - > -typedef struct { > - const char *name; > - const char *name2; > - void (*open)(void); > - void (*release)(void); > - void *(*dma_alloc)(unsigned int, gfp_t); > - void (*dma_free)(void *, unsigned int); > - int (*irqinit)(void); > -#ifdef MODULE > - void (*irqcleanup)(void); > -#endif > - void (*init)(void); > - void (*silence)(void); > - int (*setFormat)(int); > - int (*setVolume)(int); > - int (*setBass)(int); > - int (*setTreble)(int); > - int (*setGain)(int); > - void (*play)(void); > - void (*record)(void); /* optional */ > - void (*mixer_init)(void); /* optional */ > - int (*mixer_ioctl)(u_int, u_long); /* optional */ > - int (*write_sq_setup)(void); /* optional */ > - int (*read_sq_setup)(void); /* optional */ > - int (*sq_open)(mode_t); /* optional */ > - int (*state_info)(char *, size_t); /* optional */ > - void (*abort_read)(void); /* optional */ > - int min_dsp_speed; > - int max_dsp_speed; > - int version ; > - int hardware_afmts ; /* OSS says we only return h'ware info */ > - /* when queried via SNDCTL_DSP_GETFMTS */ > - int capabilities ; /* low-level reply to SNDCTL_DSP_GETCAPS */ > - SETTINGS default_hard ; /* open() or init() should set something valid */ > - SETTINGS default_soft ; /* you can make it look like old OSS, if you want to */ > -} MACHINE; > - > - /* > - * Low level stuff > - */ > - > -typedef struct { > - ssize_t (*ct_ulaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); > - ssize_t (*ct_alaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); > - ssize_t (*ct_s8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); > - ssize_t (*ct_u8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); > - ssize_t (*ct_s16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); > - ssize_t (*ct_u16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); > - ssize_t (*ct_s16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); > - ssize_t (*ct_u16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); > -} TRANS; > - > - > - /* > - * Sound queue stuff, the heart of the driver > - */ > - > -struct sound_queue { > - /* buffers allocated for this queue */ > - int numBufs; /* real limits on what the user can have */ > - int bufSize; /* in bytes */ > - char **buffers; > - > - /* current parameters */ > - int locked ; /* params cannot be modified when != 0 */ > - int user_frags ; /* user requests this many */ > - int user_frag_size ; /* of this size */ > - int max_count; /* actual # fragments <= numBufs */ > - int block_size; /* internal block size in bytes */ > - int max_active; /* in-use fragments <= max_count */ > - > - /* it shouldn't be necessary to declare any of these volatile */ > - int front, rear, count; > - int rear_size; > - /* > - * The use of the playing field depends on the hardware > - * > - * Atari, PMac: The number of frames that are loaded/playing > - * > - * Amiga: Bit 0 is set: a frame is loaded > - * Bit 1 is set: a frame is playing > - */ > - int active; > - wait_queue_head_t action_queue, open_queue, sync_queue; > - int open_mode; > - int busy, syncing, xruns, died; > -}; > - > -#define SLEEP(queue) interruptible_sleep_on_timeout(&queue, HZ) > -#define WAKE_UP(queue) (wake_up_interruptible(&queue)) > - > -#endif /* _cs4218_h_ */ > --- linux-2.6.21-rc2-mm1/arch/ppc/8xx_io/cs4218_tdm.c 2007-03-02 20:14:59.000000000 +0100 > +++ /dev/null 2006-09-19 00:45:31.000000000 +0200 > @@ -1,2833 +0,0 @@ > - > -/* This is a modified version of linux/drivers/sound/dmasound.c to > - * support the CS4218 codec on the 8xx TDM port. Thanks to everyone > - * that contributed to the dmasound software (which includes me :-). > - * > - * The CS4218 is configured in Mode 4, sub-mode 0. This provides > - * left/right data only on the TDM port, as a 32-bit word, per frame > - * pulse. The control of the CS4218 is provided by some other means, > - * like the SPI port. > - * Dan Malek (dmalek@jlc.net) > - */ > - > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > - > -#include > -#include > -#include > -#include > -#include > - > -/* Should probably do something different with this path name..... > - * Actually, I should just stop using it... > - */ > -#include "cs4218.h" > -#include > - > -#include > -#include > -#include > - > -#define DMASND_CS4218 5 > - > -#define MAX_CATCH_RADIUS 10 > -#define MIN_BUFFERS 4 > -#define MIN_BUFSIZE 4 > -#define MAX_BUFSIZE 128 > - > -#define HAS_8BIT_TABLES > - > -static int sq_unit = -1; > -static int mixer_unit = -1; > -static int state_unit = -1; > -static int irq_installed = 0; > -static char **sound_buffers = NULL; > -static char **sound_read_buffers = NULL; > - > -static DEFINE_SPINLOCK(cs4218_lock); > - > -/* Local copies of things we put in the control register. Output > - * volume, like most codecs is really attenuation. > - */ > -static int cs4218_rate_index; > - > -/* > - * Stuff for outputting a beep. The values range from -327 to +327 > - * so we can multiply by an amplitude in the range 0..100 to get a > - * signed short value to put in the output buffer. > - */ > -static short beep_wform[256] = { > - 0, 40, 79, 117, 153, 187, 218, 245, > - 269, 288, 304, 316, 323, 327, 327, 324, > - 318, 310, 299, 288, 275, 262, 249, 236, > - 224, 213, 204, 196, 190, 186, 183, 182, > - 182, 183, 186, 189, 192, 196, 200, 203, > - 206, 208, 209, 209, 209, 207, 204, 201, > - 197, 193, 188, 183, 179, 174, 170, 166, > - 163, 161, 160, 159, 159, 160, 161, 162, > - 164, 166, 168, 169, 171, 171, 171, 170, > - 169, 167, 163, 159, 155, 150, 144, 139, > - 133, 128, 122, 117, 113, 110, 107, 105, > - 103, 103, 103, 103, 104, 104, 105, 105, > - 105, 103, 101, 97, 92, 86, 78, 68, > - 58, 45, 32, 18, 3, -11, -26, -41, > - -55, -68, -79, -88, -95, -100, -102, -102, > - -99, -93, -85, -75, -62, -48, -33, -16, > - 0, 16, 33, 48, 62, 75, 85, 93, > - 99, 102, 102, 100, 95, 88, 79, 68, > - 55, 41, 26, 11, -3, -18, -32, -45, > - -58, -68, -78, -86, -92, -97, -101, -103, > - -105, -105, -105, -104, -104, -103, -103, -103, > - -103, -105, -107, -110, -113, -117, -122, -128, > - -133, -139, -144, -150, -155, -159, -163, -167, > - -169, -170, -171, -171, -171, -169, -168, -166, > - -164, -162, -161, -160, -159, -159, -160, -161, > - -163, -166, -170, -174, -179, -183, -188, -193, > - -197, -201, -204, -207, -209, -209, -209, -208, > - -206, -203, -200, -196, -192, -189, -186, -183, > - -182, -182, -183, -186, -190, -196, -204, -213, > - -224, -236, -249, -262, -275, -288, -299, -310, > - -318, -324, -327, -327, -323, -316, -304, -288, > - -269, -245, -218, -187, -153, -117, -79, -40, > -}; > - > -#define BEEP_SPEED 5 /* 22050 Hz sample rate */ > -#define BEEP_BUFLEN 512 > -#define BEEP_VOLUME 15 /* 0 - 100 */ > - > -static int beep_volume = BEEP_VOLUME; > -static int beep_playing = 0; > -static int beep_state = 0; > -static short *beep_buf; > -static void (*orig_mksound)(unsigned int, unsigned int); > - > -/* This is found someplace else......I guess in the keyboard driver > - * we don't include. > - */ > -static void (*kd_mksound)(unsigned int, unsigned int); > - > -static int catchRadius = 0; > -static int numBufs = 4, bufSize = 32; > -static int numReadBufs = 4, readbufSize = 32; > - > - > -/* TDM/Serial transmit and receive buffer descriptors. > -*/ > -static volatile cbd_t *rx_base, *rx_cur, *tx_base, *tx_cur; > - > -module_param(catchRadius, int, 0); > -module_param(numBufs, int, 0); > -module_param(bufSize, int, 0); > -module_param(numreadBufs, int, 0); > -module_param(readbufSize, int, 0); > - > -#define arraysize(x) (sizeof(x)/sizeof(*(x))) > -#define le2be16(x) (((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff)) > -#define le2be16dbl(x) (((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff)) > - > -#define IOCTL_IN(arg, ret) \ > - do { int error = get_user(ret, (int *)(arg)); \ > - if (error) return error; \ > - } while (0) > -#define IOCTL_OUT(arg, ret) ioctl_return((int *)(arg), ret) > - > -/* CS4218 serial port control in mode 4. > -*/ > -#define CS_INTMASK ((uint)0x40000000) > -#define CS_DO1 ((uint)0x20000000) > -#define CS_LATTEN ((uint)0x1f000000) > -#define CS_RATTEN ((uint)0x00f80000) > -#define CS_MUTE ((uint)0x00040000) > -#define CS_ISL ((uint)0x00020000) > -#define CS_ISR ((uint)0x00010000) > -#define CS_LGAIN ((uint)0x0000f000) > -#define CS_RGAIN ((uint)0x00000f00) > - > -#define CS_LATTEN_SET(X) (((X) & 0x1f) << 24) > -#define CS_RATTEN_SET(X) (((X) & 0x1f) << 19) > -#define CS_LGAIN_SET(X) (((X) & 0x0f) << 12) > -#define CS_RGAIN_SET(X) (((X) & 0x0f) << 8) > - > -#define CS_LATTEN_GET(X) (((X) >> 24) & 0x1f) > -#define CS_RATTEN_GET(X) (((X) >> 19) & 0x1f) > -#define CS_LGAIN_GET(X) (((X) >> 12) & 0x0f) > -#define CS_RGAIN_GET(X) (((X) >> 8) & 0x0f) > - > -/* The control register is effectively write only. We have to keep a copy > - * of what we write. > - */ > -static uint cs4218_control; > - > -/* A place to store expanding information. > -*/ > -static int expand_bal; > -static int expand_data; > - > -/* Since I can't make the microcode patch work for the SPI, I just > - * clock the bits using software. > - */ > -static void sw_spi_init(void); > -static void sw_spi_io(u_char *obuf, u_char *ibuf, uint bcnt); > -static uint cs4218_ctl_write(uint ctlreg); > - > -/*** Some low level helpers **************************************************/ > - > -/* 16 bit mu-law */ > - > -static short ulaw2dma16[] = { > - -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956, > - -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764, > - -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412, > - -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316, > - -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, > - -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, > - -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, > - -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, > - -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, > - -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, > - -876, -844, -812, -780, -748, -716, -684, -652, > - -620, -588, -556, -524, -492, -460, -428, -396, > - -372, -356, -340, -324, -308, -292, -276, -260, > - -244, -228, -212, -196, -180, -164, -148, -132, > - -120, -112, -104, -96, -88, -80, -72, -64, > - -56, -48, -40, -32, -24, -16, -8, 0, > - 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, > - 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, > - 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, > - 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, > - 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, > - 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, > - 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, > - 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, > - 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, > - 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, > - 876, 844, 812, 780, 748, 716, 684, 652, > - 620, 588, 556, 524, 492, 460, 428, 396, > - 372, 356, 340, 324, 308, 292, 276, 260, > - 244, 228, 212, 196, 180, 164, 148, 132, > - 120, 112, 104, 96, 88, 80, 72, 64, > - 56, 48, 40, 32, 24, 16, 8, 0, > -}; > - > -/* 16 bit A-law */ > - > -static short alaw2dma16[] = { > - -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, > - -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, > - -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, > - -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, > - -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944, > - -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, > - -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472, > - -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, > - -344, -328, -376, -360, -280, -264, -312, -296, > - -472, -456, -504, -488, -408, -392, -440, -424, > - -88, -72, -120, -104, -24, -8, -56, -40, > - -216, -200, -248, -232, -152, -136, -184, -168, > - -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, > - -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, > - -688, -656, -752, -720, -560, -528, -624, -592, > - -944, -912, -1008, -976, -816, -784, -880, -848, > - 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, > - 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, > - 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, > - 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, > - 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, > - 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, > - 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, > - 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, > - 344, 328, 376, 360, 280, 264, 312, 296, > - 472, 456, 504, 488, 408, 392, 440, 424, > - 88, 72, 120, 104, 24, 8, 56, 40, > - 216, 200, 248, 232, 152, 136, 184, 168, > - 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, > - 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, > - 688, 656, 752, 720, 560, 528, 624, 592, > - 944, 912, 1008, 976, 816, 784, 880, 848, > -}; > - > - > -/*** Translations ************************************************************/ > - > - > -static ssize_t cs4218_ct_law(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft); > -static ssize_t cs4218_ct_s8(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft); > -static ssize_t cs4218_ct_u8(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft); > -static ssize_t cs4218_ct_s16(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft); > -static ssize_t cs4218_ct_u16(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft); > -static ssize_t cs4218_ctx_law(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft); > -static ssize_t cs4218_ctx_s8(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft); > -static ssize_t cs4218_ctx_u8(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft); > -static ssize_t cs4218_ctx_s16(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft); > -static ssize_t cs4218_ctx_u16(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft); > -static ssize_t cs4218_ct_s16_read(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft); > -static ssize_t cs4218_ct_u16_read(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft); > - > - > -/*** Low level stuff *********************************************************/ > - > -struct cs_sound_settings { > - MACHINE mach; /* machine dependent things */ > - SETTINGS hard; /* hardware settings */ > - SETTINGS soft; /* software settings */ > - SETTINGS dsp; /* /dev/dsp default settings */ > - TRANS *trans_write; /* supported translations for playback */ > - TRANS *trans_read; /* supported translations for record */ > - int volume_left; /* volume (range is machine dependent) */ > - int volume_right; > - int bass; /* tone (range is machine dependent) */ > - int treble; > - int gain; > - int minDev; /* minor device number currently open */ > -}; > - > -static struct cs_sound_settings sound; > - > -static void *CS_Alloc(unsigned int size, gfp_t flags); > -static void CS_Free(void *ptr, unsigned int size); > -static int CS_IrqInit(void); > -#ifdef MODULE > -static void CS_IrqCleanup(void); > -#endif /* MODULE */ > -static void CS_Silence(void); > -static void CS_Init(void); > -static void CS_Play(void); > -static void CS_Record(void); > -static int CS_SetFormat(int format); > -static int CS_SetVolume(int volume); > -static void cs4218_tdm_tx_intr(void *devid); > -static void cs4218_tdm_rx_intr(void *devid); > -static void cs4218_intr(void *devid); > -static int cs_get_volume(uint reg); > -static int cs_volume_setter(int volume, int mute); > -static int cs_get_gain(uint reg); > -static int cs_set_gain(int gain); > -static void cs_mksound(unsigned int hz, unsigned int ticks); > -static void cs_nosound(unsigned long xx); > - > -/*** Mid level stuff *********************************************************/ > - > - > -static void sound_silence(void); > -static void sound_init(void); > -static int sound_set_format(int format); > -static int sound_set_speed(int speed); > -static int sound_set_stereo(int stereo); > -static int sound_set_volume(int volume); > - > -static ssize_t sound_copy_translate(const u_char *userPtr, > - size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft); > -static ssize_t sound_copy_translate_read(const u_char *userPtr, > - size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft); > - > - > -/* > - * /dev/mixer abstraction > - */ > - > -struct sound_mixer { > - int busy; > - int modify_counter; > -}; > - > -static struct sound_mixer mixer; > - > -static struct sound_queue sq; > -static struct sound_queue read_sq; > - > -#define sq_block_address(i) (sq.buffers[i]) > -#define SIGNAL_RECEIVED (signal_pending(current)) > -#define NON_BLOCKING(open_mode) (open_mode & O_NONBLOCK) > -#define ONE_SECOND HZ /* in jiffies (100ths of a second) */ > -#define NO_TIME_LIMIT 0xffffffff > - > -/* > - * /dev/sndstat > - */ > - > -struct sound_state { > - int busy; > - char buf[512]; > - int len, ptr; > -}; > - > -static struct sound_state state; > - > -/*** Common stuff ********************************************************/ > - > -static long long sound_lseek(struct file *file, long long offset, int orig); > - > -/*** Config & Setup **********************************************************/ > - > -void dmasound_setup(char *str, int *ints); > - > -/*** Translations ************************************************************/ > - > - > -/* ++TeSche: radically changed for new expanding purposes... > - * > - * These two routines now deal with copying/expanding/translating the samples > - * from user space into our buffer at the right frequency. They take care about > - * how much data there's actually to read, how much buffer space there is and > - * to convert samples into the right frequency/encoding. They will only work on > - * complete samples so it may happen they leave some bytes in the input stream > - * if the user didn't write a multiple of the current sample size. They both > - * return the number of bytes they've used from both streams so you may detect > - * such a situation. Luckily all programs should be able to cope with that. > - * > - * I think I've optimized anything as far as one can do in plain C, all > - * variables should fit in registers and the loops are really short. There's > - * one loop for every possible situation. Writing a more generalized and thus > - * parameterized loop would only produce slower code. Feel free to optimize > - * this in assembler if you like. :) > - * > - * I think these routines belong here because they're not yet really hardware > - * independent, especially the fact that the Falcon can play 16bit samples > - * only in stereo is hardcoded in both of them! > - * > - * ++geert: split in even more functions (one per format) > - */ > - > -static ssize_t cs4218_ct_law(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft) > -{ > - short *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16; > - ssize_t count, used; > - short *p = (short *) &frame[*frameUsed]; > - int val, stereo = sound.soft.stereo; > - > - frameLeft >>= 2; > - if (stereo) > - userCount >>= 1; > - used = count = min(userCount, frameLeft); > - while (count > 0) { > - u_char data; > - if (get_user(data, userPtr++)) > - return -EFAULT; > - val = table[data]; > - *p++ = val; > - if (stereo) { > - if (get_user(data, userPtr++)) > - return -EFAULT; > - val = table[data]; > - } > - *p++ = val; > - count--; > - } > - *frameUsed += used * 4; > - return stereo? used * 2: used; > -} > - > - > -static ssize_t cs4218_ct_s8(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft) > -{ > - ssize_t count, used; > - short *p = (short *) &frame[*frameUsed]; > - int val, stereo = sound.soft.stereo; > - > - frameLeft >>= 2; > - if (stereo) > - userCount >>= 1; > - used = count = min(userCount, frameLeft); > - while (count > 0) { > - u_char data; > - if (get_user(data, userPtr++)) > - return -EFAULT; > - val = data << 8; > - *p++ = val; > - if (stereo) { > - if (get_user(data, userPtr++)) > - return -EFAULT; > - val = data << 8; > - } > - *p++ = val; > - count--; > - } > - *frameUsed += used * 4; > - return stereo? used * 2: used; > -} > - > - > -static ssize_t cs4218_ct_u8(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft) > -{ > - ssize_t count, used; > - short *p = (short *) &frame[*frameUsed]; > - int val, stereo = sound.soft.stereo; > - > - frameLeft >>= 2; > - if (stereo) > - userCount >>= 1; > - used = count = min(userCount, frameLeft); > - while (count > 0) { > - u_char data; > - if (get_user(data, userPtr++)) > - return -EFAULT; > - val = (data ^ 0x80) << 8; > - *p++ = val; > - if (stereo) { > - if (get_user(data, userPtr++)) > - return -EFAULT; > - val = (data ^ 0x80) << 8; > - } > - *p++ = val; > - count--; > - } > - *frameUsed += used * 4; > - return stereo? used * 2: used; > -} > - > - > -/* This is the default format of the codec. Signed, 16-bit stereo > - * generated by an application shouldn't have to be copied at all. > - * We should just get the phsical address of the buffers and update > - * the TDM BDs directly. > - */ > -static ssize_t cs4218_ct_s16(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft) > -{ > - ssize_t count, used; > - int stereo = sound.soft.stereo; > - short *fp = (short *) &frame[*frameUsed]; > - > - frameLeft >>= 2; > - userCount >>= (stereo? 2: 1); > - used = count = min(userCount, frameLeft); > - if (!stereo) { > - short *up = (short *) userPtr; > - while (count > 0) { > - short data; > - if (get_user(data, up++)) > - return -EFAULT; > - *fp++ = data; > - *fp++ = data; > - count--; > - } > - } else { > - if (copy_from_user(fp, userPtr, count * 4)) > - return -EFAULT; > - } > - *frameUsed += used * 4; > - return stereo? used * 4: used * 2; > -} > - > -static ssize_t cs4218_ct_u16(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft) > -{ > - ssize_t count, used; > - int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); > - int stereo = sound.soft.stereo; > - short *fp = (short *) &frame[*frameUsed]; > - short *up = (short *) userPtr; > - > - frameLeft >>= 2; > - userCount >>= (stereo? 2: 1); > - used = count = min(userCount, frameLeft); > - while (count > 0) { > - int data; > - if (get_user(data, up++)) > - return -EFAULT; > - data ^= mask; > - *fp++ = data; > - if (stereo) { > - if (get_user(data, up++)) > - return -EFAULT; > - data ^= mask; > - } > - *fp++ = data; > - count--; > - } > - *frameUsed += used * 4; > - return stereo? used * 4: used * 2; > -} > - > - > -static ssize_t cs4218_ctx_law(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft) > -{ > - unsigned short *table = (unsigned short *) > - (sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16); > - unsigned int data = expand_data; > - unsigned int *p = (unsigned int *) &frame[*frameUsed]; > - int bal = expand_bal; > - int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; > - int utotal, ftotal; > - int stereo = sound.soft.stereo; > - > - frameLeft >>= 2; > - if (stereo) > - userCount >>= 1; > - ftotal = frameLeft; > - utotal = userCount; > - while (frameLeft) { > - u_char c; > - if (bal < 0) { > - if (userCount == 0) > - break; > - if (get_user(c, userPtr++)) > - return -EFAULT; > - data = table[c]; > - if (stereo) { > - if (get_user(c, userPtr++)) > - return -EFAULT; > - data = (data << 16) + table[c]; > - } else > - data = (data << 16) + data; > - userCount--; > - bal += hSpeed; > - } > - *p++ = data; > - frameLeft--; > - bal -= sSpeed; > - } > - expand_bal = bal; > - expand_data = data; > - *frameUsed += (ftotal - frameLeft) * 4; > - utotal -= userCount; > - return stereo? utotal * 2: utotal; > -} > - > - > -static ssize_t cs4218_ctx_s8(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft) > -{ > - unsigned int *p = (unsigned int *) &frame[*frameUsed]; > - unsigned int data = expand_data; > - int bal = expand_bal; > - int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; > - int stereo = sound.soft.stereo; > - int utotal, ftotal; > - > - frameLeft >>= 2; > - if (stereo) > - userCount >>= 1; > - ftotal = frameLeft; > - utotal = userCount; > - while (frameLeft) { > - u_char c; > - if (bal < 0) { > - if (userCount == 0) > - break; > - if (get_user(c, userPtr++)) > - return -EFAULT; > - data = c << 8; > - if (stereo) { > - if (get_user(c, userPtr++)) > - return -EFAULT; > - data = (data << 16) + (c << 8); > - } else > - data = (data << 16) + data; > - userCount--; > - bal += hSpeed; > - } > - *p++ = data; > - frameLeft--; > - bal -= sSpeed; > - } > - expand_bal = bal; > - expand_data = data; > - *frameUsed += (ftotal - frameLeft) * 4; > - utotal -= userCount; > - return stereo? utotal * 2: utotal; > -} > - > - > -static ssize_t cs4218_ctx_u8(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft) > -{ > - unsigned int *p = (unsigned int *) &frame[*frameUsed]; > - unsigned int data = expand_data; > - int bal = expand_bal; > - int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; > - int stereo = sound.soft.stereo; > - int utotal, ftotal; > - > - frameLeft >>= 2; > - if (stereo) > - userCount >>= 1; > - ftotal = frameLeft; > - utotal = userCount; > - while (frameLeft) { > - u_char c; > - if (bal < 0) { > - if (userCount == 0) > - break; > - if (get_user(c, userPtr++)) > - return -EFAULT; > - data = (c ^ 0x80) << 8; > - if (stereo) { > - if (get_user(c, userPtr++)) > - return -EFAULT; > - data = (data << 16) + ((c ^ 0x80) << 8); > - } else > - data = (data << 16) + data; > - userCount--; > - bal += hSpeed; > - } > - *p++ = data; > - frameLeft--; > - bal -= sSpeed; > - } > - expand_bal = bal; > - expand_data = data; > - *frameUsed += (ftotal - frameLeft) * 4; > - utotal -= userCount; > - return stereo? utotal * 2: utotal; > -} > - > - > -static ssize_t cs4218_ctx_s16(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft) > -{ > - unsigned int *p = (unsigned int *) &frame[*frameUsed]; > - unsigned int data = expand_data; > - unsigned short *up = (unsigned short *) userPtr; > - int bal = expand_bal; > - int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; > - int stereo = sound.soft.stereo; > - int utotal, ftotal; > - > - frameLeft >>= 2; > - userCount >>= (stereo? 2: 1); > - ftotal = frameLeft; > - utotal = userCount; > - while (frameLeft) { > - unsigned short c; > - if (bal < 0) { > - if (userCount == 0) > - break; > - if (get_user(data, up++)) > - return -EFAULT; > - if (stereo) { > - if (get_user(c, up++)) > - return -EFAULT; > - data = (data << 16) + c; > - } else > - data = (data << 16) + data; > - userCount--; > - bal += hSpeed; > - } > - *p++ = data; > - frameLeft--; > - bal -= sSpeed; > - } > - expand_bal = bal; > - expand_data = data; > - *frameUsed += (ftotal - frameLeft) * 4; > - utotal -= userCount; > - return stereo? utotal * 4: utotal * 2; > -} > - > - > -static ssize_t cs4218_ctx_u16(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft) > -{ > - int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); > - unsigned int *p = (unsigned int *) &frame[*frameUsed]; > - unsigned int data = expand_data; > - unsigned short *up = (unsigned short *) userPtr; > - int bal = expand_bal; > - int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; > - int stereo = sound.soft.stereo; > - int utotal, ftotal; > - > - frameLeft >>= 2; > - userCount >>= (stereo? 2: 1); > - ftotal = frameLeft; > - utotal = userCount; > - while (frameLeft) { > - unsigned short c; > - if (bal < 0) { > - if (userCount == 0) > - break; > - if (get_user(data, up++)) > - return -EFAULT; > - data ^= mask; > - if (stereo) { > - if (get_user(c, up++)) > - return -EFAULT; > - data = (data << 16) + (c ^ mask); > - } else > - data = (data << 16) + data; > - userCount--; > - bal += hSpeed; > - } > - *p++ = data; > - frameLeft--; > - bal -= sSpeed; > - } > - expand_bal = bal; > - expand_data = data; > - *frameUsed += (ftotal - frameLeft) * 4; > - utotal -= userCount; > - return stereo? utotal * 4: utotal * 2; > -} > - > -static ssize_t cs4218_ct_s8_read(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft) > -{ > - ssize_t count, used; > - short *p = (short *) &frame[*frameUsed]; > - int val, stereo = sound.soft.stereo; > - > - frameLeft >>= 2; > - if (stereo) > - userCount >>= 1; > - used = count = min(userCount, frameLeft); > - while (count > 0) { > - u_char data; > - > - val = *p++; > - data = val >> 8; > - if (put_user(data, (u_char *)userPtr++)) > - return -EFAULT; > - if (stereo) { > - val = *p; > - data = val >> 8; > - if (put_user(data, (u_char *)userPtr++)) > - return -EFAULT; > - } > - p++; > - count--; > - } > - *frameUsed += used * 4; > - return stereo? used * 2: used; > -} > - > - > -static ssize_t cs4218_ct_u8_read(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft) > -{ > - ssize_t count, used; > - short *p = (short *) &frame[*frameUsed]; > - int val, stereo = sound.soft.stereo; > - > - frameLeft >>= 2; > - if (stereo) > - userCount >>= 1; > - used = count = min(userCount, frameLeft); > - while (count > 0) { > - u_char data; > - > - val = *p++; > - data = (val >> 8) ^ 0x80; > - if (put_user(data, (u_char *)userPtr++)) > - return -EFAULT; > - if (stereo) { > - val = *p; > - data = (val >> 8) ^ 0x80; > - if (put_user(data, (u_char *)userPtr++)) > - return -EFAULT; > - } > - p++; > - count--; > - } > - *frameUsed += used * 4; > - return stereo? used * 2: used; > -} > - > - > -static ssize_t cs4218_ct_s16_read(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft) > -{ > - ssize_t count, used; > - int stereo = sound.soft.stereo; > - short *fp = (short *) &frame[*frameUsed]; > - > - frameLeft >>= 2; > - userCount >>= (stereo? 2: 1); > - used = count = min(userCount, frameLeft); > - if (!stereo) { > - short *up = (short *) userPtr; > - while (count > 0) { > - short data; > - data = *fp; > - if (put_user(data, up++)) > - return -EFAULT; > - fp+=2; > - count--; > - } > - } else { > - if (copy_to_user((u_char *)userPtr, fp, count * 4)) > - return -EFAULT; > - } > - *frameUsed += used * 4; > - return stereo? used * 4: used * 2; > -} > - > -static ssize_t cs4218_ct_u16_read(const u_char *userPtr, size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft) > -{ > - ssize_t count, used; > - int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); > - int stereo = sound.soft.stereo; > - short *fp = (short *) &frame[*frameUsed]; > - short *up = (short *) userPtr; > - > - frameLeft >>= 2; > - userCount >>= (stereo? 2: 1); > - used = count = min(userCount, frameLeft); > - while (count > 0) { > - int data; > - > - data = *fp++; > - data ^= mask; > - if (put_user(data, up++)) > - return -EFAULT; > - if (stereo) { > - data = *fp; > - data ^= mask; > - if (put_user(data, up++)) > - return -EFAULT; > - } > - fp++; > - count--; > - } > - *frameUsed += used * 4; > - return stereo? used * 4: used * 2; > -} > - > -static TRANS transCSNormal = { > - cs4218_ct_law, cs4218_ct_law, cs4218_ct_s8, cs4218_ct_u8, > - cs4218_ct_s16, cs4218_ct_u16, cs4218_ct_s16, cs4218_ct_u16 > -}; > - > -static TRANS transCSExpand = { > - cs4218_ctx_law, cs4218_ctx_law, cs4218_ctx_s8, cs4218_ctx_u8, > - cs4218_ctx_s16, cs4218_ctx_u16, cs4218_ctx_s16, cs4218_ctx_u16 > -}; > - > -static TRANS transCSNormalRead = { > - NULL, NULL, cs4218_ct_s8_read, cs4218_ct_u8_read, > - cs4218_ct_s16_read, cs4218_ct_u16_read, > - cs4218_ct_s16_read, cs4218_ct_u16_read > -}; > - > -/*** Low level stuff *********************************************************/ > - > -static void *CS_Alloc(unsigned int size, gfp_t flags) > -{ > - int order; > - > - size >>= 13; > - for (order=0; order < 5; order++) { > - if (size == 0) > - break; > - size >>= 1; > - } > - return (void *)__get_free_pages(flags, order); > -} > - > -static void CS_Free(void *ptr, unsigned int size) > -{ > - int order; > - > - size >>= 13; > - for (order=0; order < 5; order++) { > - if (size == 0) > - break; > - size >>= 1; > - } > - free_pages((ulong)ptr, order); > -} > - > -static int __init CS_IrqInit(void) > -{ > - cpm_install_handler(CPMVEC_SMC2, cs4218_intr, NULL); > - return 1; > -} > - > -#ifdef MODULE > -static void CS_IrqCleanup(void) > -{ > - volatile smc_t *sp; > - volatile cpm8xx_t *cp; > - > - /* First disable transmitter and receiver. > - */ > - sp = &cpmp->cp_smc[1]; > - sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); > - > - /* And now shut down the SMC. > - */ > - cp = cpmp; /* Get pointer to Communication Processor */ > - cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2, > - CPM_CR_STOP_TX) | CPM_CR_FLG; > - while (cp->cp_cpcr & CPM_CR_FLG); > - > - /* Release the interrupt handler. > - */ > - cpm_free_handler(CPMVEC_SMC2); > - > - kfree(beep_buf); > - kd_mksound = orig_mksound; > -} > -#endif /* MODULE */ > - > -static void CS_Silence(void) > -{ > - volatile smc_t *sp; > - > - /* Disable transmitter. > - */ > - sp = &cpmp->cp_smc[1]; > - sp->smc_smcmr &= ~SMCMR_TEN; > -} > - > -/* Frequencies depend upon external oscillator. There are two > - * choices, 12.288 and 11.2896 MHz. The RPCG audio supports both through > - * and external control register selection bit. > - */ > -static int cs4218_freqs[] = { > - /* 12.288 11.2896 */ > - 48000, 44100, > - 32000, 29400, > - 24000, 22050, > - 19200, 17640, > - 16000, 14700, > - 12000, 11025, > - 9600, 8820, > - 8000, 7350 > -}; > - > -static void CS_Init(void) > -{ > - int i, tolerance; > - > - switch (sound.soft.format) { > - case AFMT_S16_LE: > - case AFMT_U16_LE: > - sound.hard.format = AFMT_S16_LE; > - break; > - default: > - sound.hard.format = AFMT_S16_BE; > - break; > - } > - sound.hard.stereo = 1; > - sound.hard.size = 16; > - > - /* > - * If we have a sample rate which is within catchRadius percent > - * of the requested value, we don't have to expand the samples. > - * Otherwise choose the next higher rate. > - */ > - i = (sizeof(cs4218_freqs) / sizeof(int)); > - do { > - tolerance = catchRadius * cs4218_freqs[--i] / 100; > - } while (sound.soft.speed > cs4218_freqs[i] + tolerance && i > 0); > - if (sound.soft.speed >= cs4218_freqs[i] - tolerance) > - sound.trans_write = &transCSNormal; > - else > - sound.trans_write = &transCSExpand; > - sound.trans_read = &transCSNormalRead; > - sound.hard.speed = cs4218_freqs[i]; > - cs4218_rate_index = i; > - > - /* The CS4218 has seven selectable clock dividers for the sample > - * clock. The HIOX then provides one of two external rates. > - * An even numbered frequency table index uses the high external > - * clock rate. > - */ > - *(uint *)HIOX_CSR4_ADDR &= ~(HIOX_CSR4_AUDCLKHI | HIOX_CSR4_AUDCLKSEL); > - if ((i & 1) == 0) > - *(uint *)HIOX_CSR4_ADDR |= HIOX_CSR4_AUDCLKHI; > - i >>= 1; > - *(uint *)HIOX_CSR4_ADDR |= (i & HIOX_CSR4_AUDCLKSEL); > - > - expand_bal = -sound.soft.speed; > -} > - > -static int CS_SetFormat(int format) > -{ > - int size; > - > - switch (format) { > - case AFMT_QUERY: > - return sound.soft.format; > - case AFMT_MU_LAW: > - case AFMT_A_LAW: > - case AFMT_U8: > - case AFMT_S8: > - size = 8; > - break; > - case AFMT_S16_BE: > - case AFMT_U16_BE: > - case AFMT_S16_LE: > - case AFMT_U16_LE: > - size = 16; > - break; > - default: /* :-) */ > - printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n", > - format); > - size = 8; > - format = AFMT_U8; > - } > - > - sound.soft.format = format; > - sound.soft.size = size; > - if (sound.minDev == SND_DEV_DSP) { > - sound.dsp.format = format; > - sound.dsp.size = size; > - } > - > - CS_Init(); > - > - return format; > -} > - > -/* Volume is the amount of attenuation we tell the codec to impose > - * on the outputs. There are 32 levels, with 0 the "loudest". > - */ > -#define CS_VOLUME_TO_MASK(x) (31 - ((((x) - 1) * 31) / 99)) > -#define CS_MASK_TO_VOLUME(y) (100 - ((y) * 99 / 31)) > - > -static int cs_get_volume(uint reg) > -{ > - int volume; > - > - volume = CS_MASK_TO_VOLUME(CS_LATTEN_GET(reg)); > - volume |= CS_MASK_TO_VOLUME(CS_RATTEN_GET(reg)) << 8; > - return volume; > -} > - > -static int cs_volume_setter(int volume, int mute) > -{ > - uint tempctl; > - > - if (mute && volume == 0) { > - tempctl = cs4218_control | CS_MUTE; > - } else { > - tempctl = cs4218_control & ~CS_MUTE; > - tempctl = tempctl & ~(CS_LATTEN | CS_RATTEN); > - tempctl |= CS_LATTEN_SET(CS_VOLUME_TO_MASK(volume & 0xff)); > - tempctl |= CS_RATTEN_SET(CS_VOLUME_TO_MASK((volume >> 8) & 0xff)); > - volume = cs_get_volume(tempctl); > - } > - if (tempctl != cs4218_control) { > - cs4218_ctl_write(tempctl); > - } > - return volume; > -} > - > - > -/* Gain has 16 steps from 0 to 15. These are in 1.5dB increments from > - * 0 (no gain) to 22.5 dB. > - */ > -#define CS_RECLEVEL_TO_GAIN(v) \ > - ((v) < 0 ? 0 : (v) > 100 ? 15 : (v) * 3 / 20) > -#define CS_GAIN_TO_RECLEVEL(v) (((v) * 20 + 2) / 3) > - > -static int cs_get_gain(uint reg) > -{ > - int gain; > - > - gain = CS_GAIN_TO_RECLEVEL(CS_LGAIN_GET(reg)); > - gain |= CS_GAIN_TO_RECLEVEL(CS_RGAIN_GET(reg)) << 8; > - return gain; > -} > - > -static int cs_set_gain(int gain) > -{ > - uint tempctl; > - > - tempctl = cs4218_control & ~(CS_LGAIN | CS_RGAIN); > - tempctl |= CS_LGAIN_SET(CS_RECLEVEL_TO_GAIN(gain & 0xff)); > - tempctl |= CS_RGAIN_SET(CS_RECLEVEL_TO_GAIN((gain >> 8) & 0xff)); > - gain = cs_get_gain(tempctl); > - > - if (tempctl != cs4218_control) { > - cs4218_ctl_write(tempctl); > - } > - return gain; > -} > - > -static int CS_SetVolume(int volume) > -{ > - return cs_volume_setter(volume, CS_MUTE); > -} > - > -static void CS_Play(void) > -{ > - int i, count; > - unsigned long flags; > - volatile cbd_t *bdp; > - volatile cpm8xx_t *cp; > - > - /* Protect buffer */ > - spin_lock_irqsave(&cs4218_lock, flags); > -#if 0 > - if (awacs_beep_state) { > - /* sound takes precedence over beeps */ > - out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); > - out_le32(&awacs->control, > - (in_le32(&awacs->control) & ~0x1f00) > - | (awacs_rate_index << 8)); > - out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE); > - out_le32(&awacs_txdma->cmdptr, virt_to_bus(&(awacs_tx_cmds[(sq.front+sq.active) % sq.max_count]))); > - > - beep_playing = 0; > - awacs_beep_state = 0; > - } > -#endif > - i = sq.front + sq.active; > - if (i >= sq.max_count) > - i -= sq.max_count; > - while (sq.active < 2 && sq.active < sq.count) { > - count = (sq.count == sq.active + 1)?sq.rear_size:sq.block_size; > - if (count < sq.block_size && !sq.syncing) > - /* last block not yet filled, and we're not syncing. */ > - break; > - > - bdp = &tx_base[i]; > - bdp->cbd_datlen = count; > - > - flush_dcache_range((ulong)sound_buffers[i], > - (ulong)(sound_buffers[i] + count)); > - > - if (++i >= sq.max_count) > - i = 0; > - > - if (sq.active == 0) { > - /* The SMC does not load its fifo until the first > - * TDM frame pulse, so the transmit data gets shifted > - * by one word. To compensate for this, we incorrectly > - * transmit the first buffer and shorten it by one > - * word. Subsequent buffers are then aligned properly. > - */ > - bdp->cbd_datlen -= 2; > - > - /* Start up the SMC Transmitter. > - */ > - cp = cpmp; > - cp->cp_smc[1].smc_smcmr |= SMCMR_TEN; > - cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2, > - CPM_CR_RESTART_TX) | CPM_CR_FLG; > - while (cp->cp_cpcr & CPM_CR_FLG); > - } > - > - /* Buffer is ready now. > - */ > - bdp->cbd_sc |= BD_SC_READY; > - > - ++sq.active; > - } > - spin_unlock_irqrestore(&cs4218_lock, flags); > -} > - > - > -static void CS_Record(void) > -{ > - unsigned long flags; > - volatile smc_t *sp; > - > - if (read_sq.active) > - return; > - > - /* Protect buffer */ > - spin_lock_irqsave(&cs4218_lock, flags); > - > - /* This is all we have to do......Just start it up. > - */ > - sp = &cpmp->cp_smc[1]; > - sp->smc_smcmr |= SMCMR_REN; > - > - read_sq.active = 1; > - > - spin_unlock_irqrestore(&cs4218_lock, flags); > -} > - > - > -static void > -cs4218_tdm_tx_intr(void *devid) > -{ > - int i = sq.front; > - volatile cbd_t *bdp; > - > - while (sq.active > 0) { > - bdp = &tx_base[i]; > - if (bdp->cbd_sc & BD_SC_READY) > - break; /* this frame is still going */ > - --sq.count; > - --sq.active; > - if (++i >= sq.max_count) > - i = 0; > - } > - if (i != sq.front) > - WAKE_UP(sq.action_queue); > - sq.front = i; > - > - CS_Play(); > - > - if (!sq.active) > - WAKE_UP(sq.sync_queue); > -} > - > - > -static void > -cs4218_tdm_rx_intr(void *devid) > -{ > - > - /* We want to blow 'em off when shutting down. > - */ > - if (read_sq.active == 0) > - return; > - > - /* Check multiple buffers in case we were held off from > - * interrupt processing for a long time. Geeze, I really hope > - * this doesn't happen. > - */ > - while ((rx_base[read_sq.rear].cbd_sc & BD_SC_EMPTY) == 0) { > - > - /* Invalidate the data cache range for this buffer. > - */ > - invalidate_dcache_range( > - (uint)(sound_read_buffers[read_sq.rear]), > - (uint)(sound_read_buffers[read_sq.rear] + read_sq.block_size)); > - > - /* Make buffer available again and move on. > - */ > - rx_base[read_sq.rear].cbd_sc |= BD_SC_EMPTY; > - read_sq.rear++; > - > - /* Wrap the buffer ring. > - */ > - if (read_sq.rear >= read_sq.max_active) > - read_sq.rear = 0; > - > - /* If we have caught up to the front buffer, bump it. > - * This will cause weird (but not fatal) results if the > - * read loop is currently using this buffer. The user is > - * behind in this case anyway, so weird things are going > - * to happen. > - */ > - if (read_sq.rear == read_sq.front) { > - read_sq.front++; > - if (read_sq.front >= read_sq.max_active) > - read_sq.front = 0; > - } > - } > - > - WAKE_UP(read_sq.action_queue); > -} > - > -static void cs_nosound(unsigned long xx) > -{ > - unsigned long flags; > - > - /* not sure if this is needed, since hardware command is #if 0'd */ > - spin_lock_irqsave(&cs4218_lock, flags); > - if (beep_playing) { > -#if 0 > - st_le16(&beep_dbdma_cmd->command, DBDMA_STOP); > -#endif > - beep_playing = 0; > - } > - spin_unlock_irqrestore(&cs4218_lock, flags); > -} > - > -static DEFINE_TIMER(beep_timer, cs_nosound, 0, 0); > - > -static void cs_mksound(unsigned int hz, unsigned int ticks) > -{ > - unsigned long flags; > - int beep_speed = BEEP_SPEED; > - int srate = cs4218_freqs[beep_speed]; > - int period, ncycles, nsamples; > - int i, j, f; > - short *p; > - static int beep_hz_cache; > - static int beep_nsamples_cache; > - static int beep_volume_cache; > - > - if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) { > -#if 1 > - /* this is a hack for broken X server code */ > - hz = 750; > - ticks = 12; > -#else > - /* cancel beep currently playing */ > - awacs_nosound(0); > - return; > -#endif > - } > - /* lock while modifying beep_timer */ > - spin_lock_irqsave(&cs4218_lock, flags); > - del_timer(&beep_timer); > - if (ticks) { > - beep_timer.expires = jiffies + ticks; > - add_timer(&beep_timer); > - } > - if (beep_playing || sq.active || beep_buf == NULL) { > - spin_unlock_irqrestore(&cs4218_lock, flags); > - return; /* too hard, sorry :-( */ > - } > - beep_playing = 1; > -#if 0 > - st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS); > -#endif > - spin_unlock_irqrestore(&cs4218_lock, flags); > - > - if (hz == beep_hz_cache && beep_volume == beep_volume_cache) { > - nsamples = beep_nsamples_cache; > - } else { > - period = srate * 256 / hz; /* fixed point */ > - ncycles = BEEP_BUFLEN * 256 / period; > - nsamples = (period * ncycles) >> 8; > - f = ncycles * 65536 / nsamples; > - j = 0; > - p = beep_buf; > - for (i = 0; i < nsamples; ++i, p += 2) { > - p[0] = p[1] = beep_wform[j >> 8] * beep_volume; > - j = (j + f) & 0xffff; > - } > - beep_hz_cache = hz; > - beep_volume_cache = beep_volume; > - beep_nsamples_cache = nsamples; > - } > - > -#if 0 > - st_le16(&beep_dbdma_cmd->req_count, nsamples*4); > - st_le16(&beep_dbdma_cmd->xfer_status, 0); > - st_le32(&beep_dbdma_cmd->cmd_dep, virt_to_bus(beep_dbdma_cmd)); > - st_le32(&beep_dbdma_cmd->phy_addr, virt_to_bus(beep_buf)); > - awacs_beep_state = 1; > - > - spin_lock_irqsave(&cs4218_lock, flags); > - if (beep_playing) { /* i.e. haven't been terminated already */ > - out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16); > - out_le32(&awacs->control, > - (in_le32(&awacs->control) & ~0x1f00) > - | (beep_speed << 8)); > - out_le32(&awacs->byteswap, 0); > - out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); > - out_le32(&awacs_txdma->control, RUN | (RUN << 16)); > - } > - spin_unlock_irqrestore(&cs4218_lock, flags); > -#endif > -} > - > -static MACHINE mach_cs4218 = { > - .owner = THIS_MODULE, > - .name = "HIOX CS4218", > - .name2 = "Built-in Sound", > - .dma_alloc = CS_Alloc, > - .dma_free = CS_Free, > - .irqinit = CS_IrqInit, > -#ifdef MODULE > - .irqcleanup = CS_IrqCleanup, > -#endif /* MODULE */ > - .init = CS_Init, > - .silence = CS_Silence, > - .setFormat = CS_SetFormat, > - .setVolume = CS_SetVolume, > - .play = CS_Play > -}; > - > - > -/*** Mid level stuff *********************************************************/ > - > - > -static void sound_silence(void) > -{ > - /* update hardware settings one more */ > - (*sound.mach.init)(); > - > - (*sound.mach.silence)(); > -} > - > - > -static void sound_init(void) > -{ > - (*sound.mach.init)(); > -} > - > - > -static int sound_set_format(int format) > -{ > - return(*sound.mach.setFormat)(format); > -} > - > - > -static int sound_set_speed(int speed) > -{ > - if (speed < 0) > - return(sound.soft.speed); > - > - sound.soft.speed = speed; > - (*sound.mach.init)(); > - if (sound.minDev == SND_DEV_DSP) > - sound.dsp.speed = sound.soft.speed; > - > - return(sound.soft.speed); > -} > - > - > -static int sound_set_stereo(int stereo) > -{ > - if (stereo < 0) > - return(sound.soft.stereo); > - > - stereo = !!stereo; /* should be 0 or 1 now */ > - > - sound.soft.stereo = stereo; > - if (sound.minDev == SND_DEV_DSP) > - sound.dsp.stereo = stereo; > - (*sound.mach.init)(); > - > - return(stereo); > -} > - > - > -static int sound_set_volume(int volume) > -{ > - return(*sound.mach.setVolume)(volume); > -} > - > -static ssize_t sound_copy_translate(const u_char *userPtr, > - size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft) > -{ > - ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL; > - > - switch (sound.soft.format) { > - case AFMT_MU_LAW: > - ct_func = sound.trans_write->ct_ulaw; > - break; > - case AFMT_A_LAW: > - ct_func = sound.trans_write->ct_alaw; > - break; > - case AFMT_S8: > - ct_func = sound.trans_write->ct_s8; > - break; > - case AFMT_U8: > - ct_func = sound.trans_write->ct_u8; > - break; > - case AFMT_S16_BE: > - ct_func = sound.trans_write->ct_s16be; > - break; > - case AFMT_U16_BE: > - ct_func = sound.trans_write->ct_u16be; > - break; > - case AFMT_S16_LE: > - ct_func = sound.trans_write->ct_s16le; > - break; > - case AFMT_U16_LE: > - ct_func = sound.trans_write->ct_u16le; > - break; > - } > - if (ct_func) > - return ct_func(userPtr, userCount, frame, frameUsed, frameLeft); > - else > - return 0; > -} > - > -static ssize_t sound_copy_translate_read(const u_char *userPtr, > - size_t userCount, > - u_char frame[], ssize_t *frameUsed, > - ssize_t frameLeft) > -{ > - ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL; > - > - switch (sound.soft.format) { > - case AFMT_MU_LAW: > - ct_func = sound.trans_read->ct_ulaw; > - break; > - case AFMT_A_LAW: > - ct_func = sound.trans_read->ct_alaw; > - break; > - case AFMT_S8: > - ct_func = sound.trans_read->ct_s8; > - break; > - case AFMT_U8: > - ct_func = sound.trans_read->ct_u8; > - break; > - case AFMT_S16_BE: > - ct_func = sound.trans_read->ct_s16be; > - break; > - case AFMT_U16_BE: > - ct_func = sound.trans_read->ct_u16be; > - break; > - case AFMT_S16_LE: > - ct_func = sound.trans_read->ct_s16le; > - break; > - case AFMT_U16_LE: > - ct_func = sound.trans_read->ct_u16le; > - break; > - } > - if (ct_func) > - return ct_func(userPtr, userCount, frame, frameUsed, frameLeft); > - else > - return 0; > -} > - > - > -/* > - * /dev/mixer abstraction > - */ > - > -static int mixer_open(struct inode *inode, struct file *file) > -{ > - mixer.busy = 1; > - return nonseekable_open(inode, file); > -} > - > - > -static int mixer_release(struct inode *inode, struct file *file) > -{ > - mixer.busy = 0; > - return 0; > -} > - > - > -static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, > - u_long arg) > -{ > - int data; > - uint tmpcs; > - > - if (_SIOC_DIR(cmd) & _SIOC_WRITE) > - mixer.modify_counter++; > - if (cmd == OSS_GETVERSION) > - return IOCTL_OUT(arg, SOUND_VERSION); > - switch (cmd) { > - case SOUND_MIXER_INFO: { > - mixer_info info; > - strlcpy(info.id, "CS4218_TDM", sizeof(info.id)); > - strlcpy(info.name, "CS4218_TDM", sizeof(info.name)); > - info.name[sizeof(info.name)-1] = 0; > - info.modify_counter = mixer.modify_counter; > - if (copy_to_user((int *)arg, &info, sizeof(info))) > - return -EFAULT; > - return 0; > - } > - case SOUND_MIXER_READ_DEVMASK: > - data = SOUND_MASK_VOLUME | SOUND_MASK_LINE > - | SOUND_MASK_MIC | SOUND_MASK_RECLEV > - | SOUND_MASK_ALTPCM; > - return IOCTL_OUT(arg, data); > - case SOUND_MIXER_READ_RECMASK: > - data = SOUND_MASK_LINE | SOUND_MASK_MIC; > - return IOCTL_OUT(arg, data); > - case SOUND_MIXER_READ_RECSRC: > - if (cs4218_control & CS_DO1) > - data = SOUND_MASK_LINE; > - else > - data = SOUND_MASK_MIC; > - return IOCTL_OUT(arg, data); > - case SOUND_MIXER_WRITE_RECSRC: > - IOCTL_IN(arg, data); > - data &= (SOUND_MASK_LINE | SOUND_MASK_MIC); > - if (data & SOUND_MASK_LINE) > - tmpcs = cs4218_control | > - (CS_ISL | CS_ISR | CS_DO1); > - if (data & SOUND_MASK_MIC) > - tmpcs = cs4218_control & > - ~(CS_ISL | CS_ISR | CS_DO1); > - if (tmpcs != cs4218_control) > - cs4218_ctl_write(tmpcs); > - return IOCTL_OUT(arg, data); > - case SOUND_MIXER_READ_STEREODEVS: > - data = SOUND_MASK_VOLUME | SOUND_MASK_RECLEV; > - return IOCTL_OUT(arg, data); > - case SOUND_MIXER_READ_CAPS: > - return IOCTL_OUT(arg, 0); > - case SOUND_MIXER_READ_VOLUME: > - data = (cs4218_control & CS_MUTE)? 0: > - cs_get_volume(cs4218_control); > - return IOCTL_OUT(arg, data); > - case SOUND_MIXER_WRITE_VOLUME: > - IOCTL_IN(arg, data); > - return IOCTL_OUT(arg, sound_set_volume(data)); > - case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ > - IOCTL_IN(arg, data); > - beep_volume = data & 0xff; > - /* fall through */ > - case SOUND_MIXER_READ_ALTPCM: > - return IOCTL_OUT(arg, beep_volume); > - case SOUND_MIXER_WRITE_RECLEV: > - IOCTL_IN(arg, data); > - data = cs_set_gain(data); > - return IOCTL_OUT(arg, data); > - case SOUND_MIXER_READ_RECLEV: > - data = cs_get_gain(cs4218_control); > - return IOCTL_OUT(arg, data); > - } > - > - return -EINVAL; > -} > - > - > -static const struct file_operations mixer_fops = > -{ > - .owner = THIS_MODULE, > - .llseek = sound_lseek, > - .ioctl = mixer_ioctl, > - .open = mixer_open, > - .release = mixer_release, > -}; > - > - > -static void __init mixer_init(void) > -{ > - mixer_unit = register_sound_mixer(&mixer_fops, -1); > - if (mixer_unit < 0) > - return; > - > - mixer.busy = 0; > - sound.treble = 0; > - sound.bass = 0; > - > - /* Set Line input, no gain, no attenuation. > - */ > - cs4218_control = CS_ISL | CS_ISR | CS_DO1; > - cs4218_control |= CS_LGAIN_SET(0) | CS_RGAIN_SET(0); > - cs4218_control |= CS_LATTEN_SET(0) | CS_RATTEN_SET(0); > - cs4218_ctl_write(cs4218_control); > -} > - > - > -/* > - * Sound queue stuff, the heart of the driver > - */ > - > - > -static int sq_allocate_buffers(void) > -{ > - int i; > - > - if (sound_buffers) > - return 0; > - sound_buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL); > - if (!sound_buffers) > - return -ENOMEM; > - for (i = 0; i < numBufs; i++) { > - sound_buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL); > - if (!sound_buffers[i]) { > - while (i--) > - sound.mach.dma_free (sound_buffers[i], bufSize << 10); > - kfree (sound_buffers); > - sound_buffers = 0; > - return -ENOMEM; > - } > - } > - return 0; > -} > - > - > -static void sq_release_buffers(void) > -{ > - int i; > - > - if (sound_buffers) { > - for (i = 0; i < numBufs; i++) > - sound.mach.dma_free (sound_buffers[i], bufSize << 10); > - kfree (sound_buffers); > - sound_buffers = 0; > - } > -} > - > - > -static int sq_allocate_read_buffers(void) > -{ > - int i; > - > - if (sound_read_buffers) > - return 0; > - sound_read_buffers = kmalloc(numReadBufs * sizeof(char *), GFP_KERNEL); > - if (!sound_read_buffers) > - return -ENOMEM; > - for (i = 0; i < numBufs; i++) { > - sound_read_buffers[i] = sound.mach.dma_alloc (readbufSize<<10, > - GFP_KERNEL); > - if (!sound_read_buffers[i]) { > - while (i--) > - sound.mach.dma_free (sound_read_buffers[i], > - readbufSize << 10); > - kfree (sound_read_buffers); > - sound_read_buffers = 0; > - return -ENOMEM; > - } > - } > - return 0; > -} > - > -static void sq_release_read_buffers(void) > -{ > - int i; > - > - if (sound_read_buffers) { > - cpmp->cp_smc[1].smc_smcmr &= ~SMCMR_REN; > - for (i = 0; i < numReadBufs; i++) > - sound.mach.dma_free (sound_read_buffers[i], > - bufSize << 10); > - kfree (sound_read_buffers); > - sound_read_buffers = 0; > - } > -} > - > - > -static void sq_setup(int numBufs, int bufSize, char **write_buffers) > -{ > - int i; > - volatile cbd_t *bdp; > - volatile cpm8xx_t *cp; > - volatile smc_t *sp; > - > - /* Make sure the SMC transmit is shut down. > - */ > - cp = cpmp; > - sp = &cpmp->cp_smc[1]; > - sp->smc_smcmr &= ~SMCMR_TEN; > - > - sq.max_count = numBufs; > - sq.max_active = numBufs; > - sq.block_size = bufSize; > - sq.buffers = write_buffers; > - > - sq.front = sq.count = 0; > - sq.rear = -1; > - sq.syncing = 0; > - sq.active = 0; > - > - bdp = tx_base; > - for (i=0; i - bdp->cbd_bufaddr = virt_to_bus(write_buffers[i]); > - bdp++; > - } > - > - /* This causes the SMC to sync up with the first buffer again. > - */ > - cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2, CPM_CR_INIT_TX) | CPM_CR_FLG; > - while (cp->cp_cpcr & CPM_CR_FLG); > -} > - > -static void read_sq_setup(int numBufs, int bufSize, char **read_buffers) > -{ > - int i; > - volatile cbd_t *bdp; > - volatile cpm8xx_t *cp; > - volatile smc_t *sp; > - > - /* Make sure the SMC receive is shut down. > - */ > - cp = cpmp; > - sp = &cpmp->cp_smc[1]; > - sp->smc_smcmr &= ~SMCMR_REN; > - > - read_sq.max_count = numBufs; > - read_sq.max_active = numBufs; > - read_sq.block_size = bufSize; > - read_sq.buffers = read_buffers; > - > - read_sq.front = read_sq.count = 0; > - read_sq.rear = 0; > - read_sq.rear_size = 0; > - read_sq.syncing = 0; > - read_sq.active = 0; > - > - bdp = rx_base; > - for (i=0; i - bdp->cbd_bufaddr = virt_to_bus(read_buffers[i]); > - bdp->cbd_datlen = read_sq.block_size; > - bdp++; > - } > - > - /* This causes the SMC to sync up with the first buffer again. > - */ > - cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2, CPM_CR_INIT_RX) | CPM_CR_FLG; > - while (cp->cp_cpcr & CPM_CR_FLG); > -} > - > - > -static void sq_play(void) > -{ > - (*sound.mach.play)(); > -} > - > - > -/* ++TeSche: radically changed this one too */ > - > -static ssize_t sq_write(struct file *file, const char *src, size_t uLeft, > - loff_t *ppos) > -{ > - ssize_t uWritten = 0; > - u_char *dest; > - ssize_t uUsed, bUsed, bLeft; > - > - /* ++TeSche: Is something like this necessary? > - * Hey, that's an honest question! Or does any other part of the > - * filesystem already checks this situation? I really don't know. > - */ > - if (uLeft == 0) > - return 0; > - > - /* The interrupt doesn't start to play the last, incomplete frame. > - * Thus we can append to it without disabling the interrupts! (Note > - * also that sq.rear isn't affected by the interrupt.) > - */ > - > - if (sq.count > 0 && (bLeft = sq.block_size-sq.rear_size) > 0) { > - dest = sq_block_address(sq.rear); > - bUsed = sq.rear_size; > - uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft); > - if (uUsed <= 0) > - return uUsed; > - src += uUsed; > - uWritten += uUsed; > - uLeft -= uUsed; > - sq.rear_size = bUsed; > - } > - > - do { > - while (sq.count == sq.max_active) { > - sq_play(); > - if (NON_BLOCKING(sq.open_mode)) > - return uWritten > 0 ? uWritten : -EAGAIN; > - SLEEP(sq.action_queue); > - if (SIGNAL_RECEIVED) > - return uWritten > 0 ? uWritten : -EINTR; > - } > - > - /* Here, we can avoid disabling the interrupt by first > - * copying and translating the data, and then updating > - * the sq variables. Until this is done, the interrupt > - * won't see the new frame and we can work on it > - * undisturbed. > - */ > - > - dest = sq_block_address((sq.rear+1) % sq.max_count); > - bUsed = 0; > - bLeft = sq.block_size; > - uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft); > - if (uUsed <= 0) > - break; > - src += uUsed; > - uWritten += uUsed; > - uLeft -= uUsed; > - if (bUsed) { > - sq.rear = (sq.rear+1) % sq.max_count; > - sq.rear_size = bUsed; > - sq.count++; > - } > - } while (bUsed); /* uUsed may have been 0 */ > - > - sq_play(); > - > - return uUsed < 0? uUsed: uWritten; > -} > - > - > -/***********/ > - > -/* Here is how the values are used for reading. > - * The value 'active' simply indicates the DMA is running. This is > - * done so the driver semantics are DMA starts when the first read is > - * posted. The value 'front' indicates the buffer we should next > - * send to the user. The value 'rear' indicates the buffer the DMA is > - * currently filling. When 'front' == 'rear' the buffer "ring" is > - * empty (we always have an empty available). The 'rear_size' is used > - * to track partial offsets into the current buffer. Right now, I just keep > - * The DMA running. If the reader can't keep up, the interrupt tosses > - * the oldest buffer. We could also shut down the DMA in this case. > - */ > -static ssize_t sq_read(struct file *file, char *dst, size_t uLeft, > - loff_t *ppos) > -{ > - > - ssize_t uRead, bLeft, bUsed, uUsed; > - > - if (uLeft == 0) > - return 0; > - > - if (!read_sq.active) > - CS_Record(); /* Kick off the record process. */ > - > - uRead = 0; > - > - /* Move what the user requests, depending upon other options. > - */ > - while (uLeft > 0) { > - > - /* When front == rear, the DMA is not done yet. > - */ > - while (read_sq.front == read_sq.rear) { > - if (NON_BLOCKING(read_sq.open_mode)) { > - return uRead > 0 ? uRead : -EAGAIN; > - } > - SLEEP(read_sq.action_queue); > - if (SIGNAL_RECEIVED) > - return uRead > 0 ? uRead : -EINTR; > - } > - > - /* The amount we move is either what is left in the > - * current buffer or what the user wants. > - */ > - bLeft = read_sq.block_size - read_sq.rear_size; > - bUsed = read_sq.rear_size; > - uUsed = sound_copy_translate_read(dst, uLeft, > - read_sq.buffers[read_sq.front], &bUsed, bLeft); > - if (uUsed <= 0) > - return uUsed; > - dst += uUsed; > - uRead += uUsed; > - uLeft -= uUsed; > - read_sq.rear_size += bUsed; > - if (read_sq.rear_size >= read_sq.block_size) { > - read_sq.rear_size = 0; > - read_sq.front++; > - if (read_sq.front >= read_sq.max_active) > - read_sq.front = 0; > - } > - } > - return uRead; > -} > - > -static int sq_open(struct inode *inode, struct file *file) > -{ > - int rc = 0; > - > - if (file->f_mode & FMODE_WRITE) { > - if (sq.busy) { > - rc = -EBUSY; > - if (NON_BLOCKING(file->f_flags)) > - goto err_out; > - rc = -EINTR; > - while (sq.busy) { > - SLEEP(sq.open_queue); > - if (SIGNAL_RECEIVED) > - goto err_out; > - } > - } > - sq.busy = 1; /* Let's play spot-the-race-condition */ > - > - if (sq_allocate_buffers()) goto err_out_nobusy; > - > - sq_setup(numBufs, bufSize<<10,sound_buffers); > - sq.open_mode = file->f_mode; > - } > - > - > - if (file->f_mode & FMODE_READ) { > - if (read_sq.busy) { > - rc = -EBUSY; > - if (NON_BLOCKING(file->f_flags)) > - goto err_out; > - rc = -EINTR; > - while (read_sq.busy) { > - SLEEP(read_sq.open_queue); > - if (SIGNAL_RECEIVED) > - goto err_out; > - } > - rc = 0; > - } > - read_sq.busy = 1; > - if (sq_allocate_read_buffers()) goto err_out_nobusy; > - > - read_sq_setup(numReadBufs,readbufSize<<10, sound_read_buffers); > - read_sq.open_mode = file->f_mode; > - } > - > - /* Start up the 4218 by: > - * Reset. > - * Enable, unreset. > - */ > - *((volatile uint *)HIOX_CSR4_ADDR) &= ~HIOX_CSR4_RSTAUDIO; > - eieio(); > - *((volatile uint *)HIOX_CSR4_ADDR) |= HIOX_CSR4_ENAUDIO; > - mdelay(50); > - *((volatile uint *)HIOX_CSR4_ADDR) |= HIOX_CSR4_RSTAUDIO; > - > - /* We need to send the current control word in case someone > - * opened /dev/mixer and changed things while we were shut > - * down. Chances are good the initialization that follows > - * would have done this, but it is still possible it wouldn't. > - */ > - cs4218_ctl_write(cs4218_control); > - > - sound.minDev = iminor(inode) & 0x0f; > - sound.soft = sound.dsp; > - sound.hard = sound.dsp; > - sound_init(); > - if ((iminor(inode) & 0x0f) == SND_DEV_AUDIO) { > - sound_set_speed(8000); > - sound_set_stereo(0); > - sound_set_format(AFMT_MU_LAW); > - } > - > - return nonseekable_open(inode, file); > - > -err_out_nobusy: > - if (file->f_mode & FMODE_WRITE) { > - sq.busy = 0; > - WAKE_UP(sq.open_queue); > - } > - if (file->f_mode & FMODE_READ) { > - read_sq.busy = 0; > - WAKE_UP(read_sq.open_queue); > - } > -err_out: > - return rc; > -} > - > - > -static void sq_reset(void) > -{ > - sound_silence(); > - sq.active = 0; > - sq.count = 0; > - sq.front = (sq.rear+1) % sq.max_count; > -#if 0 > - init_tdm_buffers(); > -#endif > -} > - > - > -static int sq_fsync(struct file *filp, struct dentry *dentry) > -{ > - int rc = 0; > - > - sq.syncing = 1; > - sq_play(); /* there may be an incomplete frame waiting */ > - > - while (sq.active) { > - SLEEP(sq.sync_queue); > - if (SIGNAL_RECEIVED) { > - /* While waiting for audio output to drain, an > - * interrupt occurred. Stop audio output immediately > - * and clear the queue. */ > - sq_reset(); > - rc = -EINTR; > - break; > - } > - } > - > - sq.syncing = 0; > - return rc; > -} > - > -static int sq_release(struct inode *inode, struct file *file) > -{ > - int rc = 0; > - > - if (sq.busy) > - rc = sq_fsync(file, file->f_path.dentry); > - sound.soft = sound.dsp; > - sound.hard = sound.dsp; > - sound_silence(); > - > - sq_release_read_buffers(); > - sq_release_buffers(); > - > - if (file->f_mode & FMODE_READ) { > - read_sq.busy = 0; > - WAKE_UP(read_sq.open_queue); > - } > - > - if (file->f_mode & FMODE_WRITE) { > - sq.busy = 0; > - WAKE_UP(sq.open_queue); > - } > - > - /* Shut down the SMC. > - */ > - cpmp->cp_smc[1].smc_smcmr &= ~(SMCMR_TEN | SMCMR_REN); > - > - /* Shut down the codec. > - */ > - *((volatile uint *)HIOX_CSR4_ADDR) |= HIOX_CSR4_RSTAUDIO; > - eieio(); > - *((volatile uint *)HIOX_CSR4_ADDR) &= ~HIOX_CSR4_ENAUDIO; > - > - /* Wake up a process waiting for the queue being released. > - * Note: There may be several processes waiting for a call > - * to open() returning. */ > - > - return rc; > -} > - > - > -static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd, > - u_long arg) > -{ > - u_long fmt; > - int data; > -#if 0 > - int size, nbufs; > -#else > - int size; > -#endif > - > - switch (cmd) { > - case SNDCTL_DSP_RESET: > - sq_reset(); > - return 0; > - case SNDCTL_DSP_POST: > - case SNDCTL_DSP_SYNC: > - return sq_fsync(file, file->f_path.dentry); > - > - /* ++TeSche: before changing any of these it's > - * probably wise to wait until sound playing has > - * settled down. */ > - case SNDCTL_DSP_SPEED: > - sq_fsync(file, file->f_path.dentry); > - IOCTL_IN(arg, data); > - return IOCTL_OUT(arg, sound_set_speed(data)); > - case SNDCTL_DSP_STEREO: > - sq_fsync(file, file->f_path.dentry); > - IOCTL_IN(arg, data); > - return IOCTL_OUT(arg, sound_set_stereo(data)); > - case SOUND_PCM_WRITE_CHANNELS: > - sq_fsync(file, file->f_path.dentry); > - IOCTL_IN(arg, data); > - return IOCTL_OUT(arg, sound_set_stereo(data-1)+1); > - case SNDCTL_DSP_SETFMT: > - sq_fsync(file, file->f_path.dentry); > - IOCTL_IN(arg, data); > - return IOCTL_OUT(arg, sound_set_format(data)); > - case SNDCTL_DSP_GETFMTS: > - fmt = 0; > - if (sound.trans_write) { > - if (sound.trans_write->ct_ulaw) > - fmt |= AFMT_MU_LAW; > - if (sound.trans_write->ct_alaw) > - fmt |= AFMT_A_LAW; > - if (sound.trans_write->ct_s8) > - fmt |= AFMT_S8; > - if (sound.trans_write->ct_u8) > - fmt |= AFMT_U8; > - if (sound.trans_write->ct_s16be) > - fmt |= AFMT_S16_BE; > - if (sound.trans_write->ct_u16be) > - fmt |= AFMT_U16_BE; > - if (sound.trans_write->ct_s16le) > - fmt |= AFMT_S16_LE; > - if (sound.trans_write->ct_u16le) > - fmt |= AFMT_U16_LE; > - } > - return IOCTL_OUT(arg, fmt); > - case SNDCTL_DSP_GETBLKSIZE: > - size = sq.block_size > - * sound.soft.size * (sound.soft.stereo + 1) > - / (sound.hard.size * (sound.hard.stereo + 1)); > - return IOCTL_OUT(arg, size); > - case SNDCTL_DSP_SUBDIVIDE: > - break; > -#if 0 /* Sorry can't do this at the moment. The CPM allocated buffers > - * long ago that can't be changed. > - */ > - case SNDCTL_DSP_SETFRAGMENT: > - if (sq.count || sq.active || sq.syncing) > - return -EINVAL; > - IOCTL_IN(arg, size); > - nbufs = size >> 16; > - if (nbufs < 2 || nbufs > numBufs) > - nbufs = numBufs; > - size &= 0xffff; > - if (size >= 8 && size <= 30) { > - size = 1 << size; > - size *= sound.hard.size * (sound.hard.stereo + 1); > - size /= sound.soft.size * (sound.soft.stereo + 1); > - if (size > (bufSize << 10)) > - size = bufSize << 10; > - } else > - size = bufSize << 10; > - sq_setup(numBufs, size, sound_buffers); > - sq.max_active = nbufs; > - return 0; > -#endif > - > - default: > - return mixer_ioctl(inode, file, cmd, arg); > - } > - return -EINVAL; > -} > - > - > - > -static const struct file_operations sq_fops = > -{ > - .owner = THIS_MODULE, > - .llseek = sound_lseek, > - .read = sq_read, /* sq_read */ > - .write = sq_write, > - .ioctl = sq_ioctl, > - .open = sq_open, > - .release = sq_release, > -}; > - > - > -static void __init sq_init(void) > -{ > - sq_unit = register_sound_dsp(&sq_fops, -1); > - if (sq_unit < 0) > - return; > - > - init_waitqueue_head(&sq.action_queue); > - init_waitqueue_head(&sq.open_queue); > - init_waitqueue_head(&sq.sync_queue); > - init_waitqueue_head(&read_sq.action_queue); > - init_waitqueue_head(&read_sq.open_queue); > - init_waitqueue_head(&read_sq.sync_queue); > - > - sq.busy = 0; > - read_sq.busy = 0; > - > - /* whatever you like as startup mode for /dev/dsp, > - * (/dev/audio hasn't got a startup mode). note that > - * once changed a new open() will *not* restore these! > - */ > - sound.dsp.format = AFMT_S16_BE; > - sound.dsp.stereo = 1; > - sound.dsp.size = 16; > - > - /* set minimum rate possible without expanding */ > - sound.dsp.speed = 8000; > - > - /* before the first open to /dev/dsp this wouldn't be set */ > - sound.soft = sound.dsp; > - sound.hard = sound.dsp; > - > - sound_silence(); > -} > - > -/* > - * /dev/sndstat > - */ > - > - > -/* state.buf should not overflow! */ > - > -static int state_open(struct inode *inode, struct file *file) > -{ > - char *buffer = state.buf, *mach = "", cs4218_buf[50]; > - int len = 0; > - > - if (state.busy) > - return -EBUSY; > - > - state.ptr = 0; > - state.busy = 1; > - > - sprintf(cs4218_buf, "Crystal CS4218 on TDM, "); > - mach = cs4218_buf; > - > - len += sprintf(buffer+len, "%sDMA sound driver:\n", mach); > - > - len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format); > - switch (sound.soft.format) { > - case AFMT_MU_LAW: > - len += sprintf(buffer+len, " (mu-law)"); > - break; > - case AFMT_A_LAW: > - len += sprintf(buffer+len, " (A-law)"); > - break; > - case AFMT_U8: > - len += sprintf(buffer+len, " (unsigned 8 bit)"); > - break; > - case AFMT_S8: > - len += sprintf(buffer+len, " (signed 8 bit)"); > - break; > - case AFMT_S16_BE: > - len += sprintf(buffer+len, " (signed 16 bit big)"); > - break; > - case AFMT_U16_BE: > - len += sprintf(buffer+len, " (unsigned 16 bit big)"); > - break; > - case AFMT_S16_LE: > - len += sprintf(buffer+len, " (signed 16 bit little)"); > - break; > - case AFMT_U16_LE: > - len += sprintf(buffer+len, " (unsigned 16 bit little)"); > - break; > - } > - len += sprintf(buffer+len, "\n"); > - len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n", > - sound.soft.speed, sound.hard.speed); > - len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n", > - sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono"); > - len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d" > - " sq.max_active = %d\n", > - sq.block_size, sq.max_count, sq.max_active); > - len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count, > - sq.rear_size); > - len += sprintf(buffer+len, "\tsq.active = %d sq.syncing = %d\n", > - sq.active, sq.syncing); > - state.len = len; > - return nonseekable_open(inode, file); > -} > - > - > -static int state_release(struct inode *inode, struct file *file) > -{ > - state.busy = 0; > - return 0; > -} > - > - > -static ssize_t state_read(struct file *file, char *buf, size_t count, > - loff_t *ppos) > -{ > - int n = state.len - state.ptr; > - if (n > count) > - n = count; > - if (n <= 0) > - return 0; > - if (copy_to_user(buf, &state.buf[state.ptr], n)) > - return -EFAULT; > - state.ptr += n; > - return n; > -} > - > - > -static const struct file_operations state_fops = > -{ > - .owner = THIS_MODULE, > - .llseek = sound_lseek, > - .read = state_read, > - .open = state_open, > - .release = state_release, > -}; > - > - > -static void __init state_init(void) > -{ > - state_unit = register_sound_special(&state_fops, SND_DEV_STATUS); > - if (state_unit < 0) > - return; > - state.busy = 0; > -} > - > - > -/*** Common stuff ********************************************************/ > - > -static long long sound_lseek(struct file *file, long long offset, int orig) > -{ > - return -ESPIPE; > -} > - > - > -/*** Config & Setup **********************************************************/ > - > - > -int __init tdm8xx_sound_init(void) > -{ > - int i, has_sound; > - uint dp_offset; > - volatile uint *sirp; > - volatile cbd_t *bdp; > - volatile cpm8xx_t *cp; > - volatile smc_t *sp; > - volatile smc_uart_t *up; > - volatile immap_t *immap; > - > - has_sound = 0; > - > - /* Program the SI/TSA to use TDMa, connected to SMC2, for 4 bytes. > - */ > - cp = cpmp; /* Get pointer to Communication Processor */ > - immap = (immap_t *)IMAP_ADDR; /* and to internal registers */ > - > - /* Set all TDMa control bits to zero. This enables most features > - * we want. > - */ > - cp->cp_simode &= ~0x00000fff; > - > - /* Enable common receive/transmit clock pins, use IDL format. > - * Sync on falling edge, transmit rising clock, receive falling > - * clock, delay 1 bit on both Tx and Rx. Common Tx/Rx clocks and > - * sync. > - * Connect SMC2 to TSA. > - */ > - cp->cp_simode |= 0x80000141; > - > - /* Configure port A pins for TDMa operation. > - * The RPX-Lite (MPC850/823) loses SMC2 when TDM is used. > - */ > - immap->im_ioport.iop_papar |= 0x01c0; /* Enable TDMa functions */ > - immap->im_ioport.iop_padir |= 0x00c0; /* Enable TDMa Tx/Rx */ > - immap->im_ioport.iop_padir &= ~0x0100; /* Enable L1RCLKa */ > - > - immap->im_ioport.iop_pcpar |= 0x0800; /* Enable L1RSYNCa */ > - immap->im_ioport.iop_pcdir &= ~0x0800; > - > - /* Initialize the SI TDM routing table. We use TDMa only. > - * The receive table and transmit table each have only one > - * entry, to capture/send four bytes after each frame pulse. > - * The 16-bit ram entry is 0000 0001 1000 1111. (SMC2) > - */ > - cp->cp_sigmr = 0; > - sirp = (uint *)cp->cp_siram; > - > - *sirp = 0x018f0000; /* Receive entry */ > - sirp += 64; > - *sirp = 0x018f0000; /* Tramsmit entry */ > - > - /* Enable single TDMa routing. > - */ > - cp->cp_sigmr = 0x04; > - > - /* Initialize the SMC for transparent operation. > - */ > - sp = &cpmp->cp_smc[1]; > - up = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC2]; > - > - /* We need to allocate a transmit and receive buffer > - * descriptors from dual port ram. > - */ > - dp_addr = cpm_dpalloc(sizeof(cbd_t) * numReadBufs, 8); > - > - /* Set the physical address of the host memory > - * buffers in the buffer descriptors, and the > - * virtual address for us to work with. > - */ > - bdp = (cbd_t *)&cp->cp_dpmem[dp_addr]; > - up->smc_rbase = dp_offset; > - rx_cur = rx_base = (cbd_t *)bdp; > - > - for (i=0; i<(numReadBufs-1); i++) { > - bdp->cbd_bufaddr = 0; > - bdp->cbd_datlen = 0; > - bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT; > - bdp++; > - } > - bdp->cbd_bufaddr = 0; > - bdp->cbd_datlen = 0; > - bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; > - > - /* Now, do the same for the transmit buffers. > - */ > - dp_offset = cpm_dpalloc(sizeof(cbd_t) * numBufs, 8); > - > - bdp = (cbd_t *)&cp->cp_dpmem[dp_addr]; > - up->smc_tbase = dp_offset; > - tx_cur = tx_base = (cbd_t *)bdp; > - > - for (i=0; i<(numBufs-1); i++) { > - bdp->cbd_bufaddr = 0; > - bdp->cbd_datlen = 0; > - bdp->cbd_sc = BD_SC_INTRPT; > - bdp++; > - } > - bdp->cbd_bufaddr = 0; > - bdp->cbd_datlen = 0; > - bdp->cbd_sc = (BD_SC_WRAP | BD_SC_INTRPT); > - > - /* Set transparent SMC mode. > - * A few things are specific to our application. The codec interface > - * is MSB first, hence the REVD selection. The CD/CTS pulse are > - * used by the TSA to indicate the frame start to the SMC. > - */ > - up->smc_rfcr = SCC_EB; > - up->smc_tfcr = SCC_EB; > - up->smc_mrblr = readbufSize * 1024; > - > - /* Set 16-bit reversed data, transparent mode. > - */ > - sp->smc_smcmr = smcr_mk_clen(15) | > - SMCMR_SM_TRANS | SMCMR_REVD | SMCMR_BS; > - > - /* Enable and clear events. > - * Because of FIFO delays, all we need is the receive interrupt > - * and we can process both the current receive and current > - * transmit interrupt within a few microseconds of the transmit. > - */ > - sp->smc_smce = 0xff; > - sp->smc_smcm = SMCM_TXE | SMCM_TX | SMCM_RX; > - > - /* Send the CPM an initialize command. > - */ > - cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2, > - CPM_CR_INIT_TRX) | CPM_CR_FLG; > - while (cp->cp_cpcr & CPM_CR_FLG); > - > - sound.mach = mach_cs4218; > - has_sound = 1; > - > - /* Initialize beep stuff */ > - orig_mksound = kd_mksound; > - kd_mksound = cs_mksound; > - beep_buf = kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL); > - if (beep_buf == NULL) > - printk(KERN_WARNING "dmasound: no memory for " > - "beep buffer\n"); > - > - if (!has_sound) > - return -ENODEV; > - > - /* Initialize the software SPI. > - */ > - sw_spi_init(); > - > - /* Set up sound queue, /dev/audio and /dev/dsp. */ > - > - /* Set default settings. */ > - sq_init(); > - > - /* Set up /dev/sndstat. */ > - state_init(); > - > - /* Set up /dev/mixer. */ > - mixer_init(); > - > - if (!sound.mach.irqinit()) { > - printk(KERN_ERR "DMA sound driver: Interrupt initialization failed\n"); > - return -ENODEV; > - } > -#ifdef MODULE > - irq_installed = 1; > -#endif > - > - printk(KERN_INFO "DMA sound driver installed, using %d buffers of %dk.\n", > - numBufs, bufSize); > - > - return 0; > -} > - > -/* Due to FIFOs and bit delays, the transmit interrupt occurs a few > - * microseconds ahead of the receive interrupt. > - * When we get an interrupt, we service the transmit first, then > - * check for a receive to prevent the overhead of returning through > - * the interrupt handler only to get back here right away during > - * full duplex operation. > - */ > -static void > -cs4218_intr(void *dev_id) > -{ > - volatile smc_t *sp; > - volatile cpm8xx_t *cp; > - > - sp = &cpmp->cp_smc[1]; > - > - if (sp->smc_smce & SCCM_TX) { > - sp->smc_smce = SCCM_TX; > - cs4218_tdm_tx_intr((void *)sp); > - } > - > - if (sp->smc_smce & SCCM_RX) { > - sp->smc_smce = SCCM_RX; > - cs4218_tdm_rx_intr((void *)sp); > - } > - > - if (sp->smc_smce & SCCM_TXE) { > - /* Transmit underrun. This happens with the application > - * didn't keep up sending buffers. We tell the SMC to > - * restart, which will cause it to poll the current (next) > - * BD. If the user supplied data since this occurred, > - * we just start running again. If they didn't, the SMC > - * will poll the descriptor until data is placed there. > - */ > - sp->smc_smce = SCCM_TXE; > - cp = cpmp; /* Get pointer to Communication Processor */ > - cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2, > - CPM_CR_RESTART_TX) | CPM_CR_FLG; > - while (cp->cp_cpcr & CPM_CR_FLG); > - } > -} > - > - > -#define MAXARGS 8 /* Should be sufficient for now */ > - > -void __init dmasound_setup(char *str, int *ints) > -{ > - /* check the bootstrap parameter for "dmasound=" */ > - > - switch (ints[0]) { > - case 3: > - if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS)) > - printk("dmasound_setup: invalid catch radius, using default = %d\n", catchRadius); > - else > - catchRadius = ints[3]; > - /* fall through */ > - case 2: > - if (ints[1] < MIN_BUFFERS) > - printk("dmasound_setup: invalid number of buffers, using default = %d\n", numBufs); > - else > - numBufs = ints[1]; > - if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE) > - printk("dmasound_setup: invalid buffer size, using default = %d\n", bufSize); > - else > - bufSize = ints[2]; > - break; > - case 0: > - break; > - default: > - printk("dmasound_setup: invalid number of arguments\n"); > - } > -} > - > -/* Software SPI functions. > - * These are on Port B. > - */ > -#define PB_SPICLK ((uint)0x00000002) > -#define PB_SPIMOSI ((uint)0x00000004) > -#define PB_SPIMISO ((uint)0x00000008) > - > -static > -void sw_spi_init(void) > -{ > - volatile cpm8xx_t *cp; > - volatile uint *hcsr4; > - > - hcsr4 = (volatile uint *)HIOX_CSR4_ADDR; > - cp = cpmp; /* Get pointer to Communication Processor */ > - > - *hcsr4 &= ~HIOX_CSR4_AUDSPISEL; /* Disable SPI select */ > - > - /* Make these Port B signals general purpose I/O. > - * First, make sure the clock is low. > - */ > - cp->cp_pbdat &= ~PB_SPICLK; > - cp->cp_pbpar &= ~(PB_SPICLK | PB_SPIMOSI | PB_SPIMISO); > - > - /* Clock and Master Output are outputs. > - */ > - cp->cp_pbdir |= (PB_SPICLK | PB_SPIMOSI); > - > - /* Master Input. > - */ > - cp->cp_pbdir &= ~PB_SPIMISO; > - > -} > - > -/* Write the CS4218 control word out the SPI port. While the > - * the control word is going out, the status word is arriving. > - */ > -static > -uint cs4218_ctl_write(uint ctlreg) > -{ > - uint status; > - > - sw_spi_io((u_char *)&ctlreg, (u_char *)&status, 4); > - > - /* Shadow the control register.....I guess we could do > - * the same for the status, but for now we just return it > - * and let the caller decide. > - */ > - cs4218_control = ctlreg; > - return status; > -} > - > -static > -void sw_spi_io(u_char *obuf, u_char *ibuf, uint bcnt) > -{ > - int bits, i; > - u_char outbyte, inbyte; > - volatile cpm8xx_t *cp; > - volatile uint *hcsr4; > - > - hcsr4 = (volatile uint *)HIOX_CSR4_ADDR; > - cp = cpmp; /* Get pointer to Communication Processor */ > - > - /* The timing on the bus is pretty slow. Code inefficiency > - * and eieio() is our friend here :-). > - */ > - cp->cp_pbdat &= ~PB_SPICLK; > - *hcsr4 |= HIOX_CSR4_AUDSPISEL; /* Enable SPI select */ > - eieio(); > - > - /* Clock in/out the bytes. Data is valid on the falling edge > - * of the clock. Data is MSB first. > - */ > - for (i=0; i - outbyte = *obuf++; > - inbyte = 0; > - for (bits=0; bits<8; bits++) { > - eieio(); > - cp->cp_pbdat |= PB_SPICLK; > - eieio(); > - if (outbyte & 0x80) > - cp->cp_pbdat |= PB_SPIMOSI; > - else > - cp->cp_pbdat &= ~PB_SPIMOSI; > - eieio(); > - cp->cp_pbdat &= ~PB_SPICLK; > - eieio(); > - outbyte <<= 1; > - inbyte <<= 1; > - if (cp->cp_pbdat & PB_SPIMISO) > - inbyte |= 1; > - } > - *ibuf++ = inbyte; > - } > - > - *hcsr4 &= ~HIOX_CSR4_AUDSPISEL; /* Disable SPI select */ > - eieio(); > -} > - > -void cleanup_module(void) > -{ > - if (irq_installed) { > - sound_silence(); > -#ifdef MODULE > - sound.mach.irqcleanup(); > -#endif > - } > - > - sq_release_read_buffers(); > - sq_release_buffers(); > - > - if (mixer_unit >= 0) > - unregister_sound_mixer(mixer_unit); > - if (state_unit >= 0) > - unregister_sound_special(state_unit); > - if (sq_unit >= 0) > - unregister_sound_dsp(sq_unit); > -} > - > -module_init(tdm8xx_sound_init); > -module_exit(cleanup_module); > - > -