提交 fc37449f 编写于 作者: A Adrian Bunk 提交者: Linus Torvalds

The next round of scheduled OSS code removal

This patch contains the next round of scheduled OSS code removal.
Signed-off-by: NAdrian Bunk <bunk@stusta.de>
Signed-off-by: NAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
上级 5b4db0c2
......@@ -219,13 +219,6 @@ Who: Jean Delvare <khali@linux-fr.org>,
---------------------------
What: drivers depending on OBSOLETE_OSS
When: options in 2.6.22, code in 2.6.24
Why: OSS drivers with ALSA replacements
Who: Adrian Bunk <bunk@stusta.de>
---------------------------
What: ACPI procfs interface
When: July 2008
Why: ACPI sysfs conversion should be finished by January 2008.
......
/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
......@@ -2940,13 +2940,6 @@ L: linux-kernel@vger.kernel.org
L: linux-pci@atrey.karlin.mff.cuni.cz
S: Supported
PCI SOUND DRIVERS (ES1370, ES1371 and SONICVIBES)
P: Thomas Sailer
M: sailer@ife.ee.ethz.ch
L: linux-sound@vger.kernel.org
W: http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html
S: Maintained
PCI SUBSYSTEM
P: Greg Kroah-Hartman
M: gregkh@suse.de
......
......@@ -36,7 +36,6 @@ obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o
obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o
obj-$(CONFIG_SOUND_VWSND) += vwsnd.o
obj-$(CONFIG_SOUND_ICH) += i810_audio.o ac97_codec.o
obj-$(CONFIG_SOUND_ES1371) += es1371.o ac97_codec.o
obj-$(CONFIG_SOUND_AU1550_AC97) += au1550_ac97.o ac97_codec.o
obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o
obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o
......
......@@ -2,12 +2,6 @@
# Makefile for the DMA sound driver
#
dmasound_pmac-y += dmasound_awacs.o \
trans_16.o dac3550a.o tas_common.o \
tas3001c.o tas3001c_tables.o \
tas3004.o tas3004_tables.o
obj-$(CONFIG_DMASOUND_ATARI) += dmasound_core.o dmasound_atari.o
obj-$(CONFIG_DMASOUND_PMAC) += dmasound_core.o dmasound_pmac.o
obj-$(CONFIG_DMASOUND_PAULA) += dmasound_core.o dmasound_paula.o
obj-$(CONFIG_DMASOUND_Q40) += dmasound_core.o dmasound_q40.o
/*********************************************************/
/* 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_ */
/*
* 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);
}
......@@ -59,7 +59,6 @@ static inline int ioctl_return(int __user *addr, int value)
*/
#undef HAS_8BIT_TABLES
#undef HAS_RECORD
#if defined(CONFIG_DMASOUND_ATARI) || defined(CONFIG_DMASOUND_ATARI_MODULE) ||\
defined(CONFIG_DMASOUND_PAULA) || defined(CONFIG_DMASOUND_PAULA_MODULE) ||\
......@@ -83,10 +82,6 @@ static inline int ioctl_return(int __user *addr, int value)
#define DEFAULT_N_BUFFERS 4
#define DEFAULT_BUFF_SIZE (1<<15)
#if defined(CONFIG_DMASOUND_PMAC) || defined(CONFIG_DMASOUND_PMAC_MODULE)
#define HAS_RECORD
#endif
/*
* Initialization
*/
......@@ -168,9 +163,6 @@ struct sound_settings {
SETTINGS soft; /* software settings */
SETTINGS dsp; /* /dev/dsp default settings */
TRANS *trans_write; /* supported translations */
#ifdef HAS_RECORD
TRANS *trans_read; /* supported translations */
#endif
int volume_left; /* volume (range is machine dependent) */
int volume_right;
int bass; /* tone (range is machine dependent) */
......@@ -253,11 +245,6 @@ struct sound_queue {
extern struct sound_queue dmasound_write_sq;
#define write_sq dmasound_write_sq
#ifdef HAS_RECORD
extern struct sound_queue dmasound_read_sq;
#define read_sq dmasound_read_sq
#endif
extern int dmasound_catchRadius;
#define catchRadius dmasound_catchRadius
......
此差异已折叠。
......@@ -202,13 +202,6 @@ module_param(numWriteBufs, int, 0);
static unsigned int writeBufSize = DEFAULT_BUFF_SIZE ; /* in bytes */
module_param(writeBufSize, int, 0);
#ifdef HAS_RECORD
static unsigned int numReadBufs = DEFAULT_N_BUFFERS;
module_param(numReadBufs, int, 0);
static unsigned int readBufSize = DEFAULT_BUFF_SIZE; /* in bytes */
module_param(readBufSize, int, 0);
#endif
MODULE_LICENSE("GPL");
#ifdef MODULE
......@@ -403,10 +396,6 @@ static void mixer_init(void)
struct sound_queue dmasound_write_sq;
static void sq_reset_output(void) ;
#ifdef HAS_RECORD
struct sound_queue dmasound_read_sq;
static void sq_reset_input(void) ;
#endif
static int sq_allocate_buffers(struct sound_queue *sq, int num, int size)
{
......@@ -530,12 +519,6 @@ printk("dmasound_core: invalid frag count (user set %d)\n", sq->user_frags) ;
sq->rear = -1;
setup_func = dmasound.mach.write_sq_setup;
}
#ifdef HAS_RECORD
else {
sq->rear = 0;
setup_func = dmasound.mach.read_sq_setup;
}
#endif
if (setup_func)
return setup_func();
return 0 ;
......@@ -672,13 +655,6 @@ static unsigned int sq_poll(struct file *file, struct poll_table_struct *wait)
}
if (file->f_mode & FMODE_WRITE )
poll_wait(file, &write_sq.action_queue, wait);
#ifdef HAS_RECORD
if (file->f_mode & FMODE_READ)
poll_wait(file, &read_sq.action_queue, wait);
if (file->f_mode & FMODE_READ)
if (read_sq.block_size - read_sq.rear_size > 0)
mask |= POLLIN | POLLRDNORM;
#endif
if (file->f_mode & FMODE_WRITE)
if (write_sq.count < write_sq.max_active || write_sq.block_size - write_sq.rear_size > 0)
mask |= POLLOUT | POLLWRNORM;
......@@ -686,101 +662,6 @@ static unsigned int sq_poll(struct file *file, struct poll_table_struct *wait)
}
#ifdef HAS_RECORD
/*
* Here is how the values are used for reading.
* The value 'active' simply indicates the DMA is running. This is done
* so the driver semantics are DMA starts when the first read is posted.
* The value 'front' indicates the buffer we should next send to the user.
* The value 'rear' indicates the buffer the DMA is currently filling.
* When 'front' == 'rear' the buffer "ring" is empty (we always have an
* empty available). The 'rear_size' is used to track partial offsets
* into the buffer we are currently returning to the user.
* This level (> [1.5]) doesn't care what strategy the LL driver uses with
* DMA on over-run. It can leave it running (and keep active == 1) or it
* can kill it and set active == 0 in which case this routine will spot
* it and restart the DMA.
*/
static ssize_t sq_read(struct file *file, char __user *dst, size_t uLeft,
loff_t *ppos)
{
ssize_t uRead, bLeft, bUsed, uUsed;
if (uLeft == 0)
return 0;
/* cater for the compatibility mode - record compiled in but no LL */
if (dmasound.mach.record == NULL)
return -EINVAL ;
/* see comment in sq_write()
*/
if( shared_resources_initialised == 0) {
dmasound.mach.init() ;
shared_resources_initialised = 1 ;
}
/* set up the sq if it is not already done. see comments in sq_write().
*/
if (read_sq.locked == 0) {
if ((uRead = sq_setup(&read_sq)) < 0)
return uRead ;
}
uRead = 0;
/* Move what the user requests, depending upon other options.
*/
while (uLeft > 0) {
/* we happened to get behind and the LL driver killed DMA
then we should set it going again. This also sets it
going the first time through.
*/
if ( !read_sq.active )
dmasound.mach.record();
/* When front == rear, the DMA is not done yet.
*/
while (read_sq.front == read_sq.rear) {
if (read_sq.open_mode & O_NONBLOCK) {
return uRead > 0 ? uRead : -EAGAIN;
}
SLEEP(read_sq.action_queue);
if (signal_pending(current))
return uRead > 0 ? uRead : -EINTR;
}
/* The amount we move is either what is left in the
* current buffer or what the user wants.
*/
bLeft = read_sq.block_size - read_sq.rear_size;
bUsed = read_sq.rear_size;
uUsed = sound_copy_translate(dmasound.trans_read, dst, uLeft,
read_sq.buffers[read_sq.front],
&bUsed, bLeft);
if (uUsed <= 0)
return uUsed;
dst += uUsed;
uRead += uUsed;
uLeft -= uUsed;
read_sq.rear_size += bUsed;
if (read_sq.rear_size >= read_sq.block_size) {
read_sq.rear_size = 0;
read_sq.front++;
if (read_sq.front >= read_sq.max_active)
read_sq.front = 0;
}
}
return uRead;
}
#endif /* HAS_RECORD */
static inline void sq_init_waitqueue(struct sound_queue *sq)
{
init_waitqueue_head(&sq->action_queue);
......@@ -854,23 +735,6 @@ static int sq_open2(struct sound_queue *sq, struct file *file, mode_t mode,
#define write_sq_open(file) \
sq_open2(&write_sq, file, FMODE_WRITE, numWriteBufs, writeBufSize )
#ifdef HAS_RECORD
#define read_sq_init_waitqueue() sq_init_waitqueue(&read_sq)
#if 0 /* blocking open() */
#define read_sq_wake_up(file) sq_wake_up(&read_sq, file, FMODE_READ)
#endif
#define read_sq_release_buffers() sq_release_buffers(&read_sq)
#define read_sq_open(file) \
sq_open2(&read_sq, file, FMODE_READ, numReadBufs, readBufSize )
#else
#define read_sq_init_waitqueue() do {} while (0)
#if 0 /* blocking open() */
#define read_sq_wake_up(file) do {} while (0)
#endif
#define read_sq_release_buffers() do {} while (0)
#define sq_reset_input() do {} while (0)
#endif
static int sq_open(struct inode *inode, struct file *file)
{
int rc;
......@@ -881,25 +745,11 @@ static int sq_open(struct inode *inode, struct file *file)
rc = write_sq_open(file); /* checks the f_mode */
if (rc)
goto out;
#ifdef HAS_RECORD
if (dmasound.mach.record) {
rc = read_sq_open(file); /* checks the f_mode */
if (rc)
goto out;
} else { /* no record function installed; in compat mode */
if (file->f_mode & FMODE_READ) {
/* TODO: if O_RDWR, release any resources grabbed by write part */
rc = -ENXIO;
goto out;
}
}
#else /* !HAS_RECORD */
if (file->f_mode & FMODE_READ) {
/* TODO: if O_RDWR, release any resources grabbed by write part */
rc = -ENXIO ; /* I think this is what is required by open(2) */
goto out;
}
#endif /* HAS_RECORD */
if (dmasound.mach.sq_open)
dmasound.mach.sq_open(file->f_mode);
......@@ -956,43 +806,9 @@ static void sq_reset_output(void)
write_sq.user_frag_size = 0 ;
}
#ifdef HAS_RECORD
static void sq_reset_input(void)
{
if (dmasound.mach.record && read_sq.active) {
if (dmasound.mach.abort_read) { /* this routine must really be present */
read_sq.syncing = 1 ;
/* this can use the read_sq.sync_queue to sleep if
necessary - it should not return until DMA
is really stopped - because we might deallocate
the buffers as the next action...
*/
dmasound.mach.abort_read() ;
} else {
printk(KERN_ERR
"dmasound_core: %s has no abort_read()!! all bets are off\n",
dmasound.mach.name) ;
}
}
read_sq.syncing =
read_sq.active =
read_sq.front =
read_sq.count =
read_sq.rear = 0 ;
/* OK - we can unlock the parameters and fragment settings */
read_sq.locked = 0 ;
read_sq.user_frags = 0 ;
read_sq.user_frag_size = 0 ;
}
#endif
static void sq_reset(void)
{
sq_reset_output() ;
sq_reset_input() ;
/* we could consider resetting the shared_resources_owner here... but I
think it is probably still rather non-obvious to application writer
*/
......@@ -1038,17 +854,6 @@ static int sq_release(struct inode *inode, struct file *file)
lock_kernel();
#ifdef HAS_RECORD
/* probably best to do the read side first - so that time taken to do it
overlaps with playing any remaining output samples.
*/
if (file->f_mode & FMODE_READ) {
sq_reset_input() ; /* make sure dma is stopped and all is quiet */
read_sq_release_buffers();
read_sq.busy = 0;
}
#endif
if (file->f_mode & FMODE_WRITE) {
if (write_sq.busy)
rc = sq_fsync(file, file->f_path.dentry);
......@@ -1105,11 +910,6 @@ static int shared_resources_are_mine(mode_t md)
static int queues_are_quiescent(void)
{
#ifdef HAS_RECORD
if (dmasound.mach.record)
if (read_sq.locked)
return 0 ;
#endif
if (write_sq.locked)
return 0 ;
return 1 ;
......@@ -1185,13 +985,6 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
the read_sq ones.
*/
size = 0 ;
#ifdef HAS_RECORD
if (dmasound.mach.record && (file->f_mode & FMODE_READ)) {
if ( !read_sq.locked )
sq_setup(&read_sq) ; /* set params */
size = read_sq.user_frag_size ;
}
#endif
if (file->f_mode & FMODE_WRITE) {
if ( !write_sq.locked )
sq_setup(&write_sq) ;
......@@ -1214,8 +1007,6 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
everything - read, however, is killed imediately.
*/
result = 0 ;
if ((file->f_mode & FMODE_READ) && dmasound.mach.record)
sq_reset_input() ;
if (file->f_mode & FMODE_WRITE) {
result = sq_fsync(file, file->f_path.dentry);
sq_reset_output() ;
......@@ -1294,13 +1085,6 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
result = 0 ;
nbufs = (data >> 16) & 0x7fff ; /* 0x7fff is 'use maximum' */
size = data & 0xffff;
#ifdef HAS_RECORD
if ((file->f_mode & FMODE_READ) && dmasound.mach.record) {
result = set_queue_frags(&read_sq, nbufs, size) ;
if (result)
return result ;
}
#endif
if (file->f_mode & FMODE_WRITE) {
result = set_queue_frags(&write_sq, nbufs, size) ;
if (result)
......@@ -1348,20 +1132,6 @@ static const struct file_operations sq_fops =
.release = sq_release,
};
#ifdef HAS_RECORD
static const struct file_operations sq_fops_record =
{
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = sq_write,
.poll = sq_poll,
.ioctl = sq_ioctl,
.open = sq_open,
.release = sq_release,
.read = sq_read,
};
#endif
static int sq_init(void)
{
const struct file_operations *fops = &sq_fops;
......@@ -1369,10 +1139,6 @@ static int sq_init(void)
int sq_unit;
#endif
#ifdef HAS_RECORD
if (dmasound.mach.record)
fops = &sq_fops_record;
#endif
sq_unit = register_sound_dsp(fops, -1);
if (sq_unit < 0) {
printk(KERN_ERR "dmasound_core: couldn't register fops\n") ;
......@@ -1380,7 +1146,6 @@ static int sq_init(void)
}
write_sq_init_waitqueue();
read_sq_init_waitqueue();
/* These parameters will be restored for every clean open()
* in the case of multiple open()s (e.g. dsp0 & dsp1) they
......@@ -1406,11 +1171,7 @@ static int sq_init(void)
driver.
*/
#ifdef HAS_RECORD
#define STAT_BUFF_LEN 1024
#else
#define STAT_BUFF_LEN 768
#endif
/* this is how much space we will allow the low-level driver to use
in the stat buffer. Currently, 2 * (80 character line + <NL>).
......@@ -1518,11 +1279,6 @@ static int state_open(struct inode *inode, struct file *file)
len += sprintf(buffer+len,"Allocated:%8s%6s\n","Buffers","Size") ;
len += sprintf(buffer+len,"%9s:%8d%6d\n",
"write", write_sq.numBufs, write_sq.bufSize) ;
#ifdef HAS_RECORD
if (dmasound.mach.record)
len += sprintf(buffer+len,"%9s:%8d%6d\n",
"read", read_sq.numBufs, read_sq.bufSize) ;
#endif
len += sprintf(buffer+len,
"Current : MaxFrg FragSiz MaxAct Frnt Rear "
"Cnt RrSize A B S L xruns\n") ;
......@@ -1531,14 +1287,6 @@ static int state_open(struct inode *inode, struct file *file)
write_sq.max_active, write_sq.front, write_sq.rear,
write_sq.count, write_sq.rear_size, write_sq.active,
write_sq.busy, write_sq.syncing, write_sq.locked, write_sq.xruns) ;
#ifdef HAS_RECORD
if (dmasound.mach.record)
len += sprintf(buffer+len,"%9s:%7d%8d%7d%5d%5d%4d%7d%2d%2d%2d%2d%7d\n",
"read", read_sq.max_count, read_sq.block_size,
read_sq.max_active, read_sq.front, read_sq.rear,
read_sq.count, read_sq.rear_size, read_sq.active,
read_sq.busy, read_sq.syncing, read_sq.locked, read_sq.xruns) ;
#endif
#ifdef DEBUG_DMASOUND
printk("dmasound: stat buffer used %d bytes\n", len) ;
#endif
......@@ -1638,13 +1386,6 @@ int dmasound_init(void)
(dmasound.mach.version >> 8), (dmasound.mach.version & 0xff)) ;
printk(KERN_INFO "Write will use %4d fragments of %7d bytes as default\n",
numWriteBufs, writeBufSize) ;
#ifdef HAS_RECORD
if (dmasound.mach.record)
printk(KERN_INFO
"Read will use %4d fragments of %7d bytes as default\n",
numReadBufs, readBufSize) ;
#endif
return 0;
}
......@@ -1659,7 +1400,6 @@ void dmasound_deinit(void)
}
write_sq_release_buffers();
read_sq_release_buffers();
if (mixer_unit >= 0)
unregister_sound_mixer(mixer_unit);
......@@ -1684,36 +1424,12 @@ static int dmasound_setup(char *str)
*/
switch (ints[0]) {
#ifdef HAS_RECORD
case 5:
if ((ints[5] < 0) || (ints[5] > MAX_CATCH_RADIUS))
printk("dmasound_setup: invalid catch radius, using default = %d\n", catchRadius);
else
catchRadius = ints[5];
/* fall through */
case 4:
if (ints[4] < MIN_BUFFERS)
printk("dmasound_setup: invalid number of read buffers, using default = %d\n",
numReadBufs);
else
numReadBufs = ints[4];
/* fall through */
case 3:
if ((size = ints[3]) < 256) /* check for small buffer specs */
size <<= 10 ;
if (size < MIN_BUFSIZE || size > MAX_BUFSIZE)
printk("dmasound_setup: invalid read buffer size, using default = %d\n", readBufSize);
else
readBufSize = size;
/* fall through */
#else
case 3:
if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
printk("dmasound_setup: invalid catch radius, using default = %d\n", catchRadius);
else
catchRadius = ints[3];
/* fall through */
#endif
case 2:
if (ints[1] < MIN_BUFFERS)
printk("dmasound_setup: invalid number of buffers, using default = %d\n", numWriteBufs);
......@@ -1830,9 +1546,6 @@ EXPORT_SYMBOL(dmasound_init);
EXPORT_SYMBOL(dmasound_deinit);
#endif
EXPORT_SYMBOL(dmasound_write_sq);
#ifdef HAS_RECORD
EXPORT_SYMBOL(dmasound_read_sq);
#endif
EXPORT_SYMBOL(dmasound_catchRadius);
#ifdef HAS_8BIT_TABLES
EXPORT_SYMBOL(dmasound_ulaw2dma8);
......
此差异已折叠。
/*
* 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_ */
#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
};
此差异已折叠。
/*
* 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_ */
此差异已折叠。
#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);
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册