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>
---------------------------
-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.
+++ /dev/null
-/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
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
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
# 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
+++ /dev/null
-/*********************************************************/
-/* 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_ */
+++ /dev/null
-/*
- * 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);
-}
*/
#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) ||\
#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
*/
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) */
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
+++ /dev/null
-/*
- * 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);
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
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)
{
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 ;
}
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;
}
-#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);
#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;
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);
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
*/
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);
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 ;
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) ;
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() ;
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)
.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;
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") ;
}
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
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>).
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") ;
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
(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;
}
}
write_sq_release_buffers();
- read_sq_release_buffers();
if (mixer_unit >= 0)
unregister_sound_mixer(mixer_unit);
*/
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);
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);
+++ /dev/null
-/*
- * 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
-};
+++ /dev/null
-/*
- * 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_ */
+++ /dev/null
-#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
-};
+++ /dev/null
-/*
- * 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
-};
+++ /dev/null
-/*
- * 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_ */
+++ /dev/null
-#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
-};
+++ /dev/null
-#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);
-}
+++ /dev/null
-#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:
- */
+++ /dev/null
-#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:
- */
+++ /dev/null
-#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
+++ /dev/null
-/*
- * 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,
-};
+++ /dev/null
-/*****************************************************************************/
-
-/*
- * 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 */