diff options
author | Adrian Bunk <bunk@stusta.de> | 2007-10-18 03:06:12 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-18 14:37:26 -0700 |
commit | fc37449f7959aeedc2d38b183468ae73c9166fb6 (patch) | |
tree | 3aaf169f3b9d9c9deb69802aa7c81354d55cf0c8 | |
parent | 5b4db0c2f25925fcfc17fa7233b7b90dc023d207 (diff) | |
download | linux-stable-fc37449f7959aeedc2d38b183468ae73c9166fb6.tar.gz linux-stable-fc37449f7959aeedc2d38b183468ae73c9166fb6.tar.bz2 linux-stable-fc37449f7959aeedc2d38b183468ae73c9166fb6.zip |
The next round of scheduled OSS code removal
This patch contains the next round of scheduled OSS code removal.
Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | Documentation/feature-removal-schedule.txt | 7 | ||||
-rw-r--r-- | Documentation/sound/oss/es1371 | 64 | ||||
-rw-r--r-- | MAINTAINERS | 7 | ||||
-rw-r--r-- | sound/oss/Makefile | 1 | ||||
-rw-r--r-- | sound/oss/dmasound/Makefile | 6 | ||||
-rw-r--r-- | sound/oss/dmasound/awacs_defs.h | 251 | ||||
-rw-r--r-- | sound/oss/dmasound/dac3550a.c | 209 | ||||
-rw-r--r-- | sound/oss/dmasound/dmasound.h | 13 | ||||
-rw-r--r-- | sound/oss/dmasound/dmasound_awacs.c | 3215 | ||||
-rw-r--r-- | sound/oss/dmasound/dmasound_core.c | 287 | ||||
-rw-r--r-- | sound/oss/dmasound/tas3001c.c | 849 | ||||
-rw-r--r-- | sound/oss/dmasound/tas3001c.h | 64 | ||||
-rw-r--r-- | sound/oss/dmasound/tas3001c_tables.c | 375 | ||||
-rw-r--r-- | sound/oss/dmasound/tas3004.c | 1138 | ||||
-rw-r--r-- | sound/oss/dmasound/tas3004.h | 77 | ||||
-rw-r--r-- | sound/oss/dmasound/tas3004_tables.c | 301 | ||||
-rw-r--r-- | sound/oss/dmasound/tas_common.c | 214 | ||||
-rw-r--r-- | sound/oss/dmasound/tas_common.h | 284 | ||||
-rw-r--r-- | sound/oss/dmasound/tas_eq_prefs.h | 24 | ||||
-rw-r--r-- | sound/oss/dmasound/tas_ioctl.h | 23 | ||||
-rw-r--r-- | sound/oss/dmasound/trans_16.c | 898 | ||||
-rw-r--r-- | sound/oss/es1371.c | 3131 |
22 files changed, 0 insertions, 11438 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 5b25162cd9a4..6b0f963f5379 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -219,13 +219,6 @@ Who: Jean Delvare <khali@linux-fr.org>, --------------------------- -What: drivers depending on OBSOLETE_OSS -When: options in 2.6.22, code in 2.6.24 -Why: OSS drivers with ALSA replacements -Who: Adrian Bunk <bunk@stusta.de> - ---------------------------- - What: ACPI procfs interface When: July 2008 Why: ACPI sysfs conversion should be finished by January 2008. diff --git a/Documentation/sound/oss/es1371 b/Documentation/sound/oss/es1371 deleted file mode 100644 index c3151266771c..000000000000 --- a/Documentation/sound/oss/es1371 +++ /dev/null @@ -1,64 +0,0 @@ -/proc/sound, /dev/sndstat -------------------------- - -/proc/sound and /dev/sndstat is not supported by the -driver. To find out whether the driver succeeded loading, -check the kernel log (dmesg). - - -ALaw/uLaw sample formats ------------------------- - -This driver does not support the ALaw/uLaw sample formats. -ALaw is the default mode when opening a sound device -using OSS/Free. The reason for the lack of support is -that the hardware does not support these formats, and adding -conversion routines to the kernel would lead to very ugly -code in the presence of the mmap interface to the driver. -And since xquake uses mmap, mmap is considered important :-) -and no sane application uses ALaw/uLaw these days anyway. -In short, playing a Sun .au file as follows: - -cat my_file.au > /dev/dsp - -does not work. Instead, you may use the play script from -Chris Bagwell's sox-12.14 package (available from the URL -below) to play many different audio file formats. -The script automatically determines the audio format -and does do audio conversions if necessary. -http://home.sprynet.com/sprynet/cbagwell/projects.html - - -Blocking vs. nonblocking IO ---------------------------- - -Unlike OSS/Free this driver honours the O_NONBLOCK file flag -not only during open, but also during read and write. -This is an effort to make the sound driver interface more -regular. Timidity has problems with this; a patch -is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html. -(Timidity patched will also run on OSS/Free). - - -MIDI UART ---------- - -The driver supports a simple MIDI UART interface, with -no ioctl's supported. - - -MIDI synthesizer ----------------- - -This soundcard does not have any hardware MIDI synthesizer; -MIDI synthesis has to be done in software. To allow this -the driver/soundcard supports two PCM (/dev/dsp) interfaces. - -There is a freely available software package that allows -MIDI file playback on this soundcard called Timidity. -See http://www.cgs.fi/~tt/timidity/. - - - -Thomas Sailer -t.sailer@alumni.ethz.ch diff --git a/MAINTAINERS b/MAINTAINERS index 92c9f3a11a9d..2534dc4aa95a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2940,13 +2940,6 @@ L: linux-kernel@vger.kernel.org L: linux-pci@atrey.karlin.mff.cuni.cz S: Supported -PCI SOUND DRIVERS (ES1370, ES1371 and SONICVIBES) -P: Thomas Sailer -M: sailer@ife.ee.ethz.ch -L: linux-sound@vger.kernel.org -W: http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html -S: Maintained - PCI SUBSYSTEM P: Greg Kroah-Hartman M: gregkh@suse.de diff --git a/sound/oss/Makefile b/sound/oss/Makefile index 1200670017bd..f883c4b676ab 100644 --- a/sound/oss/Makefile +++ b/sound/oss/Makefile @@ -36,7 +36,6 @@ obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o obj-$(CONFIG_SOUND_VWSND) += vwsnd.o obj-$(CONFIG_SOUND_ICH) += i810_audio.o ac97_codec.o -obj-$(CONFIG_SOUND_ES1371) += es1371.o ac97_codec.o obj-$(CONFIG_SOUND_AU1550_AC97) += au1550_ac97.o ac97_codec.o obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o diff --git a/sound/oss/dmasound/Makefile b/sound/oss/dmasound/Makefile index 4611636b1a81..3c1531652d11 100644 --- a/sound/oss/dmasound/Makefile +++ b/sound/oss/dmasound/Makefile @@ -2,12 +2,6 @@ # Makefile for the DMA sound driver # -dmasound_pmac-y += dmasound_awacs.o \ - trans_16.o dac3550a.o tas_common.o \ - tas3001c.o tas3001c_tables.o \ - tas3004.o tas3004_tables.o - obj-$(CONFIG_DMASOUND_ATARI) += dmasound_core.o dmasound_atari.o -obj-$(CONFIG_DMASOUND_PMAC) += dmasound_core.o dmasound_pmac.o obj-$(CONFIG_DMASOUND_PAULA) += dmasound_core.o dmasound_paula.o obj-$(CONFIG_DMASOUND_Q40) += dmasound_core.o dmasound_q40.o diff --git a/sound/oss/dmasound/awacs_defs.h b/sound/oss/dmasound/awacs_defs.h deleted file mode 100644 index 2194f46b046c..000000000000 --- a/sound/oss/dmasound/awacs_defs.h +++ /dev/null @@ -1,251 +0,0 @@ -/*********************************************************/ -/* This file was written by someone, somewhere, sometime */ -/* And is released into the Public Domain */ -/*********************************************************/ - -#ifndef _AWACS_DEFS_H_ -#define _AWACS_DEFS_H_ - -/*******************************/ -/* AWACs Audio Register Layout */ -/*******************************/ - -struct awacs_regs { - unsigned control; /* Audio control register */ - unsigned pad0[3]; - unsigned codec_ctrl; /* Codec control register */ - unsigned pad1[3]; - unsigned codec_stat; /* Codec status register */ - unsigned pad2[3]; - unsigned clip_count; /* Clipping count register */ - unsigned pad3[3]; - unsigned byteswap; /* Data is little-endian if 1 */ -}; - -/*******************/ -/* Audio Bit Masks */ -/*******************/ - -/* Audio Control Reg Bit Masks */ -/* ----- ------- --- --- ----- */ -#define MASK_ISFSEL (0xf) /* Input SubFrame Select */ -#define MASK_OSFSEL (0xf << 4) /* Output SubFrame Select */ -#define MASK_RATE (0x7 << 8) /* Sound Rate */ -#define MASK_CNTLERR (0x1 << 11) /* Error */ -#define MASK_PORTCHG (0x1 << 12) /* Port Change */ -#define MASK_IEE (0x1 << 13) /* Enable Interrupt on Error */ -#define MASK_IEPC (0x1 << 14) /* Enable Interrupt on Port Change */ -#define MASK_SSFSEL (0x3 << 15) /* Status SubFrame Select */ - -/* Audio Codec Control Reg Bit Masks */ -/* ----- ----- ------- --- --- ----- */ -#define MASK_NEWECMD (0x1 << 24) /* Lock: don't write to reg when 1 */ -#define MASK_EMODESEL (0x3 << 22) /* Send info out on which frame? */ -#define MASK_EXMODEADDR (0x3ff << 12) /* Extended Mode Address -- 10 bits */ -#define MASK_EXMODEDATA (0xfff) /* Extended Mode Data -- 12 bits */ - -/* Audio Codec Control Address Values / Masks */ -/* ----- ----- ------- ------- ------ - ----- */ -#define MASK_ADDR0 (0x0 << 12) /* Expanded Data Mode Address 0 */ -#define MASK_ADDR_MUX MASK_ADDR0 /* Mux Control */ -#define MASK_ADDR_GAIN MASK_ADDR0 - -#define MASK_ADDR1 (0x1 << 12) /* Expanded Data Mode Address 1 */ -#define MASK_ADDR_MUTE MASK_ADDR1 -#define MASK_ADDR_RATE MASK_ADDR1 - -#define MASK_ADDR2 (0x2 << 12) /* Expanded Data Mode Address 2 */ -#define MASK_ADDR_VOLA MASK_ADDR2 /* Volume Control A -- Headphones */ -#define MASK_ADDR_VOLHD MASK_ADDR2 - -#define MASK_ADDR4 (0x4 << 12) /* Expanded Data Mode Address 4 */ -#define MASK_ADDR_VOLC MASK_ADDR4 /* Volume Control C -- Speaker */ -#define MASK_ADDR_VOLSPK MASK_ADDR4 - -/* additional registers of screamer */ -#define MASK_ADDR5 (0x5 << 12) /* Expanded Data Mode Address 5 */ -#define MASK_ADDR6 (0x6 << 12) /* Expanded Data Mode Address 6 */ -#define MASK_ADDR7 (0x7 << 12) /* Expanded Data Mode Address 7 */ - -/* Address 0 Bit Masks & Macros */ -/* ------- - --- ----- - ------ */ -#define MASK_GAINRIGHT (0xf) /* Gain Right Mask */ -#define MASK_GAINLEFT (0xf << 4) /* Gain Left Mask */ -#define MASK_GAINLINE (0x1 << 8) /* Disable Mic preamp */ -#define MASK_GAINMIC (0x0 << 8) /* Enable Mic preamp */ - -#define MASK_MUX_CD (0x1 << 9) /* Select CD in MUX */ -#define MASK_MUX_MIC (0x1 << 10) /* Select Mic in MUX */ -#define MASK_MUX_AUDIN (0x1 << 11) /* Select Audio In in MUX */ -#define MASK_MUX_LINE MASK_MUX_AUDIN - -#define GAINRIGHT(x) ((x) & MASK_GAINRIGHT) -#define GAINLEFT(x) (((x) << 4) & MASK_GAINLEFT) - -#define DEF_CD_GAIN 0x00bb -#define DEF_MIC_GAIN 0x00cc - -/* Address 1 Bit Masks */ -/* ------- - --- ----- */ -#define MASK_ADDR1RES1 (0x3) /* Reserved */ -#define MASK_RECALIBRATE (0x1 << 2) /* Recalibrate */ -#define MASK_SAMPLERATE (0x7 << 3) /* Sample Rate: */ -#define MASK_LOOPTHRU (0x1 << 6) /* Loopthrough Enable */ -#define MASK_CMUTE (0x1 << 7) /* Output C (Speaker) Mute when 1 */ -#define MASK_SPKMUTE MASK_CMUTE -#define MASK_ADDR1RES2 (0x1 << 8) /* Reserved */ -#define MASK_AMUTE (0x1 << 9) /* Output A (Headphone) Mute when 1 */ -#define MASK_HDMUTE MASK_AMUTE -#define MASK_PAROUT0 (0x1 << 10) /* Parallel Output 0 */ -#define MASK_PAROUT1 (0x2 << 10) /* Parallel Output 1 */ - -#define MASK_MIC_BOOST (0x4) /* screamer mic boost */ - -#define SAMPLERATE_48000 (0x0 << 3) /* 48 or 44.1 kHz */ -#define SAMPLERATE_32000 (0x1 << 3) /* 32 or 29.4 kHz */ -#define SAMPLERATE_24000 (0x2 << 3) /* 24 or 22.05 kHz */ -#define SAMPLERATE_19200 (0x3 << 3) /* 19.2 or 17.64 kHz */ -#define SAMPLERATE_16000 (0x4 << 3) /* 16 or 14.7 kHz */ -#define SAMPLERATE_12000 (0x5 << 3) /* 12 or 11.025 kHz */ -#define SAMPLERATE_9600 (0x6 << 3) /* 9.6 or 8.82 kHz */ -#define SAMPLERATE_8000 (0x7 << 3) /* 8 or 7.35 kHz */ - -/* Address 2 & 4 Bit Masks & Macros */ -/* ------- - - - --- ----- - ------ */ -#define MASK_OUTVOLRIGHT (0xf) /* Output Right Volume */ -#define MASK_ADDR2RES1 (0x2 << 4) /* Reserved */ -#define MASK_ADDR4RES1 MASK_ADDR2RES1 -#define MASK_OUTVOLLEFT (0xf << 6) /* Output Left Volume */ -#define MASK_ADDR2RES2 (0x2 << 10) /* Reserved */ -#define MASK_ADDR4RES2 MASK_ADDR2RES2 - -#define VOLRIGHT(x) (((~(x)) & MASK_OUTVOLRIGHT)) -#define VOLLEFT(x) (((~(x)) << 6) & MASK_OUTVOLLEFT) - -/* Audio Codec Status Reg Bit Masks */ -/* ----- ----- ------ --- --- ----- */ -#define MASK_EXTEND (0x1 << 23) /* Extend */ -#define MASK_VALID (0x1 << 22) /* Valid Data? */ -#define MASK_OFLEFT (0x1 << 21) /* Overflow Left */ -#define MASK_OFRIGHT (0x1 << 20) /* Overflow Right */ -#define MASK_ERRCODE (0xf << 16) /* Error Code */ -#define MASK_REVISION (0xf << 12) /* Revision Number */ -#define MASK_MFGID (0xf << 8) /* Mfg. ID */ -#define MASK_CODSTATRES (0xf << 4) /* bits 4 - 7 reserved */ -#define MASK_INPPORT (0xf) /* Input Port */ -#define MASK_HDPCONN 8 /* headphone plugged in */ - -/* Clipping Count Reg Bit Masks */ -/* -------- ----- --- --- ----- */ -#define MASK_CLIPLEFT (0xff << 7) /* Clipping Count, Left Channel */ -#define MASK_CLIPRIGHT (0xff) /* Clipping Count, Right Channel */ - -/* DBDMA ChannelStatus Bit Masks */ -/* ----- ------------- --- ----- */ -#define MASK_CSERR (0x1 << 7) /* Error */ -#define MASK_EOI (0x1 << 6) /* End of Input -- only for Input Channel */ -#define MASK_CSUNUSED (0x1f << 1) /* bits 1-5 not used */ -#define MASK_WAIT (0x1) /* Wait */ - -/* Various Rates */ -/* ------- ----- */ -#define RATE_48000 (0x0 << 8) /* 48 kHz */ -#define RATE_44100 (0x0 << 8) /* 44.1 kHz */ -#define RATE_32000 (0x1 << 8) /* 32 kHz */ -#define RATE_29400 (0x1 << 8) /* 29.4 kHz */ -#define RATE_24000 (0x2 << 8) /* 24 kHz */ -#define RATE_22050 (0x2 << 8) /* 22.05 kHz */ -#define RATE_19200 (0x3 << 8) /* 19.2 kHz */ -#define RATE_17640 (0x3 << 8) /* 17.64 kHz */ -#define RATE_16000 (0x4 << 8) /* 16 kHz */ -#define RATE_14700 (0x4 << 8) /* 14.7 kHz */ -#define RATE_12000 (0x5 << 8) /* 12 kHz */ -#define RATE_11025 (0x5 << 8) /* 11.025 kHz */ -#define RATE_9600 (0x6 << 8) /* 9.6 kHz */ -#define RATE_8820 (0x6 << 8) /* 8.82 kHz */ -#define RATE_8000 (0x7 << 8) /* 8 kHz */ -#define RATE_7350 (0x7 << 8) /* 7.35 kHz */ - -#define RATE_LOW 1 /* HIGH = 48kHz, etc; LOW = 44.1kHz, etc. */ - -/*******************/ -/* Burgundy values */ -/*******************/ - -#define MASK_ADDR_BURGUNDY_INPSEL21 (0x11 << 12) -#define MASK_ADDR_BURGUNDY_INPSEL3 (0x12 << 12) - -#define MASK_ADDR_BURGUNDY_GAINCH1 (0x13 << 12) -#define MASK_ADDR_BURGUNDY_GAINCH2 (0x14 << 12) -#define MASK_ADDR_BURGUNDY_GAINCH3 (0x15 << 12) -#define MASK_ADDR_BURGUNDY_GAINCH4 (0x16 << 12) - -#define MASK_ADDR_BURGUNDY_VOLCH1 (0x20 << 12) -#define MASK_ADDR_BURGUNDY_VOLCH2 (0x21 << 12) -#define MASK_ADDR_BURGUNDY_VOLCH3 (0x22 << 12) -#define MASK_ADDR_BURGUNDY_VOLCH4 (0x23 << 12) - -#define MASK_ADDR_BURGUNDY_OUTPUTSELECTS (0x2B << 12) -#define MASK_ADDR_BURGUNDY_OUTPUTENABLES (0x2F << 12) - -#define MASK_ADDR_BURGUNDY_MASTER_VOLUME (0x30 << 12) - -#define MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES (0x60 << 12) - -#define MASK_ADDR_BURGUNDY_ATTENSPEAKER (0x62 << 12) -#define MASK_ADDR_BURGUNDY_ATTENLINEOUT (0x63 << 12) -#define MASK_ADDR_BURGUNDY_ATTENHP (0x64 << 12) - -#define MASK_ADDR_BURGUNDY_VOLCD (MASK_ADDR_BURGUNDY_VOLCH1) -#define MASK_ADDR_BURGUNDY_VOLLINE (MASK_ADDR_BURGUNDY_VOLCH2) -#define MASK_ADDR_BURGUNDY_VOLMIC (MASK_ADDR_BURGUNDY_VOLCH3) -#define MASK_ADDR_BURGUNDY_VOLMODEM (MASK_ADDR_BURGUNDY_VOLCH4) - -#define MASK_ADDR_BURGUNDY_GAINCD (MASK_ADDR_BURGUNDY_GAINCH1) -#define MASK_ADDR_BURGUNDY_GAINLINE (MASK_ADDR_BURGUNDY_GAINCH2) -#define MASK_ADDR_BURGUNDY_GAINMIC (MASK_ADDR_BURGUNDY_GAINCH3) -#define MASK_ADDR_BURGUNDY_GAINMODEM (MASK_ADDR_BURGUNDY_VOLCH4) - - -/* These are all default values for the burgundy */ -#define DEF_BURGUNDY_INPSEL21 (0xAA) -#define DEF_BURGUNDY_INPSEL3 (0x0A) - -#define DEF_BURGUNDY_GAINCD (0x33) -#define DEF_BURGUNDY_GAINLINE (0x44) -#define DEF_BURGUNDY_GAINMIC (0x44) -#define DEF_BURGUNDY_GAINMODEM (0x06) - -/* Remember: lowest volume here is 0x9b */ -#define DEF_BURGUNDY_VOLCD (0xCCCCCCCC) -#define DEF_BURGUNDY_VOLLINE (0x00000000) -#define DEF_BURGUNDY_VOLMIC (0x00000000) -#define DEF_BURGUNDY_VOLMODEM (0xCCCCCCCC) - -#define DEF_BURGUNDY_OUTPUTSELECTS (0x010f010f) -#define DEF_BURGUNDY_OUTPUTENABLES (0x0A) - -#define DEF_BURGUNDY_MASTER_VOLUME (0xFFFFFFFF) - -#define DEF_BURGUNDY_MORE_OUTPUTENABLES (0x7E) - -#define DEF_BURGUNDY_ATTENSPEAKER (0x44) -#define DEF_BURGUNDY_ATTENLINEOUT (0xCC) -#define DEF_BURGUNDY_ATTENHP (0xCC) - -/*********************/ -/* i2s layout values */ -/*********************/ - -#define I2S_REG_INT_CTL 0x00 -#define I2S_REG_SERIAL_FORMAT 0x10 -#define I2S_REG_CODEC_MSG_OUT 0x20 -#define I2S_REG_CODEC_MSG_IN 0x30 -#define I2S_REG_FRAME_COUNT 0x40 -#define I2S_REG_FRAME_MATCH 0x50 -#define I2S_REG_DATAWORD_SIZES 0x60 -#define I2S_REG_PEAKLEVEL_SEL 0x70 -#define I2S_REG_PEAKLEVEL_IN0 0x80 -#define I2S_REG_PEAKLEVEL_IN1 0x90 - -#endif /* _AWACS_DEFS_H_ */ diff --git a/sound/oss/dmasound/dac3550a.c b/sound/oss/dmasound/dac3550a.c deleted file mode 100644 index 0f0d03a55dab..000000000000 --- a/sound/oss/dmasound/dac3550a.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Driver for the i2c/i2s based DAC3550a sound chip used - * on some Apple iBooks. Also known as "DACA". - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/proc_fs.h> -#include <linux/ioport.h> -#include <linux/sysctl.h> -#include <linux/types.h> -#include <linux/i2c.h> -#include <linux/init.h> -#include <asm/uaccess.h> -#include <asm/errno.h> -#include <asm/io.h> - -#include "dmasound.h" - -/* FYI: This code was derived from the tas3001c.c Texas/Tumbler mixer - * control code, as well as info derived from the AppleDACAAudio driver - * from Darwin CVS (main thing I derived being register numbers and - * values, as well as when to make the calls). */ - -#define I2C_DRIVERID_DACA (0xFDCB) - -#define DACA_VERSION "0.1" -#define DACA_DATE "20010930" - -static int cur_left_vol; -static int cur_right_vol; -static struct i2c_client *daca_client; - -static int daca_attach_adapter(struct i2c_adapter *adapter); -static int daca_detect_client(struct i2c_adapter *adapter, int address); -static int daca_detach_client(struct i2c_client *client); - -struct i2c_driver daca_driver = { - .driver = { - .name = "DAC3550A driver V " DACA_VERSION, - }, - .id = I2C_DRIVERID_DACA, - .attach_adapter = daca_attach_adapter, - .detach_client = daca_detach_client, -}; - -#define VOL_MAX ((1<<20) - 1) - -void daca_get_volume(uint * left_vol, uint *right_vol) -{ - *left_vol = cur_left_vol >> 5; - *right_vol = cur_right_vol >> 5; -} - -int daca_set_volume(uint left_vol, uint right_vol) -{ - unsigned short voldata; - - if (!daca_client) - return -1; - - /* Derived from experience, not from any specific values */ - left_vol <<= 5; - right_vol <<= 5; - - if (left_vol > VOL_MAX) - left_vol = VOL_MAX; - if (right_vol > VOL_MAX) - right_vol = VOL_MAX; - - voldata = ((left_vol >> 14) & 0x3f) << 8; - voldata |= (right_vol >> 14) & 0x3f; - - if (i2c_smbus_write_word_data(daca_client, 2, voldata) < 0) { - printk("daca: failed to set volume \n"); - return -1; - } - - cur_left_vol = left_vol; - cur_right_vol = right_vol; - - return 0; -} - -int daca_leave_sleep(void) -{ - if (!daca_client) - return -1; - - /* Do a short sleep, just to make sure I2C bus is awake and paying - * attention to us - */ - msleep(20); - /* Write the sample rate reg the value it needs */ - i2c_smbus_write_byte_data(daca_client, 1, 8); - daca_set_volume(cur_left_vol >> 5, cur_right_vol >> 5); - /* Another short delay, just to make sure the other I2C bus writes - * have taken... - */ - msleep(20); - /* Write the global config reg - invert right power amp, - * DAC on, use 5-volt mode */ - i2c_smbus_write_byte_data(daca_client, 3, 0x45); - - return 0; -} - -int daca_enter_sleep(void) -{ - if (!daca_client) - return -1; - - i2c_smbus_write_byte_data(daca_client, 1, 8); - daca_set_volume(cur_left_vol >> 5, cur_right_vol >> 5); - - /* Write the global config reg - invert right power amp, - * DAC on, enter low-power mode, use 5-volt mode - */ - i2c_smbus_write_byte_data(daca_client, 3, 0x65); - - return 0; -} - -static int daca_attach_adapter(struct i2c_adapter *adapter) -{ - if (!strncmp(adapter->name, "mac-io", 6)) - daca_detect_client(adapter, 0x4d); - return 0; -} - -static int daca_init_client(struct i2c_client * new_client) -{ - /* - * Probe is not working with the current i2c-keywest - * driver. We try to use addr 0x4d on each adapters - * instead, by setting the format register. - * - * FIXME: I'm sure that can be obtained from the - * device-tree. --BenH. - */ - - /* Write the global config reg - invert right power amp, - * DAC on, use 5-volt mode - */ - if (i2c_smbus_write_byte_data(new_client, 3, 0x45)) - return -1; - - i2c_smbus_write_byte_data(new_client, 1, 8); - daca_client = new_client; - daca_set_volume(15000, 15000); - - return 0; -} - -static int daca_detect_client(struct i2c_adapter *adapter, int address) -{ - const char *client_name = "DAC 3550A Digital Equalizer"; - struct i2c_client *new_client; - int rc = -ENODEV; - - new_client = kzalloc(sizeof(*new_client), GFP_KERNEL); - if (!new_client) - return -ENOMEM; - - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &daca_driver; - new_client->flags = 0; - strcpy(new_client->name, client_name); - - if (daca_init_client(new_client)) - goto bail; - - /* Tell the i2c layer a new client has arrived */ - if (i2c_attach_client(new_client)) - goto bail; - - return 0; - bail: - kfree(new_client); - return rc; -} - - -static int daca_detach_client(struct i2c_client *client) -{ - if (client == daca_client) - daca_client = NULL; - - i2c_detach_client(client); - kfree(client); - return 0; -} - -void daca_cleanup(void) -{ - i2c_del_driver(&daca_driver); -} - -int daca_init(void) -{ - printk("dac3550a driver version %s (%s)\n",DACA_VERSION,DACA_DATE); - return i2c_add_driver(&daca_driver); -} diff --git a/sound/oss/dmasound/dmasound.h b/sound/oss/dmasound/dmasound.h index 25dd5a318eb4..d978b0096564 100644 --- a/sound/oss/dmasound/dmasound.h +++ b/sound/oss/dmasound/dmasound.h @@ -59,7 +59,6 @@ static inline int ioctl_return(int __user *addr, int value) */ #undef HAS_8BIT_TABLES -#undef HAS_RECORD #if defined(CONFIG_DMASOUND_ATARI) || defined(CONFIG_DMASOUND_ATARI_MODULE) ||\ defined(CONFIG_DMASOUND_PAULA) || defined(CONFIG_DMASOUND_PAULA_MODULE) ||\ @@ -83,10 +82,6 @@ static inline int ioctl_return(int __user *addr, int value) #define DEFAULT_N_BUFFERS 4 #define DEFAULT_BUFF_SIZE (1<<15) -#if defined(CONFIG_DMASOUND_PMAC) || defined(CONFIG_DMASOUND_PMAC_MODULE) -#define HAS_RECORD -#endif - /* * Initialization */ @@ -168,9 +163,6 @@ struct sound_settings { SETTINGS soft; /* software settings */ SETTINGS dsp; /* /dev/dsp default settings */ TRANS *trans_write; /* supported translations */ -#ifdef HAS_RECORD - TRANS *trans_read; /* supported translations */ -#endif int volume_left; /* volume (range is machine dependent) */ int volume_right; int bass; /* tone (range is machine dependent) */ @@ -253,11 +245,6 @@ struct sound_queue { extern struct sound_queue dmasound_write_sq; #define write_sq dmasound_write_sq -#ifdef HAS_RECORD -extern struct sound_queue dmasound_read_sq; -#define read_sq dmasound_read_sq -#endif - extern int dmasound_catchRadius; #define catchRadius dmasound_catchRadius diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c deleted file mode 100644 index 8f6388004f44..000000000000 --- a/sound/oss/dmasound/dmasound_awacs.c +++ /dev/null @@ -1,3215 +0,0 @@ -/* - * linux/sound/oss/dmasound/dmasound_awacs.c - * - * PowerMac `AWACS' and `Burgundy' DMA Sound Driver - * with some limited support for DACA & Tumbler - * - * See linux/sound/oss/dmasound/dmasound_core.c for copyright and - * history prior to 2001/01/26. - * - * 26/01/2001 ed 0.1 Iain Sandoe - * - added version info. - * - moved dbdma command buffer allocation to PMacXXXSqSetup() - * - fixed up beep dbdma cmd buffers - * - * 08/02/2001 [0.2] - * - make SNDCTL_DSP_GETFMTS return the correct info for the h/w - * - move soft format translations to a separate file - * - [0.3] make SNDCTL_DSP_GETCAPS return correct info. - * - [0.4] more informative machine name strings. - * - [0.5] - * - record changes. - * - made the default_hard/soft entries. - * 04/04/2001 [0.6] - * - minor correction to bit assignments in awacs_defs.h - * - incorporate mixer changes from 2.2.x back-port. - * - take out passthru as a rec input (it isn't). - * - make Input Gain slider work the 'right way up'. - * - try to make the mixer sliders more logical - so now the - * input selectors are just two-state (>50% == ON) and the - * Input Gain slider handles the rest of the gain issues. - * - try to pick slider representations that most closely match - * the actual use - e.g. IGain for input gain... - * - first stab at over/under-run detection. - * - minor cosmetic changes to IRQ identification. - * - fix bug where rates > max would be reported as supported. - * - first stab at over/under-run detection. - * - make use of i2c for mixer settings conditional on perch - * rather than cuda (some machines without perch have cuda). - * - fix bug where TX stops when dbdma status comes up "DEAD" - * so far only reported on PowerComputing clones ... but. - * - put in AWACS/Screamer register write timeouts. - * - part way to partitioning the init() stuff - * - first pass at 'tumbler' stuff (not support - just an attempt - * to allow the driver to load on new G4s). - * 01/02/2002 [0.7] - BenH - * - all sort of minor bits went in since the latest update, I - * bumped the version number for that reason - * - * 07/26/2002 [0.8] - BenH - * - More minor bits since last changelog (I should be more careful - * with those) - * - Support for snapper & better tumbler integration by Toby Sargeant - * - Headphone detect for scremer by Julien Blache - * - More tumbler fixed by Andreas Schwab - * 11/29/2003 [0.8.1] - Renzo Davoli (King Enzo) - * - Support for Snapper line in - * - snapper input resampling (for rates < 44100) - * - software line gain control - */ - -/* GENERAL FIXME/TODO: check that the assumptions about what is written to - mac-io is valid for DACA & Tumbler. - - This driver is in bad need of a rewrite. The dbdma code has to be split, - some proper device-tree parsing code has to be written, etc... -*/ - -#include <linux/types.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/soundcard.h> -#include <linux/adb.h> -#include <linux/nvram.h> -#include <linux/tty.h> -#include <linux/vt_kern.h> -#include <linux/spinlock.h> -#include <linux/kmod.h> -#include <linux/interrupt.h> -#include <linux/input.h> -#include <linux/mutex.h> -#ifdef CONFIG_ADB_CUDA -#include <linux/cuda.h> -#endif -#ifdef CONFIG_ADB_PMU -#include <linux/pmu.h> -#endif - -#include <asm/uaccess.h> -#include <asm/prom.h> -#include <asm/machdep.h> -#include <asm/io.h> -#include <asm/dbdma.h> -#include <asm/pmac_feature.h> -#include <asm/irq.h> -#include <asm/nvram.h> - -#include "awacs_defs.h" -#include "dmasound.h" -#include "tas3001c.h" -#include "tas3004.h" -#include "tas_common.h" - -#define DMASOUND_AWACS_REVISION 0 -#define DMASOUND_AWACS_EDITION 7 - -#define AWACS_SNAPPER 110 /* fake revision # for snapper */ -#define AWACS_BURGUNDY 100 /* fake revision # for burgundy */ -#define AWACS_TUMBLER 90 /* fake revision # for tumbler */ -#define AWACS_DACA 80 /* fake revision # for daca (ibook) */ -#define AWACS_AWACS 2 /* holding revision for AWACS */ -#define AWACS_SCREAMER 3 /* holding revision for Screamer */ -/* - * Interrupt numbers and addresses, & info obtained from the device tree. - */ -static int awacs_irq, awacs_tx_irq, awacs_rx_irq; -static volatile struct awacs_regs __iomem *awacs; -static volatile u32 __iomem *i2s; -static volatile struct dbdma_regs __iomem *awacs_txdma, *awacs_rxdma; -static int awacs_rate_index; -static int awacs_subframe; -static struct device_node* awacs_node; -static struct device_node* i2s_node; -static struct resource awacs_rsrc[3]; - -static char awacs_name[64]; -static int awacs_revision; -static int awacs_sleeping; -static DEFINE_MUTEX(dmasound_mutex); - -static int sound_device_id; /* exists after iMac revA */ -static int hw_can_byteswap = 1 ; /* most pmac sound h/w can */ - -/* model info */ -/* To be replaced with better interaction with pmac_feature.c */ -static int is_pbook_3X00; -static int is_pbook_g3; - -/* expansion info */ -static int has_perch; -static int has_ziva; - -/* for earlier powerbooks which need fiddling with mac-io to enable - * cd etc. -*/ -static unsigned char __iomem *latch_base; -static unsigned char __iomem *macio_base; - -/* - * Space for the DBDMA command blocks. - */ -static void *awacs_tx_cmd_space; -static volatile struct dbdma_cmd *awacs_tx_cmds; -static int number_of_tx_cmd_buffers; - -static void *awacs_rx_cmd_space; -static volatile struct dbdma_cmd *awacs_rx_cmds; -static int number_of_rx_cmd_buffers; - -/* - * Cached values of AWACS registers (we can't read them). - * Except on the burgundy (and screamer). XXX - */ - -int awacs_reg[8]; -int awacs_reg1_save; - -/* tracking values for the mixer contents -*/ - -static int spk_vol; -static int line_vol; -static int passthru_vol; - -static int ip_gain; /* mic preamp settings */ -static int rec_lev = 0x4545 ; /* default CD gain 69 % */ -static int mic_lev; -static int cd_lev = 0x6363 ; /* 99 % */ -static int line_lev; - -static int hdp_connected; - -/* - * 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, -}; - -/* beep support */ -#define BEEP_SRATE 22050 /* 22050 Hz sample rate */ -#define BEEP_BUFLEN 512 -#define BEEP_VOLUME 15 /* 0 - 100 */ - -static int beep_vol = BEEP_VOLUME; -static int beep_playing; -static int awacs_beep_state; -static short *beep_buf; -static void *beep_dbdma_cmd_space; -static volatile struct dbdma_cmd *beep_dbdma_cmd; - -/* Burgundy functions */ -static void awacs_burgundy_wcw(unsigned addr,unsigned newval); -static unsigned awacs_burgundy_rcw(unsigned addr); -static void awacs_burgundy_write_volume(unsigned address, int volume); -static int awacs_burgundy_read_volume(unsigned address); -static void awacs_burgundy_write_mvolume(unsigned address, int volume); -static int awacs_burgundy_read_mvolume(unsigned address); - -/* we will allocate a single 'emergency' dbdma cmd block to use if the - tx status comes up "DEAD". This happens on some PowerComputing Pmac - clones, either owing to a bug in dbdma or some interaction between - IDE and sound. However, this measure would deal with DEAD status if - if appeared elsewhere. - - for the sake of memory efficiency we'll allocate this cmd as part of - the beep cmd stuff. -*/ - -static volatile struct dbdma_cmd *emergency_dbdma_cmd; - -#ifdef CONFIG_PM -/* - * Stuff for restoring after a sleep. - */ -static void awacs_sleep_notify(struct pmu_sleep_notifier *self, int when); -struct pmu_sleep_notifier awacs_sleep_notifier = { - awacs_sleep_notify, SLEEP_LEVEL_SOUND, -}; -#endif /* CONFIG_PM */ - -/* for (soft) sample rate translations */ -int expand_bal; /* Balance factor for expanding (not volume!) */ -int expand_read_bal; /* Balance factor for expanding reads (not volume!) */ - -/*** Low level stuff *********************************************************/ - -static void *PMacAlloc(unsigned int size, gfp_t flags); -static void PMacFree(void *ptr, unsigned int size); -static int PMacIrqInit(void); -#ifdef MODULE -static void PMacIrqCleanup(void); -#endif -static void PMacSilence(void); -static void PMacInit(void); -static int PMacSetFormat(int format); -static int PMacSetVolume(int volume); -static void PMacPlay(void); -static void PMacRecord(void); -static irqreturn_t pmac_awacs_tx_intr(int irq, void *devid); -static irqreturn_t pmac_awacs_rx_intr(int irq, void *devid); -static irqreturn_t pmac_awacs_intr(int irq, void *devid); -static void awacs_write(int val); -static int awacs_get_volume(int reg, int lshift); -static int awacs_volume_setter(int volume, int n, int mute, int lshift); - - -/*** Mid level stuff **********************************************************/ - -static int PMacMixerIoctl(u_int cmd, u_long arg); -static int PMacWriteSqSetup(void); -static int PMacReadSqSetup(void); -static void PMacAbortRead(void); - -extern TRANS transAwacsNormal ; -extern TRANS transAwacsExpand ; -extern TRANS transAwacsNormalRead ; -extern TRANS transAwacsExpandRead ; - -extern int daca_init(void); -extern void daca_cleanup(void); -extern int daca_set_volume(uint left_vol, uint right_vol); -extern void daca_get_volume(uint * left_vol, uint *right_vol); -extern int daca_enter_sleep(void); -extern int daca_leave_sleep(void); - -#define TRY_LOCK() \ - if ((rc = mutex_lock_interruptible(&dmasound_mutex)) != 0) \ - return rc; -#define LOCK() mutex_lock(&dmasound_mutex); - -#define UNLOCK() mutex_unlock(&dmasound_mutex); - -/* We use different versions that the ones provided in dmasound.h - * - * FIXME: Use different names ;) - */ -#undef IOCTL_IN -#undef IOCTL_OUT - -#define IOCTL_IN(arg, ret) \ - rc = get_user(ret, (int __user *)(arg)); \ - if (rc) break; -#define IOCTL_OUT(arg, ret) \ - ioctl_return2((int __user *)(arg), ret) - -static inline int ioctl_return2(int __user *addr, int value) -{ - return value < 0 ? value : put_user(value, addr); -} - - -/*** AE - TUMBLER / SNAPPER START ************************************************/ - - -int gpio_audio_reset, gpio_audio_reset_pol; -int gpio_amp_mute, gpio_amp_mute_pol; -int gpio_headphone_mute, gpio_headphone_mute_pol; -int gpio_headphone_detect, gpio_headphone_detect_pol; -int gpio_headphone_irq; - -int -setup_audio_gpio(const char *name, const char* compatible, int *gpio_addr, int* gpio_pol) -{ - struct device_node *gpiop; - struct device_node *np; - const u32* pp; - int ret = -ENODEV; - - gpiop = of_find_node_by_name(NULL, "gpio"); - if (!gpiop) - goto done; - - np = of_get_next_child(gpiop, NULL); - while(np != 0) { - if (name) { - const char *property = - of_get_property(np,"audio-gpio",NULL); - if (property != 0 && strcmp(property,name) == 0) - break; - } else if (compatible && of_device_is_compatible(np, compatible)) - break; - np = of_get_next_child(gpiop, np); - } - if (!np) - goto done; - pp = of_get_property(np, "AAPL,address", NULL); - if (!pp) - goto done; - *gpio_addr = (*pp) & 0x0000ffff; - pp = of_get_property(np, "audio-gpio-active-state", NULL); - if (pp) - *gpio_pol = *pp; - else - *gpio_pol = 1; - ret = irq_of_parse_and_map(np, 0); -done: - of_node_put(np); - of_node_put(gpiop); - return ret; -} - -static inline void -write_audio_gpio(int gpio_addr, int data) -{ - if (!gpio_addr) - return; - pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, gpio_addr, data ? 0x05 : 0x04); -} - -static inline int -read_audio_gpio(int gpio_addr) -{ - if (!gpio_addr) - return 0; - return ((pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio_addr, 0) & 0x02) !=0); -} - -/* - * Headphone interrupt via GPIO (Tumbler, Snapper, DACA) - */ -static irqreturn_t -headphone_intr(int irq, void *devid) -{ - unsigned long flags; - - spin_lock_irqsave(&dmasound.lock, flags); - if (read_audio_gpio(gpio_headphone_detect) == gpio_headphone_detect_pol) { - printk(KERN_INFO "Audio jack plugged, muting speakers.\n"); - write_audio_gpio(gpio_headphone_mute, !gpio_headphone_mute_pol); - write_audio_gpio(gpio_amp_mute, gpio_amp_mute_pol); - tas_output_device_change(sound_device_id,TAS_OUTPUT_HEADPHONES,0); - } else { - printk(KERN_INFO "Audio jack unplugged, enabling speakers.\n"); - write_audio_gpio(gpio_amp_mute, !gpio_amp_mute_pol); - write_audio_gpio(gpio_headphone_mute, gpio_headphone_mute_pol); - tas_output_device_change(sound_device_id,TAS_OUTPUT_INTERNAL_SPKR,0); - } - spin_unlock_irqrestore(&dmasound.lock, flags); - return IRQ_HANDLED; -} - - -/* Initialize tumbler */ - -static int -tas_dmasound_init(void) -{ - setup_audio_gpio( - "audio-hw-reset", - NULL, - &gpio_audio_reset, - &gpio_audio_reset_pol); - setup_audio_gpio( - "amp-mute", - NULL, - &gpio_amp_mute, - &gpio_amp_mute_pol); - setup_audio_gpio("headphone-mute", - NULL, - &gpio_headphone_mute, - &gpio_headphone_mute_pol); - gpio_headphone_irq = setup_audio_gpio( - "headphone-detect", - NULL, - &gpio_headphone_detect, - &gpio_headphone_detect_pol); - /* Fix some broken OF entries in desktop machines */ - if (!gpio_headphone_irq) - gpio_headphone_irq = setup_audio_gpio( - NULL, - "keywest-gpio15", - &gpio_headphone_detect, - &gpio_headphone_detect_pol); - - write_audio_gpio(gpio_audio_reset, gpio_audio_reset_pol); - msleep(100); - write_audio_gpio(gpio_audio_reset, !gpio_audio_reset_pol); - msleep(100); - if (gpio_headphone_irq) { - if (request_irq(gpio_headphone_irq,headphone_intr,0,"Headphone detect",NULL) < 0) { - printk(KERN_ERR "tumbler: Can't request headphone interrupt\n"); - gpio_headphone_irq = 0; - } else { - u8 val; - /* Activate headphone status interrupts */ - val = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio_headphone_detect, 0); - pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, gpio_headphone_detect, val | 0x80); - /* Trigger it */ - headphone_intr(0, NULL); - } - } - if (!gpio_headphone_irq) { - /* Some machine enter this case ? */ - printk(KERN_WARNING "tumbler: Headphone detect IRQ not found, enabling all outputs !\n"); - write_audio_gpio(gpio_amp_mute, !gpio_amp_mute_pol); - write_audio_gpio(gpio_headphone_mute, !gpio_headphone_mute_pol); - } - return 0; -} - - -static int -tas_dmasound_cleanup(void) -{ - if (gpio_headphone_irq) - free_irq(gpio_headphone_irq, NULL); - return 0; -} - -/* We don't support 48k yet */ -static int tas_freqs[1] = { 44100 } ; -static int tas_freqs_ok[1] = { 1 } ; - -/* don't know what to do really - just have to leave it where - * OF left things -*/ - -static int -tas_set_frame_rate(void) -{ - if (i2s) { - out_le32(i2s + (I2S_REG_SERIAL_FORMAT >> 2), 0x41190000); - out_le32(i2s + (I2S_REG_DATAWORD_SIZES >> 2), 0x02000200); - } - dmasound.hard.speed = 44100 ; - awacs_rate_index = 0 ; - return 44100 ; -} - -static int -tas_mixer_ioctl(u_int cmd, u_long arg) -{ - int __user *argp = (int __user *)arg; - int data; - int rc; - - rc=tas_device_ioctl(cmd, arg); - if (rc != -EINVAL) { - return rc; - } - - if ((cmd & ~0xff) == MIXER_WRITE(0) && - tas_supported_mixers() & (1<<(cmd & 0xff))) { - rc = get_user(data, argp); - if (rc<0) return rc; - tas_set_mixer_level(cmd & 0xff, data); - tas_get_mixer_level(cmd & 0xff, &data); - return ioctl_return2(argp, data); - } - if ((cmd & ~0xff) == MIXER_READ(0) && - tas_supported_mixers() & (1<<(cmd & 0xff))) { - tas_get_mixer_level(cmd & 0xff, &data); - return ioctl_return2(argp, data); - } - - switch(cmd) { - case SOUND_MIXER_READ_DEVMASK: - data = tas_supported_mixers() | SOUND_MASK_SPEAKER; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_STEREODEVS: - data = tas_stereo_mixers(); - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_CAPS: - rc = IOCTL_OUT(arg, 0); - break; - case SOUND_MIXER_READ_RECMASK: - // XXX FIXME: find a way to check what is really available */ - data = SOUND_MASK_LINE | SOUND_MASK_MIC; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_RECSRC: - if (awacs_reg[0] & MASK_MUX_AUDIN) - data |= SOUND_MASK_LINE; - if (awacs_reg[0] & MASK_MUX_MIC) - data |= SOUND_MASK_MIC; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_RECSRC: - IOCTL_IN(arg, data); - data =0; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_SPEAKER: /* really bell volume */ - IOCTL_IN(arg, data); - beep_vol = data & 0xff; - /* fall through */ - case SOUND_MIXER_READ_SPEAKER: - rc = IOCTL_OUT(arg, (beep_vol<<8) | beep_vol); - break; - case SOUND_MIXER_OUTMASK: - case SOUND_MIXER_OUTSRC: - default: - rc = -EINVAL; - } - - return rc; -} - -static void __init -tas_init_frame_rates(const unsigned int *prop, unsigned int l) -{ - int i ; - if (prop) { - for (i=0; i<1; i++) - tas_freqs_ok[i] = 0; - for (l /= sizeof(int); l > 0; --l) { - unsigned int r = *prop++; - /* Apple 'Fixed' format */ - if (r >= 0x10000) - r >>= 16; - for (i = 0; i < 1; ++i) { - if (r == tas_freqs[i]) { - tas_freqs_ok[i] = 1; - break; - } - } - } - } - /* else we assume that all the rates are available */ -} - - -/*** AE - TUMBLER / SNAPPER END ************************************************/ - - - -/*** Low level stuff *********************************************************/ - -/* - * PCI PowerMac, with AWACS, Screamer, Burgundy, DACA or Tumbler and DBDMA. - */ -static void *PMacAlloc(unsigned int size, gfp_t flags) -{ - return kmalloc(size, flags); -} - -static void PMacFree(void *ptr, unsigned int size) -{ - kfree(ptr); -} - -static int __init PMacIrqInit(void) -{ - if (awacs) - if (request_irq(awacs_irq, pmac_awacs_intr, 0, "Built-in Sound misc", NULL)) - return 0; - if (request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "Built-in Sound out", NULL) - || request_irq(awacs_rx_irq, pmac_awacs_rx_intr, 0, "Built-in Sound in", NULL)) - return 0; - return 1; -} - -#ifdef MODULE -static void PMacIrqCleanup(void) -{ - /* turn off input & output dma */ - DBDMA_DO_STOP(awacs_txdma); - DBDMA_DO_STOP(awacs_rxdma); - - if (awacs) - /* disable interrupts from awacs interface */ - out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff); - - /* Switch off the sound clock */ - pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 0); - /* Make sure proper bits are set on pismo & tipb */ - if ((machine_is_compatible("PowerBook3,1") || - machine_is_compatible("PowerBook3,2")) && awacs) { - awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1; - awacs_write(MASK_ADDR1 | awacs_reg[1]); - msleep(200); - } - if (awacs) - free_irq(awacs_irq, NULL); - free_irq(awacs_tx_irq, NULL); - free_irq(awacs_rx_irq, NULL); - - if (awacs) - iounmap(awacs); - if (i2s) - iounmap(i2s); - iounmap(awacs_txdma); - iounmap(awacs_rxdma); - - release_mem_region(awacs_rsrc[0].start, - awacs_rsrc[0].end - awacs_rsrc[0].start + 1); - release_mem_region(awacs_rsrc[1].start, - awacs_rsrc[1].end - awacs_rsrc[1].start + 1); - release_mem_region(awacs_rsrc[2].start, - awacs_rsrc[2].end - awacs_rsrc[2].start + 1); - - kfree(awacs_tx_cmd_space); - kfree(awacs_rx_cmd_space); - kfree(beep_dbdma_cmd_space); - kfree(beep_buf); -#ifdef CONFIG_PM - pmu_unregister_sleep_notifier(&awacs_sleep_notifier); -#endif -} -#endif /* MODULE */ - -static void PMacSilence(void) -{ - /* turn off output dma */ - DBDMA_DO_STOP(awacs_txdma); -} - -/* don't know what to do really - just have to leave it where - * OF left things -*/ - -static int daca_set_frame_rate(void) -{ - if (i2s) { - out_le32(i2s + (I2S_REG_SERIAL_FORMAT >> 2), 0x41190000); - out_le32(i2s + (I2S_REG_DATAWORD_SIZES >> 2), 0x02000200); - } - dmasound.hard.speed = 44100 ; - awacs_rate_index = 0 ; - return 44100 ; -} - -static int awacs_freqs[8] = { - 44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350 -}; -static int awacs_freqs_ok[8] = { 1, 1, 1, 1, 1, 1, 1, 1 }; - -static int -awacs_set_frame_rate(int desired, int catch_r) -{ - int tolerance, i = 8 ; - /* - * 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. - * N.B.: burgundy awacs only works at 44100 Hz. - */ - do { - tolerance = catch_r * awacs_freqs[--i] / 100; - if (awacs_freqs_ok[i] - && dmasound.soft.speed <= awacs_freqs[i] + tolerance) - break; - } while (i > 0); - dmasound.hard.speed = awacs_freqs[i]; - awacs_rate_index = i; - - out_le32(&awacs->control, MASK_IEPC | (i << 8) | 0x11 ); - awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) | (i << 3); - awacs_write(awacs_reg[1] | MASK_ADDR1); - return dmasound.hard.speed; -} - -static int -burgundy_set_frame_rate(void) -{ - awacs_rate_index = 0 ; - awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) ; - /* XXX disable error interrupt on burgundy for now */ - out_le32(&awacs->control, MASK_IEPC | 0 | 0x11 | MASK_IEE); - return 44100 ; -} - -static int -set_frame_rate(int desired, int catch_r) -{ - switch (awacs_revision) { - case AWACS_BURGUNDY: - dmasound.hard.speed = burgundy_set_frame_rate(); - break ; - case AWACS_TUMBLER: - case AWACS_SNAPPER: - dmasound.hard.speed = tas_set_frame_rate(); - break ; - case AWACS_DACA: - dmasound.hard.speed = - daca_set_frame_rate(); - break ; - default: - dmasound.hard.speed = awacs_set_frame_rate(desired, - catch_r); - break ; - } - return dmasound.hard.speed ; -} - -static void -awacs_recalibrate(void) -{ - /* Sorry for the horrible delays... I hope to get that improved - * by making the whole PM process asynchronous in a future version - */ - msleep(750); - awacs_reg[1] |= MASK_CMUTE | MASK_AMUTE; - awacs_write(awacs_reg[1] | MASK_RECALIBRATE | MASK_ADDR1); - msleep(1000); - awacs_write(awacs_reg[1] | MASK_ADDR1); -} - -static void PMacInit(void) -{ - int tolerance; - - switch (dmasound.soft.format) { - case AFMT_S16_LE: - case AFMT_U16_LE: - if (hw_can_byteswap) - dmasound.hard.format = AFMT_S16_LE; - else - dmasound.hard.format = AFMT_S16_BE; - break; - default: - dmasound.hard.format = AFMT_S16_BE; - break; - } - dmasound.hard.stereo = 1; - dmasound.hard.size = 16; - - /* set dmasound.hard.speed - on the basis of what we want (soft) - * and the tolerance we'll allow. - */ - set_frame_rate(dmasound.soft.speed, catchRadius) ; - - tolerance = (catchRadius * dmasound.hard.speed) / 100; - if (dmasound.soft.speed >= dmasound.hard.speed - tolerance) { - dmasound.trans_write = &transAwacsNormal; - dmasound.trans_read = &transAwacsNormalRead; - } else { - dmasound.trans_write = &transAwacsExpand; - dmasound.trans_read = &transAwacsExpandRead; - } - - if (awacs) { - if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) - out_le32(&awacs->byteswap, BS_VAL); - else - out_le32(&awacs->byteswap, 0); - } - - expand_bal = -dmasound.soft.speed; - expand_read_bal = -dmasound.soft.speed; -} - -static int PMacSetFormat(int format) -{ - int size; - int req_format = format; - - switch (format) { - case AFMT_QUERY: - return dmasound.soft.format; - case AFMT_MU_LAW: - case AFMT_A_LAW: - case AFMT_U8: - case AFMT_S8: - size = 8; - break; - case AFMT_S16_LE: - if(!hw_can_byteswap) - format = AFMT_S16_BE; - case AFMT_S16_BE: - size = 16; - break; - case AFMT_U16_LE: - if(!hw_can_byteswap) - format = AFMT_U16_BE; - case AFMT_U16_BE: - size = 16; - break; - default: /* :-) */ - printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n", - format); - size = 8; - format = AFMT_U8; - } - - if (req_format == format) { - dmasound.soft.format = format; - dmasound.soft.size = size; - if (dmasound.minDev == SND_DEV_DSP) { - dmasound.dsp.format = format; - dmasound.dsp.size = size; - } - } - - return format; -} - -#define AWACS_VOLUME_TO_MASK(x) (15 - ((((x) - 1) * 15) / 99)) -#define AWACS_MASK_TO_VOLUME(y) (100 - ((y) * 99 / 15)) - -static int awacs_get_volume(int reg, int lshift) -{ - int volume; - - volume = AWACS_MASK_TO_VOLUME((reg >> lshift) & 0xf); - volume |= AWACS_MASK_TO_VOLUME(reg & 0xf) << 8; - return volume; -} - -static int awacs_volume_setter(int volume, int n, int mute, int lshift) -{ - int r1, rn; - - if (mute && volume == 0) { - r1 = awacs_reg[1] | mute; - } else { - r1 = awacs_reg[1] & ~mute; - rn = awacs_reg[n] & ~(0xf | (0xf << lshift)); - rn |= ((AWACS_VOLUME_TO_MASK(volume & 0xff) & 0xf) << lshift); - rn |= AWACS_VOLUME_TO_MASK((volume >> 8) & 0xff) & 0xf; - awacs_reg[n] = rn; - awacs_write((n << 12) | rn); - volume = awacs_get_volume(rn, lshift); - } - if (r1 != awacs_reg[1]) { - awacs_reg[1] = r1; - awacs_write(r1 | MASK_ADDR1); - } - return volume; -} - -static int PMacSetVolume(int volume) -{ - printk(KERN_WARNING "Bogus call to PMacSetVolume !\n"); - return 0; -} - -static void awacs_setup_for_beep(int speed) -{ - out_le32(&awacs->control, - (in_le32(&awacs->control) & ~0x1f00) - | ((speed > 0 ? speed : awacs_rate_index) << 8)); - - if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE) && speed == -1) - out_le32(&awacs->byteswap, BS_VAL); - else - out_le32(&awacs->byteswap, 0); -} - -/* CHECK: how much of this *really* needs IRQs masked? */ -static void __PMacPlay(void) -{ - volatile struct dbdma_cmd *cp; - int next_frg, count; - - count = 300 ; /* > two cycles at the lowest sample rate */ - - /* what we want to send next */ - next_frg = (write_sq.front + write_sq.active) % write_sq.max_count; - - if (awacs_beep_state) { - /* sound takes precedence over beeps */ - /* stop the dma channel */ - out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); - while ( (in_le32(&awacs_txdma->status) & RUN) && count--) - udelay(1); - if (awacs) - awacs_setup_for_beep(-1); - out_le32(&awacs_txdma->cmdptr, - virt_to_bus(&(awacs_tx_cmds[next_frg]))); - - beep_playing = 0; - awacs_beep_state = 0; - } - /* this won't allow more than two frags to be in the output queue at - once. (or one, if the max frags is 2 - because count can't exceed - 2 in that case) - */ - while (write_sq.active < 2 && write_sq.active < write_sq.count) { - count = (write_sq.count == write_sq.active + 1) ? - write_sq.rear_size:write_sq.block_size ; - if (count < write_sq.block_size) { - if (!write_sq.syncing) /* last block not yet filled,*/ - break; /* and we're not syncing or POST-ed */ - else { - /* pretend the block is full to force a new - block to be started on the next write */ - write_sq.rear_size = write_sq.block_size ; - write_sq.syncing &= ~2 ; /* clear POST */ - } - } - cp = &awacs_tx_cmds[next_frg]; - st_le16(&cp->req_count, count); - st_le16(&cp->xfer_status, 0); - st_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS); - /* put a STOP at the end of the queue - but only if we have - space for it. This means that, if we under-run and we only - have two fragments, we might re-play sound from an existing - queued frag. I guess the solution to that is not to set two - frags if you are likely to under-run... - */ - if (write_sq.count < write_sq.max_count) { - if (++next_frg >= write_sq.max_count) - next_frg = 0 ; /* wrap */ - /* if we get here then we've underrun so we will stop*/ - st_le16(&awacs_tx_cmds[next_frg].command, DBDMA_STOP); - } - /* set the dbdma controller going, if it is not already */ - if (write_sq.active == 0) - out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp)); - (void)in_le32(&awacs_txdma->status); - out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE)); - ++write_sq.active; - } -} - -static void PMacPlay(void) -{ - LOCK(); - if (!awacs_sleeping) { - unsigned long flags; - - spin_lock_irqsave(&dmasound.lock, flags); - __PMacPlay(); - spin_unlock_irqrestore(&dmasound.lock, flags); - } - UNLOCK(); -} - -static void PMacRecord(void) -{ - unsigned long flags; - - if (read_sq.active) - return; - - spin_lock_irqsave(&dmasound.lock, flags); - - /* This is all we have to do......Just start it up. - */ - out_le32(&awacs_rxdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE)); - read_sq.active = 1; - - spin_unlock_irqrestore(&dmasound.lock, flags); -} - -/* if the TX status comes up "DEAD" - reported on some Power Computing machines - we need to re-start the dbdma - but from a different physical start address - and with a different transfer length. It would get very messy to do this - with the normal dbdma_cmd blocks - we would have to re-write the buffer start - addresses each time. So, we will keep a single dbdma_cmd block which can be - fiddled with. - When DEAD status is first reported the content of the faulted dbdma block is - copied into the emergency buffer and we note that the buffer is in use. - we then bump the start physical address by the amount that was successfully - output before it died. - On any subsequent DEAD result we just do the bump-ups (we know that we are - already using the emergency dbdma_cmd). - CHECK: this just tries to "do it". It is possible that we should abandon - xfers when the number of residual bytes gets below a certain value - I can - see that this might cause a loop-forever if too small a transfer causes - DEAD status. However this is a TODO for now - we'll see what gets reported. - When we get a successful transfer result with the emergency buffer we just - pretend that it completed using the original dmdma_cmd and carry on. The - 'next_cmd' field will already point back to the original loop of blocks. -*/ - -static irqreturn_t -pmac_awacs_tx_intr(int irq, void *devid) -{ - int i = write_sq.front; - int stat; - int i_nowrap = write_sq.front; - volatile struct dbdma_cmd *cp; - /* != 0 when we are dealing with a DEAD xfer */ - static int emergency_in_use; - - spin_lock(&dmasound.lock); - while (write_sq.active > 0) { /* we expect to have done something*/ - if (emergency_in_use) /* we are dealing with DEAD xfer */ - cp = emergency_dbdma_cmd ; - else - cp = &awacs_tx_cmds[i]; - stat = ld_le16(&cp->xfer_status); - if (stat & DEAD) { - unsigned short req, res ; - unsigned int phy ; -#ifdef DEBUG_DMASOUND -printk("dmasound_pmac: tx-irq: xfer died - patching it up...\n") ; -#endif - /* to clear DEAD status we must first clear RUN - set it to quiescent to be on the safe side */ - (void)in_le32(&awacs_txdma->status); - out_le32(&awacs_txdma->control, - (RUN|PAUSE|FLUSH|WAKE) << 16); - write_sq.died++ ; - if (!emergency_in_use) { /* new problem */ - memcpy((void *)emergency_dbdma_cmd, (void *)cp, - sizeof(struct dbdma_cmd)); - emergency_in_use = 1; - cp = emergency_dbdma_cmd; - } - /* now bump the values to reflect the amount - we haven't yet shifted */ - req = ld_le16(&cp->req_count); - res = ld_le16(&cp->res_count); - phy = ld_le32(&cp->phy_addr); - phy += (req - res); - st_le16(&cp->req_count, res); - st_le16(&cp->res_count, 0); - st_le16(&cp->xfer_status, 0); - st_le32(&cp->phy_addr, phy); - st_le32(&cp->cmd_dep, virt_to_bus(&awacs_tx_cmds[(i+1)%write_sq.max_count])); - st_le16(&cp->command, OUTPUT_MORE | BR_ALWAYS | INTR_ALWAYS); - - /* point at our patched up command block */ - out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp)); - /* we must re-start the controller */ - (void)in_le32(&awacs_txdma->status); - /* should complete clearing the DEAD status */ - out_le32(&awacs_txdma->control, - ((RUN|WAKE) << 16) + (RUN|WAKE)); - break; /* this block is still going */ - } - if ((stat & ACTIVE) == 0) - break; /* this frame is still going */ - if (emergency_in_use) - emergency_in_use = 0 ; /* done that */ - --write_sq.count; - --write_sq.active; - i_nowrap++; - if (++i >= write_sq.max_count) - i = 0; - } - - /* if we stopped and we were not sync-ing - then we under-ran */ - if( write_sq.syncing == 0 ){ - stat = in_le32(&awacs_txdma->status) ; - /* we hit the dbdma_stop */ - if( (stat & ACTIVE) == 0 ) write_sq.xruns++ ; - } - - /* if we used some data up then wake the writer to supply some more*/ - if (i_nowrap != write_sq.front) - WAKE_UP(write_sq.action_queue); - write_sq.front = i; - - /* but make sure we funnel what we've already got */\ - if (!awacs_sleeping) - __PMacPlay(); - - /* make the wake-on-empty conditional on syncing */ - if (!write_sq.active && (write_sq.syncing & 1)) - WAKE_UP(write_sq.sync_queue); /* any time we're empty */ - spin_unlock(&dmasound.lock); - return IRQ_HANDLED; -} - - -static irqreturn_t -pmac_awacs_rx_intr(int irq, void *devid) -{ - int stat ; - /* For some reason on my PowerBook G3, I get one interrupt - * when the interrupt vector is installed (like something is - * pending). This happens before the dbdma is initialized by - * us, so I just check the command pointer and if it is zero, - * just blow it off. - */ - if (in_le32(&awacs_rxdma->cmdptr) == 0) - return IRQ_HANDLED; - - /* We also want to blow 'em off when shutting down. - */ - if (read_sq.active == 0) - return IRQ_HANDLED; - - spin_lock(&dmasound.lock); - /* 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 ((stat=awacs_rx_cmds[read_sq.rear].xfer_status)) { - - /* if we got a "DEAD" status then just log it for now. - and try to restart dma. - TODO: figure out how best to fix it up - */ - if (stat & DEAD){ -#ifdef DEBUG_DMASOUND -printk("dmasound_pmac: rx-irq: DIED - attempting resurection\n"); -#endif - /* to clear DEAD status we must first clear RUN - set it to quiescent to be on the safe side */ - (void)in_le32(&awacs_txdma->status); - out_le32(&awacs_txdma->control, - (RUN|PAUSE|FLUSH|WAKE) << 16); - awacs_rx_cmds[read_sq.rear].xfer_status = 0; - awacs_rx_cmds[read_sq.rear].res_count = 0; - read_sq.died++ ; - (void)in_le32(&awacs_txdma->status); - /* re-start the same block */ - out_le32(&awacs_rxdma->cmdptr, - virt_to_bus(&awacs_rx_cmds[read_sq.rear])); - /* we must re-start the controller */ - (void)in_le32(&awacs_rxdma->status); - /* should complete clearing the DEAD status */ - out_le32(&awacs_rxdma->control, - ((RUN|WAKE) << 16) + (RUN|WAKE)); - spin_unlock(&dmasound.lock); - return IRQ_HANDLED; /* try this block again */ - } - /* Clear status and move on to next buffer. - */ - awacs_rx_cmds[read_sq.rear].xfer_status = 0; - 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++; - read_sq.xruns++ ; /* we overan */ - if (read_sq.front >= read_sq.max_active) - read_sq.front = 0; - } - } - - WAKE_UP(read_sq.action_queue); - spin_unlock(&dmasound.lock); - return IRQ_HANDLED; -} - - -static irqreturn_t -pmac_awacs_intr(int irq, void *devid) -{ - int ctrl; - int status; - int r1; - - spin_lock(&dmasound.lock); - ctrl = in_le32(&awacs->control); - status = in_le32(&awacs->codec_stat); - - if (ctrl & MASK_PORTCHG) { - /* tested on Screamer, should work on others too */ - if (awacs_revision == AWACS_SCREAMER) { - if (((status & MASK_HDPCONN) >> 3) && (hdp_connected == 0)) { - hdp_connected = 1; - - r1 = awacs_reg[1] | MASK_SPKMUTE; - awacs_reg[1] = r1; - awacs_write(r1 | MASK_ADDR_MUTE); - } else if (((status & MASK_HDPCONN) >> 3 == 0) && (hdp_connected == 1)) { - hdp_connected = 0; - - r1 = awacs_reg[1] & ~MASK_SPKMUTE; - awacs_reg[1] = r1; - awacs_write(r1 | MASK_ADDR_MUTE); - } - } - } - if (ctrl & MASK_CNTLERR) { - int err = (in_le32(&awacs->codec_stat) & MASK_ERRCODE) >> 16; - /* CHECK: we just swallow burgundy errors at the moment..*/ - if (err != 0 && awacs_revision != AWACS_BURGUNDY) - printk(KERN_ERR "dmasound_pmac: error %x\n", err); - } - /* Writing 1s to the CNTLERR and PORTCHG bits clears them... */ - out_le32(&awacs->control, ctrl); - spin_unlock(&dmasound.lock); - return IRQ_HANDLED; -} - -static void -awacs_write(int val) -{ - int count = 300 ; - if (awacs_revision >= AWACS_DACA || !awacs) - return ; - - while ((in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) && count--) - udelay(1) ; /* timeout is > 2 samples at lowest rate */ - out_le32(&awacs->codec_ctrl, val | (awacs_subframe << 22)); - (void)in_le32(&awacs->byteswap); -} - -/* this is called when the beep timer expires... it will be called even - if the beep has been overidden by other sound output. -*/ -static void awacs_nosound(unsigned long xx) -{ - unsigned long flags; - int count = 600 ; /* > four samples at lowest rate */ - - spin_lock_irqsave(&dmasound.lock, flags); - if (beep_playing) { - st_le16(&beep_dbdma_cmd->command, DBDMA_STOP); - out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); - while ((in_le32(&awacs_txdma->status) & RUN) && count--) - udelay(1); - if (awacs) - awacs_setup_for_beep(-1); - beep_playing = 0; - } - spin_unlock_irqrestore(&dmasound.lock, flags); -} - -/* - * We generate the beep with a single dbdma command that loops a buffer - * forever - without generating interrupts. - * - * So, to stop it you have to stop dma output as per awacs_nosound. - */ -static int awacs_beep_event(struct input_dev *dev, unsigned int type, - unsigned int code, int hz) -{ - unsigned long flags; - int beep_speed = 0; - int srate; - 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 (type != EV_SND) - return -1; - switch (code) { - case SND_BELL: - if (hz) - hz = 1000; - break; - case SND_TONE: - break; - default: - return -1; - } - - if (beep_buf == NULL) - return -1; - - /* quick-hack fix for DACA, Burgundy & Tumbler */ - - if (awacs_revision >= AWACS_DACA){ - srate = 44100 ; - } else { - for (i = 0; i < 8 && awacs_freqs[i] >= BEEP_SRATE; ++i) - if (awacs_freqs_ok[i]) - beep_speed = i; - srate = awacs_freqs[beep_speed]; - } - - if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) { - /* cancel beep currently playing */ - awacs_nosound(0); - return 0; - } - - spin_lock_irqsave(&dmasound.lock, flags); - if (beep_playing || write_sq.active || beep_buf == NULL) { - spin_unlock_irqrestore(&dmasound.lock, flags); - return -1; /* too hard, sorry :-( */ - } - beep_playing = 1; - st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS); - spin_unlock_irqrestore(&dmasound.lock, flags); - - if (hz == beep_hz_cache && beep_vol == 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_vol; - j = (j + f) & 0xffff; - } - beep_hz_cache = hz; - beep_volume_cache = beep_vol; - beep_nsamples_cache = nsamples; - } - - 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(&dmasound.lock, flags); - if (beep_playing) { /* i.e. haven't been terminated already */ - int count = 300 ; - out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16); - while ((in_le32(&awacs_txdma->status) & RUN) && count--) - udelay(1); /* timeout > 2 samples at lowest rate*/ - if (awacs) - awacs_setup_for_beep(beep_speed); - out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); - (void)in_le32(&awacs_txdma->status); - out_le32(&awacs_txdma->control, RUN | (RUN << 16)); - } - spin_unlock_irqrestore(&dmasound.lock, flags); - - return 0; -} - -/* used in init and for wake-up */ - -static void -load_awacs(void) -{ - awacs_write(awacs_reg[0] + MASK_ADDR0); - awacs_write(awacs_reg[1] + MASK_ADDR1); - awacs_write(awacs_reg[2] + MASK_ADDR2); - awacs_write(awacs_reg[4] + MASK_ADDR4); - - if (awacs_revision == AWACS_SCREAMER) { - awacs_write(awacs_reg[5] + MASK_ADDR5); - msleep(100); - awacs_write(awacs_reg[6] + MASK_ADDR6); - msleep(2); - awacs_write(awacs_reg[1] + MASK_ADDR1); - awacs_write(awacs_reg[7] + MASK_ADDR7); - } - if (awacs) { - if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) - out_le32(&awacs->byteswap, BS_VAL); - else - out_le32(&awacs->byteswap, 0); - } -} - -#ifdef CONFIG_PM -/* - * Save state when going to sleep, restore it afterwards. - */ -/* FIXME: sort out disabling/re-enabling of read stuff as well */ -static void awacs_sleep_notify(struct pmu_sleep_notifier *self, int when) -{ - unsigned long flags; - - switch (when) { - case PBOOK_SLEEP_NOW: - LOCK(); - awacs_sleeping = 1; - /* Tell the rest of the driver we are now going to sleep */ - mb(); - if (awacs_revision == AWACS_SCREAMER || - awacs_revision == AWACS_AWACS) { - awacs_reg1_save = awacs_reg[1]; - awacs_reg[1] |= MASK_AMUTE | MASK_CMUTE; - awacs_write(MASK_ADDR1 | awacs_reg[1]); - } - - PMacSilence(); - /* stop rx - if going - a bit of a daft user... but */ - out_le32(&awacs_rxdma->control, (RUN|WAKE|FLUSH << 16)); - /* deny interrupts */ - if (awacs) - disable_irq(awacs_irq); - disable_irq(awacs_tx_irq); - disable_irq(awacs_rx_irq); - /* Chip specific sleep code */ - switch (awacs_revision) { - case AWACS_TUMBLER: - case AWACS_SNAPPER: - write_audio_gpio(gpio_headphone_mute, gpio_headphone_mute_pol); - write_audio_gpio(gpio_amp_mute, gpio_amp_mute_pol); - tas_enter_sleep(); - write_audio_gpio(gpio_audio_reset, gpio_audio_reset_pol); - break ; - case AWACS_DACA: - daca_enter_sleep(); - break ; - case AWACS_BURGUNDY: - break ; - case AWACS_SCREAMER: - case AWACS_AWACS: - default: - out_le32(&awacs->control, 0x11) ; - break ; - } - /* Disable sound clock */ - pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 0); - /* According to Darwin, we do that after turning off the sound - * chip clock. All this will have to be cleaned up once we properly - * parse the OF sound-objects - */ - if ((machine_is_compatible("PowerBook3,1") || - machine_is_compatible("PowerBook3,2")) && awacs) { - awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1; - awacs_write(MASK_ADDR1 | awacs_reg[1]); - msleep(200); - } - break; - case PBOOK_WAKE: - /* Enable sound clock */ - pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 1); - if ((machine_is_compatible("PowerBook3,1") || - machine_is_compatible("PowerBook3,2")) && awacs) { - msleep(100); - awacs_reg[1] &= ~(MASK_PAROUT0 | MASK_PAROUT1); - awacs_write(MASK_ADDR1 | awacs_reg[1]); - msleep(300); - } else - msleep(1000); - /* restore settings */ - switch (awacs_revision) { - case AWACS_TUMBLER: - case AWACS_SNAPPER: - write_audio_gpio(gpio_headphone_mute, gpio_headphone_mute_pol); - write_audio_gpio(gpio_amp_mute, gpio_amp_mute_pol); - write_audio_gpio(gpio_audio_reset, gpio_audio_reset_pol); - msleep(100); - write_audio_gpio(gpio_audio_reset, !gpio_audio_reset_pol); - msleep(150); - tas_leave_sleep(); /* Stub for now */ - headphone_intr(0, NULL); - break; - case AWACS_DACA: - msleep(10); /* Check this !!! */ - daca_leave_sleep(); - break ; /* dont know how yet */ - case AWACS_BURGUNDY: - break ; - case AWACS_SCREAMER: - case AWACS_AWACS: - default: - load_awacs() ; - break ; - } - /* Recalibrate chip */ - if (awacs_revision == AWACS_SCREAMER && awacs) - awacs_recalibrate(); - /* Make sure dma is stopped */ - PMacSilence(); - if (awacs) - enable_irq(awacs_irq); - enable_irq(awacs_tx_irq); - enable_irq(awacs_rx_irq); - if (awacs) { - /* OK, allow ints back again */ - out_le32(&awacs->control, MASK_IEPC - | (awacs_rate_index << 8) | 0x11 - | (awacs_revision < AWACS_DACA ? MASK_IEE: 0)); - } - if (macio_base && is_pbook_g3) { - /* FIXME: should restore the setup we had...*/ - out_8(macio_base + 0x37, 3); - } else if (is_pbook_3X00) { - in_8(latch_base + 0x190); - } - /* Remove mute */ - if (awacs_revision == AWACS_SCREAMER || - awacs_revision == AWACS_AWACS) { - awacs_reg[1] = awacs_reg1_save; - awacs_write(MASK_ADDR1 | awacs_reg[1]); - } - awacs_sleeping = 0; - /* Resume pending sounds. */ - /* we don't try to restart input... */ - spin_lock_irqsave(&dmasound.lock, flags); - __PMacPlay(); - spin_unlock_irqrestore(&dmasound.lock, flags); - UNLOCK(); - } -} -#endif /* CONFIG_PM */ - - -/* All the burgundy functions: */ - -/* Waits for busy flag to clear */ -static inline void -awacs_burgundy_busy_wait(void) -{ - int count = 50; /* > 2 samples at 44k1 */ - while ((in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) && count--) - udelay(1) ; -} - -static inline void -awacs_burgundy_extend_wait(void) -{ - int count = 50 ; /* > 2 samples at 44k1 */ - while ((!(in_le32(&awacs->codec_stat) & MASK_EXTEND)) && count--) - udelay(1) ; - count = 50; - while ((in_le32(&awacs->codec_stat) & MASK_EXTEND) && count--) - udelay(1); -} - -static void -awacs_burgundy_wcw(unsigned addr, unsigned val) -{ - out_le32(&awacs->codec_ctrl, addr + 0x200c00 + (val & 0xff)); - awacs_burgundy_busy_wait(); - out_le32(&awacs->codec_ctrl, addr + 0x200d00 +((val>>8) & 0xff)); - awacs_burgundy_busy_wait(); - out_le32(&awacs->codec_ctrl, addr + 0x200e00 +((val>>16) & 0xff)); - awacs_burgundy_busy_wait(); - out_le32(&awacs->codec_ctrl, addr + 0x200f00 +((val>>24) & 0xff)); - awacs_burgundy_busy_wait(); -} - -static unsigned -awacs_burgundy_rcw(unsigned addr) -{ - unsigned val = 0; - unsigned long flags; - - /* should have timeouts here */ - spin_lock_irqsave(&dmasound.lock, flags); - - out_le32(&awacs->codec_ctrl, addr + 0x100000); - awacs_burgundy_busy_wait(); - awacs_burgundy_extend_wait(); - val += (in_le32(&awacs->codec_stat) >> 4) & 0xff; - - out_le32(&awacs->codec_ctrl, addr + 0x100100); - awacs_burgundy_busy_wait(); - awacs_burgundy_extend_wait(); - val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<8; - - out_le32(&awacs->codec_ctrl, addr + 0x100200); - awacs_burgundy_busy_wait(); - awacs_burgundy_extend_wait(); - val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<16; - - out_le32(&awacs->codec_ctrl, addr + 0x100300); - awacs_burgundy_busy_wait(); - awacs_burgundy_extend_wait(); - val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<24; - - spin_unlock_irqrestore(&dmasound.lock, flags); - - return val; -} - - -static void -awacs_burgundy_wcb(unsigned addr, unsigned val) -{ - out_le32(&awacs->codec_ctrl, addr + 0x300000 + (val & 0xff)); - awacs_burgundy_busy_wait(); -} - -static unsigned -awacs_burgundy_rcb(unsigned addr) -{ - unsigned val = 0; - unsigned long flags; - - /* should have timeouts here */ - spin_lock_irqsave(&dmasound.lock, flags); - - out_le32(&awacs->codec_ctrl, addr + 0x100000); - awacs_burgundy_busy_wait(); - awacs_burgundy_extend_wait(); - val += (in_le32(&awacs->codec_stat) >> 4) & 0xff; - - spin_unlock_irqrestore(&dmasound.lock, flags); - - return val; -} - -static int -awacs_burgundy_check(void) -{ - /* Checks to see the chip is alive and kicking */ - int error = in_le32(&awacs->codec_ctrl) & MASK_ERRCODE; - - return error == 0xf0000; -} - -static int -awacs_burgundy_init(void) -{ - if (awacs_burgundy_check()) { - printk(KERN_WARNING "dmasound_pmac: burgundy not working :-(\n"); - return 1; - } - - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_OUTPUTENABLES, - DEF_BURGUNDY_OUTPUTENABLES); - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, - DEF_BURGUNDY_MORE_OUTPUTENABLES); - awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_OUTPUTSELECTS, - DEF_BURGUNDY_OUTPUTSELECTS); - - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL21, - DEF_BURGUNDY_INPSEL21); - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL3, - DEF_BURGUNDY_INPSEL3); - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINCD, - DEF_BURGUNDY_GAINCD); - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINLINE, - DEF_BURGUNDY_GAINLINE); - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMIC, - DEF_BURGUNDY_GAINMIC); - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMODEM, - DEF_BURGUNDY_GAINMODEM); - - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER, - DEF_BURGUNDY_ATTENSPEAKER); - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENLINEOUT, - DEF_BURGUNDY_ATTENLINEOUT); - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENHP, - DEF_BURGUNDY_ATTENHP); - - awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_MASTER_VOLUME, - DEF_BURGUNDY_MASTER_VOLUME); - awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLCD, - DEF_BURGUNDY_VOLCD); - awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLLINE, - DEF_BURGUNDY_VOLLINE); - awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLMIC, - DEF_BURGUNDY_VOLMIC); - return 0; -} - -static void -awacs_burgundy_write_volume(unsigned address, int volume) -{ - int hardvolume,lvolume,rvolume; - - lvolume = (volume & 0xff) ? (volume & 0xff) + 155 : 0; - rvolume = ((volume >>8)&0xff) ? ((volume >> 8)&0xff ) + 155 : 0; - - hardvolume = lvolume + (rvolume << 16); - - awacs_burgundy_wcw(address, hardvolume); -} - -static int -awacs_burgundy_read_volume(unsigned address) -{ - int softvolume,wvolume; - - wvolume = awacs_burgundy_rcw(address); - - softvolume = (wvolume & 0xff) - 155; - softvolume += (((wvolume >> 16) & 0xff) - 155)<<8; - - return softvolume > 0 ? softvolume : 0; -} - -static int -awacs_burgundy_read_mvolume(unsigned address) -{ - int lvolume,rvolume,wvolume; - - wvolume = awacs_burgundy_rcw(address); - - wvolume &= 0xffff; - - rvolume = (wvolume & 0xff) - 155; - lvolume = ((wvolume & 0xff00)>>8) - 155; - - return lvolume + (rvolume << 8); -} - -static void -awacs_burgundy_write_mvolume(unsigned address, int volume) -{ - int lvolume,rvolume,hardvolume; - - lvolume = (volume &0xff) ? (volume & 0xff) + 155 :0; - rvolume = ((volume >>8) & 0xff) ? (volume >> 8) + 155 :0; - - hardvolume = lvolume + (rvolume << 8); - hardvolume += (hardvolume << 16); - - awacs_burgundy_wcw(address, hardvolume); -} - -/* End burgundy functions */ - -/* Set up output volumes on machines with the 'perch/whisper' extension card. - * this has an SGS i2c chip (7433) which is accessed using the cuda. - * - * TODO: split this out and make use of the other parts of the SGS chip to - * do Bass, Treble etc. - */ - -static void -awacs_enable_amp(int spkr_vol) -{ -#ifdef CONFIG_ADB_CUDA - struct adb_request req; - - if (sys_ctrler != SYS_CTRLER_CUDA) - return; - - /* turn on headphones */ - cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, - 0x8a, 4, 0); - while (!req.complete) cuda_poll(); - cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, - 0x8a, 6, 0); - while (!req.complete) cuda_poll(); - - /* turn on speaker */ - cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, - 0x8a, 3, (100 - (spkr_vol & 0xff)) * 32 / 100); - while (!req.complete) cuda_poll(); - cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, - 0x8a, 5, (100 - ((spkr_vol >> 8) & 0xff)) * 32 / 100); - while (!req.complete) cuda_poll(); - - cuda_request(&req, NULL, 5, CUDA_PACKET, - CUDA_GET_SET_IIC, 0x8a, 1, 0x29); - while (!req.complete) cuda_poll(); -#endif /* CONFIG_ADB_CUDA */ -} - - -/*** Mid level stuff *********************************************************/ - - -/* - * /dev/mixer abstraction - */ - -static void do_line_lev(int data) -{ - line_lev = data ; - awacs_reg[0] &= ~MASK_MUX_AUDIN; - if ((data & 0xff) >= 50) - awacs_reg[0] |= MASK_MUX_AUDIN; - awacs_write(MASK_ADDR0 | awacs_reg[0]); -} - -static void do_ip_gain(int data) -{ - ip_gain = data ; - data &= 0xff; - awacs_reg[0] &= ~MASK_GAINLINE; - if (awacs_revision == AWACS_SCREAMER) { - awacs_reg[6] &= ~MASK_MIC_BOOST ; - if (data >= 33) { - awacs_reg[0] |= MASK_GAINLINE; - if( data >= 66) - awacs_reg[6] |= MASK_MIC_BOOST ; - } - awacs_write(MASK_ADDR6 | awacs_reg[6]) ; - } else { - if (data >= 50) - awacs_reg[0] |= MASK_GAINLINE; - } - awacs_write(MASK_ADDR0 | awacs_reg[0]); -} - -static void do_mic_lev(int data) -{ - mic_lev = data ; - data &= 0xff; - awacs_reg[0] &= ~MASK_MUX_MIC; - if (data >= 50) - awacs_reg[0] |= MASK_MUX_MIC; - awacs_write(MASK_ADDR0 | awacs_reg[0]); -} - -static void do_cd_lev(int data) -{ - cd_lev = data ; - awacs_reg[0] &= ~MASK_MUX_CD; - if ((data & 0xff) >= 50) - awacs_reg[0] |= MASK_MUX_CD; - awacs_write(MASK_ADDR0 | awacs_reg[0]); -} - -static void do_rec_lev(int data) -{ - int left, right ; - rec_lev = data ; - /* need to fudge this to use the volume setter routine */ - left = 100 - (data & 0xff) ; if( left < 0 ) left = 0 ; - right = 100 - ((data >> 8) & 0xff) ; if( right < 0 ) right = 0 ; - left |= (right << 8 ); - left = awacs_volume_setter(left, 0, 0, 4); -} - -static void do_passthru_vol(int data) -{ - passthru_vol = data ; - awacs_reg[1] &= ~MASK_LOOPTHRU; - if (awacs_revision == AWACS_SCREAMER) { - if( data ) { /* switch it on for non-zero */ - awacs_reg[1] |= MASK_LOOPTHRU; - awacs_write(MASK_ADDR1 | awacs_reg[1]); - } - data = awacs_volume_setter(data, 5, 0, 6) ; - } else { - if ((data & 0xff) >= 50) - awacs_reg[1] |= MASK_LOOPTHRU; - awacs_write(MASK_ADDR1 | awacs_reg[1]); - data = (awacs_reg[1] & MASK_LOOPTHRU)? 100: 0; - } -} - -static int awacs_mixer_ioctl(u_int cmd, u_long arg) -{ - int data; - int rc; - - switch (cmd) { - case SOUND_MIXER_READ_CAPS: - /* say we will allow multiple inputs? prob. wrong - so I'm switching it to single */ - return IOCTL_OUT(arg, 1); - case SOUND_MIXER_READ_DEVMASK: - data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER - | SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD - | SOUND_MASK_IGAIN | SOUND_MASK_RECLEV - | SOUND_MASK_ALTPCM - | SOUND_MASK_MONITOR; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_RECMASK: - data = SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_RECSRC: - data = 0; - if (awacs_reg[0] & MASK_MUX_AUDIN) - data |= SOUND_MASK_LINE; - if (awacs_reg[0] & MASK_MUX_MIC) - data |= SOUND_MASK_MIC; - if (awacs_reg[0] & MASK_MUX_CD) - data |= SOUND_MASK_CD; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_RECSRC: - IOCTL_IN(arg, data); - data &= (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD); - awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC - | MASK_MUX_AUDIN); - if (data & SOUND_MASK_LINE) - awacs_reg[0] |= MASK_MUX_AUDIN; - if (data & SOUND_MASK_MIC) - awacs_reg[0] |= MASK_MUX_MIC; - if (data & SOUND_MASK_CD) - awacs_reg[0] |= MASK_MUX_CD; - awacs_write(awacs_reg[0] | MASK_ADDR0); - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_STEREODEVS: - data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER| SOUND_MASK_RECLEV ; - if (awacs_revision == AWACS_SCREAMER) - data |= SOUND_MASK_MONITOR ; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_VOLUME: - IOCTL_IN(arg, data); - line_vol = data ; - awacs_volume_setter(data, 2, 0, 6); - /* fall through */ - case SOUND_MIXER_READ_VOLUME: - rc = IOCTL_OUT(arg, line_vol); - break; - case SOUND_MIXER_WRITE_SPEAKER: - IOCTL_IN(arg, data); - spk_vol = data ; - if (has_perch) - awacs_enable_amp(data); - else - (void)awacs_volume_setter(data, 4, MASK_CMUTE, 6); - /* fall though */ - case SOUND_MIXER_READ_SPEAKER: - rc = IOCTL_OUT(arg, spk_vol); - break; - case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ - IOCTL_IN(arg, data); - beep_vol = data & 0xff; - /* fall through */ - case SOUND_MIXER_READ_ALTPCM: - rc = IOCTL_OUT(arg, beep_vol); - break; - case SOUND_MIXER_WRITE_LINE: - IOCTL_IN(arg, data); - do_line_lev(data) ; - /* fall through */ - case SOUND_MIXER_READ_LINE: - rc = IOCTL_OUT(arg, line_lev); - break; - case SOUND_MIXER_WRITE_IGAIN: - IOCTL_IN(arg, data); - do_ip_gain(data) ; - /* fall through */ - case SOUND_MIXER_READ_IGAIN: - rc = IOCTL_OUT(arg, ip_gain); - break; - case SOUND_MIXER_WRITE_MIC: - IOCTL_IN(arg, data); - do_mic_lev(data); - /* fall through */ - case SOUND_MIXER_READ_MIC: - rc = IOCTL_OUT(arg, mic_lev); - break; - case SOUND_MIXER_WRITE_CD: - IOCTL_IN(arg, data); - do_cd_lev(data); - /* fall through */ - case SOUND_MIXER_READ_CD: - rc = IOCTL_OUT(arg, cd_lev); - break; - case SOUND_MIXER_WRITE_RECLEV: - IOCTL_IN(arg, data); - do_rec_lev(data) ; - /* fall through */ - case SOUND_MIXER_READ_RECLEV: - rc = IOCTL_OUT(arg, rec_lev); - break; - case MIXER_WRITE(SOUND_MIXER_MONITOR): - IOCTL_IN(arg, data); - do_passthru_vol(data) ; - /* fall through */ - case MIXER_READ(SOUND_MIXER_MONITOR): - rc = IOCTL_OUT(arg, passthru_vol); - break; - default: - rc = -EINVAL; - } - - return rc; -} - -static void awacs_mixer_init(void) -{ - awacs_volume_setter(line_vol, 2, 0, 6); - if (has_perch) - awacs_enable_amp(spk_vol); - else - (void)awacs_volume_setter(spk_vol, 4, MASK_CMUTE, 6); - do_line_lev(line_lev) ; - do_ip_gain(ip_gain) ; - do_mic_lev(mic_lev) ; - do_cd_lev(cd_lev) ; - do_rec_lev(rec_lev) ; - do_passthru_vol(passthru_vol) ; -} - -static int burgundy_mixer_ioctl(u_int cmd, u_long arg) -{ - int data; - int rc; - - /* We are, we are, we are... Burgundy or better */ - switch(cmd) { - case SOUND_MIXER_READ_DEVMASK: - data = SOUND_MASK_VOLUME | SOUND_MASK_CD | - SOUND_MASK_LINE | SOUND_MASK_MIC | - SOUND_MASK_SPEAKER | SOUND_MASK_ALTPCM; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_RECMASK: - data = SOUND_MASK_LINE | SOUND_MASK_MIC - | SOUND_MASK_CD; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_RECSRC: - data = 0; - if (awacs_reg[0] & MASK_MUX_AUDIN) - data |= SOUND_MASK_LINE; - if (awacs_reg[0] & MASK_MUX_MIC) - data |= SOUND_MASK_MIC; - if (awacs_reg[0] & MASK_MUX_CD) - data |= SOUND_MASK_CD; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_RECSRC: - IOCTL_IN(arg, data); - data &= (SOUND_MASK_LINE - | SOUND_MASK_MIC | SOUND_MASK_CD); - awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC - | MASK_MUX_AUDIN); - if (data & SOUND_MASK_LINE) - awacs_reg[0] |= MASK_MUX_AUDIN; - if (data & SOUND_MASK_MIC) - awacs_reg[0] |= MASK_MUX_MIC; - if (data & SOUND_MASK_CD) - awacs_reg[0] |= MASK_MUX_CD; - awacs_write(awacs_reg[0] | MASK_ADDR0); - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_STEREODEVS: - data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER - | SOUND_MASK_RECLEV | SOUND_MASK_CD - | SOUND_MASK_LINE; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_CAPS: - rc = IOCTL_OUT(arg, 0); - break; - case SOUND_MIXER_WRITE_VOLUME: - IOCTL_IN(arg, data); - awacs_burgundy_write_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME, data); - /* Fall through */ - case SOUND_MIXER_READ_VOLUME: - rc = IOCTL_OUT(arg, awacs_burgundy_read_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME)); - break; - case SOUND_MIXER_WRITE_SPEAKER: - IOCTL_IN(arg, data); - if (!(data & 0xff)) { - /* Mute the left speaker */ - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, - awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x2); - } else { - /* Unmute the left speaker */ - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, - awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x2); - } - if (!(data & 0xff00)) { - /* Mute the right speaker */ - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, - awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x4); - } else { - /* Unmute the right speaker */ - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, - awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x4); - } - - data = (((data&0xff)*16)/100 > 0xf ? 0xf : - (((data&0xff)*16)/100)) + - ((((data>>8)*16)/100 > 0xf ? 0xf : - ((((data>>8)*16)/100)))<<4); - - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER, ~data); - /* Fall through */ - case SOUND_MIXER_READ_SPEAKER: - data = awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER); - data = (((data & 0xf)*100)/16) + ((((data>>4)*100)/16)<<8); - rc = IOCTL_OUT(arg, (~data) & 0x0000ffff); - break; - case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ - IOCTL_IN(arg, data); - beep_vol = data & 0xff; - /* fall through */ - case SOUND_MIXER_READ_ALTPCM: - rc = IOCTL_OUT(arg, beep_vol); - break; - case SOUND_MIXER_WRITE_LINE: - IOCTL_IN(arg, data); - awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLLINE, data); - - /* fall through */ - case SOUND_MIXER_READ_LINE: - data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLLINE); - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_MIC: - IOCTL_IN(arg, data); - /* Mic is mono device */ - data = (data << 8) + (data << 24); - awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLMIC, data); - /* fall through */ - case SOUND_MIXER_READ_MIC: - data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLMIC); - data <<= 24; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_CD: - IOCTL_IN(arg, data); - awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLCD, data); - /* fall through */ - case SOUND_MIXER_READ_CD: - data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLCD); - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_RECLEV: - IOCTL_IN(arg, data); - data = awacs_volume_setter(data, 0, 0, 4); - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_RECLEV: - data = awacs_get_volume(awacs_reg[0], 4); - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_OUTMASK: - case SOUND_MIXER_OUTSRC: - default: - rc = -EINVAL; - } - - return rc; -} - -static int daca_mixer_ioctl(u_int cmd, u_long arg) -{ - int data; - int rc; - - /* And the DACA's no genius either! */ - - switch(cmd) { - case SOUND_MIXER_READ_DEVMASK: - data = SOUND_MASK_VOLUME; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_RECMASK: - data = 0; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_RECSRC: - data = 0; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_RECSRC: - IOCTL_IN(arg, data); - data =0; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_STEREODEVS: - data = SOUND_MASK_VOLUME; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_CAPS: - rc = IOCTL_OUT(arg, 0); - break; - case SOUND_MIXER_WRITE_VOLUME: - IOCTL_IN(arg, data); - daca_set_volume(data, data); - /* Fall through */ - case SOUND_MIXER_READ_VOLUME: - daca_get_volume(& data, &data); - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_OUTMASK: - case SOUND_MIXER_OUTSRC: - default: - rc = -EINVAL; - } - return rc; -} - -static int PMacMixerIoctl(u_int cmd, u_long arg) -{ - int rc; - - /* Different IOCTLS for burgundy and, eventually, DACA & Tumbler */ - - TRY_LOCK(); - - switch (awacs_revision){ - case AWACS_BURGUNDY: - rc = burgundy_mixer_ioctl(cmd, arg); - break ; - case AWACS_DACA: - rc = daca_mixer_ioctl(cmd, arg); - break; - case AWACS_TUMBLER: - case AWACS_SNAPPER: - rc = tas_mixer_ioctl(cmd, arg); - break ; - default: /* ;-)) */ - rc = awacs_mixer_ioctl(cmd, arg); - } - - UNLOCK(); - - return rc; -} - -static void PMacMixerInit(void) -{ - switch (awacs_revision) { - case AWACS_TUMBLER: - printk("AE-Init tumbler mixer\n"); - break ; - case AWACS_SNAPPER: - printk("AE-Init snapper mixer\n"); - break ; - case AWACS_DACA: - case AWACS_BURGUNDY: - break ; /* don't know yet */ - case AWACS_AWACS: - case AWACS_SCREAMER: - default: - awacs_mixer_init() ; - break ; - } -} - -/* Write/Read sq setup functions: - Check to see if we have enough (or any) dbdma cmd buffers for the - user's fragment settings. If not, allocate some. If this fails we will - point at the beep buffer - as an emergency provision - to stop dma tromping - on some random bit of memory (if someone lets it go anyway). - The command buffers are then set up to point to the fragment buffers - (allocated elsewhere). We need n+1 commands the last of which holds - a NOP + loop to start. -*/ - -static int PMacWriteSqSetup(void) -{ - int i, count = 600 ; - volatile struct dbdma_cmd *cp; - - LOCK(); - - /* stop the controller from doing any output - if it isn't already. - it _should_ be before this is called anyway */ - - out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); - while ((in_le32(&awacs_txdma->status) & RUN) && count--) - udelay(1); -#ifdef DEBUG_DMASOUND -if (count <= 0) - printk("dmasound_pmac: write sq setup: timeout waiting for dma to stop\n"); -#endif - - if ((write_sq.max_count + 1) > number_of_tx_cmd_buffers) { - kfree(awacs_tx_cmd_space); - number_of_tx_cmd_buffers = 0; - - /* we need nbufs + 1 (for the loop) and we should request + 1 - again because the DBDMA_ALIGN might pull the start up by up - to sizeof(struct dbdma_cmd) - 4. - */ - - awacs_tx_cmd_space = kmalloc - ((write_sq.max_count + 1 + 1) * sizeof(struct dbdma_cmd), - GFP_KERNEL); - if (awacs_tx_cmd_space == NULL) { - /* don't leave it dangling - nasty but better than a - random address */ - out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); - printk(KERN_ERR - "dmasound_pmac: can't allocate dbdma cmd buffers" - ", driver disabled\n"); - UNLOCK(); - return -ENOMEM; - } - awacs_tx_cmds = (volatile struct dbdma_cmd *) - DBDMA_ALIGN(awacs_tx_cmd_space); - number_of_tx_cmd_buffers = write_sq.max_count + 1; - } - - cp = awacs_tx_cmds; - memset((void *)cp, 0, (write_sq.max_count+1) * sizeof(struct dbdma_cmd)); - for (i = 0; i < write_sq.max_count; ++i, ++cp) { - st_le32(&cp->phy_addr, virt_to_bus(write_sq.buffers[i])); - } - st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS); - st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds)); - /* point the controller at the command stack - ready to go */ - out_le32(&awacs_txdma->cmdptr, virt_to_bus(awacs_tx_cmds)); - UNLOCK(); - return 0; -} - -static int PMacReadSqSetup(void) -{ - int i, count = 600; - volatile struct dbdma_cmd *cp; - - LOCK(); - - /* stop the controller from doing any input - if it isn't already. - it _should_ be before this is called anyway */ - - out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); - while ((in_le32(&awacs_rxdma->status) & RUN) && count--) - udelay(1); -#ifdef DEBUG_DMASOUND -if (count <= 0) - printk("dmasound_pmac: read sq setup: timeout waiting for dma to stop\n"); -#endif - - if ((read_sq.max_count+1) > number_of_rx_cmd_buffers ) { - kfree(awacs_rx_cmd_space); - number_of_rx_cmd_buffers = 0; - - /* we need nbufs + 1 (for the loop) and we should request + 1 again - because the DBDMA_ALIGN might pull the start up by up to - sizeof(struct dbdma_cmd) - 4 (assuming kmalloc aligns 32 bits). - */ - - awacs_rx_cmd_space = kmalloc - ((read_sq.max_count + 1 + 1) * sizeof(struct dbdma_cmd), - GFP_KERNEL); - if (awacs_rx_cmd_space == NULL) { - /* don't leave it dangling - nasty but better than a - random address */ - out_le32(&awacs_rxdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); - printk(KERN_ERR - "dmasound_pmac: can't allocate dbdma cmd buffers" - ", driver disabled\n"); - UNLOCK(); - return -ENOMEM; - } - awacs_rx_cmds = (volatile struct dbdma_cmd *) - DBDMA_ALIGN(awacs_rx_cmd_space); - number_of_rx_cmd_buffers = read_sq.max_count + 1 ; - } - cp = awacs_rx_cmds; - memset((void *)cp, 0, (read_sq.max_count+1) * sizeof(struct dbdma_cmd)); - - /* Set dma buffers up in a loop */ - for (i = 0; i < read_sq.max_count; i++,cp++) { - st_le32(&cp->phy_addr, virt_to_bus(read_sq.buffers[i])); - st_le16(&cp->command, INPUT_MORE + INTR_ALWAYS); - st_le16(&cp->req_count, read_sq.block_size); - st_le16(&cp->xfer_status, 0); - } - - /* The next two lines make the thing loop around. - */ - st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS); - st_le32(&cp->cmd_dep, virt_to_bus(awacs_rx_cmds)); - /* point the controller at the command stack - ready to go */ - out_le32(&awacs_rxdma->cmdptr, virt_to_bus(awacs_rx_cmds)); - - UNLOCK(); - return 0; -} - -/* TODO: this needs work to guarantee that when it returns DMA has stopped - but in a more elegant way than is done here.... -*/ - -static void PMacAbortRead(void) -{ - int i; - volatile struct dbdma_cmd *cp; - - LOCK(); - /* give it a chance to update the output and provide the IRQ - that is expected. - */ - - out_le32(&awacs_rxdma->control, ((FLUSH) << 16) + FLUSH ); - - cp = awacs_rx_cmds; - for (i = 0; i < read_sq.max_count; i++,cp++) - st_le16(&cp->command, DBDMA_STOP); - /* - * We should probably wait for the thing to stop before we - * release the memory. - */ - - msleep(100) ; /* give it a (small) chance to act */ - - /* apply the sledgehammer approach - just stop it now */ - - out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); - UNLOCK(); -} - -extern char *get_afmt_string(int); -static int PMacStateInfo(char *b, size_t sp) -{ - int i, len = 0; - len = sprintf(b,"HW rates: "); - switch (awacs_revision){ - case AWACS_DACA: - case AWACS_BURGUNDY: - len += sprintf(b,"44100 ") ; - break ; - case AWACS_TUMBLER: - case AWACS_SNAPPER: - for (i=0; i<1; i++){ - if (tas_freqs_ok[i]) - len += sprintf(b+len,"%d ", tas_freqs[i]) ; - } - break ; - case AWACS_AWACS: - case AWACS_SCREAMER: - default: - for (i=0; i<8; i++){ - if (awacs_freqs_ok[i]) - len += sprintf(b+len,"%d ", awacs_freqs[i]) ; - } - break ; - } - len += sprintf(b+len,"s/sec\n") ; - if (len < sp) { - len += sprintf(b+len,"HW AFMTS: "); - i = AFMT_U16_BE ; - while (i) { - if (i & dmasound.mach.hardware_afmts) - len += sprintf(b+len,"%s ", - get_afmt_string(i & dmasound.mach.hardware_afmts)); - i >>= 1 ; - } - len += sprintf(b+len,"\n") ; - } - return len ; -} - -/*** Machine definitions *****************************************************/ - -static SETTINGS def_hard = { - .format = AFMT_S16_BE, - .stereo = 1, - .size = 16, - .speed = 44100 -} ; - -static SETTINGS def_soft = { - .format = AFMT_S16_BE, - .stereo = 1, - .size = 16, - .speed = 44100 -} ; - -static MACHINE machPMac = { - .name = awacs_name, - .name2 = "PowerMac Built-in Sound", - .owner = THIS_MODULE, - .dma_alloc = PMacAlloc, - .dma_free = PMacFree, - .irqinit = PMacIrqInit, -#ifdef MODULE - .irqcleanup = PMacIrqCleanup, -#endif /* MODULE */ - .init = PMacInit, - .silence = PMacSilence, - .setFormat = PMacSetFormat, - .setVolume = PMacSetVolume, - .play = PMacPlay, - .record = NULL, /* default to no record */ - .mixer_init = PMacMixerInit, - .mixer_ioctl = PMacMixerIoctl, - .write_sq_setup = PMacWriteSqSetup, - .read_sq_setup = PMacReadSqSetup, - .state_info = PMacStateInfo, - .abort_read = PMacAbortRead, - .min_dsp_speed = 7350, - .max_dsp_speed = 44100, - .version = ((DMASOUND_AWACS_REVISION<<8) + DMASOUND_AWACS_EDITION) -}; - - -/*** Config & Setup **********************************************************/ - -/* Check for pmac models that we care about in terms of special actions. -*/ - -void __init -set_model(void) -{ - /* portables/lap-tops */ - - if (machine_is_compatible("AAPL,3400/2400") || - machine_is_compatible("AAPL,3500")) { - is_pbook_3X00 = 1 ; - } - if (machine_is_compatible("PowerBook1,1") || /* lombard */ - machine_is_compatible("AAPL,PowerBook1998")){ /* wallstreet */ - is_pbook_g3 = 1 ; - return ; - } -} - -/* Get the OF node that tells us about the registers, interrupts etc. to use - for sound IO. - - On most machines the sound IO OF node is the 'davbus' node. On newer pmacs - with DACA (& Tumbler) the node to use is i2s-a. On much older machines i.e. - before 9500 there is no davbus node and we have to use the 'awacs' property. - - In the latter case we signal this by setting the codec value - so that the - code that looks for chip properties knows how to go about it. -*/ - -static struct device_node* __init -get_snd_io_node(void) -{ - struct device_node *np; - - /* set up awacs_node for early OF which doesn't have a full set of - * properties on davbus - */ - awacs_node = of_find_node_by_name(NULL, "awacs"); - if (awacs_node) - awacs_revision = AWACS_AWACS; - - /* powermac models after 9500 (other than those which use DACA or - * Tumbler) have a node called "davbus". - */ - np = of_find_node_by_name(NULL, "davbus"); - /* - * if we didn't find a davbus device, try 'i2s-a' since - * this seems to be what iBooks (& Tumbler) have. - */ - if (np == NULL) { - i2s_node = of_find_node_by_name(NULL, "i2s-a"); - np = of_node_get(i2s_node); - } - - /* if we didn't find this - perhaps we are on an early model - * which _only_ has an 'awacs' node - */ - if (np == NULL && awacs_node) - np = of_node_get(awacs_node); - - /* if we failed all these return null - this will cause the - * driver to give up... - */ - return np ; -} - -/* Get the OF node that contains the info about the sound chip, inputs s-rates - etc. - This node does not exist (or contains much reduced info) on earlier machines - we have to deduce the info other ways for these. -*/ - -static struct device_node* __init -get_snd_info_node(struct device_node *io) -{ - struct device_node *info; - - for_each_node_by_name(info, "sound") - if (info->parent == io) - break; - return info; -} - -/* Find out what type of codec we have. -*/ - -static int __init -get_codec_type(struct device_node *info) -{ - /* already set if pre-davbus model and info will be NULL */ - int codec = awacs_revision ; - - if (info) { - /* must do awacs first to allow screamer to overide it */ - if (of_device_is_compatible(info, "awacs")) - codec = AWACS_AWACS ; - if (of_device_is_compatible(info, "screamer")) - codec = AWACS_SCREAMER; - if (of_device_is_compatible(info, "burgundy")) - codec = AWACS_BURGUNDY ; - if (of_device_is_compatible(info, "daca")) - codec = AWACS_DACA; - if (of_device_is_compatible(info, "tumbler")) - codec = AWACS_TUMBLER; - if (of_device_is_compatible(info, "snapper")) - codec = AWACS_SNAPPER; - } - return codec ; -} - -/* find out what type, if any, of expansion card we have -*/ -static void __init -get_expansion_type(void) -{ - struct device_node *dn; - - dn = of_find_node_by_name(NULL, "perch"); - if (dn != NULL) - has_perch = 1; - of_node_put(dn); - - dn = of_find_node_by_name(NULL, "pb-ziva-pc"); - if (dn != NULL) - has_ziva = 1; - of_node_put(dn); - /* need to work out how we deal with iMac SRS module */ -} - -/* set up frame rates. - * I suspect that these routines don't quite go about it the right way: - * - where there is more than one rate - I think that the first property - * value is the number of rates. - * TODO: check some more device trees and modify accordingly - * Set dmasound.mach.max_dsp_rate on the basis of these routines. -*/ - -static void __init -awacs_init_frame_rates(const unsigned int *prop, unsigned int l) -{ - int i ; - if (prop) { - for (i=0; i<8; i++) - awacs_freqs_ok[i] = 0 ; - for (l /= sizeof(int); l > 0; --l) { - unsigned int r = *prop++; - /* Apple 'Fixed' format */ - if (r >= 0x10000) - r >>= 16; - for (i = 0; i < 8; ++i) { - if (r == awacs_freqs[i]) { - awacs_freqs_ok[i] = 1; - break; - } - } - } - } - /* else we assume that all the rates are available */ -} - -static void __init -burgundy_init_frame_rates(const unsigned int *prop, unsigned int l) -{ - int temp[9] ; - int i = 0 ; - if (prop) { - for (l /= sizeof(int); l > 0; --l) { - unsigned int r = *prop++; - /* Apple 'Fixed' format */ - if (r >= 0x10000) - r >>= 16; - temp[i] = r ; - i++ ; if(i>=9) i=8; - } - } -#ifdef DEBUG_DMASOUND -if (i > 1){ - int j; - printk("dmasound_pmac: burgundy with multiple frame rates\n"); - for(j=0; j<i; j++) - printk("%d ", temp[j]) ; - printk("\n") ; -} -#endif -} - -static void __init -daca_init_frame_rates(const unsigned int *prop, unsigned int l) -{ - int temp[9] ; - int i = 0 ; - if (prop) { - for (l /= sizeof(int); l > 0; --l) { - unsigned int r = *prop++; - /* Apple 'Fixed' format */ - if (r >= 0x10000) - r >>= 16; - temp[i] = r ; - i++ ; if(i>=9) i=8; - - } - } -#ifdef DEBUG_DMASOUND -if (i > 1){ - int j; - printk("dmasound_pmac: DACA with multiple frame rates\n"); - for(j=0; j<i; j++) - printk("%d ", temp[j]) ; - printk("\n") ; -} -#endif -} - -static void __init -init_frame_rates(const unsigned int *prop, unsigned int l) -{ - switch (awacs_revision) { - case AWACS_TUMBLER: - case AWACS_SNAPPER: - tas_init_frame_rates(prop, l); - break ; - case AWACS_DACA: - daca_init_frame_rates(prop, l); - break ; - case AWACS_BURGUNDY: - burgundy_init_frame_rates(prop, l); - break ; - default: - awacs_init_frame_rates(prop, l); - break ; - } -} - -/* find things/machines that can't do mac-io byteswap -*/ - -static void __init -set_hw_byteswap(struct device_node *io) -{ - struct device_node *mio ; - unsigned int kl = 0 ; - - /* if seems that Keylargo can't byte-swap */ - - for (mio = io->parent; mio ; mio = mio->parent) { - if (strcmp(mio->name, "mac-io") == 0) { - if (of_device_is_compatible(mio, "Keylargo")) - kl = 1; - break; - } - } - hw_can_byteswap = !kl; -} - -/* Allocate the resources necessary for beep generation. This cannot be (quite) - done statically (yet) because we cannot do virt_to_bus() on static vars when - the code is loaded as a module. - - for the sake of saving the possibility that two allocations will incur the - overhead of two pull-ups in DBDMA_ALIGN() we allocate the 'emergency' dmdma - command here as well... even tho' it is not part of the beep process. -*/ - -int32_t -__init setup_beep(void) -{ - /* Initialize beep stuff */ - /* want one cmd buffer for beeps, and a second one for emergencies - - i.e. dbdma error conditions. - ask for three to allow for pull up in DBDMA_ALIGN(). - */ - beep_dbdma_cmd_space = - kmalloc((2 + 1) * sizeof(struct dbdma_cmd), GFP_KERNEL); - if(beep_dbdma_cmd_space == NULL) { - printk(KERN_ERR "dmasound_pmac: no beep dbdma cmd space\n") ; - return -ENOMEM ; - } - beep_dbdma_cmd = (volatile struct dbdma_cmd *) - DBDMA_ALIGN(beep_dbdma_cmd_space); - /* set up emergency dbdma cmd */ - emergency_dbdma_cmd = beep_dbdma_cmd+1 ; - beep_buf = kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL); - if (beep_buf == NULL) { - printk(KERN_ERR "dmasound_pmac: no memory for beep buffer\n"); - kfree(beep_dbdma_cmd_space) ; - return -ENOMEM ; - } - return 0 ; -} - -static struct input_dev *awacs_beep_dev; - -int __init dmasound_awacs_init(void) -{ - struct device_node *io = NULL, *info = NULL; - int vol, res; - - if (!machine_is(powermac)) - return -ENODEV; - - awacs_subframe = 0; - awacs_revision = 0; - hw_can_byteswap = 1 ; /* most can */ - - /* look for models we need to handle specially */ - set_model() ; - - /* find the OF node that tells us about the dbdma stuff - */ - io = get_snd_io_node(); - if (io == NULL) { -#ifdef DEBUG_DMASOUND -printk("dmasound_pmac: couldn't find sound io OF node\n"); -#endif - goto no_device; - } - - /* find the OF node that tells us about the sound sub-system - * this doesn't exist on pre-davbus machines (earlier than 9500) - */ - if (awacs_revision != AWACS_AWACS) { /* set for pre-davbus */ - info = get_snd_info_node(io) ; - if (info == NULL){ -#ifdef DEBUG_DMASOUND -printk("dmasound_pmac: couldn't find 'sound' OF node\n"); -#endif - goto no_device; - } - } - - awacs_revision = get_codec_type(info) ; - if (awacs_revision == 0) { -#ifdef DEBUG_DMASOUND -printk("dmasound_pmac: couldn't find a Codec we can handle\n"); -#endif - goto no_device; /* we don't know this type of h/w */ - } - - /* set up perch, ziva, SRS or whatever else we have as sound - * expansion. - */ - get_expansion_type(); - - /* we've now got enough information to make up the audio topology. - * we will map the sound part of mac-io now so that we can probe for - * other info if necessary (early AWACS we want to read chip ids) - */ - - if (of_get_address(io, 2, NULL, NULL) == NULL) { - /* OK - maybe we need to use the 'awacs' node (on earlier - * machines). - */ - if (awacs_node) { - of_node_put(io); - io = of_node_get(awacs_node); - if (of_get_address(io, 2, NULL, NULL) == NULL) { - printk("dmasound_pmac: can't use %s\n", - io->full_name); - goto no_device; - } - } else - printk("dmasound_pmac: can't use %s\n", io->full_name); - } - - if (of_address_to_resource(io, 0, &awacs_rsrc[0]) || - request_mem_region(awacs_rsrc[0].start, - awacs_rsrc[0].end - awacs_rsrc[0].start + 1, - " (IO)") == NULL) { - printk(KERN_ERR "dmasound: can't request IO resource !\n"); - goto no_device; - } - if (of_address_to_resource(io, 1, &awacs_rsrc[1]) || - request_mem_region(awacs_rsrc[1].start, - awacs_rsrc[1].end - awacs_rsrc[1].start + 1, - " (tx dma)") == NULL) { - release_mem_region(awacs_rsrc[0].start, - awacs_rsrc[0].end - awacs_rsrc[0].start + 1); - printk(KERN_ERR "dmasound: can't request Tx DMA resource !\n"); - goto no_device; - } - if (of_address_to_resource(io, 2, &awacs_rsrc[2]) || - request_mem_region(awacs_rsrc[2].start, - awacs_rsrc[2].end - awacs_rsrc[2].start + 1, - " (rx dma)") == NULL) { - release_mem_region(awacs_rsrc[0].start, - awacs_rsrc[0].end - awacs_rsrc[0].start + 1); - release_mem_region(awacs_rsrc[1].start, - awacs_rsrc[1].end - awacs_rsrc[1].start + 1); - printk(KERN_ERR "dmasound: can't request Rx DMA resource !\n"); - goto no_device; - } - - awacs_beep_dev = input_allocate_device(); - if (!awacs_beep_dev) { - release_mem_region(awacs_rsrc[0].start, - awacs_rsrc[0].end - awacs_rsrc[0].start + 1); - release_mem_region(awacs_rsrc[1].start, - awacs_rsrc[1].end - awacs_rsrc[1].start + 1); - release_mem_region(awacs_rsrc[2].start, - awacs_rsrc[2].end - awacs_rsrc[2].start + 1); - printk(KERN_ERR "dmasound: can't allocate input device !\n"); - goto no_device; - } - - awacs_beep_dev->name = "dmasound beeper"; - awacs_beep_dev->phys = "macio/input0"; - awacs_beep_dev->id.bustype = BUS_HOST; - awacs_beep_dev->event = awacs_beep_event; - awacs_beep_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); - awacs_beep_dev->evbit[0] = BIT(EV_SND); - - /* all OF versions I've seen use this value */ - if (i2s_node) - i2s = ioremap(awacs_rsrc[0].start, 0x1000); - else - awacs = ioremap(awacs_rsrc[0].start, 0x1000); - awacs_txdma = ioremap(awacs_rsrc[1].start, 0x100); - awacs_rxdma = ioremap(awacs_rsrc[2].start, 0x100); - - /* first of all make sure that the chip is powered up....*/ - pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, io, 0, 1); - if (awacs_revision == AWACS_SCREAMER && awacs) - awacs_recalibrate(); - - awacs_irq = irq_of_parse_and_map(io, 0); - awacs_tx_irq = irq_of_parse_and_map(io, 1); - awacs_rx_irq = irq_of_parse_and_map(io, 2); - - /* Hack for legacy crap that will be killed someday */ - of_node_put(awacs_node); - awacs_node = of_node_get(io); - - /* if we have an awacs or screamer - probe the chip to make - * sure we have the right revision. - */ - - if (awacs_revision <= AWACS_SCREAMER){ - uint32_t temp, rev, mfg ; - /* find out the awacs revision from the chip */ - temp = in_le32(&awacs->codec_stat); - rev = (temp >> 12) & 0xf; - mfg = (temp >> 8) & 0xf; -#ifdef DEBUG_DMASOUND -printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev); -#endif - if (rev >= AWACS_SCREAMER) - awacs_revision = AWACS_SCREAMER ; - else - awacs_revision = rev ; - } - - dmasound.mach = machPMac; - - /* find out other bits & pieces from OF, these may be present - only on some models ... so be careful. - */ - - /* in the absence of a frame rates property we will use the defaults - */ - - if (info) { - const unsigned int *prop; - unsigned int l; - - sound_device_id = 0; - /* device ID appears post g3 b&w */ - prop = of_get_property(info, "device-id", NULL); - if (prop != 0) - sound_device_id = *prop; - - /* look for a property saying what sample rates - are available */ - - prop = of_get_property(info, "sample-rates", &l); - if (prop == 0) - prop = of_get_property(info, "output-frame-rates", &l); - - /* if it's there use it to set up frame rates */ - init_frame_rates(prop, l) ; - of_node_put(info); - info = NULL; - } - - if (awacs) - out_le32(&awacs->control, 0x11); /* set everything quiesent */ - - set_hw_byteswap(io) ; /* figure out if the h/w can do it */ - -#ifdef CONFIG_NVRAM - /* get default volume from nvram */ - vol = ((pmac_xpram_read( 8 ) & 7 ) << 1 ); -#else - vol = 0; -#endif - - /* set up tracking values */ - spk_vol = vol * 100 ; - spk_vol /= 7 ; /* get set value to a percentage */ - spk_vol |= (spk_vol << 8) ; /* equal left & right */ - line_vol = passthru_vol = spk_vol ; - - /* fill regs that are shared between AWACS & Burgundy */ - - awacs_reg[2] = vol + (vol << 6); - awacs_reg[4] = vol + (vol << 6); - awacs_reg[5] = vol + (vol << 6); /* screamer has loopthru vol control */ - awacs_reg[6] = 0; /* maybe should be vol << 3 for PCMCIA speaker */ - awacs_reg[7] = 0; - - awacs_reg[0] = MASK_MUX_CD; - awacs_reg[1] = MASK_LOOPTHRU; - - /* FIXME: Only machines with external SRS module need MASK_PAROUT */ - if (has_perch || sound_device_id == 0x5 - || /*sound_device_id == 0x8 ||*/ sound_device_id == 0xb) - awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1; - - switch (awacs_revision) { - case AWACS_TUMBLER: - tas_register_driver(&tas3001c_hooks); - tas_init(I2C_DRIVERID_TAS3001C, I2C_DRIVERNAME_TAS3001C); - tas_dmasound_init(); - tas_post_init(); - break ; - case AWACS_SNAPPER: - tas_register_driver(&tas3004_hooks); - tas_init(I2C_DRIVERID_TAS3004,I2C_DRIVERNAME_TAS3004); - tas_dmasound_init(); - tas_post_init(); - break; - case AWACS_DACA: - daca_init(); - break; - case AWACS_BURGUNDY: - awacs_burgundy_init(); - break ; - case AWACS_SCREAMER: - case AWACS_AWACS: - default: - load_awacs(); - break ; - } - - /* enable/set-up external modules - when we know how */ - - if (has_perch) - awacs_enable_amp(100 * 0x101); - - /* Reset dbdma channels */ - out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16); - while (in_le32(&awacs_txdma->status) & RUN) - udelay(1); - out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16); - while (in_le32(&awacs_rxdma->status) & RUN) - udelay(1); - - /* Initialize beep stuff */ - if ((res=setup_beep())) - return res ; - -#ifdef CONFIG_PM - pmu_register_sleep_notifier(&awacs_sleep_notifier); -#endif /* CONFIG_PM */ - - /* Powerbooks have odd ways of enabling inputs such as - an expansion-bay CD or sound from an internal modem - or a PC-card modem. */ - if (is_pbook_3X00) { - /* - * Enable CD and PC-card sound inputs. - * This is done by reading from address - * f301a000, + 0x10 to enable the expansion-bay - * CD sound input, + 0x80 to enable the PC-card - * sound input. The 0x100 enables the SCSI bus - * terminator power. - */ - latch_base = ioremap (0xf301a000, 0x1000); - in_8(latch_base + 0x190); - - } else if (is_pbook_g3) { - struct device_node* mio; - macio_base = NULL; - for (mio = io->parent; mio; mio = mio->parent) { - if (strcmp(mio->name, "mac-io") == 0) { - struct resource r; - if (of_address_to_resource(mio, 0, &r) == 0) - macio_base = ioremap(r.start, 0x40); - break; - } - } - /* - * Enable CD sound input. - * The relevant bits for writing to this byte are 0x8f. - * I haven't found out what the 0x80 bit does. - * For the 0xf bits, writing 3 or 7 enables the CD - * input, any other value disables it. Values - * 1, 3, 5, 7 enable the microphone. Values 0, 2, - * 4, 6, 8 - f enable the input from the modem. - * -- paulus. - */ - if (macio_base) - out_8(macio_base + 0x37, 3); - } - - if (hw_can_byteswap) - dmasound.mach.hardware_afmts = (AFMT_S16_BE | AFMT_S16_LE) ; - else - dmasound.mach.hardware_afmts = AFMT_S16_BE ; - - /* shut out chips that do output only. - * may need to extend this to machines which have no inputs - even tho' - * they use screamer - IIRC one of the powerbooks is like this. - */ - - if (awacs_revision != AWACS_DACA) { - dmasound.mach.capabilities = DSP_CAP_DUPLEX ; - dmasound.mach.record = PMacRecord ; - } - - dmasound.mach.default_hard = def_hard ; - dmasound.mach.default_soft = def_soft ; - - switch (awacs_revision) { - case AWACS_BURGUNDY: - sprintf(awacs_name, "PowerMac Burgundy ") ; - break ; - case AWACS_DACA: - sprintf(awacs_name, "PowerMac DACA ") ; - break ; - case AWACS_TUMBLER: - sprintf(awacs_name, "PowerMac Tumbler ") ; - break ; - case AWACS_SNAPPER: - sprintf(awacs_name, "PowerMac Snapper ") ; - break ; - case AWACS_SCREAMER: - sprintf(awacs_name, "PowerMac Screamer ") ; - break ; - case AWACS_AWACS: - default: - sprintf(awacs_name, "PowerMac AWACS rev %d ", awacs_revision) ; - break ; - } - - /* - * XXX: we should handle errors here, but that would mean - * rewriting the whole init code. later.. - */ - input_register_device(awacs_beep_dev); - - of_node_put(io); - - return dmasound_init(); - -no_device: - of_node_put(info); - of_node_put(awacs_node); - of_node_put(i2s_node); - of_node_put(io); - return -ENODEV ; -} - -static void __exit dmasound_awacs_cleanup(void) -{ - input_unregister_device(awacs_beep_dev); - - switch (awacs_revision) { - case AWACS_TUMBLER: - case AWACS_SNAPPER: - tas_dmasound_cleanup(); - tas_cleanup(); - break ; - case AWACS_DACA: - daca_cleanup(); - break; - } - dmasound_deinit(); - - of_node_put(awacs_node); - of_node_put(i2s_node); -} - -MODULE_DESCRIPTION("PowerMac built-in audio driver."); -MODULE_LICENSE("GPL"); - -module_init(dmasound_awacs_init); -module_exit(dmasound_awacs_cleanup); diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c index f4056a9c371b..a003c0ea9303 100644 --- a/sound/oss/dmasound/dmasound_core.c +++ b/sound/oss/dmasound/dmasound_core.c @@ -202,13 +202,6 @@ module_param(numWriteBufs, int, 0); static unsigned int writeBufSize = DEFAULT_BUFF_SIZE ; /* in bytes */ module_param(writeBufSize, int, 0); -#ifdef HAS_RECORD -static unsigned int numReadBufs = DEFAULT_N_BUFFERS; -module_param(numReadBufs, int, 0); -static unsigned int readBufSize = DEFAULT_BUFF_SIZE; /* in bytes */ -module_param(readBufSize, int, 0); -#endif - MODULE_LICENSE("GPL"); #ifdef MODULE @@ -403,10 +396,6 @@ static void mixer_init(void) struct sound_queue dmasound_write_sq; static void sq_reset_output(void) ; -#ifdef HAS_RECORD -struct sound_queue dmasound_read_sq; -static void sq_reset_input(void) ; -#endif static int sq_allocate_buffers(struct sound_queue *sq, int num, int size) { @@ -530,12 +519,6 @@ printk("dmasound_core: invalid frag count (user set %d)\n", sq->user_frags) ; sq->rear = -1; setup_func = dmasound.mach.write_sq_setup; } -#ifdef HAS_RECORD - else { - sq->rear = 0; - setup_func = dmasound.mach.read_sq_setup; - } -#endif if (setup_func) return setup_func(); return 0 ; @@ -672,13 +655,6 @@ static unsigned int sq_poll(struct file *file, struct poll_table_struct *wait) } if (file->f_mode & FMODE_WRITE ) poll_wait(file, &write_sq.action_queue, wait); -#ifdef HAS_RECORD - if (file->f_mode & FMODE_READ) - poll_wait(file, &read_sq.action_queue, wait); - if (file->f_mode & FMODE_READ) - if (read_sq.block_size - read_sq.rear_size > 0) - mask |= POLLIN | POLLRDNORM; -#endif if (file->f_mode & FMODE_WRITE) if (write_sq.count < write_sq.max_active || write_sq.block_size - write_sq.rear_size > 0) mask |= POLLOUT | POLLWRNORM; @@ -686,101 +662,6 @@ static unsigned int sq_poll(struct file *file, struct poll_table_struct *wait) } -#ifdef HAS_RECORD - /* - * 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 buffer we are currently returning to the user. - - * This level (> [1.5]) doesn't care what strategy the LL driver uses with - * DMA on over-run. It can leave it running (and keep active == 1) or it - * can kill it and set active == 0 in which case this routine will spot - * it and restart the DMA. - */ - -static ssize_t sq_read(struct file *file, char __user *dst, size_t uLeft, - loff_t *ppos) -{ - - ssize_t uRead, bLeft, bUsed, uUsed; - - if (uLeft == 0) - return 0; - - /* cater for the compatibility mode - record compiled in but no LL */ - if (dmasound.mach.record == NULL) - return -EINVAL ; - - /* see comment in sq_write() - */ - - if( shared_resources_initialised == 0) { - dmasound.mach.init() ; - shared_resources_initialised = 1 ; - } - - /* set up the sq if it is not already done. see comments in sq_write(). - */ - - if (read_sq.locked == 0) { - if ((uRead = sq_setup(&read_sq)) < 0) - return uRead ; - } - - uRead = 0; - - /* Move what the user requests, depending upon other options. - */ - while (uLeft > 0) { - - /* we happened to get behind and the LL driver killed DMA - then we should set it going again. This also sets it - going the first time through. - */ - if ( !read_sq.active ) - dmasound.mach.record(); - - /* When front == rear, the DMA is not done yet. - */ - while (read_sq.front == read_sq.rear) { - if (read_sq.open_mode & O_NONBLOCK) { - return uRead > 0 ? uRead : -EAGAIN; - } - SLEEP(read_sq.action_queue); - if (signal_pending(current)) - 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(dmasound.trans_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; -} -#endif /* HAS_RECORD */ - static inline void sq_init_waitqueue(struct sound_queue *sq) { init_waitqueue_head(&sq->action_queue); @@ -854,23 +735,6 @@ static int sq_open2(struct sound_queue *sq, struct file *file, mode_t mode, #define write_sq_open(file) \ sq_open2(&write_sq, file, FMODE_WRITE, numWriteBufs, writeBufSize ) -#ifdef HAS_RECORD -#define read_sq_init_waitqueue() sq_init_waitqueue(&read_sq) -#if 0 /* blocking open() */ -#define read_sq_wake_up(file) sq_wake_up(&read_sq, file, FMODE_READ) -#endif -#define read_sq_release_buffers() sq_release_buffers(&read_sq) -#define read_sq_open(file) \ - sq_open2(&read_sq, file, FMODE_READ, numReadBufs, readBufSize ) -#else -#define read_sq_init_waitqueue() do {} while (0) -#if 0 /* blocking open() */ -#define read_sq_wake_up(file) do {} while (0) -#endif -#define read_sq_release_buffers() do {} while (0) -#define sq_reset_input() do {} while (0) -#endif - static int sq_open(struct inode *inode, struct file *file) { int rc; @@ -881,25 +745,11 @@ static int sq_open(struct inode *inode, struct file *file) rc = write_sq_open(file); /* checks the f_mode */ if (rc) goto out; -#ifdef HAS_RECORD - if (dmasound.mach.record) { - rc = read_sq_open(file); /* checks the f_mode */ - if (rc) - goto out; - } else { /* no record function installed; in compat mode */ - if (file->f_mode & FMODE_READ) { - /* TODO: if O_RDWR, release any resources grabbed by write part */ - rc = -ENXIO; - goto out; - } - } -#else /* !HAS_RECORD */ if (file->f_mode & FMODE_READ) { /* TODO: if O_RDWR, release any resources grabbed by write part */ rc = -ENXIO ; /* I think this is what is required by open(2) */ goto out; } -#endif /* HAS_RECORD */ if (dmasound.mach.sq_open) dmasound.mach.sq_open(file->f_mode); @@ -956,43 +806,9 @@ static void sq_reset_output(void) write_sq.user_frag_size = 0 ; } -#ifdef HAS_RECORD - -static void sq_reset_input(void) -{ - if (dmasound.mach.record && read_sq.active) { - if (dmasound.mach.abort_read) { /* this routine must really be present */ - read_sq.syncing = 1 ; - /* this can use the read_sq.sync_queue to sleep if - necessary - it should not return until DMA - is really stopped - because we might deallocate - the buffers as the next action... - */ - dmasound.mach.abort_read() ; - } else { - printk(KERN_ERR - "dmasound_core: %s has no abort_read()!! all bets are off\n", - dmasound.mach.name) ; - } - } - read_sq.syncing = - read_sq.active = - read_sq.front = - read_sq.count = - read_sq.rear = 0 ; - - /* OK - we can unlock the parameters and fragment settings */ - read_sq.locked = 0 ; - read_sq.user_frags = 0 ; - read_sq.user_frag_size = 0 ; -} - -#endif - static void sq_reset(void) { sq_reset_output() ; - sq_reset_input() ; /* we could consider resetting the shared_resources_owner here... but I think it is probably still rather non-obvious to application writer */ @@ -1038,17 +854,6 @@ static int sq_release(struct inode *inode, struct file *file) lock_kernel(); -#ifdef HAS_RECORD - /* probably best to do the read side first - so that time taken to do it - overlaps with playing any remaining output samples. - */ - if (file->f_mode & FMODE_READ) { - sq_reset_input() ; /* make sure dma is stopped and all is quiet */ - read_sq_release_buffers(); - read_sq.busy = 0; - } -#endif - if (file->f_mode & FMODE_WRITE) { if (write_sq.busy) rc = sq_fsync(file, file->f_path.dentry); @@ -1105,11 +910,6 @@ static int shared_resources_are_mine(mode_t md) static int queues_are_quiescent(void) { -#ifdef HAS_RECORD - if (dmasound.mach.record) - if (read_sq.locked) - return 0 ; -#endif if (write_sq.locked) return 0 ; return 1 ; @@ -1185,13 +985,6 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd, the read_sq ones. */ size = 0 ; -#ifdef HAS_RECORD - if (dmasound.mach.record && (file->f_mode & FMODE_READ)) { - if ( !read_sq.locked ) - sq_setup(&read_sq) ; /* set params */ - size = read_sq.user_frag_size ; - } -#endif if (file->f_mode & FMODE_WRITE) { if ( !write_sq.locked ) sq_setup(&write_sq) ; @@ -1214,8 +1007,6 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd, everything - read, however, is killed imediately. */ result = 0 ; - if ((file->f_mode & FMODE_READ) && dmasound.mach.record) - sq_reset_input() ; if (file->f_mode & FMODE_WRITE) { result = sq_fsync(file, file->f_path.dentry); sq_reset_output() ; @@ -1294,13 +1085,6 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd, result = 0 ; nbufs = (data >> 16) & 0x7fff ; /* 0x7fff is 'use maximum' */ size = data & 0xffff; -#ifdef HAS_RECORD - if ((file->f_mode & FMODE_READ) && dmasound.mach.record) { - result = set_queue_frags(&read_sq, nbufs, size) ; - if (result) - return result ; - } -#endif if (file->f_mode & FMODE_WRITE) { result = set_queue_frags(&write_sq, nbufs, size) ; if (result) @@ -1348,20 +1132,6 @@ static const struct file_operations sq_fops = .release = sq_release, }; -#ifdef HAS_RECORD -static const struct file_operations sq_fops_record = -{ - .owner = THIS_MODULE, - .llseek = no_llseek, - .write = sq_write, - .poll = sq_poll, - .ioctl = sq_ioctl, - .open = sq_open, - .release = sq_release, - .read = sq_read, -}; -#endif - static int sq_init(void) { const struct file_operations *fops = &sq_fops; @@ -1369,10 +1139,6 @@ static int sq_init(void) int sq_unit; #endif -#ifdef HAS_RECORD - if (dmasound.mach.record) - fops = &sq_fops_record; -#endif sq_unit = register_sound_dsp(fops, -1); if (sq_unit < 0) { printk(KERN_ERR "dmasound_core: couldn't register fops\n") ; @@ -1380,7 +1146,6 @@ static int sq_init(void) } write_sq_init_waitqueue(); - read_sq_init_waitqueue(); /* These parameters will be restored for every clean open() * in the case of multiple open()s (e.g. dsp0 & dsp1) they @@ -1406,11 +1171,7 @@ static int sq_init(void) driver. */ -#ifdef HAS_RECORD -#define STAT_BUFF_LEN 1024 -#else #define STAT_BUFF_LEN 768 -#endif /* this is how much space we will allow the low-level driver to use in the stat buffer. Currently, 2 * (80 character line + <NL>). @@ -1518,11 +1279,6 @@ static int state_open(struct inode *inode, struct file *file) len += sprintf(buffer+len,"Allocated:%8s%6s\n","Buffers","Size") ; len += sprintf(buffer+len,"%9s:%8d%6d\n", "write", write_sq.numBufs, write_sq.bufSize) ; -#ifdef HAS_RECORD - if (dmasound.mach.record) - len += sprintf(buffer+len,"%9s:%8d%6d\n", - "read", read_sq.numBufs, read_sq.bufSize) ; -#endif len += sprintf(buffer+len, "Current : MaxFrg FragSiz MaxAct Frnt Rear " "Cnt RrSize A B S L xruns\n") ; @@ -1531,14 +1287,6 @@ static int state_open(struct inode *inode, struct file *file) write_sq.max_active, write_sq.front, write_sq.rear, write_sq.count, write_sq.rear_size, write_sq.active, write_sq.busy, write_sq.syncing, write_sq.locked, write_sq.xruns) ; -#ifdef HAS_RECORD - if (dmasound.mach.record) - len += sprintf(buffer+len,"%9s:%7d%8d%7d%5d%5d%4d%7d%2d%2d%2d%2d%7d\n", - "read", read_sq.max_count, read_sq.block_size, - read_sq.max_active, read_sq.front, read_sq.rear, - read_sq.count, read_sq.rear_size, read_sq.active, - read_sq.busy, read_sq.syncing, read_sq.locked, read_sq.xruns) ; -#endif #ifdef DEBUG_DMASOUND printk("dmasound: stat buffer used %d bytes\n", len) ; #endif @@ -1638,13 +1386,6 @@ int dmasound_init(void) (dmasound.mach.version >> 8), (dmasound.mach.version & 0xff)) ; printk(KERN_INFO "Write will use %4d fragments of %7d bytes as default\n", numWriteBufs, writeBufSize) ; -#ifdef HAS_RECORD - if (dmasound.mach.record) - printk(KERN_INFO - "Read will use %4d fragments of %7d bytes as default\n", - numReadBufs, readBufSize) ; -#endif - return 0; } @@ -1659,7 +1400,6 @@ void dmasound_deinit(void) } write_sq_release_buffers(); - read_sq_release_buffers(); if (mixer_unit >= 0) unregister_sound_mixer(mixer_unit); @@ -1684,36 +1424,12 @@ static int dmasound_setup(char *str) */ switch (ints[0]) { -#ifdef HAS_RECORD - case 5: - if ((ints[5] < 0) || (ints[5] > MAX_CATCH_RADIUS)) - printk("dmasound_setup: invalid catch radius, using default = %d\n", catchRadius); - else - catchRadius = ints[5]; - /* fall through */ - case 4: - if (ints[4] < MIN_BUFFERS) - printk("dmasound_setup: invalid number of read buffers, using default = %d\n", - numReadBufs); - else - numReadBufs = ints[4]; - /* fall through */ - case 3: - if ((size = ints[3]) < 256) /* check for small buffer specs */ - size <<= 10 ; - if (size < MIN_BUFSIZE || size > MAX_BUFSIZE) - printk("dmasound_setup: invalid read buffer size, using default = %d\n", readBufSize); - else - readBufSize = size; - /* fall through */ -#else 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 */ -#endif case 2: if (ints[1] < MIN_BUFFERS) printk("dmasound_setup: invalid number of buffers, using default = %d\n", numWriteBufs); @@ -1830,9 +1546,6 @@ EXPORT_SYMBOL(dmasound_init); EXPORT_SYMBOL(dmasound_deinit); #endif EXPORT_SYMBOL(dmasound_write_sq); -#ifdef HAS_RECORD -EXPORT_SYMBOL(dmasound_read_sq); -#endif EXPORT_SYMBOL(dmasound_catchRadius); #ifdef HAS_8BIT_TABLES EXPORT_SYMBOL(dmasound_ulaw2dma8); diff --git a/sound/oss/dmasound/tas3001c.c b/sound/oss/dmasound/tas3001c.c deleted file mode 100644 index 4b7dbdd2a438..000000000000 --- a/sound/oss/dmasound/tas3001c.c +++ /dev/null @@ -1,849 +0,0 @@ -/* - * Driver for the i2c/i2s based TA3004 sound chip used - * on some Apple hardware. Also known as "snapper". - * - * Tobias Sargeant <tobias.sargeant@bigpond.com> - * Based upon, tas3001c.c by Christopher C. Chimelis <chris@debian.org>: - * - * TODO: - * ----- - * * Enable control over input line 2 (is this connected?) - * * Implement sleep support (at least mute everything and - * * set gains to minimum during sleep) - * * Look into some of Darwin's tweaks regarding the mute - * * lines (delays & different behaviour on some HW) - * - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/proc_fs.h> -#include <linux/ioport.h> -#include <linux/sysctl.h> -#include <linux/types.h> -#include <linux/i2c.h> -#include <linux/init.h> -#include <linux/soundcard.h> -#include <linux/workqueue.h> -#include <asm/uaccess.h> -#include <asm/errno.h> -#include <asm/io.h> -#include <asm/prom.h> - -#include "dmasound.h" -#include "tas_common.h" -#include "tas3001c.h" - -#include "tas_ioctl.h" - -#define TAS3001C_BIQUAD_FILTER_COUNT 6 -#define TAS3001C_BIQUAD_CHANNEL_COUNT 2 - -#define VOL_DEFAULT (100 * 4 / 5) -#define INPUT_DEFAULT (100 * 4 / 5) -#define BASS_DEFAULT (100 / 2) -#define TREBLE_DEFAULT (100 / 2) - -struct tas3001c_data_t { - struct tas_data_t super; - int device_id; - int output_id; - int speaker_id; - struct tas_drce_t drce_state; - struct work_struct change; -}; - - -static const union tas_biquad_t -tas3001c_eq_unity={ - .buf = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } -}; - - -static inline unsigned char db_to_regval(short db) { - int r=0; - - r=(db+0x59a0) / 0x60; - - if (r < 0x91) return 0x91; - if (r > 0xef) return 0xef; - return r; -} - -static inline short quantize_db(short db) { - return db_to_regval(db) * 0x60 - 0x59a0; -} - - -static inline int -register_width(enum tas3001c_reg_t r) -{ - switch(r) { - case TAS3001C_REG_MCR: - case TAS3001C_REG_TREBLE: - case TAS3001C_REG_BASS: - return 1; - - case TAS3001C_REG_DRC: - return 2; - - case TAS3001C_REG_MIXER1: - case TAS3001C_REG_MIXER2: - return 3; - - case TAS3001C_REG_VOLUME: - return 6; - - case TAS3001C_REG_LEFT_BIQUAD0: - case TAS3001C_REG_LEFT_BIQUAD1: - case TAS3001C_REG_LEFT_BIQUAD2: - case TAS3001C_REG_LEFT_BIQUAD3: - case TAS3001C_REG_LEFT_BIQUAD4: - case TAS3001C_REG_LEFT_BIQUAD5: - case TAS3001C_REG_LEFT_BIQUAD6: - - case TAS3001C_REG_RIGHT_BIQUAD0: - case TAS3001C_REG_RIGHT_BIQUAD1: - case TAS3001C_REG_RIGHT_BIQUAD2: - case TAS3001C_REG_RIGHT_BIQUAD3: - case TAS3001C_REG_RIGHT_BIQUAD4: - case TAS3001C_REG_RIGHT_BIQUAD5: - case TAS3001C_REG_RIGHT_BIQUAD6: - return 15; - - default: - return 0; - } -} - -static int -tas3001c_write_register( struct tas3001c_data_t *self, - enum tas3001c_reg_t reg_num, - char *data, - uint write_mode) -{ - if (reg_num==TAS3001C_REG_MCR || - reg_num==TAS3001C_REG_BASS || - reg_num==TAS3001C_REG_TREBLE) { - return tas_write_byte_register(&self->super, - (uint)reg_num, - *data, - write_mode); - } else { - return tas_write_register(&self->super, - (uint)reg_num, - register_width(reg_num), - data, - write_mode); - } -} - -static int -tas3001c_sync_register( struct tas3001c_data_t *self, - enum tas3001c_reg_t reg_num) -{ - if (reg_num==TAS3001C_REG_MCR || - reg_num==TAS3001C_REG_BASS || - reg_num==TAS3001C_REG_TREBLE) { - return tas_sync_byte_register(&self->super, - (uint)reg_num, - register_width(reg_num)); - } else { - return tas_sync_register(&self->super, - (uint)reg_num, - register_width(reg_num)); - } -} - -static int -tas3001c_read_register( struct tas3001c_data_t *self, - enum tas3001c_reg_t reg_num, - char *data, - uint write_mode) -{ - return tas_read_register(&self->super, - (uint)reg_num, - register_width(reg_num), - data); -} - -static inline int -tas3001c_fast_load(struct tas3001c_data_t *self, int fast) -{ - if (fast) - self->super.shadow[TAS3001C_REG_MCR][0] |= 0x80; - else - self->super.shadow[TAS3001C_REG_MCR][0] &= 0x7f; - return tas3001c_sync_register(self,TAS3001C_REG_MCR); -} - -static uint -tas3001c_supported_mixers(struct tas3001c_data_t *self) -{ - return SOUND_MASK_VOLUME | - SOUND_MASK_PCM | - SOUND_MASK_ALTPCM | - SOUND_MASK_TREBLE | - SOUND_MASK_BASS; -} - -static int -tas3001c_mixer_is_stereo(struct tas3001c_data_t *self,int mixer) -{ - switch(mixer) { - case SOUND_MIXER_VOLUME: - return 1; - default: - return 0; - } -} - -static uint -tas3001c_stereo_mixers(struct tas3001c_data_t *self) -{ - uint r=tas3001c_supported_mixers(self); - uint i; - - for (i=1; i<SOUND_MIXER_NRDEVICES; i++) - if (r&(1<<i) && !tas3001c_mixer_is_stereo(self,i)) - r &= ~(1<<i); - return r; -} - -static int -tas3001c_get_mixer_level(struct tas3001c_data_t *self,int mixer,uint *level) -{ - if (!self) - return -1; - - *level=self->super.mixer[mixer]; - - return 0; -} - -static int -tas3001c_set_mixer_level(struct tas3001c_data_t *self,int mixer,uint level) -{ - int rc; - tas_shadow_t *shadow; - - uint temp; - uint offset=0; - - if (!self) - return -1; - - shadow=self->super.shadow; - - if (!tas3001c_mixer_is_stereo(self,mixer)) - level = tas_mono_to_stereo(level); - - switch(mixer) { - case SOUND_MIXER_VOLUME: - temp = tas3001c_gain.master[level&0xff]; - shadow[TAS3001C_REG_VOLUME][0] = (temp >> 16) & 0xff; - shadow[TAS3001C_REG_VOLUME][1] = (temp >> 8) & 0xff; - shadow[TAS3001C_REG_VOLUME][2] = (temp >> 0) & 0xff; - temp = tas3001c_gain.master[(level>>8)&0xff]; - shadow[TAS3001C_REG_VOLUME][3] = (temp >> 16) & 0xff; - shadow[TAS3001C_REG_VOLUME][4] = (temp >> 8) & 0xff; - shadow[TAS3001C_REG_VOLUME][5] = (temp >> 0) & 0xff; - rc = tas3001c_sync_register(self,TAS3001C_REG_VOLUME); - break; - case SOUND_MIXER_ALTPCM: - /* tas3001c_fast_load(self, 1); */ - level = tas_mono_to_stereo(level); - temp = tas3001c_gain.mixer[level&0xff]; - shadow[TAS3001C_REG_MIXER2][offset+0] = (temp >> 16) & 0xff; - shadow[TAS3001C_REG_MIXER2][offset+1] = (temp >> 8) & 0xff; - shadow[TAS3001C_REG_MIXER2][offset+2] = (temp >> 0) & 0xff; - rc = tas3001c_sync_register(self,TAS3001C_REG_MIXER2); - /* tas3001c_fast_load(self, 0); */ - break; - case SOUND_MIXER_PCM: - /* tas3001c_fast_load(self, 1); */ - level = tas_mono_to_stereo(level); - temp = tas3001c_gain.mixer[level&0xff]; - shadow[TAS3001C_REG_MIXER1][offset+0] = (temp >> 16) & 0xff; - shadow[TAS3001C_REG_MIXER1][offset+1] = (temp >> 8) & 0xff; - shadow[TAS3001C_REG_MIXER1][offset+2] = (temp >> 0) & 0xff; - rc = tas3001c_sync_register(self,TAS3001C_REG_MIXER1); - /* tas3001c_fast_load(self, 0); */ - break; - case SOUND_MIXER_TREBLE: - temp = tas3001c_gain.treble[level&0xff]; - shadow[TAS3001C_REG_TREBLE][0]=temp&0xff; - rc = tas3001c_sync_register(self,TAS3001C_REG_TREBLE); - break; - case SOUND_MIXER_BASS: - temp = tas3001c_gain.bass[level&0xff]; - shadow[TAS3001C_REG_BASS][0]=temp&0xff; - rc = tas3001c_sync_register(self,TAS3001C_REG_BASS); - break; - default: - rc = -1; - break; - } - if (rc < 0) - return rc; - self->super.mixer[mixer]=level; - return 0; -} - -static int -tas3001c_leave_sleep(struct tas3001c_data_t *self) -{ - unsigned char mcr = (1<<6)+(2<<4)+(2<<2); - - if (!self) - return -1; - - /* Make sure something answers on the i2c bus */ - if (tas3001c_write_register(self, TAS3001C_REG_MCR, &mcr, - WRITE_NORMAL|FORCE_WRITE) < 0) - return -1; - - tas3001c_fast_load(self, 1); - - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD0); - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD1); - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD2); - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD3); - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD4); - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD5); - - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD0); - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD1); - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD2); - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD3); - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD4); - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD5); - - tas3001c_fast_load(self, 0); - - (void)tas3001c_sync_register(self,TAS3001C_REG_BASS); - (void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE); - (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1); - (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2); - (void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME); - - return 0; -} - -static int -tas3001c_enter_sleep(struct tas3001c_data_t *self) -{ - /* Stub for now, but I have the details on low-power mode */ - if (!self) - return -1; - return 0; -} - -static int -tas3001c_sync_biquad( struct tas3001c_data_t *self, - u_int channel, - u_int filter) -{ - enum tas3001c_reg_t reg; - - if (channel >= TAS3001C_BIQUAD_CHANNEL_COUNT || - filter >= TAS3001C_BIQUAD_FILTER_COUNT) return -EINVAL; - - reg=( channel ? TAS3001C_REG_RIGHT_BIQUAD0 : TAS3001C_REG_LEFT_BIQUAD0 ) + filter; - - return tas3001c_sync_register(self,reg); -} - -static int -tas3001c_write_biquad_shadow( struct tas3001c_data_t *self, - u_int channel, - u_int filter, - const union tas_biquad_t *biquad) -{ - tas_shadow_t *shadow=self->super.shadow; - enum tas3001c_reg_t reg; - - if (channel >= TAS3001C_BIQUAD_CHANNEL_COUNT || - filter >= TAS3001C_BIQUAD_FILTER_COUNT) return -EINVAL; - - reg=( channel ? TAS3001C_REG_RIGHT_BIQUAD0 : TAS3001C_REG_LEFT_BIQUAD0 ) + filter; - - SET_4_20(shadow[reg], 0,biquad->coeff.b0); - SET_4_20(shadow[reg], 3,biquad->coeff.b1); - SET_4_20(shadow[reg], 6,biquad->coeff.b2); - SET_4_20(shadow[reg], 9,biquad->coeff.a1); - SET_4_20(shadow[reg],12,biquad->coeff.a2); - - return 0; -} - -static int -tas3001c_write_biquad( struct tas3001c_data_t *self, - u_int channel, - u_int filter, - const union tas_biquad_t *biquad) -{ - int rc; - - rc=tas3001c_write_biquad_shadow(self, channel, filter, biquad); - if (rc < 0) return rc; - - return tas3001c_sync_biquad(self, channel, filter); -} - -static int -tas3001c_write_biquad_list( struct tas3001c_data_t *self, - u_int filter_count, - u_int flags, - struct tas_biquad_ctrl_t *biquads) -{ - int i; - int rc; - - if (flags & TAS_BIQUAD_FAST_LOAD) tas3001c_fast_load(self,1); - - for (i=0; i<filter_count; i++) { - rc=tas3001c_write_biquad(self, - biquads[i].channel, - biquads[i].filter, - &biquads[i].data); - if (rc < 0) break; - } - - if (flags & TAS_BIQUAD_FAST_LOAD) { - tas3001c_fast_load(self,0); - - (void)tas3001c_sync_register(self,TAS3001C_REG_BASS); - (void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE); - (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1); - (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2); - (void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME); - } - - return rc; -} - -static int -tas3001c_read_biquad( struct tas3001c_data_t *self, - u_int channel, - u_int filter, - union tas_biquad_t *biquad) -{ - tas_shadow_t *shadow=self->super.shadow; - enum tas3001c_reg_t reg; - - if (channel >= TAS3001C_BIQUAD_CHANNEL_COUNT || - filter >= TAS3001C_BIQUAD_FILTER_COUNT) return -EINVAL; - - reg=( channel ? TAS3001C_REG_RIGHT_BIQUAD0 : TAS3001C_REG_LEFT_BIQUAD0 ) + filter; - - biquad->coeff.b0=GET_4_20(shadow[reg], 0); - biquad->coeff.b1=GET_4_20(shadow[reg], 3); - biquad->coeff.b2=GET_4_20(shadow[reg], 6); - biquad->coeff.a1=GET_4_20(shadow[reg], 9); - biquad->coeff.a2=GET_4_20(shadow[reg],12); - - return 0; -} - -static int -tas3001c_eq_rw( struct tas3001c_data_t *self, - u_int cmd, - u_long arg) -{ - int rc; - struct tas_biquad_ctrl_t biquad; - void __user *argp = (void __user *)arg; - - if (copy_from_user(&biquad, argp, sizeof(struct tas_biquad_ctrl_t))) { - return -EFAULT; - } - - if (cmd & SIOC_IN) { - rc=tas3001c_write_biquad(self, biquad.channel, biquad.filter, &biquad.data); - if (rc != 0) return rc; - } - - if (cmd & SIOC_OUT) { - rc=tas3001c_read_biquad(self, biquad.channel, biquad.filter, &biquad.data); - if (rc != 0) return rc; - - if (copy_to_user(argp, &biquad, sizeof(struct tas_biquad_ctrl_t))) { - return -EFAULT; - } - - } - return 0; -} - -static int -tas3001c_eq_list_rw( struct tas3001c_data_t *self, - u_int cmd, - u_long arg) -{ - int rc; - int filter_count; - int flags; - int i,j; - char sync_required[2][6]; - struct tas_biquad_ctrl_t biquad; - struct tas_biquad_ctrl_list_t __user *argp = (void __user *)arg; - - memset(sync_required,0,sizeof(sync_required)); - - if (copy_from_user(&filter_count, &argp->filter_count, sizeof(int))) - return -EFAULT; - - if (copy_from_user(&flags, &argp->flags, sizeof(int))) - return -EFAULT; - - if (cmd & SIOC_IN) { - } - - for (i=0; i < filter_count; i++) { - if (copy_from_user(&biquad, &argp->biquads[i], - sizeof(struct tas_biquad_ctrl_t))) { - return -EFAULT; - } - - if (cmd & SIOC_IN) { - sync_required[biquad.channel][biquad.filter]=1; - rc=tas3001c_write_biquad_shadow(self, biquad.channel, biquad.filter, &biquad.data); - if (rc != 0) return rc; - } - - if (cmd & SIOC_OUT) { - rc=tas3001c_read_biquad(self, biquad.channel, biquad.filter, &biquad.data); - if (rc != 0) return rc; - - if (copy_to_user(&argp->biquads[i], &biquad, - sizeof(struct tas_biquad_ctrl_t))) { - return -EFAULT; - } - } - } - - if (cmd & SIOC_IN) { - if (flags & TAS_BIQUAD_FAST_LOAD) tas3001c_fast_load(self,1); - for (i=0; i<2; i++) { - for (j=0; j<6; j++) { - if (sync_required[i][j]) { - rc=tas3001c_sync_biquad(self, i, j); - if (rc < 0) return rc; - } - } - } - if (flags & TAS_BIQUAD_FAST_LOAD) { - tas3001c_fast_load(self,0); - /* now we need to set up the mixers again, - because leaving fast mode resets them. */ - (void)tas3001c_sync_register(self,TAS3001C_REG_BASS); - (void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE); - (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1); - (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2); - (void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME); - } - } - - return 0; -} - -static int -tas3001c_update_drce( struct tas3001c_data_t *self, - int flags, - struct tas_drce_t *drce) -{ - tas_shadow_t *shadow; - shadow=self->super.shadow; - - shadow[TAS3001C_REG_DRC][1] = 0xc1; - - if (flags & TAS_DRCE_THRESHOLD) { - self->drce_state.threshold=quantize_db(drce->threshold); - shadow[TAS3001C_REG_DRC][2] = db_to_regval(self->drce_state.threshold); - } - - if (flags & TAS_DRCE_ENABLE) { - self->drce_state.enable = drce->enable; - } - - if (!self->drce_state.enable) { - shadow[TAS3001C_REG_DRC][0] = 0xf0; - } - -#ifdef DEBUG_DRCE - printk("DRCE IOCTL: set [ ENABLE:%x THRESH:%x\n", - self->drce_state.enable, - self->drce_state.threshold); - - printk("DRCE IOCTL: reg [ %02x %02x ]\n", - (unsigned char)shadow[TAS3001C_REG_DRC][0], - (unsigned char)shadow[TAS3001C_REG_DRC][1]); -#endif - - return tas3001c_sync_register(self, TAS3001C_REG_DRC); -} - -static int -tas3001c_drce_rw( struct tas3001c_data_t *self, - u_int cmd, - u_long arg) -{ - int rc; - struct tas_drce_ctrl_t drce_ctrl; - void __user *argp = (void __user *)arg; - - if (copy_from_user(&drce_ctrl, argp, sizeof(struct tas_drce_ctrl_t))) - return -EFAULT; - -#ifdef DEBUG_DRCE - printk("DRCE IOCTL: input [ FLAGS:%x ENABLE:%x THRESH:%x\n", - drce_ctrl.flags, - drce_ctrl.data.enable, - drce_ctrl.data.threshold); -#endif - - if (cmd & SIOC_IN) { - rc = tas3001c_update_drce(self, drce_ctrl.flags, &drce_ctrl.data); - if (rc < 0) - return rc; - } - - if (cmd & SIOC_OUT) { - if (drce_ctrl.flags & TAS_DRCE_ENABLE) - drce_ctrl.data.enable = self->drce_state.enable; - - if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) - drce_ctrl.data.threshold = self->drce_state.threshold; - - if (copy_to_user(argp, &drce_ctrl, - sizeof(struct tas_drce_ctrl_t))) { - return -EFAULT; - } - } - - return 0; -} - -static void -tas3001c_update_device_parameters(struct tas3001c_data_t *self) -{ - int i,j; - - if (!self) return; - - if (self->output_id == TAS_OUTPUT_HEADPHONES) { - tas3001c_fast_load(self, 1); - - for (i=0; i<TAS3001C_BIQUAD_CHANNEL_COUNT; i++) { - for (j=0; j<TAS3001C_BIQUAD_FILTER_COUNT; j++) { - tas3001c_write_biquad(self, i, j, &tas3001c_eq_unity); - } - } - - tas3001c_fast_load(self, 0); - - (void)tas3001c_sync_register(self,TAS3001C_REG_BASS); - (void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE); - (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1); - (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2); - (void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME); - - return; - } - - for (i=0; tas3001c_eq_prefs[i]; i++) { - struct tas_eq_pref_t *eq = tas3001c_eq_prefs[i]; - - if (eq->device_id == self->device_id && - (eq->output_id == 0 || eq->output_id == self->output_id) && - (eq->speaker_id == 0 || eq->speaker_id == self->speaker_id)) { - - tas3001c_update_drce(self, TAS_DRCE_ALL, eq->drce); - tas3001c_write_biquad_list(self, eq->filter_count, TAS_BIQUAD_FAST_LOAD, eq->biquads); - - break; - } - } -} - -static void -tas3001c_device_change_handler(struct work_struct *work) -{ - struct tas3001c_data_t *self; - self = container_of(work, struct tas3001c_data_t, change); - tas3001c_update_device_parameters(self); -} - -static int -tas3001c_output_device_change( struct tas3001c_data_t *self, - int device_id, - int output_id, - int speaker_id) -{ - self->device_id=device_id; - self->output_id=output_id; - self->speaker_id=speaker_id; - - schedule_work(&self->change); - return 0; -} - -static int -tas3001c_device_ioctl( struct tas3001c_data_t *self, - u_int cmd, - u_long arg) -{ - uint __user *argp = (void __user *)arg; - switch (cmd) { - case TAS_READ_EQ: - case TAS_WRITE_EQ: - return tas3001c_eq_rw(self, cmd, arg); - - case TAS_READ_EQ_LIST: - case TAS_WRITE_EQ_LIST: - return tas3001c_eq_list_rw(self, cmd, arg); - - case TAS_READ_EQ_FILTER_COUNT: - put_user(TAS3001C_BIQUAD_FILTER_COUNT, argp); - return 0; - - case TAS_READ_EQ_CHANNEL_COUNT: - put_user(TAS3001C_BIQUAD_CHANNEL_COUNT, argp); - return 0; - - case TAS_READ_DRCE: - case TAS_WRITE_DRCE: - return tas3001c_drce_rw(self, cmd, arg); - - case TAS_READ_DRCE_CAPS: - put_user(TAS_DRCE_ENABLE | TAS_DRCE_THRESHOLD, argp); - return 0; - - case TAS_READ_DRCE_MIN: - case TAS_READ_DRCE_MAX: { - struct tas_drce_ctrl_t drce_ctrl; - - if (copy_from_user(&drce_ctrl, argp, - sizeof(struct tas_drce_ctrl_t))) { - return -EFAULT; - } - - if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) { - if (cmd == TAS_READ_DRCE_MIN) { - drce_ctrl.data.threshold=-36<<8; - } else { - drce_ctrl.data.threshold=-6<<8; - } - } - - if (copy_to_user(argp, &drce_ctrl, - sizeof(struct tas_drce_ctrl_t))) { - return -EFAULT; - } - } - } - - return -EINVAL; -} - -static int -tas3001c_init_mixer(struct tas3001c_data_t *self) -{ - unsigned char mcr = (1<<6)+(2<<4)+(2<<2); - - /* Make sure something answers on the i2c bus */ - if (tas3001c_write_register(self, TAS3001C_REG_MCR, &mcr, - WRITE_NORMAL|FORCE_WRITE) < 0) - return -1; - - tas3001c_fast_load(self, 1); - - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD0); - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD1); - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD2); - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD3); - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD4); - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD5); - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD6); - - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD0); - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD1); - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD2); - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD3); - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD4); - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD5); - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD6); - - tas3001c_fast_load(self, 0); - - tas3001c_set_mixer_level(self, SOUND_MIXER_VOLUME, VOL_DEFAULT<<8 | VOL_DEFAULT); - tas3001c_set_mixer_level(self, SOUND_MIXER_PCM, INPUT_DEFAULT<<8 | INPUT_DEFAULT); - tas3001c_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0); - - tas3001c_set_mixer_level(self, SOUND_MIXER_BASS, BASS_DEFAULT); - tas3001c_set_mixer_level(self, SOUND_MIXER_TREBLE, TREBLE_DEFAULT); - - return 0; -} - -static int -tas3001c_uninit_mixer(struct tas3001c_data_t *self) -{ - tas3001c_set_mixer_level(self, SOUND_MIXER_VOLUME, 0); - tas3001c_set_mixer_level(self, SOUND_MIXER_PCM, 0); - tas3001c_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0); - - tas3001c_set_mixer_level(self, SOUND_MIXER_BASS, 0); - tas3001c_set_mixer_level(self, SOUND_MIXER_TREBLE, 0); - - return 0; -} - -static int -tas3001c_init(struct i2c_client *client) -{ - struct tas3001c_data_t *self; - size_t sz = sizeof(*self) + (TAS3001C_REG_MAX*sizeof(tas_shadow_t)); - int i, j; - - self = kzalloc(sz, GFP_KERNEL); - if (!self) - return -ENOMEM; - - self->super.client = client; - self->super.shadow = (tas_shadow_t *)(self+1); - self->output_id = TAS_OUTPUT_HEADPHONES; - - dev_set_drvdata(&client->dev, self); - - for (i = 0; i < TAS3001C_BIQUAD_CHANNEL_COUNT; i++) - for (j = 0; j < TAS3001C_BIQUAD_FILTER_COUNT; j++) - tas3001c_write_biquad_shadow(self, i, j, - &tas3001c_eq_unity); - - INIT_WORK(&self->change, tas3001c_device_change_handler); - return 0; -} - -static void -tas3001c_uninit(struct tas3001c_data_t *self) -{ - tas3001c_uninit_mixer(self); - kfree(self); -} - -struct tas_driver_hooks_t tas3001c_hooks = { - .init = (tas_hook_init_t)tas3001c_init, - .post_init = (tas_hook_post_init_t)tas3001c_init_mixer, - .uninit = (tas_hook_uninit_t)tas3001c_uninit, - .get_mixer_level = (tas_hook_get_mixer_level_t)tas3001c_get_mixer_level, - .set_mixer_level = (tas_hook_set_mixer_level_t)tas3001c_set_mixer_level, - .enter_sleep = (tas_hook_enter_sleep_t)tas3001c_enter_sleep, - .leave_sleep = (tas_hook_leave_sleep_t)tas3001c_leave_sleep, - .supported_mixers = (tas_hook_supported_mixers_t)tas3001c_supported_mixers, - .mixer_is_stereo = (tas_hook_mixer_is_stereo_t)tas3001c_mixer_is_stereo, - .stereo_mixers = (tas_hook_stereo_mixers_t)tas3001c_stereo_mixers, - .output_device_change = (tas_hook_output_device_change_t)tas3001c_output_device_change, - .device_ioctl = (tas_hook_device_ioctl_t)tas3001c_device_ioctl -}; diff --git a/sound/oss/dmasound/tas3001c.h b/sound/oss/dmasound/tas3001c.h deleted file mode 100644 index 3660da33a2db..000000000000 --- a/sound/oss/dmasound/tas3001c.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Header file for the i2c/i2s based TA3001c sound chip used - * on some Apple hardware. Also known as "tumbler". - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - * - * Written by Christopher C. Chimelis <chris@debian.org> - */ - -#ifndef _TAS3001C_H_ -#define _TAS3001C_H_ - -#include <linux/types.h> - -#include "tas_common.h" -#include "tas_eq_prefs.h" - -/* - * Macros that correspond to the registers that we write to - * when setting the various values. - */ - -#define TAS3001C_VERSION "0.3" -#define TAS3001C_DATE "20011214" - -#define I2C_DRIVERNAME_TAS3001C "TAS3001c driver V " TAS3001C_VERSION -#define I2C_DRIVERID_TAS3001C (I2C_DRIVERID_TAS_BASE+0) - -extern struct tas_driver_hooks_t tas3001c_hooks; -extern struct tas_gain_t tas3001c_gain; -extern struct tas_eq_pref_t *tas3001c_eq_prefs[]; - -enum tas3001c_reg_t { - TAS3001C_REG_MCR = 0x01, - TAS3001C_REG_DRC = 0x02, - - TAS3001C_REG_VOLUME = 0x04, - TAS3001C_REG_TREBLE = 0x05, - TAS3001C_REG_BASS = 0x06, - TAS3001C_REG_MIXER1 = 0x07, - TAS3001C_REG_MIXER2 = 0x08, - - TAS3001C_REG_LEFT_BIQUAD0 = 0x0a, - TAS3001C_REG_LEFT_BIQUAD1 = 0x0b, - TAS3001C_REG_LEFT_BIQUAD2 = 0x0c, - TAS3001C_REG_LEFT_BIQUAD3 = 0x0d, - TAS3001C_REG_LEFT_BIQUAD4 = 0x0e, - TAS3001C_REG_LEFT_BIQUAD5 = 0x0f, - TAS3001C_REG_LEFT_BIQUAD6 = 0x10, - - TAS3001C_REG_RIGHT_BIQUAD0 = 0x13, - TAS3001C_REG_RIGHT_BIQUAD1 = 0x14, - TAS3001C_REG_RIGHT_BIQUAD2 = 0x15, - TAS3001C_REG_RIGHT_BIQUAD3 = 0x16, - TAS3001C_REG_RIGHT_BIQUAD4 = 0x17, - TAS3001C_REG_RIGHT_BIQUAD5 = 0x18, - TAS3001C_REG_RIGHT_BIQUAD6 = 0x19, - - TAS3001C_REG_MAX = 0x20 -}; - -#endif /* _TAS3001C_H_ */ diff --git a/sound/oss/dmasound/tas3001c_tables.c b/sound/oss/dmasound/tas3001c_tables.c deleted file mode 100644 index 1768fa95f25b..000000000000 --- a/sound/oss/dmasound/tas3001c_tables.c +++ /dev/null @@ -1,375 +0,0 @@ -#include "tas_common.h" -#include "tas_eq_prefs.h" - -static struct tas_drce_t eqp_0e_2_1_drce = { - .enable = 1, - .above = { .val = 3.0 * (1<<8), .expand = 0 }, - .below = { .val = 1.0 * (1<<8), .expand = 0 }, - .threshold = -15.33 * (1<<8), - .energy = 2.4 * (1<<12), - .attack = 0.013 * (1<<12), - .decay = 0.212 * (1<<12), -}; - -static struct tas_biquad_ctrl_t eqp_0e_2_1_biquads[]={ - { .channel = 0, .filter = 0, .data = { .coeff = { 0x0FCAD3, 0xE06A58, 0x0FCAD3, 0xE06B09, 0x0F9657 } } }, - { .channel = 0, .filter = 1, .data = { .coeff = { 0x041731, 0x082E63, 0x041731, 0xFD8D08, 0x02CFBD } } }, - { .channel = 0, .filter = 2, .data = { .coeff = { 0x0FFDC7, 0xE0524C, 0x0FBFAA, 0xE0524C, 0x0FBD72 } } }, - { .channel = 0, .filter = 3, .data = { .coeff = { 0x0F3D35, 0xE228CA, 0x0EC7B2, 0xE228CA, 0x0E04E8 } } }, - { .channel = 0, .filter = 4, .data = { .coeff = { 0x0FCEBF, 0xE181C2, 0x0F2656, 0xE181C2, 0x0EF516 } } }, - { .channel = 0, .filter = 5, .data = { .coeff = { 0x0EC417, 0x073E22, 0x0B0633, 0x073E22, 0x09CA4A } } }, - - { .channel = 1, .filter = 0, .data = { .coeff = { 0x0FCAD3, 0xE06A58, 0x0FCAD3, 0xE06B09, 0x0F9657 } } }, - { .channel = 1, .filter = 1, .data = { .coeff = { 0x041731, 0x082E63, 0x041731, 0xFD8D08, 0x02CFBD } } }, - { .channel = 1, .filter = 2, .data = { .coeff = { 0x0FFDC7, 0xE0524C, 0x0FBFAA, 0xE0524C, 0x0FBD72 } } }, - { .channel = 1, .filter = 3, .data = { .coeff = { 0x0F3D35, 0xE228CA, 0x0EC7B2, 0xE228CA, 0x0E04E8 } } }, - { .channel = 1, .filter = 4, .data = { .coeff = { 0x0FCEBF, 0xE181C2, 0x0F2656, 0xE181C2, 0x0EF516 } } }, - { .channel = 1, .filter = 5, .data = { .coeff = { 0x0EC417, 0x073E22, 0x0B0633, 0x073E22, 0x09CA4A } } }, -}; - -static struct tas_eq_pref_t eqp_0e_2_1 = { - .sample_rate = 44100, - .device_id = 0x0e, - .output_id = TAS_OUTPUT_EXTERNAL_SPKR, - .speaker_id = 0x01, - - .drce = &eqp_0e_2_1_drce, - - .filter_count = 12, - .biquads = eqp_0e_2_1_biquads -}; - -/* ======================================================================== */ - -static struct tas_drce_t eqp_10_1_0_drce={ - .enable = 1, - .above = { .val = 3.0 * (1<<8), .expand = 0 }, - .below = { .val = 1.0 * (1<<8), .expand = 0 }, - .threshold = -12.46 * (1<<8), - .energy = 2.4 * (1<<12), - .attack = 0.013 * (1<<12), - .decay = 0.212 * (1<<12), -}; - -static struct tas_biquad_ctrl_t eqp_10_1_0_biquads[]={ - { .channel = 0, .filter = 0, .data = { .coeff = { 0x0F4A12, 0xE16BDA, 0x0F4A12, 0xE173F0, 0x0E9C3A } } }, - { .channel = 0, .filter = 1, .data = { .coeff = { 0x02DD54, 0x05BAA8, 0x02DD54, 0xF8001D, 0x037532 } } }, - { .channel = 0, .filter = 2, .data = { .coeff = { 0x0E2FC7, 0xE4D5DC, 0x0D7477, 0xE4D5DC, 0x0BA43F } } }, - { .channel = 0, .filter = 3, .data = { .coeff = { 0x0E7899, 0xE67CCA, 0x0D0E93, 0xE67CCA, 0x0B872D } } }, - { .channel = 0, .filter = 4, .data = { .coeff = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } }, - { .channel = 0, .filter = 5, .data = { .coeff = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } }, - - { .channel = 1, .filter = 0, .data = { .coeff = { 0x0F4A12, 0xE16BDA, 0x0F4A12, 0xE173F0, 0x0E9C3A } } }, - { .channel = 1, .filter = 1, .data = { .coeff = { 0x02DD54, 0x05BAA8, 0x02DD54, 0xF8001D, 0x037532 } } }, - { .channel = 1, .filter = 2, .data = { .coeff = { 0x0E2FC7, 0xE4D5DC, 0x0D7477, 0xE4D5DC, 0x0BA43F } } }, - { .channel = 1, .filter = 3, .data = { .coeff = { 0x0E7899, 0xE67CCA, 0x0D0E93, 0xE67CCA, 0x0B872D } } }, - { .channel = 1, .filter = 4, .data = { .coeff = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } }, - { .channel = 1, .filter = 5, .data = { .coeff = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } }, -}; - -static struct tas_eq_pref_t eqp_10_1_0 = { - .sample_rate = 44100, - .device_id = 0x10, - .output_id = TAS_OUTPUT_INTERNAL_SPKR, - .speaker_id = 0x00, - - .drce = &eqp_10_1_0_drce, - - .filter_count = 12, - .biquads = eqp_10_1_0_biquads -}; - -/* ======================================================================== */ - -static struct tas_drce_t eqp_15_2_1_drce={ - .enable = 1, - .above = { .val = 3.0 * (1<<8), .expand = 0 }, - .below = { .val = 1.0 * (1<<8), .expand = 0 }, - .threshold = -15.33 * (1<<8), - .energy = 2.4 * (1<<12), - .attack = 0.013 * (1<<12), - .decay = 0.212 * (1<<12), -}; - -static struct tas_biquad_ctrl_t eqp_15_2_1_biquads[]={ - { .channel = 0, .filter = 0, .data = { .coeff = { 0x0FE143, 0xE05204, 0x0FCCC5, 0xE05266, 0x0FAE6B } } }, - { .channel = 0, .filter = 1, .data = { .coeff = { 0x102383, 0xE03A03, 0x0FA325, 0xE03A03, 0x0FC6A8 } } }, - { .channel = 0, .filter = 2, .data = { .coeff = { 0x0FF2AB, 0xE06285, 0x0FB20A, 0xE06285, 0x0FA4B5 } } }, - { .channel = 0, .filter = 3, .data = { .coeff = { 0x0F544D, 0xE35971, 0x0D8F3A, 0xE35971, 0x0CE388 } } }, - { .channel = 0, .filter = 4, .data = { .coeff = { 0x13E1D3, 0xF3ECB5, 0x042227, 0xF3ECB5, 0x0803FA } } }, - { .channel = 0, .filter = 5, .data = { .coeff = { 0x0AC119, 0x034181, 0x078AB1, 0x034181, 0x024BCA } } }, - - { .channel = 1, .filter = 0, .data = { .coeff = { 0x0FE143, 0xE05204, 0x0FCCC5, 0xE05266, 0x0FAE6B } } }, - { .channel = 1, .filter = 1, .data = { .coeff = { 0x102383, 0xE03A03, 0x0FA325, 0xE03A03, 0x0FC6A8 } } }, - { .channel = 1, .filter = 2, .data = { .coeff = { 0x0FF2AB, 0xE06285, 0x0FB20A, 0xE06285, 0x0FA4B5 } } }, - { .channel = 1, .filter = 3, .data = { .coeff = { 0x0F544D, 0xE35971, 0x0D8F3A, 0xE35971, 0x0CE388 } } }, - { .channel = 1, .filter = 4, .data = { .coeff = { 0x13E1D3, 0xF3ECB5, 0x042227, 0xF3ECB5, 0x0803FA } } }, - { .channel = 1, .filter = 5, .data = { .coeff = { 0x0AC119, 0x034181, 0x078AB1, 0x034181, 0x024BCA } } }, -}; - -static struct tas_eq_pref_t eqp_15_2_1 = { - .sample_rate = 44100, - .device_id = 0x15, - .output_id = TAS_OUTPUT_EXTERNAL_SPKR, - .speaker_id = 0x01, - - .drce = &eqp_15_2_1_drce, - - .filter_count = 12, - .biquads = eqp_15_2_1_biquads -}; - -/* ======================================================================== */ - -static struct tas_drce_t eqp_15_1_0_drce={ - .enable = 1, - .above = { .val = 3.0 * (1<<8), .expand = 0 }, - .below = { .val = 1.0 * (1<<8), .expand = 0 }, - .threshold = 0.0 * (1<<8), - .energy = 2.4 * (1<<12), - .attack = 0.013 * (1<<12), - .decay = 0.212 * (1<<12), -}; - -static struct tas_biquad_ctrl_t eqp_15_1_0_biquads[]={ - { .channel = 0, .filter = 0, .data = { .coeff = { 0x0FAD08, 0xE0A5EF, 0x0FAD08, 0xE0A79D, 0x0F5BBE } } }, - { .channel = 0, .filter = 1, .data = { .coeff = { 0x04B38D, 0x09671B, 0x04B38D, 0x000F71, 0x02BEC5 } } }, - { .channel = 0, .filter = 2, .data = { .coeff = { 0x0FDD32, 0xE0A56F, 0x0F8A69, 0xE0A56F, 0x0F679C } } }, - { .channel = 0, .filter = 3, .data = { .coeff = { 0x0FD284, 0xE135FB, 0x0F2161, 0xE135FB, 0x0EF3E5 } } }, - { .channel = 0, .filter = 4, .data = { .coeff = { 0x0E81B1, 0xE6283F, 0x0CE49D, 0xE6283F, 0x0B664F } } }, - { .channel = 0, .filter = 5, .data = { .coeff = { 0x0F2D62, 0xE98797, 0x0D1E19, 0xE98797, 0x0C4B7B } } }, - - { .channel = 1, .filter = 0, .data = { .coeff = { 0x0FAD08, 0xE0A5EF, 0x0FAD08, 0xE0A79D, 0x0F5BBE } } }, - { .channel = 1, .filter = 1, .data = { .coeff = { 0x04B38D, 0x09671B, 0x04B38D, 0x000F71, 0x02BEC5 } } }, - { .channel = 1, .filter = 2, .data = { .coeff = { 0x0FDD32, 0xE0A56F, 0x0F8A69, 0xE0A56F, 0x0F679C } } }, - { .channel = 1, .filter = 3, .data = { .coeff = { 0x0FD284, 0xE135FB, 0x0F2161, 0xE135FB, 0x0EF3E5 } } }, - { .channel = 1, .filter = 4, .data = { .coeff = { 0x0E81B1, 0xE6283F, 0x0CE49D, 0xE6283F, 0x0B664F } } }, - { .channel = 1, .filter = 5, .data = { .coeff = { 0x0F2D62, 0xE98797, 0x0D1E19, 0xE98797, 0x0C4B7B } } }, -}; - -static struct tas_eq_pref_t eqp_15_1_0 = { - .sample_rate = 44100, - .device_id = 0x15, - .output_id = TAS_OUTPUT_INTERNAL_SPKR, - .speaker_id = 0x00, - - .drce = &eqp_15_1_0_drce, - - .filter_count = 12, - .biquads = eqp_15_1_0_biquads -}; - -/* ======================================================================== */ - -static struct tas_drce_t eqp_0f_2_1_drce={ - .enable = 1, - .above = { .val = 3.0 * (1<<8), .expand = 0 }, - .below = { .val = 1.0 * (1<<8), .expand = 0 }, - .threshold = -15.33 * (1<<8), - .energy = 2.4 * (1<<12), - .attack = 0.013 * (1<<12), - .decay = 0.212 * (1<<12), -}; - -static struct tas_biquad_ctrl_t eqp_0f_2_1_biquads[]={ - { .channel = 0, .filter = 0, .data = { .coeff = { 0x0FE143, 0xE05204, 0x0FCCC5, 0xE05266, 0x0FAE6B } } }, - { .channel = 0, .filter = 1, .data = { .coeff = { 0x102383, 0xE03A03, 0x0FA325, 0xE03A03, 0x0FC6A8 } } }, - { .channel = 0, .filter = 2, .data = { .coeff = { 0x0FF2AB, 0xE06285, 0x0FB20A, 0xE06285, 0x0FA4B5 } } }, - { .channel = 0, .filter = 3, .data = { .coeff = { 0x0F544D, 0xE35971, 0x0D8F3A, 0xE35971, 0x0CE388 } } }, - { .channel = 0, .filter = 4, .data = { .coeff = { 0x13E1D3, 0xF3ECB5, 0x042227, 0xF3ECB5, 0x0803FA } } }, - { .channel = 0, .filter = 5, .data = { .coeff = { 0x0AC119, 0x034181, 0x078AB1, 0x034181, 0x024BCA } } }, - - { .channel = 1, .filter = 0, .data = { .coeff = { 0x0FE143, 0xE05204, 0x0FCCC5, 0xE05266, 0x0FAE6B } } }, - { .channel = 1, .filter = 1, .data = { .coeff = { 0x102383, 0xE03A03, 0x0FA325, 0xE03A03, 0x0FC6A8 } } }, - { .channel = 1, .filter = 2, .data = { .coeff = { 0x0FF2AB, 0xE06285, 0x0FB20A, 0xE06285, 0x0FA4B5 } } }, - { .channel = 1, .filter = 3, .data = { .coeff = { 0x0F544D, 0xE35971, 0x0D8F3A, 0xE35971, 0x0CE388 } } }, - { .channel = 1, .filter = 4, .data = { .coeff = { 0x13E1D3, 0xF3ECB5, 0x042227, 0xF3ECB5, 0x0803FA } } }, - { .channel = 1, .filter = 5, .data = { .coeff = { 0x0AC119, 0x034181, 0x078AB1, 0x034181, 0x024BCA } } }, -}; - -static struct tas_eq_pref_t eqp_0f_2_1 = { - .sample_rate = 44100, - .device_id = 0x0f, - .output_id = TAS_OUTPUT_EXTERNAL_SPKR, - .speaker_id = 0x01, - - .drce = &eqp_0f_2_1_drce, - - .filter_count = 12, - .biquads = eqp_0f_2_1_biquads -}; - -/* ======================================================================== */ - -static struct tas_drce_t eqp_0f_1_0_drce={ - .enable = 1, - .above = { .val = 3.0 * (1<<8), .expand = 0 }, - .below = { .val = 1.0 * (1<<8), .expand = 0 }, - .threshold = -15.33 * (1<<8), - .energy = 2.4 * (1<<12), - .attack = 0.013 * (1<<12), - .decay = 0.212 * (1<<12), -}; - -static struct tas_biquad_ctrl_t eqp_0f_1_0_biquads[]={ - { .channel = 0, .filter = 0, .data = { .coeff = { 0x0FCAD3, 0xE06A58, 0x0FCAD3, 0xE06B09, 0x0F9657 } } }, - { .channel = 0, .filter = 1, .data = { .coeff = { 0x041731, 0x082E63, 0x041731, 0xFD8D08, 0x02CFBD } } }, - { .channel = 0, .filter = 2, .data = { .coeff = { 0x0FFDC7, 0xE0524C, 0x0FBFAA, 0xE0524C, 0x0FBD72 } } }, - { .channel = 0, .filter = 3, .data = { .coeff = { 0x0F3D35, 0xE228CA, 0x0EC7B2, 0xE228CA, 0x0E04E8 } } }, - { .channel = 0, .filter = 4, .data = { .coeff = { 0x0FCEBF, 0xE181C2, 0x0F2656, 0xE181C2, 0x0EF516 } } }, - { .channel = 0, .filter = 5, .data = { .coeff = { 0x0EC417, 0x073E22, 0x0B0633, 0x073E22, 0x09CA4A } } }, - - { .channel = 1, .filter = 0, .data = { .coeff = { 0x0FCAD3, 0xE06A58, 0x0FCAD3, 0xE06B09, 0x0F9657 } } }, - { .channel = 1, .filter = 1, .data = { .coeff = { 0x041731, 0x082E63, 0x041731, 0xFD8D08, 0x02CFBD } } }, - { .channel = 1, .filter = 2, .data = { .coeff = { 0x0FFDC7, 0xE0524C, 0x0FBFAA, 0xE0524C, 0x0FBD72 } } }, - { .channel = 1, .filter = 3, .data = { .coeff = { 0x0F3D35, 0xE228CA, 0x0EC7B2, 0xE228CA, 0x0E04E8 } } }, - { .channel = 1, .filter = 4, .data = { .coeff = { 0x0FCEBF, 0xE181C2, 0x0F2656, 0xE181C2, 0x0EF516 } } }, - { .channel = 1, .filter = 5, .data = { .coeff = { 0x0EC417, 0x073E22, 0x0B0633, 0x073E22, 0x09CA4A } } }, -}; - -static struct tas_eq_pref_t eqp_0f_1_0 = { - .sample_rate = 44100, - .device_id = 0x0f, - .output_id = TAS_OUTPUT_INTERNAL_SPKR, - .speaker_id = 0x00, - - .drce = &eqp_0f_1_0_drce, - - .filter_count = 12, - .biquads = eqp_0f_1_0_biquads -}; - -/* ======================================================================== */ - -static uint tas3001c_master_tab[]={ - 0x0, 0x75, 0x9c, 0xbb, - 0xdb, 0xfb, 0x11e, 0x143, - 0x16b, 0x196, 0x1c3, 0x1f5, - 0x229, 0x263, 0x29f, 0x2e1, - 0x328, 0x373, 0x3c5, 0x41b, - 0x478, 0x4dc, 0x547, 0x5b8, - 0x633, 0x6b5, 0x740, 0x7d5, - 0x873, 0x91c, 0x9d2, 0xa92, - 0xb5e, 0xc39, 0xd22, 0xe19, - 0xf20, 0x1037, 0x1161, 0x129e, - 0x13ed, 0x1551, 0x16ca, 0x185d, - 0x1a08, 0x1bcc, 0x1dac, 0x1fa7, - 0x21c1, 0x23fa, 0x2655, 0x28d6, - 0x2b7c, 0x2e4a, 0x3141, 0x3464, - 0x37b4, 0x3b35, 0x3ee9, 0x42d3, - 0x46f6, 0x4b53, 0x4ff0, 0x54ce, - 0x59f2, 0x5f5f, 0x6519, 0x6b24, - 0x7183, 0x783c, 0x7f53, 0x86cc, - 0x8ead, 0x96fa, 0x9fba, 0xa8f2, - 0xb2a7, 0xbce1, 0xc7a5, 0xd2fa, - 0xdee8, 0xeb75, 0xf8aa, 0x1068e, - 0x1152a, 0x12487, 0x134ad, 0x145a5, - 0x1577b, 0x16a37, 0x17df5, 0x192bd, - 0x1a890, 0x1bf7b, 0x1d78d, 0x1f0d1, - 0x20b55, 0x22727, 0x24456, 0x262f2, - 0x2830b -}; - -static uint tas3001c_mixer_tab[]={ - 0x0, 0x748, 0x9be, 0xbaf, - 0xda4, 0xfb1, 0x11de, 0x1431, - 0x16ad, 0x1959, 0x1c37, 0x1f4b, - 0x2298, 0x2628, 0x29fb, 0x2e12, - 0x327d, 0x3734, 0x3c47, 0x41b4, - 0x4787, 0x4dbe, 0x546d, 0x5b86, - 0x632e, 0x6b52, 0x7400, 0x7d54, - 0x873b, 0x91c6, 0x9d1a, 0xa920, - 0xb5e5, 0xc38c, 0xd21b, 0xe18f, - 0xf1f5, 0x1036a, 0x1160f, 0x129d6, - 0x13ed0, 0x1550c, 0x16ca0, 0x185c9, - 0x1a07b, 0x1bcc3, 0x1dab9, 0x1fa75, - 0x21c0f, 0x23fa3, 0x26552, 0x28d64, - 0x2b7c9, 0x2e4a2, 0x31411, 0x3463b, - 0x37b44, 0x3b353, 0x3ee94, 0x42d30, - 0x46f55, 0x4b533, 0x4fefc, 0x54ce5, - 0x59f25, 0x5f5f6, 0x65193, 0x6b23c, - 0x71835, 0x783c3, 0x7f52c, 0x86cc0, - 0x8eacc, 0x96fa5, 0x9fba0, 0xa8f1a, - 0xb2a71, 0xbce0a, 0xc7a4a, 0xd2fa0, - 0xdee7b, 0xeb752, 0xf8a9f, 0x1068e4, - 0x1152a3, 0x12486a, 0x134ac8, 0x145a55, - 0x1577ac, 0x16a370, 0x17df51, 0x192bc2, - 0x1a88f8, 0x1bf7b7, 0x1d78c9, 0x1f0d04, - 0x20b542, 0x227268, 0x244564, 0x262f26, - 0x2830af -}; - -static uint tas3001c_treble_tab[]={ - 0x96, 0x95, 0x95, 0x94, - 0x93, 0x92, 0x92, 0x91, - 0x90, 0x90, 0x8f, 0x8e, - 0x8d, 0x8d, 0x8c, 0x8b, - 0x8a, 0x8a, 0x89, 0x88, - 0x88, 0x87, 0x86, 0x85, - 0x85, 0x84, 0x83, 0x83, - 0x82, 0x81, 0x80, 0x80, - 0x7f, 0x7e, 0x7e, 0x7d, - 0x7c, 0x7b, 0x7b, 0x7a, - 0x79, 0x78, 0x78, 0x77, - 0x76, 0x76, 0x75, 0x74, - 0x73, 0x73, 0x72, 0x71, - 0x71, 0x70, 0x6e, 0x6d, - 0x6d, 0x6c, 0x6b, 0x6a, - 0x69, 0x68, 0x67, 0x66, - 0x65, 0x63, 0x62, 0x62, - 0x60, 0x5f, 0x5d, 0x5c, - 0x5a, 0x58, 0x56, 0x55, - 0x53, 0x51, 0x4f, 0x4c, - 0x4a, 0x48, 0x45, 0x43, - 0x40, 0x3d, 0x3a, 0x37, - 0x35, 0x32, 0x2e, 0x2a, - 0x27, 0x22, 0x1e, 0x1a, - 0x15, 0x11, 0xc, 0x7, - 0x1 -}; - -static uint tas3001c_bass_tab[]={ - 0x86, 0x83, 0x81, 0x7f, - 0x7d, 0x7b, 0x79, 0x78, - 0x76, 0x75, 0x74, 0x72, - 0x71, 0x6f, 0x6e, 0x6d, - 0x6c, 0x6b, 0x69, 0x67, - 0x65, 0x64, 0x61, 0x60, - 0x5e, 0x5d, 0x5c, 0x5b, - 0x5a, 0x59, 0x58, 0x57, - 0x56, 0x55, 0x55, 0x54, - 0x53, 0x52, 0x50, 0x4f, - 0x4d, 0x4c, 0x4b, 0x49, - 0x47, 0x45, 0x44, 0x42, - 0x41, 0x3f, 0x3e, 0x3d, - 0x3c, 0x3b, 0x39, 0x38, - 0x37, 0x36, 0x35, 0x34, - 0x33, 0x31, 0x30, 0x2f, - 0x2e, 0x2c, 0x2b, 0x2b, - 0x29, 0x28, 0x27, 0x26, - 0x25, 0x24, 0x22, 0x21, - 0x20, 0x1e, 0x1c, 0x19, - 0x18, 0x18, 0x17, 0x16, - 0x15, 0x14, 0x13, 0x12, - 0x11, 0x10, 0xf, 0xe, - 0xd, 0xb, 0xa, 0x9, - 0x8, 0x6, 0x4, 0x2, - 0x1 -}; - -struct tas_gain_t tas3001c_gain = { - .master = tas3001c_master_tab, - .treble = tas3001c_treble_tab, - .bass = tas3001c_bass_tab, - .mixer = tas3001c_mixer_tab -}; - -struct tas_eq_pref_t *tas3001c_eq_prefs[]={ - &eqp_0e_2_1, - &eqp_10_1_0, - &eqp_15_2_1, - &eqp_15_1_0, - &eqp_0f_2_1, - &eqp_0f_1_0, - NULL -}; diff --git a/sound/oss/dmasound/tas3004.c b/sound/oss/dmasound/tas3004.c deleted file mode 100644 index 678bf0ff6da2..000000000000 --- a/sound/oss/dmasound/tas3004.c +++ /dev/null @@ -1,1138 +0,0 @@ -/* - * Driver for the i2c/i2s based TA3004 sound chip used - * on some Apple hardware. Also known as "snapper". - * - * Tobias Sargeant <tobias.sargeant@bigpond.com> - * Based upon tas3001c.c by Christopher C. Chimelis <chris@debian.org>: - * - * Input support by Renzo Davoli <renzo@cs.unibo.it> - * - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/proc_fs.h> -#include <linux/ioport.h> -#include <linux/sysctl.h> -#include <linux/types.h> -#include <linux/i2c.h> -#include <linux/init.h> -#include <linux/soundcard.h> -#include <linux/interrupt.h> -#include <linux/workqueue.h> - -#include <asm/uaccess.h> -#include <asm/errno.h> -#include <asm/io.h> -#include <asm/prom.h> - -#include "dmasound.h" -#include "tas_common.h" -#include "tas3004.h" - -#include "tas_ioctl.h" - -/* #define DEBUG_DRCE */ - -#define TAS3004_BIQUAD_FILTER_COUNT 7 -#define TAS3004_BIQUAD_CHANNEL_COUNT 2 - -#define VOL_DEFAULT (100 * 4 / 5) -#define INPUT_DEFAULT (100 * 4 / 5) -#define BASS_DEFAULT (100 / 2) -#define TREBLE_DEFAULT (100 / 2) - -struct tas3004_data_t { - struct tas_data_t super; - int device_id; - int output_id; - int speaker_id; - struct tas_drce_t drce_state; - struct work_struct change; -}; - -#define MAKE_TIME(sec,usec) (((sec)<<12) + (50000+(usec/10)*(1<<12))/100000) - -#define MAKE_RATIO(i,f) (((i)<<8) + ((500+(f)*(1<<8))/1000)) - - -static const union tas_biquad_t tas3004_eq_unity = { - .buf = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 }, -}; - - -static const struct tas_drce_t tas3004_drce_min = { - .enable = 1, - .above = { .val = MAKE_RATIO(16,0), .expand = 0 }, - .below = { .val = MAKE_RATIO(2,0), .expand = 0 }, - .threshold = -0x59a0, - .energy = MAKE_TIME(0, 1700), - .attack = MAKE_TIME(0, 1700), - .decay = MAKE_TIME(0, 1700), -}; - - -static const struct tas_drce_t tas3004_drce_max = { - .enable = 1, - .above = { .val = MAKE_RATIO(1,500), .expand = 1 }, - .below = { .val = MAKE_RATIO(2,0), .expand = 1 }, - .threshold = -0x0, - .energy = MAKE_TIME(2,400000), - .attack = MAKE_TIME(2,400000), - .decay = MAKE_TIME(2,400000), -}; - - -static const unsigned short time_constants[]={ - MAKE_TIME(0, 1700), - MAKE_TIME(0, 3500), - MAKE_TIME(0, 6700), - MAKE_TIME(0, 13000), - MAKE_TIME(0, 26000), - MAKE_TIME(0, 53000), - MAKE_TIME(0,106000), - MAKE_TIME(0,212000), - MAKE_TIME(0,425000), - MAKE_TIME(0,850000), - MAKE_TIME(1,700000), - MAKE_TIME(2,400000), -}; - -static const unsigned short above_threshold_compression_ratio[]={ - MAKE_RATIO( 1, 70), - MAKE_RATIO( 1,140), - MAKE_RATIO( 1,230), - MAKE_RATIO( 1,330), - MAKE_RATIO( 1,450), - MAKE_RATIO( 1,600), - MAKE_RATIO( 1,780), - MAKE_RATIO( 2, 0), - MAKE_RATIO( 2,290), - MAKE_RATIO( 2,670), - MAKE_RATIO( 3,200), - MAKE_RATIO( 4, 0), - MAKE_RATIO( 5,330), - MAKE_RATIO( 8, 0), - MAKE_RATIO(16, 0), -}; - -static const unsigned short above_threshold_expansion_ratio[]={ - MAKE_RATIO(1, 60), - MAKE_RATIO(1,130), - MAKE_RATIO(1,190), - MAKE_RATIO(1,250), - MAKE_RATIO(1,310), - MAKE_RATIO(1,380), - MAKE_RATIO(1,440), - MAKE_RATIO(1,500) -}; - -static const unsigned short below_threshold_compression_ratio[]={ - MAKE_RATIO(1, 70), - MAKE_RATIO(1,140), - MAKE_RATIO(1,230), - MAKE_RATIO(1,330), - MAKE_RATIO(1,450), - MAKE_RATIO(1,600), - MAKE_RATIO(1,780), - MAKE_RATIO(2, 0) -}; - -static const unsigned short below_threshold_expansion_ratio[]={ - MAKE_RATIO(1, 60), - MAKE_RATIO(1,130), - MAKE_RATIO(1,190), - MAKE_RATIO(1,250), - MAKE_RATIO(1,310), - MAKE_RATIO(1,380), - MAKE_RATIO(1,440), - MAKE_RATIO(1,500), - MAKE_RATIO(1,560), - MAKE_RATIO(1,630), - MAKE_RATIO(1,690), - MAKE_RATIO(1,750), - MAKE_RATIO(1,810), - MAKE_RATIO(1,880), - MAKE_RATIO(1,940), - MAKE_RATIO(2, 0) -}; - -static inline int -search( unsigned short val, - const unsigned short *arr, - const int arrsize) { - /* - * This could be a binary search, but for small tables, - * a linear search is likely to be faster - */ - - int i; - - for (i=0; i < arrsize; i++) - if (arr[i] >= val) - goto _1; - return arrsize-1; - _1: - if (i == 0) - return 0; - return (arr[i]-val < val-arr[i-1]) ? i : i-1; -} - -#define SEARCH(a, b) search(a, b, ARRAY_SIZE(b)) - -static inline int -time_index(unsigned short time) -{ - return SEARCH(time, time_constants); -} - - -static inline int -above_threshold_compression_index(unsigned short ratio) -{ - return SEARCH(ratio, above_threshold_compression_ratio); -} - - -static inline int -above_threshold_expansion_index(unsigned short ratio) -{ - return SEARCH(ratio, above_threshold_expansion_ratio); -} - - -static inline int -below_threshold_compression_index(unsigned short ratio) -{ - return SEARCH(ratio, below_threshold_compression_ratio); -} - - -static inline int -below_threshold_expansion_index(unsigned short ratio) -{ - return SEARCH(ratio, below_threshold_expansion_ratio); -} - -static inline unsigned char db_to_regval(short db) { - int r=0; - - r=(db+0x59a0) / 0x60; - - if (r < 0x91) return 0x91; - if (r > 0xef) return 0xef; - return r; -} - -static inline short quantize_db(short db) -{ - return db_to_regval(db) * 0x60 - 0x59a0; -} - -static inline int -register_width(enum tas3004_reg_t r) -{ - switch(r) { - case TAS3004_REG_MCR: - case TAS3004_REG_TREBLE: - case TAS3004_REG_BASS: - case TAS3004_REG_ANALOG_CTRL: - case TAS3004_REG_TEST1: - case TAS3004_REG_TEST2: - case TAS3004_REG_MCR2: - return 1; - - case TAS3004_REG_LEFT_LOUD_BIQUAD_GAIN: - case TAS3004_REG_RIGHT_LOUD_BIQUAD_GAIN: - return 3; - - case TAS3004_REG_DRC: - case TAS3004_REG_VOLUME: - return 6; - - case TAS3004_REG_LEFT_MIXER: - case TAS3004_REG_RIGHT_MIXER: - return 9; - - case TAS3004_REG_TEST: - return 10; - - case TAS3004_REG_LEFT_BIQUAD0: - case TAS3004_REG_LEFT_BIQUAD1: - case TAS3004_REG_LEFT_BIQUAD2: - case TAS3004_REG_LEFT_BIQUAD3: - case TAS3004_REG_LEFT_BIQUAD4: - case TAS3004_REG_LEFT_BIQUAD5: - case TAS3004_REG_LEFT_BIQUAD6: - - case TAS3004_REG_RIGHT_BIQUAD0: - case TAS3004_REG_RIGHT_BIQUAD1: - case TAS3004_REG_RIGHT_BIQUAD2: - case TAS3004_REG_RIGHT_BIQUAD3: - case TAS3004_REG_RIGHT_BIQUAD4: - case TAS3004_REG_RIGHT_BIQUAD5: - case TAS3004_REG_RIGHT_BIQUAD6: - - case TAS3004_REG_LEFT_LOUD_BIQUAD: - case TAS3004_REG_RIGHT_LOUD_BIQUAD: - return 15; - - default: - return 0; - } -} - -static int -tas3004_write_register( struct tas3004_data_t *self, - enum tas3004_reg_t reg_num, - char *data, - uint write_mode) -{ - if (reg_num==TAS3004_REG_MCR || - reg_num==TAS3004_REG_BASS || - reg_num==TAS3004_REG_TREBLE || - reg_num==TAS3004_REG_ANALOG_CTRL) { - return tas_write_byte_register(&self->super, - (uint)reg_num, - *data, - write_mode); - } else { - return tas_write_register(&self->super, - (uint)reg_num, - register_width(reg_num), - data, - write_mode); - } -} - -static int -tas3004_sync_register( struct tas3004_data_t *self, - enum tas3004_reg_t reg_num) -{ - if (reg_num==TAS3004_REG_MCR || - reg_num==TAS3004_REG_BASS || - reg_num==TAS3004_REG_TREBLE || - reg_num==TAS3004_REG_ANALOG_CTRL) { - return tas_sync_byte_register(&self->super, - (uint)reg_num, - register_width(reg_num)); - } else { - return tas_sync_register(&self->super, - (uint)reg_num, - register_width(reg_num)); - } -} - -static int -tas3004_read_register( struct tas3004_data_t *self, - enum tas3004_reg_t reg_num, - char *data, - uint write_mode) -{ - return tas_read_register(&self->super, - (uint)reg_num, - register_width(reg_num), - data); -} - -static inline int -tas3004_fast_load(struct tas3004_data_t *self, int fast) -{ - if (fast) - self->super.shadow[TAS3004_REG_MCR][0] |= 0x80; - else - self->super.shadow[TAS3004_REG_MCR][0] &= 0x7f; - return tas3004_sync_register(self,TAS3004_REG_MCR); -} - -static uint -tas3004_supported_mixers(struct tas3004_data_t *self) -{ - return SOUND_MASK_VOLUME | - SOUND_MASK_PCM | - SOUND_MASK_ALTPCM | - SOUND_MASK_IMIX | - SOUND_MASK_TREBLE | - SOUND_MASK_BASS | - SOUND_MASK_MIC | - SOUND_MASK_LINE; -} - -static int -tas3004_mixer_is_stereo(struct tas3004_data_t *self, int mixer) -{ - switch(mixer) { - case SOUND_MIXER_VOLUME: - case SOUND_MIXER_PCM: - case SOUND_MIXER_ALTPCM: - case SOUND_MIXER_IMIX: - return 1; - default: - return 0; - } -} - -static uint -tas3004_stereo_mixers(struct tas3004_data_t *self) -{ - uint r = tas3004_supported_mixers(self); - uint i; - - for (i=1; i<SOUND_MIXER_NRDEVICES; i++) - if (r&(1<<i) && !tas3004_mixer_is_stereo(self,i)) - r &= ~(1<<i); - return r; -} - -static int -tas3004_get_mixer_level(struct tas3004_data_t *self, int mixer, uint *level) -{ - if (!self) - return -1; - - *level = self->super.mixer[mixer]; - - return 0; -} - -static int -tas3004_set_mixer_level(struct tas3004_data_t *self, int mixer, uint level) -{ - int rc; - tas_shadow_t *shadow; - uint temp; - uint offset=0; - - if (!self) - return -1; - - shadow = self->super.shadow; - - if (!tas3004_mixer_is_stereo(self,mixer)) - level = tas_mono_to_stereo(level); - switch(mixer) { - case SOUND_MIXER_VOLUME: - temp = tas3004_gain.master[level&0xff]; - SET_4_20(shadow[TAS3004_REG_VOLUME], 0, temp); - temp = tas3004_gain.master[(level>>8)&0xff]; - SET_4_20(shadow[TAS3004_REG_VOLUME], 3, temp); - rc = tas3004_sync_register(self,TAS3004_REG_VOLUME); - break; - case SOUND_MIXER_IMIX: - offset += 3; - case SOUND_MIXER_ALTPCM: - offset += 3; - case SOUND_MIXER_PCM: - /* - * Don't load these in fast mode. The documentation - * says it can be done in either mode, but testing it - * shows that fast mode produces ugly clicking. - */ - /* tas3004_fast_load(self,1); */ - temp = tas3004_gain.mixer[level&0xff]; - SET_4_20(shadow[TAS3004_REG_LEFT_MIXER], offset, temp); - temp = tas3004_gain.mixer[(level>>8)&0xff]; - SET_4_20(shadow[TAS3004_REG_RIGHT_MIXER], offset, temp); - rc = tas3004_sync_register(self,TAS3004_REG_LEFT_MIXER); - if (rc == 0) - rc=tas3004_sync_register(self,TAS3004_REG_RIGHT_MIXER); - /* tas3004_fast_load(self,0); */ - break; - case SOUND_MIXER_TREBLE: - temp = tas3004_gain.treble[level&0xff]; - shadow[TAS3004_REG_TREBLE][0]=temp&0xff; - rc = tas3004_sync_register(self,TAS3004_REG_TREBLE); - break; - case SOUND_MIXER_BASS: - temp = tas3004_gain.bass[level&0xff]; - shadow[TAS3004_REG_BASS][0]=temp&0xff; - rc = tas3004_sync_register(self,TAS3004_REG_BASS); - break; - case SOUND_MIXER_MIC: - if ((level&0xff)>0) { - software_input_volume = SW_INPUT_VOLUME_SCALE * (level&0xff); - if (self->super.mixer[mixer] == 0) { - self->super.mixer[SOUND_MIXER_LINE] = 0; - shadow[TAS3004_REG_ANALOG_CTRL][0]=0xc2; - rc = tas3004_sync_register(self,TAS3004_REG_ANALOG_CTRL); - } else rc=0; - } else { - self->super.mixer[SOUND_MIXER_LINE] = SW_INPUT_VOLUME_DEFAULT; - software_input_volume = SW_INPUT_VOLUME_SCALE * - (self->super.mixer[SOUND_MIXER_LINE]&0xff); - shadow[TAS3004_REG_ANALOG_CTRL][0]=0x00; - rc = tas3004_sync_register(self,TAS3004_REG_ANALOG_CTRL); - } - break; - case SOUND_MIXER_LINE: - if (self->super.mixer[SOUND_MIXER_MIC] == 0) { - software_input_volume = SW_INPUT_VOLUME_SCALE * (level&0xff); - rc=0; - } - break; - default: - rc = -1; - break; - } - if (rc < 0) - return rc; - self->super.mixer[mixer] = level; - - return 0; -} - -static int -tas3004_leave_sleep(struct tas3004_data_t *self) -{ - unsigned char mcr = (1<<6)+(2<<4)+(2<<2); - - if (!self) - return -1; - - /* Make sure something answers on the i2c bus */ - if (tas3004_write_register(self, TAS3004_REG_MCR, &mcr, - WRITE_NORMAL | FORCE_WRITE) < 0) - return -1; - - tas3004_fast_load(self, 1); - - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD0); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD1); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD2); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD3); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD4); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD5); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD6); - - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD0); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD1); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD2); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD3); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD4); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD5); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD6); - - tas3004_fast_load(self, 0); - - (void)tas3004_sync_register(self,TAS3004_REG_VOLUME); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_MIXER); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_MIXER); - (void)tas3004_sync_register(self,TAS3004_REG_TREBLE); - (void)tas3004_sync_register(self,TAS3004_REG_BASS); - (void)tas3004_sync_register(self,TAS3004_REG_ANALOG_CTRL); - - return 0; -} - -static int -tas3004_enter_sleep(struct tas3004_data_t *self) -{ - if (!self) - return -1; - return 0; -} - -static int -tas3004_sync_biquad( struct tas3004_data_t *self, - u_int channel, - u_int filter) -{ - enum tas3004_reg_t reg; - - if (channel >= TAS3004_BIQUAD_CHANNEL_COUNT || - filter >= TAS3004_BIQUAD_FILTER_COUNT) return -EINVAL; - - reg=( channel ? TAS3004_REG_RIGHT_BIQUAD0 : TAS3004_REG_LEFT_BIQUAD0 ) + filter; - - return tas3004_sync_register(self,reg); -} - -static int -tas3004_write_biquad_shadow( struct tas3004_data_t *self, - u_int channel, - u_int filter, - const union tas_biquad_t *biquad) -{ - tas_shadow_t *shadow=self->super.shadow; - enum tas3004_reg_t reg; - - if (channel >= TAS3004_BIQUAD_CHANNEL_COUNT || - filter >= TAS3004_BIQUAD_FILTER_COUNT) return -EINVAL; - - reg=( channel ? TAS3004_REG_RIGHT_BIQUAD0 : TAS3004_REG_LEFT_BIQUAD0 ) + filter; - - SET_4_20(shadow[reg], 0,biquad->coeff.b0); - SET_4_20(shadow[reg], 3,biquad->coeff.b1); - SET_4_20(shadow[reg], 6,biquad->coeff.b2); - SET_4_20(shadow[reg], 9,biquad->coeff.a1); - SET_4_20(shadow[reg],12,biquad->coeff.a2); - - return 0; -} - -static int -tas3004_write_biquad( struct tas3004_data_t *self, - u_int channel, - u_int filter, - const union tas_biquad_t *biquad) -{ - int rc; - - rc=tas3004_write_biquad_shadow(self, channel, filter, biquad); - if (rc < 0) return rc; - - return tas3004_sync_biquad(self, channel, filter); -} - -static int -tas3004_write_biquad_list( struct tas3004_data_t *self, - u_int filter_count, - u_int flags, - struct tas_biquad_ctrl_t *biquads) -{ - int i; - int rc; - - if (flags & TAS_BIQUAD_FAST_LOAD) tas3004_fast_load(self,1); - - for (i=0; i<filter_count; i++) { - rc=tas3004_write_biquad(self, - biquads[i].channel, - biquads[i].filter, - &biquads[i].data); - if (rc < 0) break; - } - - if (flags & TAS_BIQUAD_FAST_LOAD) tas3004_fast_load(self,0); - - return rc; -} - -static int -tas3004_read_biquad( struct tas3004_data_t *self, - u_int channel, - u_int filter, - union tas_biquad_t *biquad) -{ - tas_shadow_t *shadow=self->super.shadow; - enum tas3004_reg_t reg; - - if (channel >= TAS3004_BIQUAD_CHANNEL_COUNT || - filter >= TAS3004_BIQUAD_FILTER_COUNT) return -EINVAL; - - reg=( channel ? TAS3004_REG_RIGHT_BIQUAD0 : TAS3004_REG_LEFT_BIQUAD0 ) + filter; - - biquad->coeff.b0=GET_4_20(shadow[reg], 0); - biquad->coeff.b1=GET_4_20(shadow[reg], 3); - biquad->coeff.b2=GET_4_20(shadow[reg], 6); - biquad->coeff.a1=GET_4_20(shadow[reg], 9); - biquad->coeff.a2=GET_4_20(shadow[reg],12); - - return 0; -} - -static int -tas3004_eq_rw( struct tas3004_data_t *self, - u_int cmd, - u_long arg) -{ - void __user *argp = (void __user *)arg; - int rc; - struct tas_biquad_ctrl_t biquad; - - if (copy_from_user((void *)&biquad, argp, sizeof(struct tas_biquad_ctrl_t))) { - return -EFAULT; - } - - if (cmd & SIOC_IN) { - rc=tas3004_write_biquad(self, biquad.channel, biquad.filter, &biquad.data); - if (rc != 0) return rc; - } - - if (cmd & SIOC_OUT) { - rc=tas3004_read_biquad(self, biquad.channel, biquad.filter, &biquad.data); - if (rc != 0) return rc; - - if (copy_to_user(argp, &biquad, sizeof(struct tas_biquad_ctrl_t))) { - return -EFAULT; - } - - } - return 0; -} - -static int -tas3004_eq_list_rw( struct tas3004_data_t *self, - u_int cmd, - u_long arg) -{ - int rc = 0; - int filter_count; - int flags; - int i,j; - char sync_required[TAS3004_BIQUAD_CHANNEL_COUNT][TAS3004_BIQUAD_FILTER_COUNT]; - struct tas_biquad_ctrl_t biquad; - struct tas_biquad_ctrl_list_t __user *argp = (void __user *)arg; - - memset(sync_required,0,sizeof(sync_required)); - - if (copy_from_user(&filter_count, &argp->filter_count, sizeof(int))) - return -EFAULT; - - if (copy_from_user(&flags, &argp->flags, sizeof(int))) - return -EFAULT; - - if (cmd & SIOC_IN) { - } - - for (i=0; i < filter_count; i++) { - if (copy_from_user(&biquad, &argp->biquads[i], - sizeof(struct tas_biquad_ctrl_t))) { - return -EFAULT; - } - - if (cmd & SIOC_IN) { - sync_required[biquad.channel][biquad.filter]=1; - rc=tas3004_write_biquad_shadow(self, biquad.channel, biquad.filter, &biquad.data); - if (rc != 0) return rc; - } - - if (cmd & SIOC_OUT) { - rc=tas3004_read_biquad(self, biquad.channel, biquad.filter, &biquad.data); - if (rc != 0) return rc; - - if (copy_to_user(&argp->biquads[i], &biquad, - sizeof(struct tas_biquad_ctrl_t))) { - return -EFAULT; - } - } - } - - if (cmd & SIOC_IN) { - /* - * This is OK for the tas3004. For the - * tas3001c, going into fast load mode causes - * the treble and bass to be reset to 0dB, and - * volume controls to be muted. - */ - if (flags & TAS_BIQUAD_FAST_LOAD) tas3004_fast_load(self,1); - for (i=0; i<TAS3004_BIQUAD_CHANNEL_COUNT; i++) { - for (j=0; j<TAS3004_BIQUAD_FILTER_COUNT; j++) { - if (sync_required[i][j]) { - rc=tas3004_sync_biquad(self, i, j); - if (rc < 0) goto out; - } - } - } - out: - if (flags & TAS_BIQUAD_FAST_LOAD) - tas3004_fast_load(self,0); - } - - return rc; -} - -static int -tas3004_update_drce( struct tas3004_data_t *self, - int flags, - struct tas_drce_t *drce) -{ - tas_shadow_t *shadow; - int i; - shadow=self->super.shadow; - - if (flags & TAS_DRCE_ABOVE_RATIO) { - self->drce_state.above.expand = drce->above.expand; - if (drce->above.val == (1<<8)) { - self->drce_state.above.val = 1<<8; - shadow[TAS3004_REG_DRC][0] = 0x02; - - } else if (drce->above.expand) { - i=above_threshold_expansion_index(drce->above.val); - self->drce_state.above.val=above_threshold_expansion_ratio[i]; - shadow[TAS3004_REG_DRC][0] = 0x0a + (i<<3); - } else { - i=above_threshold_compression_index(drce->above.val); - self->drce_state.above.val=above_threshold_compression_ratio[i]; - shadow[TAS3004_REG_DRC][0] = 0x08 + (i<<3); - } - } - - if (flags & TAS_DRCE_BELOW_RATIO) { - self->drce_state.below.expand = drce->below.expand; - if (drce->below.val == (1<<8)) { - self->drce_state.below.val = 1<<8; - shadow[TAS3004_REG_DRC][1] = 0x02; - - } else if (drce->below.expand) { - i=below_threshold_expansion_index(drce->below.val); - self->drce_state.below.val=below_threshold_expansion_ratio[i]; - shadow[TAS3004_REG_DRC][1] = 0x08 + (i<<3); - } else { - i=below_threshold_compression_index(drce->below.val); - self->drce_state.below.val=below_threshold_compression_ratio[i]; - shadow[TAS3004_REG_DRC][1] = 0x0a + (i<<3); - } - } - - if (flags & TAS_DRCE_THRESHOLD) { - self->drce_state.threshold=quantize_db(drce->threshold); - shadow[TAS3004_REG_DRC][2] = db_to_regval(self->drce_state.threshold); - } - - if (flags & TAS_DRCE_ENERGY) { - i=time_index(drce->energy); - self->drce_state.energy=time_constants[i]; - shadow[TAS3004_REG_DRC][3] = 0x40 + (i<<4); - } - - if (flags & TAS_DRCE_ATTACK) { - i=time_index(drce->attack); - self->drce_state.attack=time_constants[i]; - shadow[TAS3004_REG_DRC][4] = 0x40 + (i<<4); - } - - if (flags & TAS_DRCE_DECAY) { - i=time_index(drce->decay); - self->drce_state.decay=time_constants[i]; - shadow[TAS3004_REG_DRC][5] = 0x40 + (i<<4); - } - - if (flags & TAS_DRCE_ENABLE) { - self->drce_state.enable = drce->enable; - } - - if (!self->drce_state.enable) { - shadow[TAS3004_REG_DRC][0] |= 0x01; - } - -#ifdef DEBUG_DRCE - printk("DRCE: set [ ENABLE:%x ABOVE:%x/%x BELOW:%x/%x THRESH:%x ENERGY:%x ATTACK:%x DECAY:%x\n", - self->drce_state.enable, - self->drce_state.above.expand,self->drce_state.above.val, - self->drce_state.below.expand,self->drce_state.below.val, - self->drce_state.threshold, - self->drce_state.energy, - self->drce_state.attack, - self->drce_state.decay); - - printk("DRCE: reg [ %02x %02x %02x %02x %02x %02x ]\n", - (unsigned char)shadow[TAS3004_REG_DRC][0], - (unsigned char)shadow[TAS3004_REG_DRC][1], - (unsigned char)shadow[TAS3004_REG_DRC][2], - (unsigned char)shadow[TAS3004_REG_DRC][3], - (unsigned char)shadow[TAS3004_REG_DRC][4], - (unsigned char)shadow[TAS3004_REG_DRC][5]); -#endif - - return tas3004_sync_register(self, TAS3004_REG_DRC); -} - -static int -tas3004_drce_rw( struct tas3004_data_t *self, - u_int cmd, - u_long arg) -{ - int rc; - struct tas_drce_ctrl_t drce_ctrl; - void __user *argp = (void __user *)arg; - - if (copy_from_user(&drce_ctrl, argp, sizeof(struct tas_drce_ctrl_t))) - return -EFAULT; - -#ifdef DEBUG_DRCE - printk("DRCE: input [ FLAGS:%x ENABLE:%x ABOVE:%x/%x BELOW:%x/%x THRESH:%x ENERGY:%x ATTACK:%x DECAY:%x\n", - drce_ctrl.flags, - drce_ctrl.data.enable, - drce_ctrl.data.above.expand,drce_ctrl.data.above.val, - drce_ctrl.data.below.expand,drce_ctrl.data.below.val, - drce_ctrl.data.threshold, - drce_ctrl.data.energy, - drce_ctrl.data.attack, - drce_ctrl.data.decay); -#endif - - if (cmd & SIOC_IN) { - rc = tas3004_update_drce(self, drce_ctrl.flags, &drce_ctrl.data); - if (rc < 0) return rc; - } - - if (cmd & SIOC_OUT) { - if (drce_ctrl.flags & TAS_DRCE_ENABLE) - drce_ctrl.data.enable = self->drce_state.enable; - if (drce_ctrl.flags & TAS_DRCE_ABOVE_RATIO) - drce_ctrl.data.above = self->drce_state.above; - if (drce_ctrl.flags & TAS_DRCE_BELOW_RATIO) - drce_ctrl.data.below = self->drce_state.below; - if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) - drce_ctrl.data.threshold = self->drce_state.threshold; - if (drce_ctrl.flags & TAS_DRCE_ENERGY) - drce_ctrl.data.energy = self->drce_state.energy; - if (drce_ctrl.flags & TAS_DRCE_ATTACK) - drce_ctrl.data.attack = self->drce_state.attack; - if (drce_ctrl.flags & TAS_DRCE_DECAY) - drce_ctrl.data.decay = self->drce_state.decay; - - if (copy_to_user(argp, &drce_ctrl, - sizeof(struct tas_drce_ctrl_t))) { - return -EFAULT; - } - } - - return 0; -} - -static void -tas3004_update_device_parameters(struct tas3004_data_t *self) -{ - char data; - int i; - - if (!self) return; - - if (self->output_id == TAS_OUTPUT_HEADPHONES) { - /* turn on allPass when headphones are plugged in */ - data = 0x02; - } else { - data = 0x00; - } - - tas3004_write_register(self, TAS3004_REG_MCR2, &data, WRITE_NORMAL | FORCE_WRITE); - - for (i=0; tas3004_eq_prefs[i]; i++) { - struct tas_eq_pref_t *eq = tas3004_eq_prefs[i]; - - if (eq->device_id == self->device_id && - (eq->output_id == 0 || eq->output_id == self->output_id) && - (eq->speaker_id == 0 || eq->speaker_id == self->speaker_id)) { - - tas3004_update_drce(self, TAS_DRCE_ALL, eq->drce); - tas3004_write_biquad_list(self, eq->filter_count, TAS_BIQUAD_FAST_LOAD, eq->biquads); - - break; - } - } -} - -static void -tas3004_device_change_handler(struct work_struct *work) -{ - struct tas3004_data_t *self; - self = container_of(work, struct tas3004_data_t, change); - tas3004_update_device_parameters(self); -} - -static int -tas3004_output_device_change( struct tas3004_data_t *self, - int device_id, - int output_id, - int speaker_id) -{ - self->device_id=device_id; - self->output_id=output_id; - self->speaker_id=speaker_id; - - schedule_work(&self->change); - - return 0; -} - -static int -tas3004_device_ioctl( struct tas3004_data_t *self, - u_int cmd, - u_long arg) -{ - uint __user *argp = (void __user *)arg; - switch (cmd) { - case TAS_READ_EQ: - case TAS_WRITE_EQ: - return tas3004_eq_rw(self, cmd, arg); - - case TAS_READ_EQ_LIST: - case TAS_WRITE_EQ_LIST: - return tas3004_eq_list_rw(self, cmd, arg); - - case TAS_READ_EQ_FILTER_COUNT: - put_user(TAS3004_BIQUAD_FILTER_COUNT, argp); - return 0; - - case TAS_READ_EQ_CHANNEL_COUNT: - put_user(TAS3004_BIQUAD_CHANNEL_COUNT, argp); - return 0; - - case TAS_READ_DRCE: - case TAS_WRITE_DRCE: - return tas3004_drce_rw(self, cmd, arg); - - case TAS_READ_DRCE_CAPS: - put_user(TAS_DRCE_ENABLE | - TAS_DRCE_ABOVE_RATIO | - TAS_DRCE_BELOW_RATIO | - TAS_DRCE_THRESHOLD | - TAS_DRCE_ENERGY | - TAS_DRCE_ATTACK | - TAS_DRCE_DECAY, - argp); - return 0; - - case TAS_READ_DRCE_MIN: - case TAS_READ_DRCE_MAX: { - struct tas_drce_ctrl_t drce_ctrl; - const struct tas_drce_t *drce_copy; - - if (copy_from_user(&drce_ctrl, argp, - sizeof(struct tas_drce_ctrl_t))) { - return -EFAULT; - } - - if (cmd == TAS_READ_DRCE_MIN) { - drce_copy=&tas3004_drce_min; - } else { - drce_copy=&tas3004_drce_max; - } - - if (drce_ctrl.flags & TAS_DRCE_ABOVE_RATIO) { - drce_ctrl.data.above=drce_copy->above; - } - if (drce_ctrl.flags & TAS_DRCE_BELOW_RATIO) { - drce_ctrl.data.below=drce_copy->below; - } - if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) { - drce_ctrl.data.threshold=drce_copy->threshold; - } - if (drce_ctrl.flags & TAS_DRCE_ENERGY) { - drce_ctrl.data.energy=drce_copy->energy; - } - if (drce_ctrl.flags & TAS_DRCE_ATTACK) { - drce_ctrl.data.attack=drce_copy->attack; - } - if (drce_ctrl.flags & TAS_DRCE_DECAY) { - drce_ctrl.data.decay=drce_copy->decay; - } - - if (copy_to_user(argp, &drce_ctrl, - sizeof(struct tas_drce_ctrl_t))) { - return -EFAULT; - } - } - } - - return -EINVAL; -} - -static int -tas3004_init_mixer(struct tas3004_data_t *self) -{ - unsigned char mcr = (1<<6)+(2<<4)+(2<<2); - - /* Make sure something answers on the i2c bus */ - if (tas3004_write_register(self, TAS3004_REG_MCR, &mcr, - WRITE_NORMAL | FORCE_WRITE) < 0) - return -1; - - tas3004_fast_load(self, 1); - - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD0); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD1); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD2); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD3); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD4); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD5); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD6); - - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD0); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD1); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD2); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD3); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD4); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD5); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD6); - - tas3004_sync_register(self, TAS3004_REG_DRC); - - tas3004_sync_register(self, TAS3004_REG_MCR2); - - tas3004_fast_load(self, 0); - - tas3004_set_mixer_level(self, SOUND_MIXER_VOLUME, VOL_DEFAULT<<8 | VOL_DEFAULT); - tas3004_set_mixer_level(self, SOUND_MIXER_PCM, INPUT_DEFAULT<<8 | INPUT_DEFAULT); - tas3004_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0); - tas3004_set_mixer_level(self, SOUND_MIXER_IMIX, 0); - - tas3004_set_mixer_level(self, SOUND_MIXER_BASS, BASS_DEFAULT); - tas3004_set_mixer_level(self, SOUND_MIXER_TREBLE, TREBLE_DEFAULT); - - tas3004_set_mixer_level(self, SOUND_MIXER_LINE,SW_INPUT_VOLUME_DEFAULT); - - return 0; -} - -static int -tas3004_uninit_mixer(struct tas3004_data_t *self) -{ - tas3004_set_mixer_level(self, SOUND_MIXER_VOLUME, 0); - tas3004_set_mixer_level(self, SOUND_MIXER_PCM, 0); - tas3004_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0); - tas3004_set_mixer_level(self, SOUND_MIXER_IMIX, 0); - - tas3004_set_mixer_level(self, SOUND_MIXER_BASS, 0); - tas3004_set_mixer_level(self, SOUND_MIXER_TREBLE, 0); - - tas3004_set_mixer_level(self, SOUND_MIXER_LINE, 0); - - return 0; -} - -static int -tas3004_init(struct i2c_client *client) -{ - struct tas3004_data_t *self; - size_t sz = sizeof(*self) + (TAS3004_REG_MAX*sizeof(tas_shadow_t)); - char drce_init[] = { 0x69, 0x22, 0x9f, 0xb0, 0x60, 0xa0 }; - char mcr2 = 0; - int i, j; - - self = kzalloc(sz, GFP_KERNEL); - if (!self) - return -ENOMEM; - - self->super.client = client; - self->super.shadow = (tas_shadow_t *)(self+1); - self->output_id = TAS_OUTPUT_HEADPHONES; - - dev_set_drvdata(&client->dev, self); - - for (i = 0; i < TAS3004_BIQUAD_CHANNEL_COUNT; i++) - for (j = 0; j<TAS3004_BIQUAD_FILTER_COUNT; j++) - tas3004_write_biquad_shadow(self, i, j, - &tas3004_eq_unity); - - tas3004_write_register(self, TAS3004_REG_MCR2, &mcr2, WRITE_SHADOW); - tas3004_write_register(self, TAS3004_REG_DRC, drce_init, WRITE_SHADOW); - - INIT_WORK(&self->change, tas3004_device_change_handler); - return 0; -} - -static void -tas3004_uninit(struct tas3004_data_t *self) -{ - tas3004_uninit_mixer(self); - kfree(self); -} - - -struct tas_driver_hooks_t tas3004_hooks = { - .init = (tas_hook_init_t)tas3004_init, - .post_init = (tas_hook_post_init_t)tas3004_init_mixer, - .uninit = (tas_hook_uninit_t)tas3004_uninit, - .get_mixer_level = (tas_hook_get_mixer_level_t)tas3004_get_mixer_level, - .set_mixer_level = (tas_hook_set_mixer_level_t)tas3004_set_mixer_level, - .enter_sleep = (tas_hook_enter_sleep_t)tas3004_enter_sleep, - .leave_sleep = (tas_hook_leave_sleep_t)tas3004_leave_sleep, - .supported_mixers = (tas_hook_supported_mixers_t)tas3004_supported_mixers, - .mixer_is_stereo = (tas_hook_mixer_is_stereo_t)tas3004_mixer_is_stereo, - .stereo_mixers = (tas_hook_stereo_mixers_t)tas3004_stereo_mixers, - .output_device_change = (tas_hook_output_device_change_t)tas3004_output_device_change, - .device_ioctl = (tas_hook_device_ioctl_t)tas3004_device_ioctl -}; diff --git a/sound/oss/dmasound/tas3004.h b/sound/oss/dmasound/tas3004.h deleted file mode 100644 index c6d584bf2ca4..000000000000 --- a/sound/oss/dmasound/tas3004.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Header file for the i2c/i2s based TA3004 sound chip used - * on some Apple hardware. Also known as "tumbler". - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - * - * Written by Christopher C. Chimelis <chris@debian.org> - */ - -#ifndef _TAS3004_H_ -#define _TAS3004_H_ - -#include <linux/types.h> - -#include "tas_common.h" -#include "tas_eq_prefs.h" - -/* - * Macros that correspond to the registers that we write to - * when setting the various values. - */ - -#define TAS3004_VERSION "0.3" -#define TAS3004_DATE "20011214" - -#define I2C_DRIVERNAME_TAS3004 "TAS3004 driver V " TAS3004_VERSION -#define I2C_DRIVERID_TAS3004 (I2C_DRIVERID_TAS_BASE+1) - -extern struct tas_driver_hooks_t tas3004_hooks; -extern struct tas_gain_t tas3004_gain; -extern struct tas_eq_pref_t *tas3004_eq_prefs[]; - -enum tas3004_reg_t { - TAS3004_REG_MCR = 0x01, - TAS3004_REG_DRC = 0x02, - - TAS3004_REG_VOLUME = 0x04, - TAS3004_REG_TREBLE = 0x05, - TAS3004_REG_BASS = 0x06, - TAS3004_REG_LEFT_MIXER = 0x07, - TAS3004_REG_RIGHT_MIXER = 0x08, - - TAS3004_REG_LEFT_BIQUAD0 = 0x0a, - TAS3004_REG_LEFT_BIQUAD1 = 0x0b, - TAS3004_REG_LEFT_BIQUAD2 = 0x0c, - TAS3004_REG_LEFT_BIQUAD3 = 0x0d, - TAS3004_REG_LEFT_BIQUAD4 = 0x0e, - TAS3004_REG_LEFT_BIQUAD5 = 0x0f, - TAS3004_REG_LEFT_BIQUAD6 = 0x10, - - TAS3004_REG_RIGHT_BIQUAD0 = 0x13, - TAS3004_REG_RIGHT_BIQUAD1 = 0x14, - TAS3004_REG_RIGHT_BIQUAD2 = 0x15, - TAS3004_REG_RIGHT_BIQUAD3 = 0x16, - TAS3004_REG_RIGHT_BIQUAD4 = 0x17, - TAS3004_REG_RIGHT_BIQUAD5 = 0x18, - TAS3004_REG_RIGHT_BIQUAD6 = 0x19, - - TAS3004_REG_LEFT_LOUD_BIQUAD = 0x21, - TAS3004_REG_RIGHT_LOUD_BIQUAD = 0x22, - - TAS3004_REG_LEFT_LOUD_BIQUAD_GAIN = 0x23, - TAS3004_REG_RIGHT_LOUD_BIQUAD_GAIN = 0x24, - - TAS3004_REG_TEST = 0x29, - - TAS3004_REG_ANALOG_CTRL = 0x40, - TAS3004_REG_TEST1 = 0x41, - TAS3004_REG_TEST2 = 0x42, - TAS3004_REG_MCR2 = 0x43, - - TAS3004_REG_MAX = 0x44 -}; - -#endif /* _TAS3004_H_ */ diff --git a/sound/oss/dmasound/tas3004_tables.c b/sound/oss/dmasound/tas3004_tables.c deleted file mode 100644 index b910e0a66775..000000000000 --- a/sound/oss/dmasound/tas3004_tables.c +++ /dev/null @@ -1,301 +0,0 @@ -#include "tas3004.h" -#include "tas_eq_prefs.h" - -static struct tas_drce_t eqp_17_1_0_drce={ - .enable = 1, - .above = { .val = 3.0 * (1<<8), .expand = 0 }, - .below = { .val = 1.0 * (1<<8), .expand = 0 }, - .threshold = -19.12 * (1<<8), - .energy = 2.4 * (1<<12), - .attack = 0.013 * (1<<12), - .decay = 0.212 * (1<<12), -}; - -static struct tas_biquad_ctrl_t eqp_17_1_0_biquads[]={ - { .channel = 0, .filter = 0, .data = { .coeff = { 0x0fd0d4, 0xe05e56, 0x0fd0d4, 0xe05ee1, 0x0fa234 } } }, - { .channel = 0, .filter = 1, .data = { .coeff = { 0x0910d7, 0x088e1a, 0x030651, 0x01dcb1, 0x02c892 } } }, - { .channel = 0, .filter = 2, .data = { .coeff = { 0x0ff895, 0xe0970b, 0x0f7f00, 0xe0970b, 0x0f7795 } } }, - { .channel = 0, .filter = 3, .data = { .coeff = { 0x0fd1c4, 0xe1ac22, 0x0ec8cf, 0xe1ac22, 0x0e9a94 } } }, - { .channel = 0, .filter = 4, .data = { .coeff = { 0x0f7c1c, 0xe3cc03, 0x0df786, 0xe3cc03, 0x0d73a2 } } }, - { .channel = 0, .filter = 5, .data = { .coeff = { 0x11fb92, 0xf5a1a0, 0x073cd2, 0xf5a1a0, 0x093865 } } }, - { .channel = 0, .filter = 6, .data = { .coeff = { 0x0e17a9, 0x068b6c, 0x08a0e5, 0x068b6c, 0x06b88e } } }, - - { .channel = 1, .filter = 0, .data = { .coeff = { 0x0fd0d4, 0xe05e56, 0x0fd0d4, 0xe05ee1, 0x0fa234 } } }, - { .channel = 1, .filter = 1, .data = { .coeff = { 0x0910d7, 0x088e1a, 0x030651, 0x01dcb1, 0x02c892 } } }, - { .channel = 1, .filter = 2, .data = { .coeff = { 0x0ff895, 0xe0970b, 0x0f7f00, 0xe0970b, 0x0f7795 } } }, - { .channel = 1, .filter = 3, .data = { .coeff = { 0x0fd1c4, 0xe1ac22, 0x0ec8cf, 0xe1ac22, 0x0e9a94 } } }, - { .channel = 1, .filter = 4, .data = { .coeff = { 0x0f7c1c, 0xe3cc03, 0x0df786, 0xe3cc03, 0x0d73a2 } } }, - { .channel = 1, .filter = 5, .data = { .coeff = { 0x11fb92, 0xf5a1a0, 0x073cd2, 0xf5a1a0, 0x093865 } } }, - { .channel = 1, .filter = 6, .data = { .coeff = { 0x0e17a9, 0x068b6c, 0x08a0e5, 0x068b6c, 0x06b88e } } } -}; - -static struct tas_eq_pref_t eqp_17_1_0 = { - .sample_rate = 44100, - .device_id = 0x17, - .output_id = TAS_OUTPUT_INTERNAL_SPKR, - .speaker_id = 0x00, - - .drce = &eqp_17_1_0_drce, - - .filter_count = 14, - .biquads = eqp_17_1_0_biquads -}; - -/* ======================================================================== */ - -static struct tas_drce_t eqp_18_1_0_drce={ - .enable = 1, - .above = { .val = 3.0 * (1<<8), .expand = 0 }, - .below = { .val = 1.0 * (1<<8), .expand = 0 }, - .threshold = -13.14 * (1<<8), - .energy = 2.4 * (1<<12), - .attack = 0.013 * (1<<12), - .decay = 0.212 * (1<<12), -}; - -static struct tas_biquad_ctrl_t eqp_18_1_0_biquads[]={ - { .channel = 0, .filter = 0, .data = { .coeff = { 0x0f5514, 0xe155d7, 0x0f5514, 0xe15cfa, 0x0eb14b } } }, - { .channel = 0, .filter = 1, .data = { .coeff = { 0x06ec33, 0x02abe3, 0x015eef, 0xf764d9, 0x03922d } } }, - { .channel = 0, .filter = 2, .data = { .coeff = { 0x0ef5f2, 0xe67d1f, 0x0bcf37, 0xe67d1f, 0x0ac529 } } }, - { .channel = 0, .filter = 3, .data = { .coeff = { 0x0db050, 0xe5be4d, 0x0d0c78, 0xe5be4d, 0x0abcc8 } } }, - { .channel = 0, .filter = 4, .data = { .coeff = { 0x0f1298, 0xe64ec6, 0x0cc03e, 0xe64ec6, 0x0bd2d7 } } }, - { .channel = 0, .filter = 5, .data = { .coeff = { 0x0c641a, 0x06537a, 0x08d155, 0x06537a, 0x053570 } } }, - { .channel = 0, .filter = 6, .data = { .coeff = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } }, - - { .channel = 1, .filter = 0, .data = { .coeff = { 0x0f5514, 0xe155d7, 0x0f5514, 0xe15cfa, 0x0eb14b } } }, - { .channel = 1, .filter = 1, .data = { .coeff = { 0x06ec33, 0x02abe3, 0x015eef, 0xf764d9, 0x03922d } } }, - { .channel = 1, .filter = 2, .data = { .coeff = { 0x0ef5f2, 0xe67d1f, 0x0bcf37, 0xe67d1f, 0x0ac529 } } }, - { .channel = 1, .filter = 3, .data = { .coeff = { 0x0db050, 0xe5be4d, 0x0d0c78, 0xe5be4d, 0x0abcc8 } } }, - { .channel = 1, .filter = 4, .data = { .coeff = { 0x0f1298, 0xe64ec6, 0x0cc03e, 0xe64ec6, 0x0bd2d7 } } }, - { .channel = 1, .filter = 5, .data = { .coeff = { 0x0c641a, 0x06537a, 0x08d155, 0x06537a, 0x053570 } } }, - { .channel = 1, .filter = 6, .data = { .coeff = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } } -}; - -static struct tas_eq_pref_t eqp_18_1_0 = { - .sample_rate = 44100, - .device_id = 0x18, - .output_id = TAS_OUTPUT_INTERNAL_SPKR, - .speaker_id = 0x00, - - .drce = &eqp_18_1_0_drce, - - .filter_count = 14, - .biquads = eqp_18_1_0_biquads -}; - -/* ======================================================================== */ - -static struct tas_drce_t eqp_1a_1_0_drce={ - .enable = 1, - .above = { .val = 3.0 * (1<<8), .expand = 0 }, - .below = { .val = 1.0 * (1<<8), .expand = 0 }, - .threshold = -10.75 * (1<<8), - .energy = 2.4 * (1<<12), - .attack = 0.013 * (1<<12), - .decay = 0.212 * (1<<12), -}; - -static struct tas_biquad_ctrl_t eqp_1a_1_0_biquads[]={ - { .channel = 0, .filter = 0, .data = { .coeff = { 0x0fb8fd, 0xe08e04, 0x0fb8fd, 0xe08f40, 0x0f7336 } } }, - { .channel = 0, .filter = 1, .data = { .coeff = { 0x06371d, 0x0c6e3a, 0x06371d, 0x05bfd3, 0x031ca2 } } }, - { .channel = 0, .filter = 2, .data = { .coeff = { 0x0fa1c0, 0xe18692, 0x0f030e, 0xe18692, 0x0ea4ce } } }, - { .channel = 0, .filter = 3, .data = { .coeff = { 0x0fe495, 0xe17eff, 0x0f0452, 0xe17eff, 0x0ee8e7 } } }, - { .channel = 0, .filter = 4, .data = { .coeff = { 0x100857, 0xe7e71c, 0x0e9599, 0xe7e71c, 0x0e9df1 } } }, - { .channel = 0, .filter = 5, .data = { .coeff = { 0x0fb26e, 0x06a82c, 0x0db2b4, 0x06a82c, 0x0d6522 } } }, - { .channel = 0, .filter = 6, .data = { .coeff = { 0x11419d, 0xf06cbf, 0x0a4f6e, 0xf06cbf, 0x0b910c } } }, - - { .channel = 1, .filter = 0, .data = { .coeff = { 0x0fb8fd, 0xe08e04, 0x0fb8fd, 0xe08f40, 0x0f7336 } } }, - { .channel = 1, .filter = 1, .data = { .coeff = { 0x06371d, 0x0c6e3a, 0x06371d, 0x05bfd3, 0x031ca2 } } }, - { .channel = 1, .filter = 2, .data = { .coeff = { 0x0fa1c0, 0xe18692, 0x0f030e, 0xe18692, 0x0ea4ce } } }, - { .channel = 1, .filter = 3, .data = { .coeff = { 0x0fe495, 0xe17eff, 0x0f0452, 0xe17eff, 0x0ee8e7 } } }, - { .channel = 1, .filter = 4, .data = { .coeff = { 0x100857, 0xe7e71c, 0x0e9599, 0xe7e71c, 0x0e9df1 } } }, - { .channel = 1, .filter = 5, .data = { .coeff = { 0x0fb26e, 0x06a82c, 0x0db2b4, 0x06a82c, 0x0d6522 } } }, - { .channel = 1, .filter = 6, .data = { .coeff = { 0x11419d, 0xf06cbf, 0x0a4f6e, 0xf06cbf, 0x0b910c } } } -}; - -static struct tas_eq_pref_t eqp_1a_1_0 = { - .sample_rate = 44100, - .device_id = 0x1a, - .output_id = TAS_OUTPUT_INTERNAL_SPKR, - .speaker_id = 0x00, - - .drce = &eqp_1a_1_0_drce, - - .filter_count = 14, - .biquads = eqp_1a_1_0_biquads -}; - -/* ======================================================================== */ - -static struct tas_drce_t eqp_1c_1_0_drce={ - .enable = 1, - .above = { .val = 3.0 * (1<<8), .expand = 0 }, - .below = { .val = 1.0 * (1<<8), .expand = 0 }, - .threshold = -14.34 * (1<<8), - .energy = 2.4 * (1<<12), - .attack = 0.013 * (1<<12), - .decay = 0.212 * (1<<12), -}; - -static struct tas_biquad_ctrl_t eqp_1c_1_0_biquads[]={ - { .channel = 0, .filter = 0, .data = { .coeff = { 0x0f4f95, 0xe160d4, 0x0f4f95, 0xe1686e, 0x0ea6c5 } } }, - { .channel = 0, .filter = 1, .data = { .coeff = { 0x066b92, 0x0290d4, 0x0148a0, 0xf6853f, 0x03bfc7 } } }, - { .channel = 0, .filter = 2, .data = { .coeff = { 0x0f57dc, 0xe51c91, 0x0dd1cb, 0xe51c91, 0x0d29a8 } } }, - { .channel = 0, .filter = 3, .data = { .coeff = { 0x0df1cb, 0xe4fa84, 0x0d7cdc, 0xe4fa84, 0x0b6ea7 } } }, - { .channel = 0, .filter = 4, .data = { .coeff = { 0x0eba36, 0xe6aa48, 0x0b9f52, 0xe6aa48, 0x0a5989 } } }, - { .channel = 0, .filter = 5, .data = { .coeff = { 0x0caf02, 0x05ef9d, 0x084beb, 0x05ef9d, 0x04faee } } }, - { .channel = 0, .filter = 6, .data = { .coeff = { 0x0fc686, 0xe22947, 0x0e4b5d, 0xe22947, 0x0e11e4 } } }, - - { .channel = 1, .filter = 0, .data = { .coeff = { 0x0f4f95, 0xe160d4, 0x0f4f95, 0xe1686e, 0x0ea6c5 } } }, - { .channel = 1, .filter = 1, .data = { .coeff = { 0x066b92, 0x0290d4, 0x0148a0, 0xf6853f, 0x03bfc7 } } }, - { .channel = 1, .filter = 2, .data = { .coeff = { 0x0f57dc, 0xe51c91, 0x0dd1cb, 0xe51c91, 0x0d29a8 } } }, - { .channel = 1, .filter = 3, .data = { .coeff = { 0x0df1cb, 0xe4fa84, 0x0d7cdc, 0xe4fa84, 0x0b6ea7 } } }, - { .channel = 1, .filter = 4, .data = { .coeff = { 0x0eba36, 0xe6aa48, 0x0b9f52, 0xe6aa48, 0x0a5989 } } }, - { .channel = 1, .filter = 5, .data = { .coeff = { 0x0caf02, 0x05ef9d, 0x084beb, 0x05ef9d, 0x04faee } } }, - { .channel = 1, .filter = 6, .data = { .coeff = { 0x0fc686, 0xe22947, 0x0e4b5d, 0xe22947, 0x0e11e4 } } } -}; - -static struct tas_eq_pref_t eqp_1c_1_0 = { - .sample_rate = 44100, - .device_id = 0x1c, - .output_id = TAS_OUTPUT_INTERNAL_SPKR, - .speaker_id = 0x00, - - .drce = &eqp_1c_1_0_drce, - - .filter_count = 14, - .biquads = eqp_1c_1_0_biquads -}; - -/* ======================================================================== */ - -static uint tas3004_master_tab[]={ - 0x0, 0x75, 0x9c, 0xbb, - 0xdb, 0xfb, 0x11e, 0x143, - 0x16b, 0x196, 0x1c3, 0x1f5, - 0x229, 0x263, 0x29f, 0x2e1, - 0x328, 0x373, 0x3c5, 0x41b, - 0x478, 0x4dc, 0x547, 0x5b8, - 0x633, 0x6b5, 0x740, 0x7d5, - 0x873, 0x91c, 0x9d2, 0xa92, - 0xb5e, 0xc39, 0xd22, 0xe19, - 0xf20, 0x1037, 0x1161, 0x129e, - 0x13ed, 0x1551, 0x16ca, 0x185d, - 0x1a08, 0x1bcc, 0x1dac, 0x1fa7, - 0x21c1, 0x23fa, 0x2655, 0x28d6, - 0x2b7c, 0x2e4a, 0x3141, 0x3464, - 0x37b4, 0x3b35, 0x3ee9, 0x42d3, - 0x46f6, 0x4b53, 0x4ff0, 0x54ce, - 0x59f2, 0x5f5f, 0x6519, 0x6b24, - 0x7183, 0x783c, 0x7f53, 0x86cc, - 0x8ead, 0x96fa, 0x9fba, 0xa8f2, - 0xb2a7, 0xbce1, 0xc7a5, 0xd2fa, - 0xdee8, 0xeb75, 0xf8aa, 0x1068e, - 0x1152a, 0x12487, 0x134ad, 0x145a5, - 0x1577b, 0x16a37, 0x17df5, 0x192bd, - 0x1a890, 0x1bf7b, 0x1d78d, 0x1f0d1, - 0x20b55, 0x22727, 0x24456, 0x262f2, - 0x2830b -}; - -static uint tas3004_mixer_tab[]={ - 0x0, 0x748, 0x9be, 0xbaf, - 0xda4, 0xfb1, 0x11de, 0x1431, - 0x16ad, 0x1959, 0x1c37, 0x1f4b, - 0x2298, 0x2628, 0x29fb, 0x2e12, - 0x327d, 0x3734, 0x3c47, 0x41b4, - 0x4787, 0x4dbe, 0x546d, 0x5b86, - 0x632e, 0x6b52, 0x7400, 0x7d54, - 0x873b, 0x91c6, 0x9d1a, 0xa920, - 0xb5e5, 0xc38c, 0xd21b, 0xe18f, - 0xf1f5, 0x1036a, 0x1160f, 0x129d6, - 0x13ed0, 0x1550c, 0x16ca0, 0x185c9, - 0x1a07b, 0x1bcc3, 0x1dab9, 0x1fa75, - 0x21c0f, 0x23fa3, 0x26552, 0x28d64, - 0x2b7c9, 0x2e4a2, 0x31411, 0x3463b, - 0x37b44, 0x3b353, 0x3ee94, 0x42d30, - 0x46f55, 0x4b533, 0x4fefc, 0x54ce5, - 0x59f25, 0x5f5f6, 0x65193, 0x6b23c, - 0x71835, 0x783c3, 0x7f52c, 0x86cc0, - 0x8eacc, 0x96fa5, 0x9fba0, 0xa8f1a, - 0xb2a71, 0xbce0a, 0xc7a4a, 0xd2fa0, - 0xdee7b, 0xeb752, 0xf8a9f, 0x1068e4, - 0x1152a3, 0x12486a, 0x134ac8, 0x145a55, - 0x1577ac, 0x16a370, 0x17df51, 0x192bc2, - 0x1a88f8, 0x1bf7b7, 0x1d78c9, 0x1f0d04, - 0x20b542, 0x227268, 0x244564, 0x262f26, - 0x2830af -}; - -static uint tas3004_treble_tab[]={ - 0x96, 0x95, 0x95, 0x94, - 0x93, 0x92, 0x92, 0x91, - 0x90, 0x90, 0x8f, 0x8e, - 0x8d, 0x8d, 0x8c, 0x8b, - 0x8a, 0x8a, 0x89, 0x88, - 0x88, 0x87, 0x86, 0x85, - 0x85, 0x84, 0x83, 0x83, - 0x82, 0x81, 0x80, 0x80, - 0x7f, 0x7e, 0x7e, 0x7d, - 0x7c, 0x7b, 0x7b, 0x7a, - 0x79, 0x78, 0x78, 0x77, - 0x76, 0x76, 0x75, 0x74, - 0x73, 0x73, 0x72, 0x71, - 0x71, 0x68, 0x45, 0x5b, - 0x6d, 0x6c, 0x6b, 0x6a, - 0x69, 0x68, 0x67, 0x66, - 0x65, 0x63, 0x62, 0x62, - 0x60, 0x5e, 0x5c, 0x5b, - 0x59, 0x57, 0x55, 0x53, - 0x52, 0x4f, 0x4d, 0x4a, - 0x48, 0x46, 0x43, 0x40, - 0x3d, 0x3a, 0x36, 0x33, - 0x2f, 0x2c, 0x27, 0x23, - 0x1f, 0x1a, 0x15, 0xf, - 0x8, 0x5, 0x2, 0x1, - 0x1 -}; - -static uint tas3004_bass_tab[]={ - 0x96, 0x95, 0x95, 0x94, - 0x93, 0x92, 0x92, 0x91, - 0x90, 0x90, 0x8f, 0x8e, - 0x8d, 0x8d, 0x8c, 0x8b, - 0x8a, 0x8a, 0x89, 0x88, - 0x88, 0x87, 0x86, 0x85, - 0x85, 0x84, 0x83, 0x83, - 0x82, 0x81, 0x80, 0x80, - 0x7f, 0x7e, 0x7e, 0x7d, - 0x7c, 0x7b, 0x7b, 0x7a, - 0x79, 0x78, 0x78, 0x77, - 0x76, 0x76, 0x75, 0x74, - 0x73, 0x73, 0x72, 0x71, - 0x70, 0x6f, 0x6e, 0x6d, - 0x6c, 0x6b, 0x6a, 0x6a, - 0x69, 0x67, 0x66, 0x66, - 0x65, 0x63, 0x62, 0x62, - 0x61, 0x60, 0x5e, 0x5d, - 0x5b, 0x59, 0x57, 0x55, - 0x53, 0x51, 0x4f, 0x4c, - 0x4a, 0x48, 0x46, 0x44, - 0x41, 0x3e, 0x3b, 0x38, - 0x36, 0x33, 0x2f, 0x2b, - 0x28, 0x24, 0x20, 0x1c, - 0x17, 0x12, 0xd, 0x7, - 0x1 -}; - -struct tas_gain_t tas3004_gain={ - .master = tas3004_master_tab, - .treble = tas3004_treble_tab, - .bass = tas3004_bass_tab, - .mixer = tas3004_mixer_tab -}; - -struct tas_eq_pref_t *tas3004_eq_prefs[]={ - &eqp_17_1_0, - &eqp_18_1_0, - &eqp_1a_1_0, - &eqp_1c_1_0, - NULL -}; diff --git a/sound/oss/dmasound/tas_common.c b/sound/oss/dmasound/tas_common.c deleted file mode 100644 index b295ef682192..000000000000 --- a/sound/oss/dmasound/tas_common.c +++ /dev/null @@ -1,214 +0,0 @@ -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/proc_fs.h> -#include <linux/ioport.h> -#include <linux/sysctl.h> -#include <linux/types.h> -#include <linux/i2c.h> -#include <linux/init.h> -#include <linux/soundcard.h> -#include <asm/uaccess.h> -#include <asm/errno.h> -#include <asm/io.h> -#include <asm/prom.h> - -#include "tas_common.h" - -#define CALL0(proc) \ - do { \ - struct tas_data_t *self; \ - if (!tas_client || driver_hooks == NULL) \ - return -1; \ - self = dev_get_drvdata(&tas_client->dev); \ - if (driver_hooks->proc) \ - return driver_hooks->proc(self); \ - else \ - return -EINVAL; \ - } while (0) - -#define CALL(proc,arg...) \ - do { \ - struct tas_data_t *self; \ - if (!tas_client || driver_hooks == NULL) \ - return -1; \ - self = dev_get_drvdata(&tas_client->dev); \ - if (driver_hooks->proc) \ - return driver_hooks->proc(self, ## arg); \ - else \ - return -EINVAL; \ - } while (0) - - -static u8 tas_i2c_address = 0x34; -static struct i2c_client *tas_client; - -static int tas_attach_adapter(struct i2c_adapter *); -static int tas_detach_client(struct i2c_client *); - -struct i2c_driver tas_driver = { - .driver = { - .name = "tas", - }, - .attach_adapter = tas_attach_adapter, - .detach_client = tas_detach_client, -}; - -struct tas_driver_hooks_t *driver_hooks; - -int -tas_register_driver(struct tas_driver_hooks_t *hooks) -{ - driver_hooks = hooks; - return 0; -} - -int -tas_get_mixer_level(int mixer, uint *level) -{ - CALL(get_mixer_level,mixer,level); -} - -int -tas_set_mixer_level(int mixer,uint level) -{ - CALL(set_mixer_level,mixer,level); -} - -int -tas_enter_sleep(void) -{ - CALL0(enter_sleep); -} - -int -tas_leave_sleep(void) -{ - CALL0(leave_sleep); -} - -int -tas_supported_mixers(void) -{ - CALL0(supported_mixers); -} - -int -tas_mixer_is_stereo(int mixer) -{ - CALL(mixer_is_stereo,mixer); -} - -int -tas_stereo_mixers(void) -{ - CALL0(stereo_mixers); -} - -int -tas_output_device_change(int device_id,int layout_id,int speaker_id) -{ - CALL(output_device_change,device_id,layout_id,speaker_id); -} - -int -tas_device_ioctl(u_int cmd, u_long arg) -{ - CALL(device_ioctl,cmd,arg); -} - -int -tas_post_init(void) -{ - CALL0(post_init); -} - -static int -tas_detect_client(struct i2c_adapter *adapter, int address) -{ - static const char *client_name = "tas Digital Equalizer"; - struct i2c_client *new_client; - int rc = -ENODEV; - - if (!driver_hooks) { - printk(KERN_ERR "tas_detect_client called with no hooks !\n"); - return -ENODEV; - } - - new_client = kzalloc(sizeof(*new_client), GFP_KERNEL); - if (!new_client) - return -ENOMEM; - - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &tas_driver; - strlcpy(new_client->name, client_name, DEVICE_NAME_SIZE); - - if (driver_hooks->init(new_client)) - goto bail; - - /* Tell the i2c layer a new client has arrived */ - if (i2c_attach_client(new_client)) { - driver_hooks->uninit(dev_get_drvdata(&new_client->dev)); - goto bail; - } - - tas_client = new_client; - return 0; - bail: - tas_client = NULL; - kfree(new_client); - return rc; -} - -static int -tas_attach_adapter(struct i2c_adapter *adapter) -{ - if (!strncmp(adapter->name, "mac-io", 6)) - return tas_detect_client(adapter, tas_i2c_address); - return 0; -} - -static int -tas_detach_client(struct i2c_client *client) -{ - if (client == tas_client) { - driver_hooks->uninit(dev_get_drvdata(&client->dev)); - - i2c_detach_client(client); - kfree(client); - } - return 0; -} - -void -tas_cleanup(void) -{ - i2c_del_driver(&tas_driver); -} - -int __init -tas_init(int driver_id, const char *driver_name) -{ - const u32* paddr; - struct device_node *tas_node; - - printk(KERN_INFO "tas driver [%s])\n", driver_name); - -#ifndef CONFIG_I2C_POWERMAC - request_module("i2c-powermac"); -#endif - tas_node = of_find_node_by_name("deq"); - if (tas_node == NULL) - return -ENODEV; - paddr = of_get_property(tas_node, "i2c-address", NULL); - if (paddr) { - tas_i2c_address = (*paddr) >> 1; - printk(KERN_INFO "using i2c address: 0x%x from device-tree\n", - tas_i2c_address); - } else - printk(KERN_INFO "using i2c address: 0x%x (default)\n", - tas_i2c_address); - of_node_put(tas_node); - - return i2c_add_driver(&tas_driver); -} diff --git a/sound/oss/dmasound/tas_common.h b/sound/oss/dmasound/tas_common.h deleted file mode 100644 index 0741c28e56ce..000000000000 --- a/sound/oss/dmasound/tas_common.h +++ /dev/null @@ -1,284 +0,0 @@ -#ifndef _TAS_COMMON_H_ -#define _TAS_COMMON_H_ - -#include <linux/i2c.h> -#include <linux/soundcard.h> -#include <asm/string.h> - -#define I2C_DRIVERID_TAS_BASE (0xFEBA) - -#define SET_4_20(shadow, offset, val) \ - do { \ - (shadow)[(offset)+0] = ((val) >> 16) & 0xff; \ - (shadow)[(offset)+1] = ((val) >> 8) & 0xff; \ - (shadow)[(offset)+2] = ((val) >> 0) & 0xff; \ - } while (0) - -#define GET_4_20(shadow, offset) \ - (((u_int)((shadow)[(offset)+0]) << 16) | \ - ((u_int)((shadow)[(offset)+1]) << 8) | \ - ((u_int)((shadow)[(offset)+2]) << 0)) - - -#define TAS_BIQUAD_FAST_LOAD 0x01 - -#define TAS_DRCE_ENABLE 0x01 -#define TAS_DRCE_ABOVE_RATIO 0x02 -#define TAS_DRCE_BELOW_RATIO 0x04 -#define TAS_DRCE_THRESHOLD 0x08 -#define TAS_DRCE_ENERGY 0x10 -#define TAS_DRCE_ATTACK 0x20 -#define TAS_DRCE_DECAY 0x40 - -#define TAS_DRCE_ALL 0x7f - - -#define TAS_OUTPUT_HEADPHONES 0x00 -#define TAS_OUTPUT_INTERNAL_SPKR 0x01 -#define TAS_OUTPUT_EXTERNAL_SPKR 0x02 - - -union tas_biquad_t { - struct { - int b0,b1,b2,a1,a2; - } coeff; - int buf[5]; -}; - -struct tas_biquad_ctrl_t { - u_int channel:4; - u_int filter:4; - - union tas_biquad_t data; -}; - -struct tas_biquad_ctrl_list_t { - int flags; - int filter_count; - struct tas_biquad_ctrl_t biquads[0]; -}; - -struct tas_ratio_t { - unsigned short val; /* 8.8 */ - unsigned short expand; /* 0 = compress, !0 = expand. */ -}; - -struct tas_drce_t { - unsigned short enable; - struct tas_ratio_t above; - struct tas_ratio_t below; - short threshold; /* dB, 8.8 signed */ - unsigned short energy; /* seconds, 4.12 unsigned */ - unsigned short attack; /* seconds, 4.12 unsigned */ - unsigned short decay; /* seconds, 4.12 unsigned */ -}; - -struct tas_drce_ctrl_t { - uint flags; - - struct tas_drce_t data; -}; - -struct tas_gain_t -{ - unsigned int *master; - unsigned int *treble; - unsigned int *bass; - unsigned int *mixer; -}; - -typedef char tas_shadow_t[0x45]; - -struct tas_data_t -{ - struct i2c_client *client; - tas_shadow_t *shadow; - uint mixer[SOUND_MIXER_NRDEVICES]; -}; - -typedef int (*tas_hook_init_t)(struct i2c_client *); -typedef int (*tas_hook_post_init_t)(struct tas_data_t *); -typedef void (*tas_hook_uninit_t)(struct tas_data_t *); - -typedef int (*tas_hook_get_mixer_level_t)(struct tas_data_t *,int,uint *); -typedef int (*tas_hook_set_mixer_level_t)(struct tas_data_t *,int,uint); - -typedef int (*tas_hook_enter_sleep_t)(struct tas_data_t *); -typedef int (*tas_hook_leave_sleep_t)(struct tas_data_t *); - -typedef int (*tas_hook_supported_mixers_t)(struct tas_data_t *); -typedef int (*tas_hook_mixer_is_stereo_t)(struct tas_data_t *,int); -typedef int (*tas_hook_stereo_mixers_t)(struct tas_data_t *); - -typedef int (*tas_hook_output_device_change_t)(struct tas_data_t *,int,int,int); -typedef int (*tas_hook_device_ioctl_t)(struct tas_data_t *,u_int,u_long); - -struct tas_driver_hooks_t { - /* - * All hardware initialisation must be performed in - * post_init(), as tas_dmasound_init() does a hardware reset. - * - * init() is called before tas_dmasound_init() so that - * ouput_device_change() is always called after i2c driver - * initialisation. The implication is that - * output_device_change() must cope with the fact that it - * may be called before post_init(). - */ - - tas_hook_init_t init; - tas_hook_post_init_t post_init; - tas_hook_uninit_t uninit; - - tas_hook_get_mixer_level_t get_mixer_level; - tas_hook_set_mixer_level_t set_mixer_level; - - tas_hook_enter_sleep_t enter_sleep; - tas_hook_leave_sleep_t leave_sleep; - - tas_hook_supported_mixers_t supported_mixers; - tas_hook_mixer_is_stereo_t mixer_is_stereo; - tas_hook_stereo_mixers_t stereo_mixers; - - tas_hook_output_device_change_t output_device_change; - tas_hook_device_ioctl_t device_ioctl; -}; - -enum tas_write_mode_t { - WRITE_HW = 0x01, - WRITE_SHADOW = 0x02, - WRITE_NORMAL = 0x03, - FORCE_WRITE = 0x04 -}; - -static inline uint -tas_mono_to_stereo(uint mono) -{ - mono &=0xff; - return mono | (mono<<8); -} - -/* - * Todo: make these functions a bit more efficient ! - */ -static inline int -tas_write_register( struct tas_data_t *self, - uint reg_num, - uint reg_width, - char *data, - uint write_mode) -{ - int rc; - - if (reg_width==0 || data==NULL || self==NULL) - return -EINVAL; - if (!(write_mode & FORCE_WRITE) && - !memcmp(data,self->shadow[reg_num],reg_width)) - return 0; - - if (write_mode & WRITE_SHADOW) - memcpy(self->shadow[reg_num],data,reg_width); - if (write_mode & WRITE_HW) { - rc=i2c_smbus_write_i2c_block_data(self->client, - reg_num, - reg_width, - data); - if (rc < 0) { - printk("tas: I2C block write failed \n"); - return rc; - } - } - return 0; -} - -static inline int -tas_sync_register( struct tas_data_t *self, - uint reg_num, - uint reg_width) -{ - int rc; - - if (reg_width==0 || self==NULL) - return -EINVAL; - rc=i2c_smbus_write_i2c_block_data(self->client, - reg_num, - reg_width, - self->shadow[reg_num]); - if (rc < 0) { - printk("tas: I2C block write failed \n"); - return rc; - } - return 0; -} - -static inline int -tas_write_byte_register( struct tas_data_t *self, - uint reg_num, - char data, - uint write_mode) -{ - if (self==NULL) - return -1; - if (!(write_mode & FORCE_WRITE) && data != self->shadow[reg_num][0]) - return 0; - if (write_mode & WRITE_SHADOW) - self->shadow[reg_num][0]=data; - if (write_mode & WRITE_HW) { - if (i2c_smbus_write_byte_data(self->client, reg_num, data) < 0) { - printk("tas: I2C byte write failed \n"); - return -1; - } - } - return 0; -} - -static inline int -tas_sync_byte_register( struct tas_data_t *self, - uint reg_num, - uint reg_width) -{ - if (reg_width==0 || self==NULL) - return -1; - if (i2c_smbus_write_byte_data( - self->client, reg_num, self->shadow[reg_num][0]) < 0) { - printk("tas: I2C byte write failed \n"); - return -1; - } - return 0; -} - -static inline int -tas_read_register( struct tas_data_t *self, - uint reg_num, - uint reg_width, - char *data) -{ - if (reg_width==0 || data==NULL || self==NULL) - return -1; - memcpy(data,self->shadow[reg_num],reg_width); - return 0; -} - -extern int tas_register_driver(struct tas_driver_hooks_t *hooks); - -extern int tas_get_mixer_level(int mixer,uint *level); -extern int tas_set_mixer_level(int mixer,uint level); -extern int tas_enter_sleep(void); -extern int tas_leave_sleep(void); -extern int tas_supported_mixers(void); -extern int tas_mixer_is_stereo(int mixer); -extern int tas_stereo_mixers(void); -extern int tas_output_device_change(int,int,int); -extern int tas_device_ioctl(u_int, u_long); - -extern void tas_cleanup(void); -extern int tas_init(int driver_id,const char *driver_name); -extern int tas_post_init(void); - -#endif /* _TAS_COMMON_H_ */ -/* - * Local Variables: - * tab-width: 8 - * indent-tabs-mode: t - * c-basic-offset: 8 - * End: - */ diff --git a/sound/oss/dmasound/tas_eq_prefs.h b/sound/oss/dmasound/tas_eq_prefs.h deleted file mode 100644 index 3a994eda6abc..000000000000 --- a/sound/oss/dmasound/tas_eq_prefs.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _TAS_EQ_PREFS_H_ -#define _TAS_EQ_PREFS_H_ - -struct tas_eq_pref_t { - u_int sample_rate; - u_int device_id; - u_int output_id; - u_int speaker_id; - - struct tas_drce_t *drce; - - u_int filter_count; - struct tas_biquad_ctrl_t *biquads; -}; - -#endif /* _TAS_EQ_PREFS_H_ */ - -/* - * Local Variables: - * tab-width: 8 - * indent-tabs-mode: t - * c-basic-offset: 8 - * End: - */ diff --git a/sound/oss/dmasound/tas_ioctl.h b/sound/oss/dmasound/tas_ioctl.h deleted file mode 100644 index 9d12b373b4a9..000000000000 --- a/sound/oss/dmasound/tas_ioctl.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _TAS_IOCTL_H_ -#define _TAS_IOCTL_H_ - -#include <linux/soundcard.h> - - -#define TAS_READ_EQ _SIOR('t',0,struct tas_biquad_ctrl_t) -#define TAS_WRITE_EQ _SIOW('t',0,struct tas_biquad_ctrl_t) - -#define TAS_READ_EQ_LIST _SIOR('t',1,struct tas_biquad_ctrl_t) -#define TAS_WRITE_EQ_LIST _SIOW('t',1,struct tas_biquad_ctrl_t) - -#define TAS_READ_EQ_FILTER_COUNT _SIOR('t',2,int) -#define TAS_READ_EQ_CHANNEL_COUNT _SIOR('t',3,int) - -#define TAS_READ_DRCE _SIOR('t',4,struct tas_drce_ctrl_t) -#define TAS_WRITE_DRCE _SIOW('t',4,struct tas_drce_ctrl_t) - -#define TAS_READ_DRCE_CAPS _SIOR('t',5,int) -#define TAS_READ_DRCE_MIN _SIOR('t',6,int) -#define TAS_READ_DRCE_MAX _SIOR('t',7,int) - -#endif diff --git a/sound/oss/dmasound/trans_16.c b/sound/oss/dmasound/trans_16.c deleted file mode 100644 index ca973ac2a30a..000000000000 --- a/sound/oss/dmasound/trans_16.c +++ /dev/null @@ -1,898 +0,0 @@ -/* - * linux/sound/oss/dmasound/trans_16.c - * - * 16 bit translation routines. Only used by Power mac at present. - * - * See linux/sound/oss/dmasound/dmasound_core.c for copyright and - * history prior to 08/02/2001. - * - * 08/02/2001 Iain Sandoe - * split from dmasound_awacs.c - * 11/29/2003 Renzo Davoli (King Enzo) - * - input resampling (for soft rate < hard rate) - * - software line in gain control - */ - -#include <linux/soundcard.h> -#include <asm/uaccess.h> -#include "dmasound.h" - -extern int expand_bal; /* Balance factor for expanding (not volume!) */ -static short dmasound_alaw2dma16[] ; -static short dmasound_ulaw2dma16[] ; - -static ssize_t pmac_ct_law(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ct_s8(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ct_u8(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ct_s16(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ct_u16(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); - -static ssize_t pmac_ctx_law(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ctx_s8(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ctx_u8(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ctx_s16(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ctx_u16(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); - -static ssize_t pmac_ct_s16_read(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ct_u16_read(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); - -/*** Translations ************************************************************/ - -static int expand_data; /* Data for expanding */ - -static ssize_t pmac_ct_law(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - short *table = dmasound.soft.format == AFMT_MU_LAW - ? dmasound_ulaw2dma16 : dmasound_alaw2dma16; - ssize_t count, used; - short *p = (short *) &frame[*frameUsed]; - int val, stereo = dmasound.soft.stereo; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - used = count = min_t(unsigned long, 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 pmac_ct_s8(const u_char __user *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 = dmasound.soft.stereo; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - used = count = min_t(unsigned long, 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 pmac_ct_u8(const u_char __user *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 = dmasound.soft.stereo; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - used = count = min_t(unsigned long, 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; -} - - -static ssize_t pmac_ct_s16(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - ssize_t count, used; - int stereo = dmasound.soft.stereo; - short *fp = (short *) &frame[*frameUsed]; - - frameLeft >>= 2; - userCount >>= (stereo? 2: 1); - used = count = min_t(unsigned long, userCount, frameLeft); - if (!stereo) { - short __user *up = (short __user *) 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 pmac_ct_u16(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - ssize_t count, used; - int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); - int stereo = dmasound.soft.stereo; - short *fp = (short *) &frame[*frameUsed]; - short __user *up = (short __user *) userPtr; - - frameLeft >>= 2; - userCount >>= (stereo? 2: 1); - used = count = min_t(unsigned long, userCount, frameLeft); - while (count > 0) { - short 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 pmac_ctx_law(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - unsigned short *table = (unsigned short *) - (dmasound.soft.format == AFMT_MU_LAW - ? dmasound_ulaw2dma16 : dmasound_alaw2dma16); - unsigned int data = expand_data; - unsigned int *p = (unsigned int *) &frame[*frameUsed]; - int bal = expand_bal; - int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int utotal, ftotal; - int stereo = dmasound.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 pmac_ctx_s8(const u_char __user *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 = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int stereo = dmasound.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 pmac_ctx_u8(const u_char __user *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 = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int stereo = dmasound.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 pmac_ctx_s16(const u_char __user *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 __user *up = (unsigned short __user *) userPtr; - int bal = expand_bal; - int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int stereo = dmasound.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 pmac_ctx_u16(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); - unsigned int *p = (unsigned int *) &frame[*frameUsed]; - unsigned int data = expand_data; - unsigned short __user *up = (unsigned short __user *) userPtr; - int bal = expand_bal; - int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int stereo = dmasound.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; -} - -/* data in routines... */ - -static ssize_t pmac_ct_s8_read(const u_char __user *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 = dmasound.soft.stereo; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - used = count = min_t(unsigned long, userCount, frameLeft); - while (count > 0) { - u_char data; - - val = *p++; - val = (val * software_input_volume) >> 7; - data = val >> 8; - if (put_user(data, (u_char __user *)userPtr++)) - return -EFAULT; - if (stereo) { - val = *p; - val = (val * software_input_volume) >> 7; - data = val >> 8; - if (put_user(data, (u_char __user *)userPtr++)) - return -EFAULT; - } - p++; - count--; - } - *frameUsed += used * 4; - return stereo? used * 2: used; -} - - -static ssize_t pmac_ct_u8_read(const u_char __user *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 = dmasound.soft.stereo; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - used = count = min_t(unsigned long, userCount, frameLeft); - while (count > 0) { - u_char data; - - val = *p++; - val = (val * software_input_volume) >> 7; - data = (val >> 8) ^ 0x80; - if (put_user(data, (u_char __user *)userPtr++)) - return -EFAULT; - if (stereo) { - val = *p; - val = (val * software_input_volume) >> 7; - data = (val >> 8) ^ 0x80; - if (put_user(data, (u_char __user *)userPtr++)) - return -EFAULT; - } - p++; - count--; - } - *frameUsed += used * 4; - return stereo? used * 2: used; -} - -static ssize_t pmac_ct_s16_read(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - ssize_t count, used; - int stereo = dmasound.soft.stereo; - short *fp = (short *) &frame[*frameUsed]; - short __user *up = (short __user *) userPtr; - - frameLeft >>= 2; - userCount >>= (stereo? 2: 1); - used = count = min_t(unsigned long, userCount, frameLeft); - while (count > 0) { - short data; - - data = *fp++; - data = (data * software_input_volume) >> 7; - if (put_user(data, up++)) - return -EFAULT; - if (stereo) { - data = *fp; - data = (data * software_input_volume) >> 7; - if (put_user(data, up++)) - return -EFAULT; - } - fp++; - count--; - } - *frameUsed += used * 4; - return stereo? used * 4: used * 2; -} - -static ssize_t pmac_ct_u16_read(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - ssize_t count, used; - int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); - int stereo = dmasound.soft.stereo; - short *fp = (short *) &frame[*frameUsed]; - short __user *up = (short __user *) userPtr; - - frameLeft >>= 2; - userCount >>= (stereo? 2: 1); - used = count = min_t(unsigned long, userCount, frameLeft); - while (count > 0) { - int data; - - data = *fp++; - data = (data * software_input_volume) >> 7; - data ^= mask; - if (put_user(data, up++)) - return -EFAULT; - if (stereo) { - data = *fp; - data = (data * software_input_volume) >> 7; - data ^= mask; - if (put_user(data, up++)) - return -EFAULT; - } - fp++; - count--; - } - *frameUsed += used * 4; - return stereo? used * 4: used * 2; -} - -/* data in routines (reducing speed)... */ - -static ssize_t pmac_ctx_s8_read(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - short *p = (short *) &frame[*frameUsed]; - int bal = expand_read_bal; - int vall,valr, stereo = dmasound.soft.stereo; - int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int utotal, ftotal; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - ftotal = frameLeft; - utotal = userCount; - while (frameLeft) { - u_char data; - - if (bal<0 && userCount == 0) - break; - vall = *p++; - vall = (vall * software_input_volume) >> 7; - if (stereo) { - valr = *p; - valr = (valr * software_input_volume) >> 7; - } - p++; - if (bal < 0) { - data = vall >> 8; - if (put_user(data, (u_char __user *)userPtr++)) - return -EFAULT; - if (stereo) { - data = valr >> 8; - if (put_user(data, (u_char __user *)userPtr++)) - return -EFAULT; - } - userCount--; - bal += hSpeed; - } - frameLeft--; - bal -= sSpeed; - } - expand_read_bal=bal; - *frameUsed += (ftotal - frameLeft) * 4; - utotal -= userCount; - return stereo? utotal * 2: utotal; -} - - -static ssize_t pmac_ctx_u8_read(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - short *p = (short *) &frame[*frameUsed]; - int bal = expand_read_bal; - int vall,valr, stereo = dmasound.soft.stereo; - int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int utotal, ftotal; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - ftotal = frameLeft; - utotal = userCount; - while (frameLeft) { - u_char data; - - if (bal<0 && userCount == 0) - break; - - vall = *p++; - vall = (vall * software_input_volume) >> 7; - if (stereo) { - valr = *p; - valr = (valr * software_input_volume) >> 7; - } - p++; - if (bal < 0) { - data = (vall >> 8) ^ 0x80; - if (put_user(data, (u_char __user *)userPtr++)) - return -EFAULT; - if (stereo) { - data = (valr >> 8) ^ 0x80; - if (put_user(data, (u_char __user *)userPtr++)) - return -EFAULT; - } - userCount--; - bal += hSpeed; - } - frameLeft--; - bal -= sSpeed; - } - expand_read_bal=bal; - *frameUsed += (ftotal - frameLeft) * 4; - utotal -= userCount; - return stereo? utotal * 2: utotal; -} - -static ssize_t pmac_ctx_s16_read(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - int bal = expand_read_bal; - short *fp = (short *) &frame[*frameUsed]; - short __user *up = (short __user *) userPtr; - int stereo = dmasound.soft.stereo; - int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int utotal, ftotal; - - frameLeft >>= 2; - userCount >>= (stereo? 2: 1); - ftotal = frameLeft; - utotal = userCount; - while (frameLeft) { - int datal,datar; - - if (bal<0 && userCount == 0) - break; - - datal = *fp++; - datal = (datal * software_input_volume) >> 7; - if (stereo) { - datar = *fp; - datar = (datar * software_input_volume) >> 7; - } - fp++; - if (bal < 0) { - if (put_user(datal, up++)) - return -EFAULT; - if (stereo) { - if (put_user(datar, up++)) - return -EFAULT; - } - userCount--; - bal += hSpeed; - } - frameLeft--; - bal -= sSpeed; - } - expand_read_bal=bal; - *frameUsed += (ftotal - frameLeft) * 4; - utotal -= userCount; - return stereo? utotal * 4: utotal * 2; -} - -static ssize_t pmac_ctx_u16_read(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - int bal = expand_read_bal; - int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); - short *fp = (short *) &frame[*frameUsed]; - short __user *up = (short __user *) userPtr; - int stereo = dmasound.soft.stereo; - int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int utotal, ftotal; - - frameLeft >>= 2; - userCount >>= (stereo? 2: 1); - ftotal = frameLeft; - utotal = userCount; - while (frameLeft) { - int datal,datar; - - if (bal<0 && userCount == 0) - break; - - datal = *fp++; - datal = (datal * software_input_volume) >> 7; - datal ^= mask; - if (stereo) { - datar = *fp; - datar = (datar * software_input_volume) >> 7; - datar ^= mask; - } - fp++; - if (bal < 0) { - if (put_user(datal, up++)) - return -EFAULT; - if (stereo) { - if (put_user(datar, up++)) - return -EFAULT; - } - userCount--; - bal += hSpeed; - } - frameLeft--; - bal -= sSpeed; - } - expand_read_bal=bal; - *frameUsed += (ftotal - frameLeft) * 4; - utotal -= userCount; - return stereo? utotal * 4: utotal * 2; -} - - -TRANS transAwacsNormal = { - .ct_ulaw= pmac_ct_law, - .ct_alaw= pmac_ct_law, - .ct_s8= pmac_ct_s8, - .ct_u8= pmac_ct_u8, - .ct_s16be= pmac_ct_s16, - .ct_u16be= pmac_ct_u16, - .ct_s16le= pmac_ct_s16, - .ct_u16le= pmac_ct_u16, -}; - -TRANS transAwacsExpand = { - .ct_ulaw= pmac_ctx_law, - .ct_alaw= pmac_ctx_law, - .ct_s8= pmac_ctx_s8, - .ct_u8= pmac_ctx_u8, - .ct_s16be= pmac_ctx_s16, - .ct_u16be= pmac_ctx_u16, - .ct_s16le= pmac_ctx_s16, - .ct_u16le= pmac_ctx_u16, -}; - -TRANS transAwacsNormalRead = { - .ct_s8= pmac_ct_s8_read, - .ct_u8= pmac_ct_u8_read, - .ct_s16be= pmac_ct_s16_read, - .ct_u16be= pmac_ct_u16_read, - .ct_s16le= pmac_ct_s16_read, - .ct_u16le= pmac_ct_u16_read, -}; - -TRANS transAwacsExpandRead = { - .ct_s8= pmac_ctx_s8_read, - .ct_u8= pmac_ctx_u8_read, - .ct_s16be= pmac_ctx_s16_read, - .ct_u16be= pmac_ctx_u16_read, - .ct_s16le= pmac_ctx_s16_read, - .ct_u16le= pmac_ctx_u16_read, -}; - -/* translation tables */ -/* 16 bit mu-law */ - -static short dmasound_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 dmasound_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, -}; diff --git a/sound/oss/es1371.c b/sound/oss/es1371.c deleted file mode 100644 index 52648573f601..000000000000 --- a/sound/oss/es1371.c +++ /dev/null @@ -1,3131 +0,0 @@ -/*****************************************************************************/ - -/* - * es1371.c -- Creative Ensoniq ES1371. - * - * Copyright (C) 1998-2001, 2003 Thomas Sailer (t.sailer@alumni.ethz.ch) - * - * 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. - * - * Special thanks to Ensoniq - * - * Supported devices: - * /dev/dsp standard /dev/dsp device, (mostly) OSS compatible - * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible - * /dev/dsp1 additional DAC, like /dev/dsp, but outputs to mixer "SYNTH" setting - * /dev/midi simple MIDI UART interface, no ioctl - * - * NOTE: the card does not have any FM/Wavetable synthesizer, it is supposed - * to be done in software. That is what /dev/dac is for. By now (Q2 1998) - * there are several MIDI to PCM (WAV) packages, one of them is timidity. - * - * Revision history - * 04.06.1998 0.1 Initial release - * Mixer stuff should be overhauled; especially optional AC97 mixer bits - * should be detected. This results in strange behaviour of some mixer - * settings, like master volume and mic. - * 08.06.1998 0.2 First release using Alan Cox' soundcore instead of miscdevice - * 03.08.1998 0.3 Do not include modversions.h - * Now mixer behaviour can basically be selected between - * "OSS documented" and "OSS actual" behaviour - * 31.08.1998 0.4 Fix realplayer problems - dac.count issues - * 27.10.1998 0.5 Fix joystick support - * -- Oliver Neukum (c188@org.chemie.uni-muenchen.de) - * 10.12.1998 0.6 Fix drain_dac trying to wait on not yet initialized DMA - * 23.12.1998 0.7 Fix a few f_file & FMODE_ bugs - * Don't wake up app until there are fragsize bytes to read/write - * 06.01.1999 0.8 remove the silly SA_INTERRUPT flag. - * hopefully killed the egcs section type conflict - * 12.03.1999 0.9 cinfo.blocks should be reset after GETxPTR ioctl. - * reported by Johan Maes <joma@telindus.be> - * 22.03.1999 0.10 return EAGAIN instead of EBUSY when O_NONBLOCK - * read/write cannot be executed - * 07.04.1999 0.11 implemented the following ioctl's: SOUND_PCM_READ_RATE, - * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; - * Alpha fixes reported by Peter Jones <pjones@redhat.com> - * Another Alpha fix (wait_src_ready in init routine) - * reported by "Ivan N. Kokshaysky" <ink@jurassic.park.msu.ru> - * Note: joystick address handling might still be wrong on archs - * other than i386 - * 15.06.1999 0.12 Fix bad allocation bug. - * Thanks to Deti Fliegl <fliegl@in.tum.de> - * 28.06.1999 0.13 Add pci_set_master - * 03.08.1999 0.14 adapt to Linus' new __setup/__initcall - * added kernel command line option "es1371=joystickaddr" - * removed CONFIG_SOUND_ES1371_JOYPORT_BOOT kludge - * 10.08.1999 0.15 (Re)added S/PDIF module option for cards revision >= 4. - * Initial version by Dave Platt <dplatt@snulbug.mtview.ca.us>. - * module_init/__setup fixes - * 08.16.1999 0.16 Joe Cotellese <joec@ensoniq.com> - * Added detection for ES1371 revision ID so that we can - * detect the ES1373 and later parts. - * added AC97 #defines for readability - * added a /proc file system for dumping hardware state - * updated SRC and CODEC w/r functions to accommodate bugs - * in some versions of the ES137x chips. - * 31.08.1999 0.17 add spin_lock_init - * replaced current->state = x with set_current_state(x) - * 03.09.1999 0.18 change read semantics for MIDI to match - * OSS more closely; remove possible wakeup race - * 21.10.1999 0.19 Round sampling rates, requested by - * Kasamatsu Kenichi <t29w0267@ip.media.kyoto-u.ac.jp> - * 27.10.1999 0.20 Added SigmaTel 3D enhancement string - * Codec ID printing changes - * 28.10.1999 0.21 More waitqueue races fixed - * Joe Cotellese <joec@ensoniq.com> - * Changed PCI detection routine so we can more easily - * detect ES137x chip and derivatives. - * 05.01.2000 0.22 Should now work with rev7 boards; patch by - * Eric Lemar, elemar@cs.washington.edu - * 08.01.2000 0.23 Prevent some ioctl's from returning bad count values on underrun/overrun; - * Tim Janik's BSE (Bedevilled Sound Engine) found this - * 07.02.2000 0.24 Use pci_alloc_consistent and pci_register_driver - * 07.02.2000 0.25 Use ac97_codec - * 01.03.2000 0.26 SPDIF patch by Mikael Bouillot <mikael.bouillot@bigfoot.com> - * Use pci_module_init - * 21.11.2000 0.27 Initialize dma buffers in poll, otherwise poll may return a bogus mask - * 12.12.2000 0.28 More dma buffer initializations, patch from - * Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com> - * 05.01.2001 0.29 Hopefully updates will not be required anymore when Creative bumps - * the CT5880 revision. - * suggested by Stephan Müller <smueller@chronox.de> - * 31.01.2001 0.30 Register/Unregister gameport - * Fix SETTRIGGER non OSS API conformity - * 14.07.2001 0.31 Add list of laptops needing amplifier control - * 03.01.2003 0.32 open_mode fixes from Georg Acher <acher@in.tum.de> - */ - -/*****************************************************************************/ - -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/string.h> -#include <linux/ioport.h> -#include <linux/sched.h> -#include <linux/delay.h> -#include <linux/sound.h> -#include <linux/slab.h> -#include <linux/soundcard.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/poll.h> -#include <linux/bitops.h> -#include <linux/proc_fs.h> -#include <linux/spinlock.h> -#include <linux/smp_lock.h> -#include <linux/ac97_codec.h> -#include <linux/gameport.h> -#include <linux/wait.h> -#include <linux/dma-mapping.h> -#include <linux/mutex.h> -#include <linux/mm.h> -#include <linux/kernel.h> - -#include <asm/io.h> -#include <asm/page.h> -#include <asm/uaccess.h> - -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) -#define SUPPORT_JOYSTICK -#endif - -/* --------------------------------------------------------------------- */ - -#undef OSS_DOCUMENTED_MIXER_SEMANTICS -#define ES1371_DEBUG -#define DBG(x) {} -/*#define DBG(x) {x}*/ - -/* --------------------------------------------------------------------- */ - -#ifndef PCI_VENDOR_ID_ENSONIQ -#define PCI_VENDOR_ID_ENSONIQ 0x1274 -#endif - -#ifndef PCI_VENDOR_ID_ECTIVA -#define PCI_VENDOR_ID_ECTIVA 0x1102 -#endif - -#ifndef PCI_DEVICE_ID_ENSONIQ_ES1371 -#define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371 -#endif - -#ifndef PCI_DEVICE_ID_ENSONIQ_CT5880 -#define PCI_DEVICE_ID_ENSONIQ_CT5880 0x5880 -#endif - -#ifndef PCI_DEVICE_ID_ECTIVA_EV1938 -#define PCI_DEVICE_ID_ECTIVA_EV1938 0x8938 -#endif - -/* ES1371 chip ID */ -/* This is a little confusing because all ES1371 compatible chips have the - same DEVICE_ID, the only thing differentiating them is the REV_ID field. - This is only significant if you want to enable features on the later parts. - Yes, I know it's stupid and why didn't we use the sub IDs? -*/ -#define ES1371REV_ES1373_A 0x04 -#define ES1371REV_ES1373_B 0x06 -#define ES1371REV_CT5880_A 0x07 -#define CT5880REV_CT5880_C 0x02 -#define CT5880REV_CT5880_D 0x03 -#define ES1371REV_ES1371_B 0x09 -#define EV1938REV_EV1938_A 0x00 -#define ES1371REV_ES1373_8 0x08 - -#define ES1371_MAGIC ((PCI_VENDOR_ID_ENSONIQ<<16)|PCI_DEVICE_ID_ENSONIQ_ES1371) - -#define ES1371_EXTENT 0x40 -#define JOY_EXTENT 8 - -#define ES1371_REG_CONTROL 0x00 -#define ES1371_REG_STATUS 0x04 /* on the 5880 it is control/status */ -#define ES1371_REG_UART_DATA 0x08 -#define ES1371_REG_UART_STATUS 0x09 -#define ES1371_REG_UART_CONTROL 0x09 -#define ES1371_REG_UART_TEST 0x0a -#define ES1371_REG_MEMPAGE 0x0c -#define ES1371_REG_SRCONV 0x10 -#define ES1371_REG_CODEC 0x14 -#define ES1371_REG_LEGACY 0x18 -#define ES1371_REG_SERIAL_CONTROL 0x20 -#define ES1371_REG_DAC1_SCOUNT 0x24 -#define ES1371_REG_DAC2_SCOUNT 0x28 -#define ES1371_REG_ADC_SCOUNT 0x2c - -#define ES1371_REG_DAC1_FRAMEADR 0xc30 -#define ES1371_REG_DAC1_FRAMECNT 0xc34 -#define ES1371_REG_DAC2_FRAMEADR 0xc38 -#define ES1371_REG_DAC2_FRAMECNT 0xc3c -#define ES1371_REG_ADC_FRAMEADR 0xd30 -#define ES1371_REG_ADC_FRAMECNT 0xd34 - -#define ES1371_FMT_U8_MONO 0 -#define ES1371_FMT_U8_STEREO 1 -#define ES1371_FMT_S16_MONO 2 -#define ES1371_FMT_S16_STEREO 3 -#define ES1371_FMT_STEREO 1 -#define ES1371_FMT_S16 2 -#define ES1371_FMT_MASK 3 - -static const unsigned sample_size[] = { 1, 2, 2, 4 }; -static const unsigned sample_shift[] = { 0, 1, 1, 2 }; - -#define CTRL_RECEN_B 0x08000000 /* 1 = don't mix analog in to digital out */ -#define CTRL_SPDIFEN_B 0x04000000 -#define CTRL_JOY_SHIFT 24 -#define CTRL_JOY_MASK 3 -#define CTRL_JOY_200 0x00000000 /* joystick base address */ -#define CTRL_JOY_208 0x01000000 -#define CTRL_JOY_210 0x02000000 -#define CTRL_JOY_218 0x03000000 -#define CTRL_GPIO_IN0 0x00100000 /* general purpose inputs/outputs */ -#define CTRL_GPIO_IN1 0x00200000 -#define CTRL_GPIO_IN2 0x00400000 -#define CTRL_GPIO_IN3 0x00800000 -#define CTRL_GPIO_OUT0 0x00010000 -#define CTRL_GPIO_OUT1 0x00020000 -#define CTRL_GPIO_OUT2 0x00040000 -#define CTRL_GPIO_OUT3 0x00080000 -#define CTRL_MSFMTSEL 0x00008000 /* MPEG serial data fmt: 0 = Sony, 1 = I2S */ -#define CTRL_SYNCRES 0x00004000 /* AC97 warm reset */ -#define CTRL_ADCSTOP 0x00002000 /* stop ADC transfers */ -#define CTRL_PWR_INTRM 0x00001000 /* 1 = power level ints enabled */ -#define CTRL_M_CB 0x00000800 /* recording source: 0 = ADC, 1 = MPEG */ -#define CTRL_CCB_INTRM 0x00000400 /* 1 = CCB "voice" ints enabled */ -#define CTRL_PDLEV0 0x00000000 /* power down level */ -#define CTRL_PDLEV1 0x00000100 -#define CTRL_PDLEV2 0x00000200 -#define CTRL_PDLEV3 0x00000300 -#define CTRL_BREQ 0x00000080 /* 1 = test mode (internal mem test) */ -#define CTRL_DAC1_EN 0x00000040 /* enable DAC1 */ -#define CTRL_DAC2_EN 0x00000020 /* enable DAC2 */ -#define CTRL_ADC_EN 0x00000010 /* enable ADC */ -#define CTRL_UART_EN 0x00000008 /* enable MIDI uart */ -#define CTRL_JYSTK_EN 0x00000004 /* enable Joystick port */ -#define CTRL_XTALCLKDIS 0x00000002 /* 1 = disable crystal clock input */ -#define CTRL_PCICLKDIS 0x00000001 /* 1 = disable PCI clock distribution */ - - -#define STAT_INTR 0x80000000 /* wired or of all interrupt bits */ -#define CSTAT_5880_AC97_RST 0x20000000 /* CT5880 Reset bit */ -#define STAT_EN_SPDIF 0x00040000 /* enable S/PDIF circuitry */ -#define STAT_TS_SPDIF 0x00020000 /* test S/PDIF circuitry */ -#define STAT_TESTMODE 0x00010000 /* test ASIC */ -#define STAT_SYNC_ERR 0x00000100 /* 1 = codec sync error */ -#define STAT_VC 0x000000c0 /* CCB int source, 0=DAC1, 1=DAC2, 2=ADC, 3=undef */ -#define STAT_SH_VC 6 -#define STAT_MPWR 0x00000020 /* power level interrupt */ -#define STAT_MCCB 0x00000010 /* CCB int pending */ -#define STAT_UART 0x00000008 /* UART int pending */ -#define STAT_DAC1 0x00000004 /* DAC1 int pending */ -#define STAT_DAC2 0x00000002 /* DAC2 int pending */ -#define STAT_ADC 0x00000001 /* ADC int pending */ - -#define USTAT_RXINT 0x80 /* UART rx int pending */ -#define USTAT_TXINT 0x04 /* UART tx int pending */ -#define USTAT_TXRDY 0x02 /* UART tx ready */ -#define USTAT_RXRDY 0x01 /* UART rx ready */ - -#define UCTRL_RXINTEN 0x80 /* 1 = enable RX ints */ -#define UCTRL_TXINTEN 0x60 /* TX int enable field mask */ -#define UCTRL_ENA_TXINT 0x20 /* enable TX int */ -#define UCTRL_CNTRL 0x03 /* control field */ -#define UCTRL_CNTRL_SWR 0x03 /* software reset command */ - -/* sample rate converter */ -#define SRC_OKSTATE 1 - -#define SRC_RAMADDR_MASK 0xfe000000 -#define SRC_RAMADDR_SHIFT 25 -#define SRC_DAC1FREEZE (1UL << 21) -#define SRC_DAC2FREEZE (1UL << 20) -#define SRC_ADCFREEZE (1UL << 19) - - -#define SRC_WE 0x01000000 /* read/write control for SRC RAM */ -#define SRC_BUSY 0x00800000 /* SRC busy */ -#define SRC_DIS 0x00400000 /* 1 = disable SRC */ -#define SRC_DDAC1 0x00200000 /* 1 = disable accum update for DAC1 */ -#define SRC_DDAC2 0x00100000 /* 1 = disable accum update for DAC2 */ -#define SRC_DADC 0x00080000 /* 1 = disable accum update for ADC2 */ -#define SRC_CTLMASK 0x00780000 -#define SRC_RAMDATA_MASK 0x0000ffff -#define SRC_RAMDATA_SHIFT 0 - -#define SRCREG_ADC 0x78 -#define SRCREG_DAC1 0x70 -#define SRCREG_DAC2 0x74 -#define SRCREG_VOL_ADC 0x6c -#define SRCREG_VOL_DAC1 0x7c -#define SRCREG_VOL_DAC2 0x7e - -#define SRCREG_TRUNC_N 0x00 -#define SRCREG_INT_REGS 0x01 -#define SRCREG_ACCUM_FRAC 0x02 -#define SRCREG_VFREQ_FRAC 0x03 - -#define CODEC_PIRD 0x00800000 /* 0 = write AC97 register */ -#define CODEC_PIADD_MASK 0x007f0000 -#define CODEC_PIADD_SHIFT 16 -#define CODEC_PIDAT_MASK 0x0000ffff -#define CODEC_PIDAT_SHIFT 0 - -#define CODEC_RDY 0x80000000 /* AC97 read data valid */ -#define CODEC_WIP 0x40000000 /* AC97 write in progress */ -#define CODEC_PORD 0x00800000 /* 0 = write AC97 register */ -#define CODEC_POADD_MASK 0x007f0000 -#define CODEC_POADD_SHIFT 16 -#define CODEC_PODAT_MASK 0x0000ffff -#define CODEC_PODAT_SHIFT 0 - - -#define LEGACY_JFAST 0x80000000 /* fast joystick timing */ -#define LEGACY_FIRQ 0x01000000 /* force IRQ */ - -#define SCTRL_DACTEST 0x00400000 /* 1 = DAC test, test vector generation purposes */ -#define SCTRL_P2ENDINC 0x00380000 /* */ -#define SCTRL_SH_P2ENDINC 19 -#define SCTRL_P2STINC 0x00070000 /* */ -#define SCTRL_SH_P2STINC 16 -#define SCTRL_R1LOOPSEL 0x00008000 /* 0 = loop mode */ -#define SCTRL_P2LOOPSEL 0x00004000 /* 0 = loop mode */ -#define SCTRL_P1LOOPSEL 0x00002000 /* 0 = loop mode */ -#define SCTRL_P2PAUSE 0x00001000 /* 1 = pause mode */ -#define SCTRL_P1PAUSE 0x00000800 /* 1 = pause mode */ -#define SCTRL_R1INTEN 0x00000400 /* enable interrupt */ -#define SCTRL_P2INTEN 0x00000200 /* enable interrupt */ -#define SCTRL_P1INTEN 0x00000100 /* enable interrupt */ -#define SCTRL_P1SCTRLD 0x00000080 /* reload sample count register for DAC1 */ -#define SCTRL_P2DACSEN 0x00000040 /* 1 = DAC2 play back last sample when disabled */ -#define SCTRL_R1SEB 0x00000020 /* 1 = 16bit */ -#define SCTRL_R1SMB 0x00000010 /* 1 = stereo */ -#define SCTRL_R1FMT 0x00000030 /* format mask */ -#define SCTRL_SH_R1FMT 4 -#define SCTRL_P2SEB 0x00000008 /* 1 = 16bit */ -#define SCTRL_P2SMB 0x00000004 /* 1 = stereo */ -#define SCTRL_P2FMT 0x0000000c /* format mask */ -#define SCTRL_SH_P2FMT 2 -#define SCTRL_P1SEB 0x00000002 /* 1 = 16bit */ -#define SCTRL_P1SMB 0x00000001 /* 1 = stereo */ -#define SCTRL_P1FMT 0x00000003 /* format mask */ -#define SCTRL_SH_P1FMT 0 - - -/* misc stuff */ -#define POLL_COUNT 0x1000 -#define FMODE_DAC 4 /* slight misuse of mode_t */ - -/* MIDI buffer sizes */ - -#define MIDIINBUF 256 -#define MIDIOUTBUF 256 - -#define FMODE_MIDI_SHIFT 3 -#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT) -#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT) - -#define ES1371_MODULE_NAME "es1371" -#define PFX ES1371_MODULE_NAME ": " - -/* --------------------------------------------------------------------- */ - -struct es1371_state { - /* magic */ - unsigned int magic; - - /* list of es1371 devices */ - struct list_head devs; - - /* the corresponding pci_dev structure */ - struct pci_dev *dev; - - /* soundcore stuff */ - int dev_audio; - int dev_dac; - int dev_midi; - - /* hardware resources */ - unsigned long io; /* long for SPARC */ - unsigned int irq; - - /* PCI ID's */ - u16 vendor; - u16 device; - u8 rev; /* the chip revision */ - - /* options */ - int spdif_volume; /* S/PDIF output is enabled if != -1 */ - -#ifdef ES1371_DEBUG - /* debug /proc entry */ - struct proc_dir_entry *ps; -#endif /* ES1371_DEBUG */ - - struct ac97_codec *codec; - - /* wave stuff */ - unsigned ctrl; - unsigned sctrl; - unsigned dac1rate, dac2rate, adcrate; - - spinlock_t lock; - struct mutex open_mutex; - mode_t open_mode; - wait_queue_head_t open_wait; - - struct dmabuf { - void *rawbuf; - dma_addr_t dmaaddr; - unsigned buforder; - unsigned numfrag; - unsigned fragshift; - unsigned hwptr, swptr; - unsigned total_bytes; - int count; - unsigned error; /* over/underrun */ - wait_queue_head_t wait; - /* redundant, but makes calculations easier */ - unsigned fragsize; - unsigned dmasize; - unsigned fragsamples; - /* OSS stuff */ - unsigned mapped:1; - unsigned ready:1; - unsigned endcleared:1; - unsigned enabled:1; - unsigned ossfragshift; - int ossmaxfrags; - unsigned subdivision; - } dma_dac1, dma_dac2, dma_adc; - - /* midi stuff */ - struct { - unsigned ird, iwr, icnt; - unsigned ord, owr, ocnt; - wait_queue_head_t iwait; - wait_queue_head_t owait; - unsigned char ibuf[MIDIINBUF]; - unsigned char obuf[MIDIOUTBUF]; - } midi; - -#ifdef SUPPORT_JOYSTICK - struct gameport *gameport; -#endif - - struct mutex sem; -}; - -/* --------------------------------------------------------------------- */ - -static LIST_HEAD(devs); - -/* --------------------------------------------------------------------- */ - -static inline unsigned ld2(unsigned int x) -{ - unsigned r = 0; - - if (x >= 0x10000) { - x >>= 16; - r += 16; - } - if (x >= 0x100) { - x >>= 8; - r += 8; - } - if (x >= 0x10) { - x >>= 4; - r += 4; - } - if (x >= 4) { - x >>= 2; - r += 2; - } - if (x >= 2) - r++; - return r; -} - -/* --------------------------------------------------------------------- */ - -static unsigned wait_src_ready(struct es1371_state *s) -{ - unsigned int t, r; - - for (t = 0; t < POLL_COUNT; t++) { - if (!((r = inl(s->io + ES1371_REG_SRCONV)) & SRC_BUSY)) - return r; - udelay(1); - } - printk(KERN_DEBUG PFX "sample rate converter timeout r = 0x%08x\n", r); - return r; -} - -static unsigned src_read(struct es1371_state *s, unsigned reg) -{ - unsigned int temp,i,orig; - - /* wait for ready */ - temp = wait_src_ready (s); - - /* we can only access the SRC at certain times, make sure - we're allowed to before we read */ - - orig = temp; - /* expose the SRC state bits */ - outl ( (temp & SRC_CTLMASK) | (reg << SRC_RAMADDR_SHIFT) | 0x10000UL, - s->io + ES1371_REG_SRCONV); - - /* now, wait for busy and the correct time to read */ - temp = wait_src_ready (s); - - if ( (temp & 0x00870000UL ) != ( SRC_OKSTATE << 16 )){ - /* wait for the right state */ - for (i=0; i<POLL_COUNT; i++){ - temp = inl (s->io + ES1371_REG_SRCONV); - if ( (temp & 0x00870000UL ) == ( SRC_OKSTATE << 16 )) - break; - } - } - - /* hide the state bits */ - outl ((orig & SRC_CTLMASK) | (reg << SRC_RAMADDR_SHIFT), s->io + ES1371_REG_SRCONV); - return temp; - - -} - -static void src_write(struct es1371_state *s, unsigned reg, unsigned data) -{ - - unsigned int r; - - r = wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC); - r |= (reg << SRC_RAMADDR_SHIFT) & SRC_RAMADDR_MASK; - r |= (data << SRC_RAMDATA_SHIFT) & SRC_RAMDATA_MASK; - outl(r | SRC_WE, s->io + ES1371_REG_SRCONV); - -} - -/* --------------------------------------------------------------------- */ - -/* most of the following here is black magic */ -static void set_adc_rate(struct es1371_state *s, unsigned rate) -{ - unsigned long flags; - unsigned int n, truncm, freq; - - if (rate > 48000) - rate = 48000; - if (rate < 4000) - rate = 4000; - n = rate / 3000; - if ((1 << n) & ((1 << 15) | (1 << 13) | (1 << 11) | (1 << 9))) - n--; - truncm = (21 * n - 1) | 1; - freq = ((48000UL << 15) / rate) * n; - s->adcrate = (48000UL << 15) / (freq / n); - spin_lock_irqsave(&s->lock, flags); - if (rate >= 24000) { - if (truncm > 239) - truncm = 239; - src_write(s, SRCREG_ADC+SRCREG_TRUNC_N, - (((239 - truncm) >> 1) << 9) | (n << 4)); - } else { - if (truncm > 119) - truncm = 119; - src_write(s, SRCREG_ADC+SRCREG_TRUNC_N, - 0x8000 | (((119 - truncm) >> 1) << 9) | (n << 4)); - } - src_write(s, SRCREG_ADC+SRCREG_INT_REGS, - (src_read(s, SRCREG_ADC+SRCREG_INT_REGS) & 0x00ff) | - ((freq >> 5) & 0xfc00)); - src_write(s, SRCREG_ADC+SRCREG_VFREQ_FRAC, freq & 0x7fff); - src_write(s, SRCREG_VOL_ADC, n << 8); - src_write(s, SRCREG_VOL_ADC+1, n << 8); - spin_unlock_irqrestore(&s->lock, flags); -} - - -static void set_dac1_rate(struct es1371_state *s, unsigned rate) -{ - unsigned long flags; - unsigned int freq, r; - - if (rate > 48000) - rate = 48000; - if (rate < 4000) - rate = 4000; - freq = ((rate << 15) + 1500) / 3000; - s->dac1rate = (freq * 3000 + 16384) >> 15; - spin_lock_irqsave(&s->lock, flags); - r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC2 | SRC_DADC)) | SRC_DDAC1; - outl(r, s->io + ES1371_REG_SRCONV); - src_write(s, SRCREG_DAC1+SRCREG_INT_REGS, - (src_read(s, SRCREG_DAC1+SRCREG_INT_REGS) & 0x00ff) | - ((freq >> 5) & 0xfc00)); - src_write(s, SRCREG_DAC1+SRCREG_VFREQ_FRAC, freq & 0x7fff); - r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC2 | SRC_DADC)); - outl(r, s->io + ES1371_REG_SRCONV); - spin_unlock_irqrestore(&s->lock, flags); -} - -static void set_dac2_rate(struct es1371_state *s, unsigned rate) -{ - unsigned long flags; - unsigned int freq, r; - - if (rate > 48000) - rate = 48000; - if (rate < 4000) - rate = 4000; - freq = ((rate << 15) + 1500) / 3000; - s->dac2rate = (freq * 3000 + 16384) >> 15; - spin_lock_irqsave(&s->lock, flags); - r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DADC)) | SRC_DDAC2; - outl(r, s->io + ES1371_REG_SRCONV); - src_write(s, SRCREG_DAC2+SRCREG_INT_REGS, - (src_read(s, SRCREG_DAC2+SRCREG_INT_REGS) & 0x00ff) | - ((freq >> 5) & 0xfc00)); - src_write(s, SRCREG_DAC2+SRCREG_VFREQ_FRAC, freq & 0x7fff); - r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DADC)); - outl(r, s->io + ES1371_REG_SRCONV); - spin_unlock_irqrestore(&s->lock, flags); -} - -/* --------------------------------------------------------------------- */ - -static void __devinit src_init(struct es1371_state *s) -{ - unsigned int i; - - /* before we enable or disable the SRC we need - to wait for it to become ready */ - wait_src_ready(s); - - outl(SRC_DIS, s->io + ES1371_REG_SRCONV); - - for (i = 0; i < 0x80; i++) - src_write(s, i, 0); - - src_write(s, SRCREG_DAC1+SRCREG_TRUNC_N, 16 << 4); - src_write(s, SRCREG_DAC1+SRCREG_INT_REGS, 16 << 10); - src_write(s, SRCREG_DAC2+SRCREG_TRUNC_N, 16 << 4); - src_write(s, SRCREG_DAC2+SRCREG_INT_REGS, 16 << 10); - src_write(s, SRCREG_VOL_ADC, 1 << 12); - src_write(s, SRCREG_VOL_ADC+1, 1 << 12); - src_write(s, SRCREG_VOL_DAC1, 1 << 12); - src_write(s, SRCREG_VOL_DAC1+1, 1 << 12); - src_write(s, SRCREG_VOL_DAC2, 1 << 12); - src_write(s, SRCREG_VOL_DAC2+1, 1 << 12); - set_adc_rate(s, 22050); - set_dac1_rate(s, 22050); - set_dac2_rate(s, 22050); - - /* WARNING: - * enabling the sample rate converter without properly programming - * its parameters causes the chip to lock up (the SRC busy bit will - * be stuck high, and I've found no way to rectify this other than - * power cycle) - */ - wait_src_ready(s); - outl(0, s->io+ES1371_REG_SRCONV); -} - -/* --------------------------------------------------------------------- */ - -static void wrcodec(struct ac97_codec *codec, u8 addr, u16 data) -{ - struct es1371_state *s = (struct es1371_state *)codec->private_data; - unsigned long flags; - unsigned t, x; - - spin_lock_irqsave(&s->lock, flags); - for (t = 0; t < POLL_COUNT; t++) - if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP)) - break; - - /* save the current state for later */ - x = wait_src_ready(s); - - /* enable SRC state data in SRC mux */ - outl((x & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000, - s->io+ES1371_REG_SRCONV); - - /* wait for not busy (state 0) first to avoid - transition states */ - for (t=0; t<POLL_COUNT; t++){ - if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0 ) - break; - udelay(1); - } - - /* wait for a SAFE time to write addr/data and then do it, dammit */ - for (t=0; t<POLL_COUNT; t++){ - if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0x00010000) - break; - udelay(1); - } - - outl(((addr << CODEC_POADD_SHIFT) & CODEC_POADD_MASK) | - ((data << CODEC_PODAT_SHIFT) & CODEC_PODAT_MASK), s->io+ES1371_REG_CODEC); - - /* restore SRC reg */ - wait_src_ready(s); - outl(x, s->io+ES1371_REG_SRCONV); - spin_unlock_irqrestore(&s->lock, flags); -} - -static u16 rdcodec(struct ac97_codec *codec, u8 addr) -{ - struct es1371_state *s = (struct es1371_state *)codec->private_data; - unsigned long flags; - unsigned t, x; - - spin_lock_irqsave(&s->lock, flags); - - /* wait for WIP to go away */ - for (t = 0; t < 0x1000; t++) - if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP)) - break; - - /* save the current state for later */ - x = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)); - - /* enable SRC state data in SRC mux */ - outl( x | 0x00010000, - s->io+ES1371_REG_SRCONV); - - /* wait for not busy (state 0) first to avoid - transition states */ - for (t=0; t<POLL_COUNT; t++){ - if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0 ) - break; - udelay(1); - } - - /* wait for a SAFE time to write addr/data and then do it, dammit */ - for (t=0; t<POLL_COUNT; t++){ - if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0x00010000) - break; - udelay(1); - } - - outl(((addr << CODEC_POADD_SHIFT) & CODEC_POADD_MASK) | CODEC_PORD, s->io+ES1371_REG_CODEC); - /* restore SRC reg */ - wait_src_ready(s); - outl(x, s->io+ES1371_REG_SRCONV); - - /* wait for WIP again */ - for (t = 0; t < 0x1000; t++) - if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP)) - break; - - /* now wait for the stinkin' data (RDY) */ - for (t = 0; t < POLL_COUNT; t++) - if ((x = inl(s->io+ES1371_REG_CODEC)) & CODEC_RDY) - break; - - spin_unlock_irqrestore(&s->lock, flags); - return ((x & CODEC_PIDAT_MASK) >> CODEC_PIDAT_SHIFT); -} - -/* --------------------------------------------------------------------- */ - -static inline void stop_adc(struct es1371_state *s) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - s->ctrl &= ~CTRL_ADC_EN; - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); -} - -static inline void stop_dac1(struct es1371_state *s) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - s->ctrl &= ~CTRL_DAC1_EN; - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); -} - -static inline void stop_dac2(struct es1371_state *s) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - s->ctrl &= ~CTRL_DAC2_EN; - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); -} - -static void start_dac1(struct es1371_state *s) -{ - unsigned long flags; - unsigned fragremain, fshift; - - spin_lock_irqsave(&s->lock, flags); - if (!(s->ctrl & CTRL_DAC1_EN) && (s->dma_dac1.mapped || s->dma_dac1.count > 0) - && s->dma_dac1.ready) { - s->ctrl |= CTRL_DAC1_EN; - s->sctrl = (s->sctrl & ~(SCTRL_P1LOOPSEL | SCTRL_P1PAUSE | SCTRL_P1SCTRLD)) | SCTRL_P1INTEN; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - fragremain = ((- s->dma_dac1.hwptr) & (s->dma_dac1.fragsize-1)); - fshift = sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT]; - if (fragremain < 2*fshift) - fragremain = s->dma_dac1.fragsize; - outl((fragremain >> fshift) - 1, s->io+ES1371_REG_DAC1_SCOUNT); - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - outl((s->dma_dac1.fragsize >> fshift) - 1, s->io+ES1371_REG_DAC1_SCOUNT); - } - spin_unlock_irqrestore(&s->lock, flags); -} - -static void start_dac2(struct es1371_state *s) -{ - unsigned long flags; - unsigned fragremain, fshift; - - spin_lock_irqsave(&s->lock, flags); - if (!(s->ctrl & CTRL_DAC2_EN) && (s->dma_dac2.mapped || s->dma_dac2.count > 0) - && s->dma_dac2.ready) { - s->ctrl |= CTRL_DAC2_EN; - s->sctrl = (s->sctrl & ~(SCTRL_P2LOOPSEL | SCTRL_P2PAUSE | SCTRL_P2DACSEN | - SCTRL_P2ENDINC | SCTRL_P2STINC)) | SCTRL_P2INTEN | - (((s->sctrl & SCTRL_P2FMT) ? 2 : 1) << SCTRL_SH_P2ENDINC) | - (0 << SCTRL_SH_P2STINC); - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - fragremain = ((- s->dma_dac2.hwptr) & (s->dma_dac2.fragsize-1)); - fshift = sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT]; - if (fragremain < 2*fshift) - fragremain = s->dma_dac2.fragsize; - outl((fragremain >> fshift) - 1, s->io+ES1371_REG_DAC2_SCOUNT); - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - outl((s->dma_dac2.fragsize >> fshift) - 1, s->io+ES1371_REG_DAC2_SCOUNT); - } - spin_unlock_irqrestore(&s->lock, flags); -} - -static void start_adc(struct es1371_state *s) -{ - unsigned long flags; - unsigned fragremain, fshift; - - spin_lock_irqsave(&s->lock, flags); - if (!(s->ctrl & CTRL_ADC_EN) && (s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) - && s->dma_adc.ready) { - s->ctrl |= CTRL_ADC_EN; - s->sctrl = (s->sctrl & ~SCTRL_R1LOOPSEL) | SCTRL_R1INTEN; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - fragremain = ((- s->dma_adc.hwptr) & (s->dma_adc.fragsize-1)); - fshift = sample_shift[(s->sctrl & SCTRL_R1FMT) >> SCTRL_SH_R1FMT]; - if (fragremain < 2*fshift) - fragremain = s->dma_adc.fragsize; - outl((fragremain >> fshift) - 1, s->io+ES1371_REG_ADC_SCOUNT); - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - outl((s->dma_adc.fragsize >> fshift) - 1, s->io+ES1371_REG_ADC_SCOUNT); - } - spin_unlock_irqrestore(&s->lock, flags); -} - -/* --------------------------------------------------------------------- */ - -#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT) -#define DMABUF_MINORDER 1 - - -static inline void dealloc_dmabuf(struct es1371_state *s, struct dmabuf *db) -{ - struct page *page, *pend; - - if (db->rawbuf) { - /* undo marking the pages as reserved */ - pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); - for (page = virt_to_page(db->rawbuf); page <= pend; page++) - ClearPageReserved(page); - pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr); - } - db->rawbuf = NULL; - db->mapped = db->ready = 0; -} - -static int prog_dmabuf(struct es1371_state *s, struct dmabuf *db, unsigned rate, unsigned fmt, unsigned reg) -{ - int order; - unsigned bytepersec; - unsigned bufs; - struct page *page, *pend; - - db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; - if (!db->rawbuf) { - db->ready = db->mapped = 0; - for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) - if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr))) - break; - if (!db->rawbuf) - return -ENOMEM; - db->buforder = order; - /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */ - pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); - for (page = virt_to_page(db->rawbuf); page <= pend; page++) - SetPageReserved(page); - } - fmt &= ES1371_FMT_MASK; - bytepersec = rate << sample_shift[fmt]; - bufs = PAGE_SIZE << db->buforder; - if (db->ossfragshift) { - if ((1000 << db->ossfragshift) < bytepersec) - db->fragshift = ld2(bytepersec/1000); - else - db->fragshift = db->ossfragshift; - } else { - db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1)); - if (db->fragshift < 3) - db->fragshift = 3; - } - db->numfrag = bufs >> db->fragshift; - while (db->numfrag < 4 && db->fragshift > 3) { - db->fragshift--; - db->numfrag = bufs >> db->fragshift; - } - db->fragsize = 1 << db->fragshift; - if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) - db->numfrag = db->ossmaxfrags; - db->fragsamples = db->fragsize >> sample_shift[fmt]; - db->dmasize = db->numfrag << db->fragshift; - memset(db->rawbuf, (fmt & ES1371_FMT_S16) ? 0 : 0x80, db->dmasize); - outl((reg >> 8) & 15, s->io+ES1371_REG_MEMPAGE); - outl(db->dmaaddr, s->io+(reg & 0xff)); - outl((db->dmasize >> 2)-1, s->io+((reg + 4) & 0xff)); - db->enabled = 1; - db->ready = 1; - return 0; -} - -static inline int prog_dmabuf_adc(struct es1371_state *s) -{ - stop_adc(s); - return prog_dmabuf(s, &s->dma_adc, s->adcrate, (s->sctrl >> SCTRL_SH_R1FMT) & ES1371_FMT_MASK, - ES1371_REG_ADC_FRAMEADR); -} - -static inline int prog_dmabuf_dac2(struct es1371_state *s) -{ - stop_dac2(s); - return prog_dmabuf(s, &s->dma_dac2, s->dac2rate, (s->sctrl >> SCTRL_SH_P2FMT) & ES1371_FMT_MASK, - ES1371_REG_DAC2_FRAMEADR); -} - -static inline int prog_dmabuf_dac1(struct es1371_state *s) -{ - stop_dac1(s); - return prog_dmabuf(s, &s->dma_dac1, s->dac1rate, (s->sctrl >> SCTRL_SH_P1FMT) & ES1371_FMT_MASK, - ES1371_REG_DAC1_FRAMEADR); -} - -static inline unsigned get_hwptr(struct es1371_state *s, struct dmabuf *db, unsigned reg) -{ - unsigned hwptr, diff; - - outl((reg >> 8) & 15, s->io+ES1371_REG_MEMPAGE); - hwptr = (inl(s->io+(reg & 0xff)) >> 14) & 0x3fffc; - diff = (db->dmasize + hwptr - db->hwptr) % db->dmasize; - db->hwptr = hwptr; - return diff; -} - -static inline void clear_advance(void *buf, unsigned bsize, unsigned bptr, unsigned len, unsigned char c) -{ - if (bptr + len > bsize) { - unsigned x = bsize - bptr; - memset(((char *)buf) + bptr, c, x); - bptr = 0; - len -= x; - } - memset(((char *)buf) + bptr, c, len); -} - -/* call with spinlock held! */ -static void es1371_update_ptr(struct es1371_state *s) -{ - int diff; - - /* update ADC pointer */ - if (s->ctrl & CTRL_ADC_EN) { - diff = get_hwptr(s, &s->dma_adc, ES1371_REG_ADC_FRAMECNT); - s->dma_adc.total_bytes += diff; - s->dma_adc.count += diff; - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) - wake_up(&s->dma_adc.wait); - if (!s->dma_adc.mapped) { - if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) { - s->ctrl &= ~CTRL_ADC_EN; - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - s->dma_adc.error++; - } - } - } - /* update DAC1 pointer */ - if (s->ctrl & CTRL_DAC1_EN) { - diff = get_hwptr(s, &s->dma_dac1, ES1371_REG_DAC1_FRAMECNT); - s->dma_dac1.total_bytes += diff; - if (s->dma_dac1.mapped) { - s->dma_dac1.count += diff; - if (s->dma_dac1.count >= (signed)s->dma_dac1.fragsize) - wake_up(&s->dma_dac1.wait); - } else { - s->dma_dac1.count -= diff; - if (s->dma_dac1.count <= 0) { - s->ctrl &= ~CTRL_DAC1_EN; - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - s->dma_dac1.error++; - } else if (s->dma_dac1.count <= (signed)s->dma_dac1.fragsize && !s->dma_dac1.endcleared) { - clear_advance(s->dma_dac1.rawbuf, s->dma_dac1.dmasize, s->dma_dac1.swptr, - s->dma_dac1.fragsize, (s->sctrl & SCTRL_P1SEB) ? 0 : 0x80); - s->dma_dac1.endcleared = 1; - } - if (s->dma_dac1.count + (signed)s->dma_dac1.fragsize <= (signed)s->dma_dac1.dmasize) - wake_up(&s->dma_dac1.wait); - } - } - /* update DAC2 pointer */ - if (s->ctrl & CTRL_DAC2_EN) { - diff = get_hwptr(s, &s->dma_dac2, ES1371_REG_DAC2_FRAMECNT); - s->dma_dac2.total_bytes += diff; - if (s->dma_dac2.mapped) { - s->dma_dac2.count += diff; - if (s->dma_dac2.count >= (signed)s->dma_dac2.fragsize) - wake_up(&s->dma_dac2.wait); - } else { - s->dma_dac2.count -= diff; - if (s->dma_dac2.count <= 0) { - s->ctrl &= ~CTRL_DAC2_EN; - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - s->dma_dac2.error++; - } else if (s->dma_dac2.count <= (signed)s->dma_dac2.fragsize && !s->dma_dac2.endcleared) { - clear_advance(s->dma_dac2.rawbuf, s->dma_dac2.dmasize, s->dma_dac2.swptr, - s->dma_dac2.fragsize, (s->sctrl & SCTRL_P2SEB) ? 0 : 0x80); - s->dma_dac2.endcleared = 1; - } - if (s->dma_dac2.count + (signed)s->dma_dac2.fragsize <= (signed)s->dma_dac2.dmasize) - wake_up(&s->dma_dac2.wait); - } - } -} - -/* hold spinlock for the following! */ -static void es1371_handle_midi(struct es1371_state *s) -{ - unsigned char ch; - int wake; - - if (!(s->ctrl & CTRL_UART_EN)) - return; - wake = 0; - while (inb(s->io+ES1371_REG_UART_STATUS) & USTAT_RXRDY) { - ch = inb(s->io+ES1371_REG_UART_DATA); - if (s->midi.icnt < MIDIINBUF) { - s->midi.ibuf[s->midi.iwr] = ch; - s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF; - s->midi.icnt++; - } - wake = 1; - } - if (wake) - wake_up(&s->midi.iwait); - wake = 0; - while ((inb(s->io+ES1371_REG_UART_STATUS) & USTAT_TXRDY) && s->midi.ocnt > 0) { - outb(s->midi.obuf[s->midi.ord], s->io+ES1371_REG_UART_DATA); - s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF; - s->midi.ocnt--; - if (s->midi.ocnt < MIDIOUTBUF-16) - wake = 1; - } - if (wake) - wake_up(&s->midi.owait); - outb((s->midi.ocnt > 0) ? UCTRL_RXINTEN | UCTRL_ENA_TXINT : UCTRL_RXINTEN, s->io+ES1371_REG_UART_CONTROL); -} - -static irqreturn_t es1371_interrupt(int irq, void *dev_id) -{ - struct es1371_state *s = dev_id; - unsigned int intsrc, sctl; - - /* fastpath out, to ease interrupt sharing */ - intsrc = inl(s->io+ES1371_REG_STATUS); - if (!(intsrc & 0x80000000)) - return IRQ_NONE; - spin_lock(&s->lock); - /* clear audio interrupts first */ - sctl = s->sctrl; - if (intsrc & STAT_ADC) - sctl &= ~SCTRL_R1INTEN; - if (intsrc & STAT_DAC1) - sctl &= ~SCTRL_P1INTEN; - if (intsrc & STAT_DAC2) - sctl &= ~SCTRL_P2INTEN; - outl(sctl, s->io+ES1371_REG_SERIAL_CONTROL); - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - es1371_update_ptr(s); - es1371_handle_midi(s); - spin_unlock(&s->lock); - return IRQ_HANDLED; -} - -/* --------------------------------------------------------------------- */ - -static const char invalid_magic[] = KERN_CRIT PFX "invalid magic value\n"; - -#define VALIDATE_STATE(s) \ -({ \ - if (!(s) || (s)->magic != ES1371_MAGIC) { \ - printk(invalid_magic); \ - return -ENXIO; \ - } \ -}) - -/* --------------------------------------------------------------------- */ - -/* Conversion table for S/PDIF PCM volume emulation through the SRC */ -/* dB-linear table of DAC vol values; -0dB to -46.5dB with mute */ -static const unsigned short DACVolTable[101] = -{ - 0x1000, 0x0f2a, 0x0e60, 0x0da0, 0x0cea, 0x0c3e, 0x0b9a, 0x0aff, - 0x0a6d, 0x09e1, 0x095e, 0x08e1, 0x086a, 0x07fa, 0x078f, 0x072a, - 0x06cb, 0x0670, 0x061a, 0x05c9, 0x057b, 0x0532, 0x04ed, 0x04ab, - 0x046d, 0x0432, 0x03fa, 0x03c5, 0x0392, 0x0363, 0x0335, 0x030b, - 0x02e2, 0x02bc, 0x0297, 0x0275, 0x0254, 0x0235, 0x0217, 0x01fb, - 0x01e1, 0x01c8, 0x01b0, 0x0199, 0x0184, 0x0170, 0x015d, 0x014b, - 0x0139, 0x0129, 0x0119, 0x010b, 0x00fd, 0x00f0, 0x00e3, 0x00d7, - 0x00cc, 0x00c1, 0x00b7, 0x00ae, 0x00a5, 0x009c, 0x0094, 0x008c, - 0x0085, 0x007e, 0x0077, 0x0071, 0x006b, 0x0066, 0x0060, 0x005b, - 0x0057, 0x0052, 0x004e, 0x004a, 0x0046, 0x0042, 0x003f, 0x003c, - 0x0038, 0x0036, 0x0033, 0x0030, 0x002e, 0x002b, 0x0029, 0x0027, - 0x0025, 0x0023, 0x0021, 0x001f, 0x001e, 0x001c, 0x001b, 0x0019, - 0x0018, 0x0017, 0x0016, 0x0014, 0x0000 -}; - -/* - * when we are in S/PDIF mode, we want to disable any analog output so - * we filter the mixer ioctls - */ -static int mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg) -{ - struct es1371_state *s = (struct es1371_state *)codec->private_data; - int val; - unsigned long flags; - unsigned int left, right; - - VALIDATE_STATE(s); - /* filter mixer ioctls to catch PCM and MASTER volume when in S/PDIF mode */ - if (s->spdif_volume == -1) - return codec->mixer_ioctl(codec, cmd, arg); - switch (cmd) { - case SOUND_MIXER_WRITE_VOLUME: - return 0; - - case SOUND_MIXER_WRITE_PCM: /* use SRC for PCM volume */ - if (get_user(val, (int __user *)arg)) - return -EFAULT; - right = ((val >> 8) & 0xff); - left = (val & 0xff); - if (right > 100) - right = 100; - if (left > 100) - left = 100; - s->spdif_volume = (right << 8) | left; - spin_lock_irqsave(&s->lock, flags); - src_write(s, SRCREG_VOL_DAC2, DACVolTable[100 - left]); - src_write(s, SRCREG_VOL_DAC2+1, DACVolTable[100 - right]); - spin_unlock_irqrestore(&s->lock, flags); - return 0; - - case SOUND_MIXER_READ_PCM: - return put_user(s->spdif_volume, (int __user *)arg); - } - return codec->mixer_ioctl(codec, cmd, arg); -} - -/* --------------------------------------------------------------------- */ - -/* - * AC97 Mixer Register to Connections mapping of the Concert 97 board - * - * AC97_MASTER_VOL_STEREO Line Out - * AC97_MASTER_VOL_MONO TAD Output - * AC97_PCBEEP_VOL none - * AC97_PHONE_VOL TAD Input (mono) - * AC97_MIC_VOL MIC Input (mono) - * AC97_LINEIN_VOL Line Input (stereo) - * AC97_CD_VOL CD Input (stereo) - * AC97_VIDEO_VOL none - * AC97_AUX_VOL Aux Input (stereo) - * AC97_PCMOUT_VOL Wave Output (stereo) - */ - -static int es1371_open_mixdev(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct list_head *list; - struct es1371_state *s; - - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct es1371_state, devs); - if (s->codec->dev_mixer == minor) - break; - } - VALIDATE_STATE(s); - file->private_data = s; - return nonseekable_open(inode, file); -} - -static int es1371_release_mixdev(struct inode *inode, struct file *file) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - - VALIDATE_STATE(s); - return 0; -} - -static int es1371_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - struct ac97_codec *codec = s->codec; - - return mixdev_ioctl(codec, cmd, arg); -} - -static /*const*/ struct file_operations es1371_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = es1371_ioctl_mixdev, - .open = es1371_open_mixdev, - .release = es1371_release_mixdev, -}; - -/* --------------------------------------------------------------------- */ - -static int drain_dac1(struct es1371_state *s, int nonblock) -{ - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - int count, tmo; - - if (s->dma_dac1.mapped || !s->dma_dac1.ready) - return 0; - add_wait_queue(&s->dma_dac1.wait, &wait); - for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac1.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= 0) - break; - if (signal_pending(current)) - break; - if (nonblock) { - remove_wait_queue(&s->dma_dac1.wait, &wait); - set_current_state(TASK_RUNNING); - return -EBUSY; - } - tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2 / s->dac1rate; - tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT]; - if (!schedule_timeout(tmo + 1)) - DBG(printk(KERN_DEBUG PFX "dac1 dma timed out??\n");) - } - remove_wait_queue(&s->dma_dac1.wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -static int drain_dac2(struct es1371_state *s, int nonblock) -{ - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - int count, tmo; - - if (s->dma_dac2.mapped || !s->dma_dac2.ready) - return 0; - add_wait_queue(&s->dma_dac2.wait, &wait); - for (;;) { - __set_current_state(TASK_UNINTERRUPTIBLE); - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac2.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= 0) - break; - if (signal_pending(current)) - break; - if (nonblock) { - remove_wait_queue(&s->dma_dac2.wait, &wait); - set_current_state(TASK_RUNNING); - return -EBUSY; - } - tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2 / s->dac2rate; - tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT]; - if (!schedule_timeout(tmo + 1)) - DBG(printk(KERN_DEBUG PFX "dac2 dma timed out??\n");) - } - remove_wait_queue(&s->dma_dac2.wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -/* --------------------------------------------------------------------- */ - -static ssize_t es1371_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret = 0; - unsigned long flags; - unsigned swptr; - int cnt; - - VALIDATE_STATE(s); - if (s->dma_adc.mapped) - return -ENXIO; - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - mutex_lock(&s->sem); - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - goto out2; - - add_wait_queue(&s->dma_adc.wait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - swptr = s->dma_adc.swptr; - cnt = s->dma_adc.dmasize-swptr; - if (s->dma_adc.count < cnt) - cnt = s->dma_adc.count; - if (cnt <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (s->dma_adc.enabled) - start_adc(s); - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - goto out; - } - mutex_unlock(&s->sem); - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - goto out2; - } - mutex_lock(&s->sem); - if (s->dma_adc.mapped) - { - ret = -ENXIO; - goto out; - } - continue; - } - if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) { - if (!ret) - ret = -EFAULT; - goto out; - } - swptr = (swptr + cnt) % s->dma_adc.dmasize; - spin_lock_irqsave(&s->lock, flags); - s->dma_adc.swptr = swptr; - s->dma_adc.count -= cnt; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - if (s->dma_adc.enabled) - start_adc(s); - } -out: - mutex_unlock(&s->sem); -out2: - remove_wait_queue(&s->dma_adc.wait, &wait); - set_current_state(TASK_RUNNING); - return ret; -} - -static ssize_t es1371_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - unsigned long flags; - unsigned swptr; - int cnt; - - VALIDATE_STATE(s); - if (s->dma_dac2.mapped) - return -ENXIO; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - mutex_lock(&s->sem); - if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) - goto out3; - ret = 0; - add_wait_queue(&s->dma_dac2.wait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - if (s->dma_dac2.count < 0) { - s->dma_dac2.count = 0; - s->dma_dac2.swptr = s->dma_dac2.hwptr; - } - swptr = s->dma_dac2.swptr; - cnt = s->dma_dac2.dmasize-swptr; - if (s->dma_dac2.count + cnt > s->dma_dac2.dmasize) - cnt = s->dma_dac2.dmasize - s->dma_dac2.count; - if (cnt <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (s->dma_dac2.enabled) - start_dac2(s); - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - goto out; - } - mutex_unlock(&s->sem); - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - goto out2; - } - mutex_lock(&s->sem); - if (s->dma_dac2.mapped) - { - ret = -ENXIO; - goto out; - } - continue; - } - if (copy_from_user(s->dma_dac2.rawbuf + swptr, buffer, cnt)) { - if (!ret) - ret = -EFAULT; - goto out; - } - swptr = (swptr + cnt) % s->dma_dac2.dmasize; - spin_lock_irqsave(&s->lock, flags); - s->dma_dac2.swptr = swptr; - s->dma_dac2.count += cnt; - s->dma_dac2.endcleared = 0; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - if (s->dma_dac2.enabled) - start_dac2(s); - } -out: - mutex_unlock(&s->sem); -out2: - remove_wait_queue(&s->dma_dac2.wait, &wait); -out3: - set_current_state(TASK_RUNNING); - return ret; -} - -/* No kernel lock - we have our own spinlock */ -static unsigned int es1371_poll(struct file *file, struct poll_table_struct *wait) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - unsigned long flags; - unsigned int mask = 0; - - VALIDATE_STATE(s); - if (file->f_mode & FMODE_WRITE) { - if (!s->dma_dac2.ready && prog_dmabuf_dac2(s)) - return 0; - poll_wait(file, &s->dma_dac2.wait, wait); - } - if (file->f_mode & FMODE_READ) { - if (!s->dma_adc.ready && prog_dmabuf_adc(s)) - return 0; - poll_wait(file, &s->dma_adc.wait, wait); - } - spin_lock_irqsave(&s->lock, flags); - es1371_update_ptr(s); - if (file->f_mode & FMODE_READ) { - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) - mask |= POLLIN | POLLRDNORM; - } - if (file->f_mode & FMODE_WRITE) { - if (s->dma_dac2.mapped) { - if (s->dma_dac2.count >= (signed)s->dma_dac2.fragsize) - mask |= POLLOUT | POLLWRNORM; - } else { - if ((signed)s->dma_dac2.dmasize >= s->dma_dac2.count + (signed)s->dma_dac2.fragsize) - mask |= POLLOUT | POLLWRNORM; - } - } - spin_unlock_irqrestore(&s->lock, flags); - return mask; -} - -static int es1371_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - struct dmabuf *db; - int ret = 0; - unsigned long size; - - VALIDATE_STATE(s); - lock_kernel(); - mutex_lock(&s->sem); - - if (vma->vm_flags & VM_WRITE) { - if ((ret = prog_dmabuf_dac2(s)) != 0) { - goto out; - } - db = &s->dma_dac2; - } else if (vma->vm_flags & VM_READ) { - if ((ret = prog_dmabuf_adc(s)) != 0) { - goto out; - } - db = &s->dma_adc; - } else { - ret = -EINVAL; - goto out; - } - if (vma->vm_pgoff != 0) { - ret = -EINVAL; - goto out; - } - size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << db->buforder)) { - ret = -EINVAL; - goto out; - } - if (remap_pfn_range(vma, vma->vm_start, - virt_to_phys(db->rawbuf) >> PAGE_SHIFT, - size, vma->vm_page_prot)) { - ret = -EAGAIN; - goto out; - } - db->mapped = 1; -out: - mutex_unlock(&s->sem); - unlock_kernel(); - return ret; -} - -static int es1371_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int count; - int val, mapped, ret; - void __user *argp = (void __user *)arg; - int __user *p = argp; - - VALIDATE_STATE(s); - mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac2.mapped) || - ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, p); - - case SNDCTL_DSP_SYNC: - if (file->f_mode & FMODE_WRITE) - return drain_dac2(s, 0/*file->f_flags & O_NONBLOCK*/); - return 0; - - case SNDCTL_DSP_SETDUPLEX: - return 0; - - case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p); - - case SNDCTL_DSP_RESET: - if (file->f_mode & FMODE_WRITE) { - stop_dac2(s); - synchronize_irq(s->irq); - s->dma_dac2.swptr = s->dma_dac2.hwptr = s->dma_dac2.count = s->dma_dac2.total_bytes = 0; - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - synchronize_irq(s->irq); - s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; - } - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, p)) - return -EFAULT; - if (val >= 0) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - set_adc_rate(s, val); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac2(s); - s->dma_dac2.ready = 0; - set_dac2_rate(s, val); - } - } - return put_user((file->f_mode & FMODE_READ) ? s->adcrate : s->dac2rate, p); - - case SNDCTL_DSP_STEREO: - if (get_user(val, p)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val) - s->sctrl |= SCTRL_R1SMB; - else - s->sctrl &= ~SCTRL_R1SMB; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac2(s); - s->dma_dac2.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val) - s->sctrl |= SCTRL_P2SMB; - else - s->sctrl &= ~SCTRL_P2SMB; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - return 0; - - case SNDCTL_DSP_CHANNELS: - if (get_user(val, p)) - return -EFAULT; - if (val != 0) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val >= 2) - s->sctrl |= SCTRL_R1SMB; - else - s->sctrl &= ~SCTRL_R1SMB; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac2(s); - s->dma_dac2.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val >= 2) - s->sctrl |= SCTRL_P2SMB; - else - s->sctrl &= ~SCTRL_P2SMB; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - } - return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SMB : SCTRL_P2SMB)) ? 2 : 1, p); - - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(AFMT_S16_LE|AFMT_U8, p); - - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - if (get_user(val, p)) - return -EFAULT; - if (val != AFMT_QUERY) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val == AFMT_S16_LE) - s->sctrl |= SCTRL_R1SEB; - else - s->sctrl &= ~SCTRL_R1SEB; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac2(s); - s->dma_dac2.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val == AFMT_S16_LE) - s->sctrl |= SCTRL_P2SEB; - else - s->sctrl &= ~SCTRL_P2SEB; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - } - return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SEB : SCTRL_P2SEB)) ? - AFMT_S16_LE : AFMT_U8, p); - - case SNDCTL_DSP_POST: - return 0; - - case SNDCTL_DSP_GETTRIGGER: - val = 0; - if (file->f_mode & FMODE_READ && s->ctrl & CTRL_ADC_EN) - val |= PCM_ENABLE_INPUT; - if (file->f_mode & FMODE_WRITE && s->ctrl & CTRL_DAC2_EN) - val |= PCM_ENABLE_OUTPUT; - return put_user(val, p); - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, p)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - if (val & PCM_ENABLE_INPUT) { - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - return ret; - s->dma_adc.enabled = 1; - start_adc(s); - } else { - s->dma_adc.enabled = 0; - stop_adc(s); - } - } - if (file->f_mode & FMODE_WRITE) { - if (val & PCM_ENABLE_OUTPUT) { - if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) - return ret; - s->dma_dac2.enabled = 1; - start_dac2(s); - } else { - s->dma_dac2.enabled = 0; - stop_dac2(s); - } - } - return 0; - - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1371_update_ptr(s); - abinfo.fragsize = s->dma_dac2.fragsize; - count = s->dma_dac2.count; - if (count < 0) - count = 0; - abinfo.bytes = s->dma_dac2.dmasize - count; - abinfo.fragstotal = s->dma_dac2.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_dac2.fragshift; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1371_update_ptr(s); - abinfo.fragsize = s->dma_adc.fragsize; - count = s->dma_adc.count; - if (count < 0) - count = 0; - abinfo.bytes = count; - abinfo.fragstotal = s->dma_adc.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1371_update_ptr(s); - count = s->dma_dac2.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - return put_user(count, p); - - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1371_update_ptr(s); - cinfo.bytes = s->dma_adc.total_bytes; - count = s->dma_adc.count; - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_adc.fragshift; - cinfo.ptr = s->dma_adc.hwptr; - if (s->dma_adc.mapped) - s->dma_adc.count &= s->dma_adc.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); - if (copy_to_user(argp, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1371_update_ptr(s); - cinfo.bytes = s->dma_dac2.total_bytes; - count = s->dma_dac2.count; - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_dac2.fragshift; - cinfo.ptr = s->dma_dac2.hwptr; - if (s->dma_dac2.mapped) - s->dma_dac2.count &= s->dma_dac2.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); - if (copy_to_user(argp, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETBLKSIZE: - if (file->f_mode & FMODE_WRITE) { - if ((val = prog_dmabuf_dac2(s))) - return val; - return put_user(s->dma_dac2.fragsize, p); - } - if ((val = prog_dmabuf_adc(s))) - return val; - return put_user(s->dma_adc.fragsize, p); - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, p)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - s->dma_adc.ossfragshift = val & 0xffff; - s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_adc.ossfragshift < 4) - s->dma_adc.ossfragshift = 4; - if (s->dma_adc.ossfragshift > 15) - s->dma_adc.ossfragshift = 15; - if (s->dma_adc.ossmaxfrags < 4) - s->dma_adc.ossmaxfrags = 4; - } - if (file->f_mode & FMODE_WRITE) { - s->dma_dac2.ossfragshift = val & 0xffff; - s->dma_dac2.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_dac2.ossfragshift < 4) - s->dma_dac2.ossfragshift = 4; - if (s->dma_dac2.ossfragshift > 15) - s->dma_dac2.ossfragshift = 15; - if (s->dma_dac2.ossmaxfrags < 4) - s->dma_dac2.ossmaxfrags = 4; - } - return 0; - - case SNDCTL_DSP_SUBDIVIDE: - if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || - (file->f_mode & FMODE_WRITE && s->dma_dac2.subdivision)) - return -EINVAL; - if (get_user(val, p)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; - if (file->f_mode & FMODE_READ) - s->dma_adc.subdivision = val; - if (file->f_mode & FMODE_WRITE) - s->dma_dac2.subdivision = val; - return 0; - - case SOUND_PCM_READ_RATE: - return put_user((file->f_mode & FMODE_READ) ? s->adcrate : s->dac2rate, p); - - case SOUND_PCM_READ_CHANNELS: - return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SMB : SCTRL_P2SMB)) ? 2 : 1, p); - - case SOUND_PCM_READ_BITS: - return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SEB : SCTRL_P2SEB)) ? 16 : 8, p); - - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - - } - return mixdev_ioctl(s->codec, cmd, arg); -} - -static int es1371_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - struct list_head *list; - struct es1371_state *s; - - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct es1371_state, devs); - if (!((s->dev_audio ^ minor) & ~0xf)) - break; - } - VALIDATE_STATE(s); - file->private_data = s; - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & file->f_mode) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_mutex); - return -EBUSY; - } - add_wait_queue(&s->open_wait, &wait); - __set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&s->open_mutex); - schedule(); - remove_wait_queue(&s->open_wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_mutex); - } - if (file->f_mode & FMODE_READ) { - s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; - s->dma_adc.enabled = 1; - set_adc_rate(s, 8000); - } - if (file->f_mode & FMODE_WRITE) { - s->dma_dac2.ossfragshift = s->dma_dac2.ossmaxfrags = s->dma_dac2.subdivision = 0; - s->dma_dac2.enabled = 1; - set_dac2_rate(s, 8000); - } - spin_lock_irqsave(&s->lock, flags); - if (file->f_mode & FMODE_READ) { - s->sctrl &= ~SCTRL_R1FMT; - if ((minor & 0xf) == SND_DEV_DSP16) - s->sctrl |= ES1371_FMT_S16_MONO << SCTRL_SH_R1FMT; - else - s->sctrl |= ES1371_FMT_U8_MONO << SCTRL_SH_R1FMT; - } - if (file->f_mode & FMODE_WRITE) { - s->sctrl &= ~SCTRL_P2FMT; - if ((minor & 0xf) == SND_DEV_DSP16) - s->sctrl |= ES1371_FMT_S16_MONO << SCTRL_SH_P2FMT; - else - s->sctrl |= ES1371_FMT_U8_MONO << SCTRL_SH_P2FMT; - } - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); - mutex_unlock(&s->open_mutex); - mutex_init(&s->sem); - return nonseekable_open(inode, file); -} - -static int es1371_release(struct inode *inode, struct file *file) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - - VALIDATE_STATE(s); - lock_kernel(); - if (file->f_mode & FMODE_WRITE) - drain_dac2(s, file->f_flags & O_NONBLOCK); - mutex_lock(&s->open_mutex); - if (file->f_mode & FMODE_WRITE) { - stop_dac2(s); - dealloc_dmabuf(s, &s->dma_dac2); - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - dealloc_dmabuf(s, &s->dma_adc); - } - s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE)); - mutex_unlock(&s->open_mutex); - wake_up(&s->open_wait); - unlock_kernel(); - return 0; -} - -static /*const*/ struct file_operations es1371_audio_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = es1371_read, - .write = es1371_write, - .poll = es1371_poll, - .ioctl = es1371_ioctl, - .mmap = es1371_mmap, - .open = es1371_open, - .release = es1371_release, -}; - -/* --------------------------------------------------------------------- */ - -static ssize_t es1371_write_dac(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret = 0; - unsigned long flags; - unsigned swptr; - int cnt; - - VALIDATE_STATE(s); - if (s->dma_dac1.mapped) - return -ENXIO; - if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s))) - return ret; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - add_wait_queue(&s->dma_dac1.wait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - if (s->dma_dac1.count < 0) { - s->dma_dac1.count = 0; - s->dma_dac1.swptr = s->dma_dac1.hwptr; - } - swptr = s->dma_dac1.swptr; - cnt = s->dma_dac1.dmasize-swptr; - if (s->dma_dac1.count + cnt > s->dma_dac1.dmasize) - cnt = s->dma_dac1.dmasize - s->dma_dac1.count; - if (cnt <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (s->dma_dac1.enabled) - start_dac1(s); - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - break; - } - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - continue; - } - if (copy_from_user(s->dma_dac1.rawbuf + swptr, buffer, cnt)) { - if (!ret) - ret = -EFAULT; - break; - } - swptr = (swptr + cnt) % s->dma_dac1.dmasize; - spin_lock_irqsave(&s->lock, flags); - s->dma_dac1.swptr = swptr; - s->dma_dac1.count += cnt; - s->dma_dac1.endcleared = 0; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - if (s->dma_dac1.enabled) - start_dac1(s); - } - remove_wait_queue(&s->dma_dac1.wait, &wait); - set_current_state(TASK_RUNNING); - return ret; -} - -/* No kernel lock - we have our own spinlock */ -static unsigned int es1371_poll_dac(struct file *file, struct poll_table_struct *wait) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - unsigned long flags; - unsigned int mask = 0; - - VALIDATE_STATE(s); - if (!s->dma_dac1.ready && prog_dmabuf_dac1(s)) - return 0; - poll_wait(file, &s->dma_dac1.wait, wait); - spin_lock_irqsave(&s->lock, flags); - es1371_update_ptr(s); - if (s->dma_dac1.mapped) { - if (s->dma_dac1.count >= (signed)s->dma_dac1.fragsize) - mask |= POLLOUT | POLLWRNORM; - } else { - if ((signed)s->dma_dac1.dmasize >= s->dma_dac1.count + (signed)s->dma_dac1.fragsize) - mask |= POLLOUT | POLLWRNORM; - } - spin_unlock_irqrestore(&s->lock, flags); - return mask; -} - -static int es1371_mmap_dac(struct file *file, struct vm_area_struct *vma) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - int ret; - unsigned long size; - - VALIDATE_STATE(s); - if (!(vma->vm_flags & VM_WRITE)) - return -EINVAL; - lock_kernel(); - if ((ret = prog_dmabuf_dac1(s)) != 0) - goto out; - ret = -EINVAL; - if (vma->vm_pgoff != 0) - goto out; - size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << s->dma_dac1.buforder)) - goto out; - ret = -EAGAIN; - if (remap_pfn_range(vma, vma->vm_start, - virt_to_phys(s->dma_dac1.rawbuf) >> PAGE_SHIFT, - size, vma->vm_page_prot)) - goto out; - s->dma_dac1.mapped = 1; - ret = 0; -out: - unlock_kernel(); - return ret; -} - -static int es1371_ioctl_dac(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int count; - int val, ret; - int __user *p = (int __user *)arg; - - VALIDATE_STATE(s); - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, p); - - case SNDCTL_DSP_SYNC: - return drain_dac1(s, 0/*file->f_flags & O_NONBLOCK*/); - - case SNDCTL_DSP_SETDUPLEX: - return -EINVAL; - - case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p); - - case SNDCTL_DSP_RESET: - stop_dac1(s); - synchronize_irq(s->irq); - s->dma_dac1.swptr = s->dma_dac1.hwptr = s->dma_dac1.count = s->dma_dac1.total_bytes = 0; - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, p)) - return -EFAULT; - if (val >= 0) { - stop_dac1(s); - s->dma_dac1.ready = 0; - set_dac1_rate(s, val); - } - return put_user(s->dac1rate, p); - - case SNDCTL_DSP_STEREO: - if (get_user(val, p)) - return -EFAULT; - stop_dac1(s); - s->dma_dac1.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val) - s->sctrl |= SCTRL_P1SMB; - else - s->sctrl &= ~SCTRL_P1SMB; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - return 0; - - case SNDCTL_DSP_CHANNELS: - if (get_user(val, p)) - return -EFAULT; - if (val != 0) { - stop_dac1(s); - s->dma_dac1.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val >= 2) - s->sctrl |= SCTRL_P1SMB; - else - s->sctrl &= ~SCTRL_P1SMB; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - return put_user((s->sctrl & SCTRL_P1SMB) ? 2 : 1, p); - - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(AFMT_S16_LE|AFMT_U8, p); - - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - if (get_user(val, p)) - return -EFAULT; - if (val != AFMT_QUERY) { - stop_dac1(s); - s->dma_dac1.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val == AFMT_S16_LE) - s->sctrl |= SCTRL_P1SEB; - else - s->sctrl &= ~SCTRL_P1SEB; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - return put_user((s->sctrl & SCTRL_P1SEB) ? AFMT_S16_LE : AFMT_U8, p); - - case SNDCTL_DSP_POST: - return 0; - - case SNDCTL_DSP_GETTRIGGER: - return put_user((s->ctrl & CTRL_DAC1_EN) ? PCM_ENABLE_OUTPUT : 0, p); - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, p)) - return -EFAULT; - if (val & PCM_ENABLE_OUTPUT) { - if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s))) - return ret; - s->dma_dac1.enabled = 1; - start_dac1(s); - } else { - s->dma_dac1.enabled = 0; - stop_dac1(s); - } - return 0; - - case SNDCTL_DSP_GETOSPACE: - if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1371_update_ptr(s); - abinfo.fragsize = s->dma_dac1.fragsize; - count = s->dma_dac1.count; - if (count < 0) - count = 0; - abinfo.bytes = s->dma_dac1.dmasize - count; - abinfo.fragstotal = s->dma_dac1.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_dac1.fragshift; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1371_update_ptr(s); - count = s->dma_dac1.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - return put_user(count, p); - - case SNDCTL_DSP_GETOPTR: - if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1371_update_ptr(s); - cinfo.bytes = s->dma_dac1.total_bytes; - count = s->dma_dac1.count; - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_dac1.fragshift; - cinfo.ptr = s->dma_dac1.hwptr; - if (s->dma_dac1.mapped) - s->dma_dac1.count &= s->dma_dac1.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); - if (copy_to_user((void __user *)arg, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETBLKSIZE: - if ((val = prog_dmabuf_dac1(s))) - return val; - return put_user(s->dma_dac1.fragsize, p); - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, p)) - return -EFAULT; - s->dma_dac1.ossfragshift = val & 0xffff; - s->dma_dac1.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_dac1.ossfragshift < 4) - s->dma_dac1.ossfragshift = 4; - if (s->dma_dac1.ossfragshift > 15) - s->dma_dac1.ossfragshift = 15; - if (s->dma_dac1.ossmaxfrags < 4) - s->dma_dac1.ossmaxfrags = 4; - return 0; - - case SNDCTL_DSP_SUBDIVIDE: - if (s->dma_dac1.subdivision) - return -EINVAL; - if (get_user(val, p)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; - s->dma_dac1.subdivision = val; - return 0; - - case SOUND_PCM_READ_RATE: - return put_user(s->dac1rate, p); - - case SOUND_PCM_READ_CHANNELS: - return put_user((s->sctrl & SCTRL_P1SMB) ? 2 : 1, p); - - case SOUND_PCM_READ_BITS: - return put_user((s->sctrl & SCTRL_P1SEB) ? 16 : 8, p); - - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - - } - return mixdev_ioctl(s->codec, cmd, arg); -} - -static int es1371_open_dac(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - struct list_head *list; - struct es1371_state *s; - - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct es1371_state, devs); - if (!((s->dev_dac ^ minor) & ~0xf)) - break; - } - VALIDATE_STATE(s); - /* we allow opening with O_RDWR, most programs do it although they will only write */ -#if 0 - if (file->f_mode & FMODE_READ) - return -EPERM; -#endif - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - file->private_data = s; - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & FMODE_DAC) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_mutex); - return -EBUSY; - } - add_wait_queue(&s->open_wait, &wait); - __set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&s->open_mutex); - schedule(); - remove_wait_queue(&s->open_wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_mutex); - } - s->dma_dac1.ossfragshift = s->dma_dac1.ossmaxfrags = s->dma_dac1.subdivision = 0; - s->dma_dac1.enabled = 1; - set_dac1_rate(s, 8000); - spin_lock_irqsave(&s->lock, flags); - s->sctrl &= ~SCTRL_P1FMT; - if ((minor & 0xf) == SND_DEV_DSP16) - s->sctrl |= ES1371_FMT_S16_MONO << SCTRL_SH_P1FMT; - else - s->sctrl |= ES1371_FMT_U8_MONO << SCTRL_SH_P1FMT; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - s->open_mode |= FMODE_DAC; - mutex_unlock(&s->open_mutex); - return nonseekable_open(inode, file); -} - -static int es1371_release_dac(struct inode *inode, struct file *file) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - - VALIDATE_STATE(s); - lock_kernel(); - drain_dac1(s, file->f_flags & O_NONBLOCK); - mutex_lock(&s->open_mutex); - stop_dac1(s); - dealloc_dmabuf(s, &s->dma_dac1); - s->open_mode &= ~FMODE_DAC; - mutex_unlock(&s->open_mutex); - wake_up(&s->open_wait); - unlock_kernel(); - return 0; -} - -static /*const*/ struct file_operations es1371_dac_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .write = es1371_write_dac, - .poll = es1371_poll_dac, - .ioctl = es1371_ioctl_dac, - .mmap = es1371_mmap_dac, - .open = es1371_open_dac, - .release = es1371_release_dac, -}; - -/* --------------------------------------------------------------------- */ - -static ssize_t es1371_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - unsigned long flags; - unsigned ptr; - int cnt; - - VALIDATE_STATE(s); - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - if (count == 0) - return 0; - ret = 0; - add_wait_queue(&s->midi.iwait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - ptr = s->midi.ird; - cnt = MIDIINBUF - ptr; - if (s->midi.icnt < cnt) - cnt = s->midi.icnt; - if (cnt <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - break; - } - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - continue; - } - if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) { - if (!ret) - ret = -EFAULT; - break; - } - ptr = (ptr + cnt) % MIDIINBUF; - spin_lock_irqsave(&s->lock, flags); - s->midi.ird = ptr; - s->midi.icnt -= cnt; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - break; - } - __set_current_state(TASK_RUNNING); - remove_wait_queue(&s->midi.iwait, &wait); - return ret; -} - -static ssize_t es1371_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - unsigned long flags; - unsigned ptr; - int cnt; - - VALIDATE_STATE(s); - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - if (count == 0) - return 0; - ret = 0; - add_wait_queue(&s->midi.owait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - ptr = s->midi.owr; - cnt = MIDIOUTBUF - ptr; - if (s->midi.ocnt + cnt > MIDIOUTBUF) - cnt = MIDIOUTBUF - s->midi.ocnt; - if (cnt <= 0) { - __set_current_state(TASK_INTERRUPTIBLE); - es1371_handle_midi(s); - } - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - break; - } - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - continue; - } - if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) { - if (!ret) - ret = -EFAULT; - break; - } - ptr = (ptr + cnt) % MIDIOUTBUF; - spin_lock_irqsave(&s->lock, flags); - s->midi.owr = ptr; - s->midi.ocnt += cnt; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - spin_lock_irqsave(&s->lock, flags); - es1371_handle_midi(s); - spin_unlock_irqrestore(&s->lock, flags); - } - __set_current_state(TASK_RUNNING); - remove_wait_queue(&s->midi.owait, &wait); - return ret; -} - -/* No kernel lock - we have our own spinlock */ -static unsigned int es1371_midi_poll(struct file *file, struct poll_table_struct *wait) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - unsigned long flags; - unsigned int mask = 0; - - VALIDATE_STATE(s); - if (file->f_mode & FMODE_WRITE) - poll_wait(file, &s->midi.owait, wait); - if (file->f_mode & FMODE_READ) - poll_wait(file, &s->midi.iwait, wait); - spin_lock_irqsave(&s->lock, flags); - if (file->f_mode & FMODE_READ) { - if (s->midi.icnt > 0) - mask |= POLLIN | POLLRDNORM; - } - if (file->f_mode & FMODE_WRITE) { - if (s->midi.ocnt < MIDIOUTBUF) - mask |= POLLOUT | POLLWRNORM; - } - spin_unlock_irqrestore(&s->lock, flags); - return mask; -} - -static int es1371_midi_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - struct list_head *list; - struct es1371_state *s; - - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct es1371_state, devs); - if (s->dev_midi == minor) - break; - } - VALIDATE_STATE(s); - file->private_data = s; - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_mutex); - return -EBUSY; - } - add_wait_queue(&s->open_wait, &wait); - __set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&s->open_mutex); - schedule(); - remove_wait_queue(&s->open_wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_mutex); - } - spin_lock_irqsave(&s->lock, flags); - if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) { - s->midi.ird = s->midi.iwr = s->midi.icnt = 0; - s->midi.ord = s->midi.owr = s->midi.ocnt = 0; - outb(UCTRL_CNTRL_SWR, s->io+ES1371_REG_UART_CONTROL); - outb(0, s->io+ES1371_REG_UART_CONTROL); - outb(0, s->io+ES1371_REG_UART_TEST); - } - if (file->f_mode & FMODE_READ) { - s->midi.ird = s->midi.iwr = s->midi.icnt = 0; - } - if (file->f_mode & FMODE_WRITE) { - s->midi.ord = s->midi.owr = s->midi.ocnt = 0; - } - s->ctrl |= CTRL_UART_EN; - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - es1371_handle_midi(s); - spin_unlock_irqrestore(&s->lock, flags); - s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE); - mutex_unlock(&s->open_mutex); - return nonseekable_open(inode, file); -} - -static int es1371_midi_release(struct inode *inode, struct file *file) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - unsigned count, tmo; - - VALIDATE_STATE(s); - lock_kernel(); - if (file->f_mode & FMODE_WRITE) { - add_wait_queue(&s->midi.owait, &wait); - for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irqsave(&s->lock, flags); - count = s->midi.ocnt; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= 0) - break; - if (signal_pending(current)) - break; - if (file->f_flags & O_NONBLOCK) - break; - tmo = (count * HZ) / 3100; - if (!schedule_timeout(tmo ? : 1) && tmo) - printk(KERN_DEBUG PFX "midi timed out??\n"); - } - remove_wait_queue(&s->midi.owait, &wait); - set_current_state(TASK_RUNNING); - } - mutex_lock(&s->open_mutex); - s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE)); - spin_lock_irqsave(&s->lock, flags); - if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) { - s->ctrl &= ~CTRL_UART_EN; - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - } - spin_unlock_irqrestore(&s->lock, flags); - mutex_unlock(&s->open_mutex); - wake_up(&s->open_wait); - unlock_kernel(); - return 0; -} - -static /*const*/ struct file_operations es1371_midi_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = es1371_midi_read, - .write = es1371_midi_write, - .poll = es1371_midi_poll, - .open = es1371_midi_open, - .release = es1371_midi_release, -}; - -/* --------------------------------------------------------------------- */ - -/* - * for debugging purposes, we'll create a proc device that dumps the - * CODEC chipstate - */ - -#ifdef ES1371_DEBUG -static int proc_es1371_dump (char *buf, char **start, off_t fpos, int length, int *eof, void *data) -{ - struct es1371_state *s; - int cnt, len = 0; - - if (list_empty(&devs)) - return 0; - s = list_entry(devs.next, struct es1371_state, devs); - /* print out header */ - len += sprintf(buf + len, "\t\tCreative ES137x Debug Dump-o-matic\n"); - - /* print out CODEC state */ - len += sprintf (buf + len, "AC97 CODEC state\n"); - for (cnt=0; cnt <= 0x7e; cnt = cnt +2) - len+= sprintf (buf + len, "reg:0x%02x val:0x%04x\n", cnt, rdcodec(s->codec, cnt)); - - if (fpos >=len){ - *start = buf; - *eof =1; - return 0; - } - *start = buf + fpos; - if ((len -= fpos) > length) - return length; - *eof =1; - return len; - -} -#endif /* ES1371_DEBUG */ - -/* --------------------------------------------------------------------- */ - -/* maximum number of devices; only used for command line params */ -#define NR_DEVICE 5 - -static int spdif[NR_DEVICE]; -static int nomix[NR_DEVICE]; -static int amplifier[NR_DEVICE]; - -static unsigned int devindex; - -module_param_array(spdif, bool, NULL, 0); -MODULE_PARM_DESC(spdif, "if 1 the output is in S/PDIF digital mode"); -module_param_array(nomix, bool, NULL, 0); -MODULE_PARM_DESC(nomix, "if 1 no analog audio is mixed to the digital output"); -module_param_array(amplifier, bool, NULL, 0); -MODULE_PARM_DESC(amplifier, "Set to 1 if the machine needs the amp control enabling (many laptops)"); - -MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); -MODULE_DESCRIPTION("ES1371 AudioPCI97 Driver"); -MODULE_LICENSE("GPL"); - - -/* --------------------------------------------------------------------- */ - -static struct initvol { - int mixch; - int vol; -} initvol[] __devinitdata = { - { SOUND_MIXER_WRITE_LINE, 0x4040 }, - { SOUND_MIXER_WRITE_CD, 0x4040 }, - { MIXER_WRITE(SOUND_MIXER_VIDEO), 0x4040 }, - { SOUND_MIXER_WRITE_LINE1, 0x4040 }, - { SOUND_MIXER_WRITE_PCM, 0x4040 }, - { SOUND_MIXER_WRITE_VOLUME, 0x4040 }, - { MIXER_WRITE(SOUND_MIXER_PHONEOUT), 0x4040 }, - { SOUND_MIXER_WRITE_OGAIN, 0x4040 }, - { MIXER_WRITE(SOUND_MIXER_PHONEIN), 0x4040 }, - { SOUND_MIXER_WRITE_SPEAKER, 0x4040 }, - { SOUND_MIXER_WRITE_MIC, 0x4040 }, - { SOUND_MIXER_WRITE_RECLEV, 0x4040 }, - { SOUND_MIXER_WRITE_IGAIN, 0x4040 } -}; - -static struct -{ - short svid, sdid; -} amplifier_needed[] = -{ - { 0x107B, 0x2150 }, /* Gateway Solo 2150 */ - { 0x13BD, 0x100C }, /* Mebius PC-MJ100V */ - { 0x1102, 0x5938 }, /* Targa Xtender 300 */ - { 0x1102, 0x8938 }, /* IPC notebook */ - { PCI_ANY_ID, PCI_ANY_ID } -}; - -#ifdef SUPPORT_JOYSTICK - -static int __devinit es1371_register_gameport(struct es1371_state *s) -{ - struct gameport *gp; - int gpio; - - for (gpio = 0x218; gpio >= 0x200; gpio -= 0x08) - if (request_region(gpio, JOY_EXTENT, "es1371")) - break; - - if (gpio < 0x200) { - printk(KERN_ERR PFX "no free joystick address found\n"); - return -EBUSY; - } - - s->gameport = gp = gameport_allocate_port(); - if (!gp) { - printk(KERN_ERR PFX "can not allocate memory for gameport\n"); - release_region(gpio, JOY_EXTENT); - return -ENOMEM; - } - - gameport_set_name(gp, "ESS1371 Gameport"); - gameport_set_phys(gp, "isa%04x/gameport0", gpio); - gp->dev.parent = &s->dev->dev; - gp->io = gpio; - - s->ctrl |= CTRL_JYSTK_EN | (((gpio >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT); - outl(s->ctrl, s->io + ES1371_REG_CONTROL); - - gameport_register_port(gp); - - return 0; -} - -static inline void es1371_unregister_gameport(struct es1371_state *s) -{ - if (s->gameport) { - int gpio = s->gameport->io; - gameport_unregister_port(s->gameport); - release_region(gpio, JOY_EXTENT); - - } -} - -#else -static inline int es1371_register_gameport(struct es1371_state *s) { return -ENOSYS; } -static inline void es1371_unregister_gameport(struct es1371_state *s) { } -#endif /* SUPPORT_JOYSTICK */ - - -static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) -{ - struct es1371_state *s; - mm_segment_t fs; - int i, val, res = -1; - int idx; - unsigned long tmo; - signed long tmo2; - unsigned int cssr; - - if ((res=pci_enable_device(pcidev))) - return res; - - if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_IO)) - return -ENODEV; - if (pcidev->irq == 0) - return -ENODEV; - i = pci_set_dma_mask(pcidev, DMA_32BIT_MASK); - if (i) { - printk(KERN_WARNING "es1371: architecture does not support 32bit PCI busmaster DMA\n"); - return i; - } - if (!(s = kzalloc(sizeof(struct es1371_state), GFP_KERNEL))) { - printk(KERN_WARNING PFX "out of memory\n"); - return -ENOMEM; - } - - s->codec = ac97_alloc_codec(); - if(s->codec == NULL) - goto err_codec; - - init_waitqueue_head(&s->dma_adc.wait); - init_waitqueue_head(&s->dma_dac1.wait); - init_waitqueue_head(&s->dma_dac2.wait); - init_waitqueue_head(&s->open_wait); - init_waitqueue_head(&s->midi.iwait); - init_waitqueue_head(&s->midi.owait); - mutex_init(&s->open_mutex); - spin_lock_init(&s->lock); - s->magic = ES1371_MAGIC; - s->dev = pcidev; - s->io = pci_resource_start(pcidev, 0); - s->irq = pcidev->irq; - s->vendor = pcidev->vendor; - s->device = pcidev->device; - s->rev = pcidev->revision; - s->codec->private_data = s; - s->codec->id = 0; - s->codec->codec_read = rdcodec; - s->codec->codec_write = wrcodec; - printk(KERN_INFO PFX "found chip, vendor id 0x%04x device id 0x%04x revision 0x%02x\n", - s->vendor, s->device, s->rev); - if (!request_region(s->io, ES1371_EXTENT, "es1371")) { - printk(KERN_ERR PFX "io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1); - res = -EBUSY; - goto err_region; - } - if ((res=request_irq(s->irq, es1371_interrupt, IRQF_SHARED, "es1371",s))) { - printk(KERN_ERR PFX "irq %u in use\n", s->irq); - goto err_irq; - } - printk(KERN_INFO PFX "found es1371 rev %d at io %#lx irq %u\n", - s->rev, s->io, s->irq); - /* register devices */ - if ((res=(s->dev_audio = register_sound_dsp(&es1371_audio_fops,-1)))<0) - goto err_dev1; - if ((res=(s->codec->dev_mixer = register_sound_mixer(&es1371_mixer_fops, -1))) < 0) - goto err_dev2; - if ((res=(s->dev_dac = register_sound_dsp(&es1371_dac_fops, -1))) < 0) - goto err_dev3; - if ((res=(s->dev_midi = register_sound_midi(&es1371_midi_fops, -1)))<0 ) - goto err_dev4; -#ifdef ES1371_DEBUG - /* initialize the debug proc device */ - s->ps = create_proc_read_entry("es1371",0,NULL,proc_es1371_dump,NULL); -#endif /* ES1371_DEBUG */ - - /* initialize codec registers */ - s->ctrl = 0; - - /* Check amplifier requirements */ - - if (amplifier[devindex]) - s->ctrl |= CTRL_GPIO_OUT0; - else for(idx = 0; amplifier_needed[idx].svid != PCI_ANY_ID; idx++) - { - if(pcidev->subsystem_vendor == amplifier_needed[idx].svid && - pcidev->subsystem_device == amplifier_needed[idx].sdid) - { - s->ctrl |= CTRL_GPIO_OUT0; /* turn internal amplifier on */ - printk(KERN_INFO PFX "Enabling internal amplifier.\n"); - } - } - - s->sctrl = 0; - cssr = 0; - s->spdif_volume = -1; - /* check to see if s/pdif mode is being requested */ - if (spdif[devindex]) { - if (s->rev >= 4) { - printk(KERN_INFO PFX "enabling S/PDIF output\n"); - s->spdif_volume = 0; - cssr |= STAT_EN_SPDIF; - s->ctrl |= CTRL_SPDIFEN_B; - if (nomix[devindex]) /* don't mix analog inputs to s/pdif output */ - s->ctrl |= CTRL_RECEN_B; - } else { - printk(KERN_ERR PFX "revision %d does not support S/PDIF\n", s->rev); - } - } - /* initialize the chips */ - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - outl(LEGACY_JFAST, s->io+ES1371_REG_LEGACY); - pci_set_master(pcidev); /* enable bus mastering */ - /* if we are a 5880 turn on the AC97 */ - if (s->vendor == PCI_VENDOR_ID_ENSONIQ && - ((s->device == PCI_DEVICE_ID_ENSONIQ_CT5880 && s->rev >= CT5880REV_CT5880_C) || - (s->device == PCI_DEVICE_ID_ENSONIQ_ES1371 && s->rev == ES1371REV_CT5880_A) || - (s->device == PCI_DEVICE_ID_ENSONIQ_ES1371 && s->rev == ES1371REV_ES1373_8))) { - cssr |= CSTAT_5880_AC97_RST; - outl(cssr, s->io+ES1371_REG_STATUS); - /* need to delay around 20ms(bleech) to give - some CODECs enough time to wakeup */ - tmo = jiffies + (HZ / 50) + 1; - for (;;) { - tmo2 = tmo - jiffies; - if (tmo2 <= 0) - break; - schedule_timeout(tmo2); - } - } - /* AC97 warm reset to start the bitclk */ - outl(s->ctrl | CTRL_SYNCRES, s->io+ES1371_REG_CONTROL); - udelay(2); - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - /* init the sample rate converter */ - src_init(s); - /* codec init */ - if (!ac97_probe_codec(s->codec)) { - res = -ENODEV; - goto err_gp; - } - /* set default values */ - - fs = get_fs(); - set_fs(KERNEL_DS); - val = SOUND_MASK_LINE; - mixdev_ioctl(s->codec, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val); - for (i = 0; i < ARRAY_SIZE(initvol); i++) { - val = initvol[i].vol; - mixdev_ioctl(s->codec, initvol[i].mixch, (unsigned long)&val); - } - /* mute master and PCM when in S/PDIF mode */ - if (s->spdif_volume != -1) { - val = 0x0000; - s->codec->mixer_ioctl(s->codec, SOUND_MIXER_WRITE_VOLUME, (unsigned long)&val); - s->codec->mixer_ioctl(s->codec, SOUND_MIXER_WRITE_PCM, (unsigned long)&val); - } - set_fs(fs); - /* turn on S/PDIF output driver if requested */ - outl(cssr, s->io+ES1371_REG_STATUS); - - es1371_register_gameport(s); - - /* store it in the driver field */ - pci_set_drvdata(pcidev, s); - /* put it into driver list */ - list_add_tail(&s->devs, &devs); - /* increment devindex */ - if (devindex < NR_DEVICE-1) - devindex++; - return 0; - - err_gp: -#ifdef ES1371_DEBUG - if (s->ps) - remove_proc_entry("es1371", NULL); -#endif - unregister_sound_midi(s->dev_midi); - err_dev4: - unregister_sound_dsp(s->dev_dac); - err_dev3: - unregister_sound_mixer(s->codec->dev_mixer); - err_dev2: - unregister_sound_dsp(s->dev_audio); - err_dev1: - printk(KERN_ERR PFX "cannot register misc device\n"); - free_irq(s->irq, s); - err_irq: - release_region(s->io, ES1371_EXTENT); - err_region: - err_codec: - ac97_release_codec(s->codec); - kfree(s); - return res; -} - -static void __devexit es1371_remove(struct pci_dev *dev) -{ - struct es1371_state *s = pci_get_drvdata(dev); - - if (!s) - return; - list_del(&s->devs); -#ifdef ES1371_DEBUG - if (s->ps) - remove_proc_entry("es1371", NULL); -#endif /* ES1371_DEBUG */ - outl(0, s->io+ES1371_REG_CONTROL); /* switch everything off */ - outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */ - synchronize_irq(s->irq); - free_irq(s->irq, s); - es1371_unregister_gameport(s); - release_region(s->io, ES1371_EXTENT); - unregister_sound_dsp(s->dev_audio); - unregister_sound_mixer(s->codec->dev_mixer); - unregister_sound_dsp(s->dev_dac); - unregister_sound_midi(s->dev_midi); - ac97_release_codec(s->codec); - kfree(s); - pci_set_drvdata(dev, NULL); -} - -static struct pci_device_id id_table[] = { - { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, - { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_CT5880, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, - { PCI_VENDOR_ID_ECTIVA, PCI_DEVICE_ID_ECTIVA_EV1938, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, id_table); - -static struct pci_driver es1371_driver = { - .name = "es1371", - .id_table = id_table, - .probe = es1371_probe, - .remove = __devexit_p(es1371_remove), -}; - -static int __init init_es1371(void) -{ - printk(KERN_INFO PFX "version v0.32 time " __TIME__ " " __DATE__ "\n"); - return pci_register_driver(&es1371_driver); -} - -static void __exit cleanup_es1371(void) -{ - printk(KERN_INFO PFX "unloading\n"); - pci_unregister_driver(&es1371_driver); -} - -module_init(init_es1371); -module_exit(cleanup_es1371); - -/* --------------------------------------------------------------------- */ - -#ifndef MODULE - -/* format is: es1371=[spdif,[nomix,[amplifier]]] */ - -static int __init es1371_setup(char *str) -{ - static unsigned __initdata nr_dev = 0; - - if (nr_dev >= NR_DEVICE) - return 0; - - (void) - ((get_option(&str, &spdif[nr_dev]) == 2) - && (get_option(&str, &nomix[nr_dev]) == 2) - && (get_option(&str, &lifier[nr_dev]))); - - nr_dev++; - return 1; -} - -__setup("es1371=", es1371_setup); - -#endif /* MODULE */ |