aboutsummaryrefslogtreecommitdiff
path: root/sound/oss
diff options
context:
space:
mode:
Diffstat (limited to 'sound/oss')
-rw-r--r--sound/oss/.gitignore1
-rw-r--r--sound/oss/Kconfig155
-rw-r--r--sound/oss/Makefile22
-rw-r--r--sound/oss/ac97_codec.c1488
-rw-r--r--sound/oss/ad1848.c27
-rw-r--r--sound/oss/aedsp16.c19
-rw-r--r--sound/oss/au1550_ac97.c2129
-rw-r--r--sound/oss/audio.c10
-rw-r--r--sound/oss/btaudio.c1139
-rw-r--r--sound/oss/coproc.h2
-rw-r--r--sound/oss/cs4232.c526
-rw-r--r--sound/oss/dev_table.c22
-rw-r--r--sound/oss/dev_table.h2
-rw-r--r--sound/oss/dmabuf.c27
-rw-r--r--sound/oss/dmasound/Kconfig3
-rw-r--r--sound/oss/dmasound/Makefile6
-rw-r--r--sound/oss/dmasound/awacs_defs.h251
-rw-r--r--sound/oss/dmasound/dac3550a.c209
-rw-r--r--sound/oss/dmasound/dmasound.h18
-rw-r--r--sound/oss/dmasound/dmasound_atari.c34
-rw-r--r--sound/oss/dmasound/dmasound_awacs.c3215
-rw-r--r--sound/oss/dmasound/dmasound_core.c422
-rw-r--r--sound/oss/dmasound/dmasound_paula.c45
-rw-r--r--sound/oss/dmasound/dmasound_q40.c18
-rw-r--r--sound/oss/dmasound/tas3001c.c849
-rw-r--r--sound/oss/dmasound/tas3001c.h64
-rw-r--r--sound/oss/dmasound/tas3001c_tables.c375
-rw-r--r--sound/oss/dmasound/tas3004.c1138
-rw-r--r--sound/oss/dmasound/tas3004.h77
-rw-r--r--sound/oss/dmasound/tas3004_tables.c301
-rw-r--r--sound/oss/dmasound/tas_common.c214
-rw-r--r--sound/oss/dmasound/tas_common.h284
-rw-r--r--sound/oss/dmasound/tas_eq_prefs.h24
-rw-r--r--sound/oss/dmasound/tas_ioctl.h23
-rw-r--r--sound/oss/dmasound/trans_16.c898
-rw-r--r--sound/oss/es1371.c3131
-rw-r--r--sound/oss/hal2.c1558
-rw-r--r--sound/oss/hal2.h248
-rw-r--r--sound/oss/hex2hex.c2
-rw-r--r--sound/oss/i810_audio.c3656
-rw-r--r--sound/oss/kahlua.c21
-rw-r--r--sound/oss/midi_synth.c36
-rw-r--r--sound/oss/midi_synth.h2
-rw-r--r--sound/oss/midibuf.c31
-rw-r--r--sound/oss/mpu401.c27
-rw-r--r--sound/oss/msnd.c5
-rw-r--r--sound/oss/msnd.h8
-rw-r--r--sound/oss/msnd_classic.h2
-rw-r--r--sound/oss/msnd_pinnacle.c97
-rw-r--r--sound/oss/msnd_pinnacle.h2
-rw-r--r--sound/oss/opl3.c29
-rw-r--r--sound/oss/os.h1
-rw-r--r--sound/oss/pas2.h3
-rw-r--r--sound/oss/pas2_card.c23
-rw-r--r--sound/oss/pas2_mixer.c9
-rw-r--r--sound/oss/pas2_pcm.c28
-rw-r--r--sound/oss/pss.c72
-rw-r--r--sound/oss/sb_audio.c7
-rw-r--r--sound/oss/sb_card.c3
-rw-r--r--sound/oss/sb_common.c15
-rw-r--r--sound/oss/sb_ess.c33
-rw-r--r--sound/oss/sb_midi.c1
-rw-r--r--sound/oss/sb_mixer.c12
-rw-r--r--sound/oss/sequencer.c39
-rw-r--r--sound/oss/sh_dac_audio.c331
-rw-r--r--sound/oss/sleep.h18
-rw-r--r--sound/oss/sound_config.h26
-rw-r--r--sound/oss/sound_timer.c4
-rw-r--r--sound/oss/soundcard.c170
-rw-r--r--sound/oss/sscape.c1480
-rw-r--r--sound/oss/swarm_cs4297a.c89
-rw-r--r--sound/oss/sys_timer.c7
-rw-r--r--sound/oss/trident.c4658
-rw-r--r--sound/oss/trident.h358
-rw-r--r--sound/oss/trix.c2
-rw-r--r--sound/oss/uart401.c23
-rw-r--r--sound/oss/uart6850.c2
-rw-r--r--sound/oss/v_midi.c1
-rw-r--r--sound/oss/v_midi.h5
-rw-r--r--sound/oss/via82cxxx_audio.c3618
-rw-r--r--sound/oss/vidc.c13
-rw-r--r--sound/oss/vidc_fill.S2
-rw-r--r--sound/oss/vwsnd.c3485
-rw-r--r--sound/oss/waveartist.c24
84 files changed, 648 insertions, 36806 deletions
diff --git a/sound/oss/.gitignore b/sound/oss/.gitignore
index 7efb12b4550..12a3920d6fb 100644
--- a/sound/oss/.gitignore
+++ b/sound/oss/.gitignore
@@ -1,4 +1,3 @@
#Ignore generated files
-maui_boot.h
pss_boot.h
trix_boot.h
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index af37cd09bdd..48568fdf847 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -1,5 +1,3 @@
-# drivers/sound/Config.in
-#
# 18 Apr 1998, Michael Elizabeth Chastain, <mailto:mec@shout.net>
# More hacking for modularisation.
#
@@ -7,7 +5,7 @@
config SOUND_BCM_CS4297A
tristate "Crystal Sound CS4297a (for Swarm)"
- depends on SOUND_PRIME && SIBYTE_SWARM
+ depends on SIBYTE_SWARM
help
The BCM91250A has a Crystal CS4297a on synchronous serial
port B (in addition to the DB-9 serial port). Say Y or M
@@ -15,71 +13,9 @@ config SOUND_BCM_CS4297A
note that CONFIG_KGDB should not be enabled at the same
time, since it also attempts to use this UART port.
-config SOUND_VWSND
- tristate "SGI Visual Workstation Sound"
- depends on SOUND_PRIME && X86_VISWS
- help
- Say Y or M if you have an SGI Visual Workstation and you want to be
- able to use its on-board audio. Read
- <file:Documentation/sound/oss/vwsnd> for more info on this driver's
- capabilities.
-
-config SOUND_HAL2
- tristate "SGI HAL2 sound (EXPERIMENTAL)"
- depends on SOUND_PRIME && SGI_IP22 && EXPERIMENTAL
- help
- Say Y or M if you have an SGI Indy or Indigo2 system and want to be able to
- use its on-board A2 audio system.
-
-config SOUND_AU1550_AC97
- tristate "Au1550/Au1200 AC97 Sound"
- select SND_AC97_CODEC
- depends on SOUND_PRIME && (SOC_AU1550 || SOC_AU1200)
-
-config SOUND_TRIDENT
- tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core"
- depends on SOUND_PRIME && PCI
- ---help---
- Say Y or M if you have a PCI sound card utilizing the Trident
- 4DWave-DX/NX chipset or your mother board chipset has SiS 7018
- or ALi 5451 built-in. The SiS 7018 PCI Audio Core is embedded
- in SiS960 Super South Bridge and SiS540/630 Single Chipset.
- The ALi 5451 PCI Audio Core is embedded in ALi M1535, M1535D,
- M1535+ or M1535D+ South Bridge.
-
- Use lspci -n to find out if your sound card or chipset uses
- Trident 4DWave or SiS 7018. PCI ID 1023:2000 or 1023:2001 stands
- for Trident 4Dwave. PCI ID 1039:7018 stands for SiS7018. PCI ID
- 10B9:5451 stands for ALi5451.
-
- This driver supports S/PDIF in/out (record/playback) for ALi 5451
- embedded in ALi M1535+ and M1535D+. Note that they aren't all
- enabled by default; you can enable them by saying Y to "/proc file
- system support" and "Sysctl support", and after the /proc file
- system has been mounted, executing the command
-
- command what is enabled
-
- echo 0>/proc/ALi5451 pcm out is also set to S/PDIF out. (Default).
-
- echo 1>/proc/ALi5451 use S/PDIF out to output pcm data.
-
- echo 2>/proc/ALi5451 use S/PDIF out to output non-pcm data.
- (AC3...).
-
- echo 3>/proc/ALi5451 record from Ac97 in(MIC, Line in...).
- (Default).
-
- echo 4>/proc/ALi5451 no matter Ac97 settings, record from S/PDIF
- in.
-
-
- This driver differs slightly from OSS/Free, so PLEASE READ the
- comments at the top of <file:drivers/sound/trident.c>.
-
config SOUND_MSNDCLAS
tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey"
- depends on SOUND_PRIME && (m || !STANDALONE)
+ depends on (m || !STANDALONE) && ISA
help
Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or
Monterey (not for the Pinnacle or Fiji).
@@ -143,7 +79,7 @@ config MSNDCLAS_IO
config SOUND_MSNDPIN
tristate "Support for Turtle Beach MultiSound Pinnacle, Fiji"
- depends on SOUND_PRIME && (m || !STANDALONE)
+ depends on (m || !STANDALONE) && ISA
help
Say M here if you have a Turtle Beach MultiSound Pinnacle or Fiji.
See <file:Documentation/sound/oss/MultiSound> for important information
@@ -229,7 +165,7 @@ config MSNDPIN_NONPNP
configure the card's resources.
comment "MSND Pinnacle DSP section will be configured to above parameters."
- depends on SOUND_PRIME && SOUND_MSNDPIN=y && MSNDPIN_NONPNP
+ depends on SOUND_MSNDPIN=y && MSNDPIN_NONPNP
config MSNDPIN_CFG
hex "MSND Pinnacle config port 250,260,270"
@@ -242,7 +178,7 @@ config MSNDPIN_CFG
Mode".
comment "Pinnacle-specific Device Configuration (0 disables)"
- depends on SOUND_PRIME && SOUND_MSNDPIN=y && MSNDPIN_NONPNP
+ depends on SOUND_MSNDPIN=y && MSNDPIN_NONPNP
config MSNDPIN_MPU_IO
hex "MSND Pinnacle MPU I/O (e.g. 330)"
@@ -294,7 +230,7 @@ config MSNDPIN_JOYSTICK_IO
config MSND_FIFOSIZE
int "MSND buffer size (kB)"
- depends on SOUND_PRIME && (SOUND_MSNDPIN=y || SOUND_MSNDCLAS=y)
+ depends on SOUND_MSNDPIN=y || SOUND_MSNDCLAS=y
default "128"
help
Configures the size of each audio buffer, in kilobytes, for
@@ -302,9 +238,10 @@ config MSND_FIFOSIZE
and Pinnacle). Larger values reduce the chance of data overruns at
the expense of overall latency. If unsure, use the default.
-config SOUND_OSS
+menuconfig SOUND_OSS
tristate "OSS sound modules"
- depends on SOUND_PRIME && ISA_DMA_API && VIRT_TO_BUS
+ depends on ISA_DMA_API && VIRT_TO_BUS
+ depends on !GENERIC_ISA_DMA_SUPPORT_BROKEN
help
OSS is the Open Sound System suite of sound card drivers. They make
sound programming easier since they provide a common API. Say Y or
@@ -312,16 +249,16 @@ config SOUND_OSS
driver for your sound card above, then pick your driver from the
list below.
+if SOUND_OSS
+
config SOUND_TRACEINIT
bool "Verbose initialisation"
- depends on SOUND_OSS
help
Verbose soundcard initialization -- affects the format of autoprobe
and initialization messages at boot time.
config SOUND_DMAP
bool "Persistent DMA buffers"
- depends on SOUND_OSS
---help---
Linux can often have problems allocating DMA buffers for ISA sound
cards on machines with more than 16MB of RAM. This is because ISA
@@ -336,29 +273,13 @@ config SOUND_DMAP
Say Y unless you have 16MB or more RAM or a PCI sound card.
-config SOUND_SSCAPE
- tristate "Ensoniq SoundScape support"
- depends on SOUND_OSS
- depends on VIRT_TO_BUS
- help
- Answer Y if you have a sound card based on the Ensoniq SoundScape
- chipset. Such cards are being manufactured at least by Ensoniq, Spea
- and Reveal (Reveal makes also other cards).
-
- If you compile the driver into the kernel, you have to add
- "sscape=<io>,<irq>,<dma>,<mpuio>,<mpuirq>" to the kernel command
- line.
-
-
config SOUND_VMIDI
tristate "Loopback MIDI device support"
- depends on SOUND_OSS
help
Support for MIDI loopback on port 1 or 2.
config SOUND_TRIX
tristate "MediaTrix AudioTrix Pro support"
- depends on SOUND_OSS
help
Answer Y if you have the AudioTriX Pro sound card manufactured
by MediaTrix.
@@ -382,7 +303,6 @@ config TRIX_BOOT_FILE
config SOUND_MSS
tristate "Microsoft Sound System support"
- depends on SOUND_OSS
---help---
Again think carefully before answering Y to this question. It's
safe to answer Y if you have the original Windows Sound System card
@@ -414,7 +334,6 @@ config SOUND_MSS
config SOUND_MPU401
tristate "MPU-401 support (NOT for SB16)"
- depends on SOUND_OSS
---help---
Be careful with this question. The MPU401 interface is supported by
all sound cards. However, some natively supported cards have their
@@ -430,7 +349,6 @@ config SOUND_MPU401
config SOUND_PAS
tristate "ProAudioSpectrum 16 support"
- depends on SOUND_OSS
---help---
Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio
16 or Logitech SoundMan 16 sound card. Answer N if you have some
@@ -452,7 +370,6 @@ config PAS_JOYSTICK
config SOUND_PSS
tristate "PSS (AD1848, ADSP-2115, ESC614) support"
- depends on SOUND_OSS
help
Answer Y or M if you have an Orchid SW32, Cardinal DSP16, Beethoven
ADSP-16 or some other card based on the PSS chipset (AD1848 codec +
@@ -495,7 +412,6 @@ config PSS_BOOT_FILE
config SOUND_SB
tristate "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support"
- depends on SOUND_OSS
---help---
Answer Y if you have an original Sound Blaster card made by Creative
Labs or a 100% hardware compatible clone (like the Thunderboard or
@@ -508,9 +424,7 @@ config SOUND_SB
ALS-007 and ALS-1X0 chips (read <file:Documentation/sound/oss/ALS>) and
for cards based on ESS chips (read
<file:Documentation/sound/oss/ESS1868> and
- <file:Documentation/sound/oss/ESS>). If you have an SB AWE 32 or SB AWE
- 64, say Y here and also to "AWE32 synth" below and read
- <file:Documentation/sound/oss/INSTALL.awe>. If you have an IBM Mwave
+ <file:Documentation/sound/oss/ESS>). If you have an IBM Mwave
card, say Y here and read <file:Documentation/sound/oss/mwave>.
If you compile the driver into the kernel and don't want to use
@@ -522,7 +436,6 @@ config SOUND_SB
config SOUND_YM3812
tristate "Yamaha FM synthesizer (YM3812/OPL-3) support"
- depends on SOUND_OSS
---help---
Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
Answering Y is usually a safe and recommended choice, however some
@@ -538,7 +451,6 @@ config SOUND_YM3812
config SOUND_UART6850
tristate "6850 UART support"
- depends on SOUND_OSS
help
This option enables support for MIDI interfaces based on the 6850
UART chip. This interface is rarely found on sound cards. It's safe
@@ -549,7 +461,6 @@ config SOUND_UART6850
config SOUND_AEDSP16
tristate "Gallant Audio Cards (SC-6000 and SC-6600 based)"
- depends on SOUND_OSS
---help---
Answer Y if you have a Gallant's Audio Excel DSP 16 card. This
driver supports Audio Excel DSP 16 but not the III nor PnP versions
@@ -564,7 +475,7 @@ config SOUND_AEDSP16
questions.
Read the <file:Documentation/sound/oss/README.OSS> file and the head of
- <file:drivers/sound/aedsp16.c> as well as
+ <file:sound/oss/aedsp16.c> as well as
<file:Documentation/sound/oss/AudioExcelDSP16> to get more information
about this driver and its configuration.
@@ -600,44 +511,16 @@ config SC6600_CDROMBASE
Base I/O port address for the CD-ROM interface of the Audio Excel
DSP 16 card.
-choice
- prompt "Audio Excel DSP 16"
- optional
- depends on SOUND_AEDSP16
-
-config AEDSP16_MSS
- bool "MSS emulation"
- depends on SOUND_MSS
- help
- Answer Y if you want your audio card to emulate Microsoft Sound
- System. You should then say Y to "Microsoft Sound System support"
- and say N to "Audio Excel DSP 16 (SBPro emulation)".
-
-config AEDSP16_SBPRO
- bool "SBPro emulation"
- depends on SOUND_SB
- help
- Answer Y if you want your audio card to emulate Sound Blaster Pro.
- You should then say Y to "100% Sound Blaster compatibles
- (SB16/32/64, ESS, Jazz16) support" and N to "Audio Excel DSP 16 (MSS
- emulation)".
-
- If you compile the driver into the kernel, you have to add
- "aedsp16=<io>,<irq>,<dma>,<mssio>,<mpuio>,<mouirq>" to the kernel
- command line.
-
-endchoice
-
config SOUND_VIDC
tristate "VIDC 16-bit sound"
- depends on ARM && (ARCH_ACORN || ARCH_CLPS7500) && SOUND_OSS
+ depends on ARM && ARCH_ACORN
help
16-bit support for the VIDC onboard sound hardware found on Acorn
machines.
config SOUND_WAVEARTIST
tristate "Netwinder WaveArtist"
- depends on ARM && SOUND_OSS && ARCH_NETWINDER
+ depends on ARM && ARCH_NETWINDER
help
Say Y here to include support for the Rockwell WaveArtist sound
system. This driver is mainly for the NetWinder.
@@ -646,11 +529,5 @@ config SOUND_KAHLUA
tristate "XpressAudio Sound Blaster emulation"
depends on SOUND_SB
-config SOUND_SH_DAC_AUDIO
- tristate "SuperH DAC audio support"
- depends on SOUND_PRIME && CPU_SH3
+endif # SOUND_OSS
-config SOUND_SH_DAC_AUDIO_CHANNEL
- int "DAC channel"
- default "1"
- depends on SOUND_SH_DAC_AUDIO
diff --git a/sound/oss/Makefile b/sound/oss/Makefile
index 1200670017b..9bdbbde2173 100644
--- a/sound/oss/Makefile
+++ b/sound/oss/Makefile
@@ -6,17 +6,12 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_SOUND_OSS) += sound.o
-obj-$(CONFIG_SOUND_CS4232) += cs4232.o ad1848.o
# Please leave it as is, cause the link order is significant !
-obj-$(CONFIG_SOUND_SH_DAC_AUDIO) += sh_dac_audio.o
-obj-$(CONFIG_SOUND_HAL2) += hal2.o
obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o
obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o
obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o
-obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o
-obj-$(CONFIG_SOUND_CS4232) += cs4232.o uart401.o
obj-$(CONFIG_SOUND_MSS) += ad1848.o
obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o sb_lib.o uart401.o
obj-$(CONFIG_SOUND_SB) += sb.o sb_lib.o uart401.o
@@ -27,22 +22,9 @@ obj-$(CONFIG_SOUND_YM3812) += opl3.o
obj-$(CONFIG_SOUND_VMIDI) += v_midi.o
obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o
obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o
-
-obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx_audio.o ac97_codec.o
-ifeq ($(CONFIG_MIDI_VIA82CXXX),y)
- obj-$(CONFIG_SOUND_VIA82CXXX) += sound.o uart401.o
-endif
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
-obj-$(CONFIG_SOUND_BT878) += btaudio.o
-
-obj-$(CONFIG_SOUND_WM97XX) += ac97_plugin_wm97xx.o
obj-$(CONFIG_DMASOUND) += dmasound/
@@ -103,7 +85,7 @@ ifeq ($(CONFIG_PSS_HAVE_BOOT),y)
$(obj)/bin2hex pss_synth < $< > $@
else
$(obj)/pss_boot.h:
- ( \
+ $(Q)( \
echo 'static unsigned char * pss_synth = NULL;'; \
echo 'static int pss_synthLen = 0;'; \
) > $@
@@ -118,7 +100,7 @@ ifeq ($(CONFIG_TRIX_HAVE_BOOT),y)
$(obj)/hex2hex -i trix_boot < $< > $@
else
$(obj)/trix_boot.h:
- ( \
+ $(Q)( \
echo 'static unsigned char * trix_boot = NULL;'; \
echo 'static int trix_boot_len = 0;'; \
) > $@
diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c
deleted file mode 100644
index fef56cac06c..00000000000
--- a/sound/oss/ac97_codec.c
+++ /dev/null
@@ -1,1488 +0,0 @@
-/*
- * ac97_codec.c: Generic AC97 mixer/modem module
- *
- * Derived from ac97 mixer in maestro and trident driver.
- *
- * Copyright 2000 Silicon Integrated System Corporation
- *
- * 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.
- *
- **************************************************************************
- *
- * The Intel Audio Codec '97 specification is available at the Intel
- * audio homepage: http://developer.intel.com/ial/scalableplatforms/audio/
- *
- * The specification itself is currently available at:
- * ftp://download.intel.com/ial/scalableplatforms/ac97r22.pdf
- *
- **************************************************************************
- *
- * History
- * May 02, 2003 Liam Girdwood <liam.girdwood@wolfsonmicro.com>
- * Removed non existant WM9700
- * Added support for WM9705, WM9708, WM9709, WM9710, WM9711
- * WM9712 and WM9717
- * Mar 28, 2002 Randolph Bentson <bentson@holmsjoen.com>
- * corrections to support WM9707 in ViewPad 1000
- * v0.4 Mar 15 2000 Ollie Lho
- * dual codecs support verified with 4 channels output
- * v0.3 Feb 22 2000 Ollie Lho
- * bug fix for record mask setting
- * v0.2 Feb 10 2000 Ollie Lho
- * add ac97_read_proc for /proc/driver/{vendor}/ac97
- * v0.1 Jan 14 2000 Ollie Lho <ollie@sis.com.tw>
- * Isolated from trident.c to support multiple ac97 codec
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/ac97_codec.h>
-#include <asm/uaccess.h>
-#include <linux/mutex.h>
-
-#define CODEC_ID_BUFSZ 14
-
-static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel);
-static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel,
- unsigned int left, unsigned int right);
-static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val );
-static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask);
-static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg);
-
-static int ac97_init_mixer(struct ac97_codec *codec);
-
-static int wolfson_init03(struct ac97_codec * codec);
-static int wolfson_init04(struct ac97_codec * codec);
-static int wolfson_init05(struct ac97_codec * codec);
-static int wolfson_init11(struct ac97_codec * codec);
-static int wolfson_init13(struct ac97_codec * codec);
-static int tritech_init(struct ac97_codec * codec);
-static int tritech_maestro_init(struct ac97_codec * codec);
-static int sigmatel_9708_init(struct ac97_codec *codec);
-static int sigmatel_9721_init(struct ac97_codec *codec);
-static int sigmatel_9744_init(struct ac97_codec *codec);
-static int ad1886_init(struct ac97_codec *codec);
-static int eapd_control(struct ac97_codec *codec, int);
-static int crystal_digital_control(struct ac97_codec *codec, int slots, int rate, int mode);
-static int cmedia_init(struct ac97_codec * codec);
-static int cmedia_digital_control(struct ac97_codec *codec, int slots, int rate, int mode);
-static int generic_digital_control(struct ac97_codec *codec, int slots, int rate, int mode);
-
-
-/*
- * AC97 operations.
- *
- * If you are adding a codec then you should be able to use
- * eapd_ops - any codec that supports EAPD amp control (most)
- * null_ops - any ancient codec that supports nothing
- *
- * The three functions are
- * init - used for non AC97 standard initialisation
- * amplifier - used to do amplifier control (1=on 0=off)
- * digital - switch to digital modes (0 = analog)
- *
- * Not all codecs support all features, not all drivers use all the
- * operations yet
- */
-
-static struct ac97_ops null_ops = { NULL, NULL, NULL };
-static struct ac97_ops default_ops = { NULL, eapd_control, NULL };
-static struct ac97_ops default_digital_ops = { NULL, eapd_control, generic_digital_control};
-static struct ac97_ops wolfson_ops03 = { wolfson_init03, NULL, NULL };
-static struct ac97_ops wolfson_ops04 = { wolfson_init04, NULL, NULL };
-static struct ac97_ops wolfson_ops05 = { wolfson_init05, NULL, NULL };
-static struct ac97_ops wolfson_ops11 = { wolfson_init11, NULL, NULL };
-static struct ac97_ops wolfson_ops13 = { wolfson_init13, NULL, NULL };
-static struct ac97_ops tritech_ops = { tritech_init, NULL, NULL };
-static struct ac97_ops tritech_m_ops = { tritech_maestro_init, NULL, NULL };
-static struct ac97_ops sigmatel_9708_ops = { sigmatel_9708_init, NULL, NULL };
-static struct ac97_ops sigmatel_9721_ops = { sigmatel_9721_init, NULL, NULL };
-static struct ac97_ops sigmatel_9744_ops = { sigmatel_9744_init, NULL, NULL };
-static struct ac97_ops crystal_digital_ops = { NULL, eapd_control, crystal_digital_control };
-static struct ac97_ops ad1886_ops = { ad1886_init, eapd_control, NULL };
-static struct ac97_ops cmedia_ops = { NULL, eapd_control, NULL};
-static struct ac97_ops cmedia_digital_ops = { cmedia_init, eapd_control, cmedia_digital_control};
-
-/* sorted by vendor/device id */
-static const struct {
- u32 id;
- char *name;
- struct ac97_ops *ops;
- int flags;
-} ac97_codec_ids[] = {
- {0x41445303, "Analog Devices AD1819", &null_ops},
- {0x41445340, "Analog Devices AD1881", &null_ops},
- {0x41445348, "Analog Devices AD1881A", &null_ops},
- {0x41445360, "Analog Devices AD1885", &default_ops},
- {0x41445361, "Analog Devices AD1886", &ad1886_ops},
- {0x41445370, "Analog Devices AD1981", &null_ops},
- {0x41445372, "Analog Devices AD1981A", &null_ops},
- {0x41445374, "Analog Devices AD1981B", &null_ops},
- {0x41445460, "Analog Devices AD1885", &default_ops},
- {0x41445461, "Analog Devices AD1886", &ad1886_ops},
- {0x414B4D00, "Asahi Kasei AK4540", &null_ops},
- {0x414B4D01, "Asahi Kasei AK4542", &null_ops},
- {0x414B4D02, "Asahi Kasei AK4543", &null_ops},
- {0x414C4326, "ALC100P", &null_ops},
- {0x414C4710, "ALC200/200P", &null_ops},
- {0x414C4720, "ALC650", &default_digital_ops},
- {0x434D4941, "CMedia", &cmedia_ops, AC97_NO_PCM_VOLUME },
- {0x434D4942, "CMedia", &cmedia_ops, AC97_NO_PCM_VOLUME },
- {0x434D4961, "CMedia", &cmedia_digital_ops, AC97_NO_PCM_VOLUME },
- {0x43525900, "Cirrus Logic CS4297", &default_ops},
- {0x43525903, "Cirrus Logic CS4297", &default_ops},
- {0x43525913, "Cirrus Logic CS4297A rev A", &default_ops},
- {0x43525914, "Cirrus Logic CS4297A rev B", &default_ops},
- {0x43525923, "Cirrus Logic CS4298", &null_ops},
- {0x4352592B, "Cirrus Logic CS4294", &null_ops},
- {0x4352592D, "Cirrus Logic CS4294", &null_ops},
- {0x43525931, "Cirrus Logic CS4299 rev A", &crystal_digital_ops},
- {0x43525933, "Cirrus Logic CS4299 rev C", &crystal_digital_ops},
- {0x43525934, "Cirrus Logic CS4299 rev D", &crystal_digital_ops},
- {0x43585430, "CXT48", &default_ops, AC97_DELUDED_MODEM },
- {0x43585442, "CXT66", &default_ops, AC97_DELUDED_MODEM },
- {0x44543031, "Diamond Technology DT0893", &default_ops},
- {0x45838308, "ESS Allegro ES1988", &null_ops},
- {0x49434511, "ICE1232", &null_ops}, /* I hope --jk */
- {0x4e534331, "National Semiconductor LM4549", &null_ops},
- {0x53494c22, "Silicon Laboratory Si3036", &null_ops},
- {0x53494c23, "Silicon Laboratory Si3038", &null_ops},
- {0x545200FF, "TriTech TR?????", &tritech_m_ops},
- {0x54524102, "TriTech TR28022", &null_ops},
- {0x54524103, "TriTech TR28023", &null_ops},
- {0x54524106, "TriTech TR28026", &null_ops},
- {0x54524108, "TriTech TR28028", &tritech_ops},
- {0x54524123, "TriTech TR A5", &null_ops},
- {0x574D4C03, "Wolfson WM9703/07/08/17", &wolfson_ops03},
- {0x574D4C04, "Wolfson WM9704M/WM9704Q", &wolfson_ops04},
- {0x574D4C05, "Wolfson WM9705/WM9710", &wolfson_ops05},
- {0x574D4C09, "Wolfson WM9709", &null_ops},
- {0x574D4C12, "Wolfson WM9711/9712", &wolfson_ops11},
- {0x574D4C13, "Wolfson WM9713", &wolfson_ops13, AC97_DEFAULT_POWER_OFF},
- {0x83847600, "SigmaTel STAC????", &null_ops},
- {0x83847604, "SigmaTel STAC9701/3/4/5", &null_ops},
- {0x83847605, "SigmaTel STAC9704", &null_ops},
- {0x83847608, "SigmaTel STAC9708", &sigmatel_9708_ops},
- {0x83847609, "SigmaTel STAC9721/23", &sigmatel_9721_ops},
- {0x83847644, "SigmaTel STAC9744/45", &sigmatel_9744_ops},
- {0x83847652, "SigmaTel STAC9752/53", &default_ops},
- {0x83847656, "SigmaTel STAC9756/57", &sigmatel_9744_ops},
- {0x83847666, "SigmaTel STAC9750T", &sigmatel_9744_ops},
- {0x83847684, "SigmaTel STAC9783/84?", &null_ops},
- {0x57454301, "Winbond 83971D", &null_ops},
-};
-
-static const char *ac97_stereo_enhancements[] =
-{
- /* 0 */ "No 3D Stereo Enhancement",
- /* 1 */ "Analog Devices Phat Stereo",
- /* 2 */ "Creative Stereo Enhancement",
- /* 3 */ "National Semi 3D Stereo Enhancement",
- /* 4 */ "YAMAHA Ymersion",
- /* 5 */ "BBE 3D Stereo Enhancement",
- /* 6 */ "Crystal Semi 3D Stereo Enhancement",
- /* 7 */ "Qsound QXpander",
- /* 8 */ "Spatializer 3D Stereo Enhancement",
- /* 9 */ "SRS 3D Stereo Enhancement",
- /* 10 */ "Platform Tech 3D Stereo Enhancement",
- /* 11 */ "AKM 3D Audio",
- /* 12 */ "Aureal Stereo Enhancement",
- /* 13 */ "Aztech 3D Enhancement",
- /* 14 */ "Binaura 3D Audio Enhancement",
- /* 15 */ "ESS Technology Stereo Enhancement",
- /* 16 */ "Harman International VMAx",
- /* 17 */ "Nvidea 3D Stereo Enhancement",
- /* 18 */ "Philips Incredible Sound",
- /* 19 */ "Texas Instruments 3D Stereo Enhancement",
- /* 20 */ "VLSI Technology 3D Stereo Enhancement",
- /* 21 */ "TriTech 3D Stereo Enhancement",
- /* 22 */ "Realtek 3D Stereo Enhancement",
- /* 23 */ "Samsung 3D Stereo Enhancement",
- /* 24 */ "Wolfson Microelectronics 3D Enhancement",
- /* 25 */ "Delta Integration 3D Enhancement",
- /* 26 */ "SigmaTel 3D Enhancement",
- /* 27 */ "Winbond 3D Stereo Enhancement",
- /* 28 */ "Rockwell 3D Stereo Enhancement",
- /* 29 */ "Reserved 29",
- /* 30 */ "Reserved 30",
- /* 31 */ "Reserved 31"
-};
-
-/* this table has default mixer values for all OSS mixers. */
-static struct mixer_defaults {
- int mixer;
- unsigned int value;
-} mixer_defaults[SOUND_MIXER_NRDEVICES] = {
- /* all values 0 -> 100 in bytes */
- {SOUND_MIXER_VOLUME, 0x4343},
- {SOUND_MIXER_BASS, 0x4343},
- {SOUND_MIXER_TREBLE, 0x4343},
- {SOUND_MIXER_PCM, 0x4343},
- {SOUND_MIXER_SPEAKER, 0x4343},
- {SOUND_MIXER_LINE, 0x4343},
- {SOUND_MIXER_MIC, 0x0000},
- {SOUND_MIXER_CD, 0x4343},
- {SOUND_MIXER_ALTPCM, 0x4343},
- {SOUND_MIXER_IGAIN, 0x4343},
- {SOUND_MIXER_LINE1, 0x4343},
- {SOUND_MIXER_PHONEIN, 0x4343},
- {SOUND_MIXER_PHONEOUT, 0x4343},
- {SOUND_MIXER_VIDEO, 0x4343},
- {-1,0}
-};
-
-/* table to scale scale from OSS mixer value to AC97 mixer register value */
-static struct ac97_mixer_hw {
- unsigned char offset;
- int scale;
-} ac97_hw[SOUND_MIXER_NRDEVICES]= {
- [SOUND_MIXER_VOLUME] = {AC97_MASTER_VOL_STEREO,64},
- [SOUND_MIXER_BASS] = {AC97_MASTER_TONE, 16},
- [SOUND_MIXER_TREBLE] = {AC97_MASTER_TONE, 16},
- [SOUND_MIXER_PCM] = {AC97_PCMOUT_VOL, 32},
- [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 16},
- [SOUND_MIXER_LINE] = {AC97_LINEIN_VOL, 32},
- [SOUND_MIXER_MIC] = {AC97_MIC_VOL, 32},
- [SOUND_MIXER_CD] = {AC97_CD_VOL, 32},
- [SOUND_MIXER_ALTPCM] = {AC97_HEADPHONE_VOL, 64},
- [SOUND_MIXER_IGAIN] = {AC97_RECORD_GAIN, 16},
- [SOUND_MIXER_LINE1] = {AC97_AUX_VOL, 32},
- [SOUND_MIXER_PHONEIN] = {AC97_PHONE_VOL, 32},
- [SOUND_MIXER_PHONEOUT] = {AC97_MASTER_VOL_MONO, 64},
- [SOUND_MIXER_VIDEO] = {AC97_VIDEO_VOL, 32},
-};
-
-/* the following tables allow us to go from OSS <-> ac97 quickly. */
-enum ac97_recsettings {
- AC97_REC_MIC=0,
- AC97_REC_CD,
- AC97_REC_VIDEO,
- AC97_REC_AUX,
- AC97_REC_LINE,
- AC97_REC_STEREO, /* combination of all enabled outputs.. */
- AC97_REC_MONO, /*.. or the mono equivalent */
- AC97_REC_PHONE
-};
-
-static const unsigned int ac97_rm2oss[] = {
- [AC97_REC_MIC] = SOUND_MIXER_MIC,
- [AC97_REC_CD] = SOUND_MIXER_CD,
- [AC97_REC_VIDEO] = SOUND_MIXER_VIDEO,
- [AC97_REC_AUX] = SOUND_MIXER_LINE1,
- [AC97_REC_LINE] = SOUND_MIXER_LINE,
- [AC97_REC_STEREO]= SOUND_MIXER_IGAIN,
- [AC97_REC_PHONE] = SOUND_MIXER_PHONEIN
-};
-
-/* indexed by bit position */
-static const unsigned int ac97_oss_rm[] = {
- [SOUND_MIXER_MIC] = AC97_REC_MIC,
- [SOUND_MIXER_CD] = AC97_REC_CD,
- [SOUND_MIXER_VIDEO] = AC97_REC_VIDEO,
- [SOUND_MIXER_LINE1] = AC97_REC_AUX,
- [SOUND_MIXER_LINE] = AC97_REC_LINE,
- [SOUND_MIXER_IGAIN] = AC97_REC_STEREO,
- [SOUND_MIXER_PHONEIN] = AC97_REC_PHONE
-};
-
-static LIST_HEAD(codecs);
-static LIST_HEAD(codec_drivers);
-static DEFINE_MUTEX(codec_mutex);
-
-/* reads the given OSS mixer from the ac97 the caller must have insured that the ac97 knows
- about that given mixer, and should be holding a spinlock for the card */
-static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel)
-{
- u16 val;
- int ret = 0;
- int scale;
- struct ac97_mixer_hw *mh = &ac97_hw[oss_channel];
-
- val = codec->codec_read(codec , mh->offset);
-
- if (val & AC97_MUTE) {
- ret = 0;
- } else if (AC97_STEREO_MASK & (1 << oss_channel)) {
- /* nice stereo mixers .. */
- int left,right;
-
- left = (val >> 8) & 0x7f;
- right = val & 0x7f;
-
- if (oss_channel == SOUND_MIXER_IGAIN) {
- right = (right * 100) / mh->scale;
- left = (left * 100) / mh->scale;
- } else {
- /* these may have 5 or 6 bit resolution */
- if(oss_channel == SOUND_MIXER_VOLUME || oss_channel == SOUND_MIXER_ALTPCM)
- scale = (1 << codec->bit_resolution);
- else
- scale = mh->scale;
-
- right = 100 - ((right * 100) / scale);
- left = 100 - ((left * 100) / scale);
- }
- ret = left | (right << 8);
- } else if (oss_channel == SOUND_MIXER_SPEAKER) {
- ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale);
- } else if (oss_channel == SOUND_MIXER_PHONEIN) {
- ret = 100 - (((val & 0x1f) * 100) / mh->scale);
- } else if (oss_channel == SOUND_MIXER_PHONEOUT) {
- scale = (1 << codec->bit_resolution);
- ret = 100 - (((val & 0x1f) * 100) / scale);
- } else if (oss_channel == SOUND_MIXER_MIC) {
- ret = 100 - (((val & 0x1f) * 100) / mh->scale);
- /* the low bit is optional in the tone sliders and masking
- it lets us avoid the 0xf 'bypass'.. */
- } else if (oss_channel == SOUND_MIXER_BASS) {
- ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale);
- } else if (oss_channel == SOUND_MIXER_TREBLE) {
- ret = 100 - (((val & 0xe) * 100) / mh->scale);
- }
-
-#ifdef DEBUG
- printk("ac97_codec: read OSS mixer %2d (%s ac97 register 0x%02x), "
- "0x%04x -> 0x%04x\n",
- oss_channel, codec->id ? "Secondary" : "Primary",
- mh->offset, val, ret);
-#endif
-
- return ret;
-}
-
-/* write the OSS encoded volume to the given OSS encoded mixer, again caller's job to
- make sure all is well in arg land, call with spinlock held */
-static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel,
- unsigned int left, unsigned int right)
-{
- u16 val = 0;
- int scale;
- struct ac97_mixer_hw *mh = &ac97_hw[oss_channel];
-
-#ifdef DEBUG
- printk("ac97_codec: wrote OSS mixer %2d (%s ac97 register 0x%02x), "
- "left vol:%2d, right vol:%2d:",
- oss_channel, codec->id ? "Secondary" : "Primary",
- mh->offset, left, right);
-#endif
-
- if (AC97_STEREO_MASK & (1 << oss_channel)) {
- /* stereo mixers */
- if (left == 0 && right == 0) {
- val = AC97_MUTE;
- } else {
- if (oss_channel == SOUND_MIXER_IGAIN) {
- right = (right * mh->scale) / 100;
- left = (left * mh->scale) / 100;
- if (right >= mh->scale)
- right = mh->scale-1;
- if (left >= mh->scale)
- left = mh->scale-1;
- } else {
- /* these may have 5 or 6 bit resolution */
- if (oss_channel == SOUND_MIXER_VOLUME ||
- oss_channel == SOUND_MIXER_ALTPCM)
- scale = (1 << codec->bit_resolution);
- else
- scale = mh->scale;
-
- right = ((100 - right) * scale) / 100;
- left = ((100 - left) * scale) / 100;
- if (right >= scale)
- right = scale-1;
- if (left >= scale)
- left = scale-1;
- }
- val = (left << 8) | right;
- }
- } else if (oss_channel == SOUND_MIXER_BASS) {
- val = codec->codec_read(codec , mh->offset) & ~0x0f00;
- left = ((100 - left) * mh->scale) / 100;
- if (left >= mh->scale)
- left = mh->scale-1;
- val |= (left << 8) & 0x0e00;
- } else if (oss_channel == SOUND_MIXER_TREBLE) {
- val = codec->codec_read(codec , mh->offset) & ~0x000f;
- left = ((100 - left) * mh->scale) / 100;
- if (left >= mh->scale)
- left = mh->scale-1;
- val |= left & 0x000e;
- } else if(left == 0) {
- val = AC97_MUTE;
- } else if (oss_channel == SOUND_MIXER_SPEAKER) {
- left = ((100 - left) * mh->scale) / 100;
- if (left >= mh->scale)
- left = mh->scale-1;
- val = left << 1;
- } else if (oss_channel == SOUND_MIXER_PHONEIN) {
- left = ((100 - left) * mh->scale) / 100;
- if (left >= mh->scale)
- left = mh->scale-1;
- val = left;
- } else if (oss_channel == SOUND_MIXER_PHONEOUT) {
- scale = (1 << codec->bit_resolution);
- left = ((100 - left) * scale) / 100;
- if (left >= mh->scale)
- left = mh->scale-1;
- val = left;
- } else if (oss_channel == SOUND_MIXER_MIC) {
- val = codec->codec_read(codec , mh->offset) & ~0x801f;
- left = ((100 - left) * mh->scale) / 100;
- if (left >= mh->scale)
- left = mh->scale-1;
- val |= left;
- /* the low bit is optional in the tone sliders and masking
- it lets us avoid the 0xf 'bypass'.. */
- }
-#ifdef DEBUG
- printk(" 0x%04x", val);
-#endif
-
- codec->codec_write(codec, mh->offset, val);
-
-#ifdef DEBUG
- val = codec->codec_read(codec, mh->offset);
- printk(" -> 0x%04x\n", val);
-#endif
-}
-
-/* a thin wrapper for write_mixer */
-static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val )
-{
- unsigned int left,right;
-
- /* cleanse input a little */
- right = ((val >> 8) & 0xff) ;
- left = (val & 0xff) ;
-
- if (right > 100) right = 100;
- if (left > 100) left = 100;
-
- codec->mixer_state[oss_mixer] = (right << 8) | left;
- codec->write_mixer(codec, oss_mixer, left, right);
-}
-
-/* read or write the recmask, the ac97 can really have left and right recording
- inputs independantly set, but OSS doesn't seem to want us to express that to
- the user. the caller guarantees that we have a supported bit set, and they
- must be holding the card's spinlock */
-static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask)
-{
- unsigned int val;
-
- if (rw) {
- /* read it from the card */
- val = codec->codec_read(codec, AC97_RECORD_SELECT);
-#ifdef DEBUG
- printk("ac97_codec: ac97 recmask to set to 0x%04x\n", val);
-#endif
- return (1 << ac97_rm2oss[val & 0x07]);
- }
-
- /* else, write the first set in the mask as the
- output */
- /* clear out current set value first (AC97 supports only 1 input!) */
- val = (1 << ac97_rm2oss[codec->codec_read(codec, AC97_RECORD_SELECT) & 0x07]);
- if (mask != val)
- mask &= ~val;
-
- val = ffs(mask);
- val = ac97_oss_rm[val-1];
- val |= val << 8; /* set both channels */
-
-#ifdef DEBUG
- printk("ac97_codec: setting ac97 recmask to 0x%04x\n", val);
-#endif
-
- codec->codec_write(codec, AC97_RECORD_SELECT, val);
-
- return 0;
-};
-
-static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg)
-{
- int i, val = 0;
-
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- memset(&info, 0, sizeof(info));
- strlcpy(info.id, codec->name, sizeof(info.id));
- strlcpy(info.name, codec->name, sizeof(info.name));
- info.modify_counter = codec->modcnt;
- if (copy_to_user((void __user *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == SOUND_OLD_MIXER_INFO) {
- _old_mixer_info info;
- memset(&info, 0, sizeof(info));
- strlcpy(info.id, codec->name, sizeof(info.id));
- strlcpy(info.name, codec->name, sizeof(info.name));
- if (copy_to_user((void __user *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
-
- if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
- return -EINVAL;
-
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, (int __user *)arg);
-
- if (_SIOC_DIR(cmd) == _SIOC_READ) {
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* give them the current record source */
- if (!codec->recmask_io) {
- val = 0;
- } else {
- val = codec->recmask_io(codec, 1, 0);
- }
- break;
-
- case SOUND_MIXER_DEVMASK: /* give them the supported mixers */
- val = codec->supported_mixers;
- break;
-
- case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
- val = codec->record_sources;
- break;
-
- case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
- val = codec->stereo_mixers;
- break;
-
- case SOUND_MIXER_CAPS:
- val = SOUND_CAP_EXCL_INPUT;
- break;
-
- default: /* read a specific mixer */
- i = _IOC_NR(cmd);
-
- if (!supported_mixer(codec, i))
- return -EINVAL;
-
- /* do we ever want to touch the hardware? */
- /* val = codec->read_mixer(codec, i); */
- val = codec->mixer_state[i];
- break;
- }
- return put_user(val, (int __user *)arg);
- }
-
- if (_SIOC_DIR(cmd) == (_SIOC_WRITE|_SIOC_READ)) {
- codec->modcnt++;
- if (get_user(val, (int __user *)arg))
- return -EFAULT;
-
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- if (!codec->recmask_io) return -EINVAL;
- if (!val) return 0;
- if (!(val &= codec->record_sources)) return -EINVAL;
-
- codec->recmask_io(codec, 0, val);
-
- return 0;
- default: /* write a specific mixer */
- i = _IOC_NR(cmd);
-
- if (!supported_mixer(codec, i))
- return -EINVAL;
-
- ac97_set_mixer(codec, i, val);
-
- return 0;
- }
- }
- return -EINVAL;
-}
-
-/* entry point for /proc/driver/controller_vendor/ac97/%d */
-int ac97_read_proc (char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len = 0, cap, extid, val, id1, id2;
- struct ac97_codec *codec;
- int is_ac97_20 = 0;
-
- if ((codec = data) == NULL)
- return -ENODEV;
-
- id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
- id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
- len += sprintf (page+len, "Vendor name : %s\n", codec->name);
- len += sprintf (page+len, "Vendor id : %04X %04X\n", id1, id2);
-
- extid = codec->codec_read(codec, AC97_EXTENDED_ID);
- extid &= ~((1<<2)|(1<<4)|(1<<5)|(1<<10)|(1<<11)|(1<<12)|(1<<13));
- len += sprintf (page+len, "AC97 Version : %s\n",
- extid ? "2.0 or later" : "1.0");
- if (extid) is_ac97_20 = 1;
-
- cap = codec->codec_read(codec, AC97_RESET);
- len += sprintf (page+len, "Capabilities :%s%s%s%s%s%s\n",
- cap & 0x0001 ? " -dedicated MIC PCM IN channel-" : "",
- cap & 0x0002 ? " -reserved1-" : "",
- cap & 0x0004 ? " -bass & treble-" : "",
- cap & 0x0008 ? " -simulated stereo-" : "",
- cap & 0x0010 ? " -headphone out-" : "",
- cap & 0x0020 ? " -loudness-" : "");
- val = cap & 0x00c0;
- len += sprintf (page+len, "DAC resolutions :%s%s%s\n",
- " -16-bit-",
- val & 0x0040 ? " -18-bit-" : "",
- val & 0x0080 ? " -20-bit-" : "");
- val = cap & 0x0300;
- len += sprintf (page+len, "ADC resolutions :%s%s%s\n",
- " -16-bit-",
- val & 0x0100 ? " -18-bit-" : "",
- val & 0x0200 ? " -20-bit-" : "");
- len += sprintf (page+len, "3D enhancement : %s\n",
- ac97_stereo_enhancements[(cap >> 10) & 0x1f]);
-
- val = codec->codec_read(codec, AC97_GENERAL_PURPOSE);
- len += sprintf (page+len, "POP path : %s 3D\n"
- "Sim. stereo : %s\n"
- "3D enhancement : %s\n"
- "Loudness : %s\n"
- "Mono output : %s\n"
- "MIC select : %s\n"
- "ADC/DAC loopback : %s\n",
- val & 0x8000 ? "post" : "pre",
- val & 0x4000 ? "on" : "off",
- val & 0x2000 ? "on" : "off",
- val & 0x1000 ? "on" : "off",
- val & 0x0200 ? "MIC" : "MIX",
- val & 0x0100 ? "MIC2" : "MIC1",
- val & 0x0080 ? "on" : "off");
-
- extid = codec->codec_read(codec, AC97_EXTENDED_ID);
- cap = extid;
- len += sprintf (page+len, "Ext Capabilities :%s%s%s%s%s%s%s\n",
- cap & 0x0001 ? " -var rate PCM audio-" : "",
- cap & 0x0002 ? " -2x PCM audio out-" : "",
- cap & 0x0008 ? " -var rate MIC in-" : "",
- cap & 0x0040 ? " -PCM center DAC-" : "",
- cap & 0x0080 ? " -PCM surround DAC-" : "",
- cap & 0x0100 ? " -PCM LFE DAC-" : "",
- cap & 0x0200 ? " -slot/DAC mappings-" : "");
- if (is_ac97_20) {
- len += sprintf (page+len, "Front DAC rate : %d\n",
- codec->codec_read(codec, AC97_PCM_FRONT_DAC_RATE));
- }
-
- return len;
-}
-
-/**
- * codec_id - Turn id1/id2 into a PnP string
- * @id1: Vendor ID1
- * @id2: Vendor ID2
- * @buf: CODEC_ID_BUFSZ byte buffer
- *
- * Fills buf with a zero terminated PnP ident string for the id1/id2
- * pair. For convenience the return is the passed in buffer pointer.
- */
-
-static char *codec_id(u16 id1, u16 id2, char *buf)
-{
- if(id1&0x8080) {
- snprintf(buf, CODEC_ID_BUFSZ, "0x%04x:0x%04x", id1, id2);
- } else {
- buf[0] = (id1 >> 8);
- buf[1] = (id1 & 0xFF);
- buf[2] = (id2 >> 8);
- snprintf(buf+3, CODEC_ID_BUFSZ - 3, "%d", id2&0xFF);
- }
- return buf;
-}
-
-/**
- * ac97_check_modem - Check if the Codec is a modem
- * @codec: codec to check
- *
- * Return true if the device is an AC97 1.0 or AC97 2.0 modem
- */
-
-static int ac97_check_modem(struct ac97_codec *codec)
-{
- /* Check for an AC97 1.0 soft modem (ID1) */
- if(codec->codec_read(codec, AC97_RESET) & 2)
- return 1;
- /* Check for an AC97 2.x soft modem */
- codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0L);
- if(codec->codec_read(codec, AC97_EXTENDED_MODEM_ID) & 1)
- return 1;
- return 0;
-}
-
-
-/**
- * ac97_alloc_codec - Allocate an AC97 codec
- *
- * Returns a new AC97 codec structure. AC97 codecs may become
- * refcounted soon so this interface is needed. Returns with
- * one reference taken.
- */
-
-struct ac97_codec *ac97_alloc_codec(void)
-{
- struct ac97_codec *codec = kzalloc(sizeof(struct ac97_codec), GFP_KERNEL);
- if(!codec)
- return NULL;
-
- spin_lock_init(&codec->lock);
- INIT_LIST_HEAD(&codec->list);
- return codec;
-}
-
-EXPORT_SYMBOL(ac97_alloc_codec);
-
-/**
- * ac97_release_codec - Release an AC97 codec
- * @codec: codec to release
- *
- * Release an allocated AC97 codec. This will be refcounted in
- * time but for the moment is trivial. Calls the unregister
- * handler if the codec is now defunct.
- */
-
-void ac97_release_codec(struct ac97_codec *codec)
-{
- /* Remove from the list first, we don't want to be
- "rediscovered" */
- mutex_lock(&codec_mutex);
- list_del(&codec->list);
- mutex_unlock(&codec_mutex);
- /*
- * The driver needs to deal with internal
- * locking to avoid accidents here.
- */
- if(codec->driver)
- codec->driver->remove(codec, codec->driver);
- kfree(codec);
-}
-
-EXPORT_SYMBOL(ac97_release_codec);
-
-/**
- * ac97_probe_codec - Initialize and setup AC97-compatible codec
- * @codec: (in/out) Kernel info for a single AC97 codec
- *
- * Reset the AC97 codec, then initialize the mixer and
- * the rest of the @codec structure.
- *
- * The codec_read and codec_write fields of @codec are
- * required to be setup and working when this function
- * is called. All other fields are set by this function.
- *
- * codec_wait field of @codec can optionally be provided
- * when calling this function. If codec_wait is not %NULL,
- * this function will call codec_wait any time it is
- * necessary to wait for the audio chip to reach the
- * codec-ready state. If codec_wait is %NULL, then
- * the default behavior is to call schedule_timeout.
- * Currently codec_wait is used to wait for AC97 codec
- * reset to complete.
- *
- * Some codecs will power down when a register reset is
- * performed. We now check for such codecs.
- *
- * Returns 1 (true) on success, or 0 (false) on failure.
- */
-
-int ac97_probe_codec(struct ac97_codec *codec)
-{
- u16 id1, id2;
- u16 audio;
- int i;
- char cidbuf[CODEC_ID_BUFSZ];
- u16 f;
- struct list_head *l;
- struct ac97_driver *d;
-
- /* wait for codec-ready state */
- if (codec->codec_wait)
- codec->codec_wait(codec);
- else
- udelay(10);
-
- /* will the codec power down if register reset ? */
- id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
- id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
- codec->name = NULL;
- codec->codec_ops = &null_ops;
- for (i = 0; i < ARRAY_SIZE(ac97_codec_ids); i++) {
- if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
- codec->type = ac97_codec_ids[i].id;
- codec->name = ac97_codec_ids[i].name;
- codec->codec_ops = ac97_codec_ids[i].ops;
- codec->flags = ac97_codec_ids[i].flags;
- break;
- }
- }
-
- codec->model = (id1 << 16) | id2;
- if ((codec->flags & AC97_DEFAULT_POWER_OFF) == 0) {
- /* reset codec and wait for the ready bit before we continue */
- codec->codec_write(codec, AC97_RESET, 0L);
- if (codec->codec_wait)
- codec->codec_wait(codec);
- else
- udelay(10);
- }
-
- /* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should
- * be read zero.
- *
- * FIXME: is the following comment outdated? -jgarzik
- * Probing of AC97 in this way is not reliable, it is not even SAFE !!
- */
- if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) {
- printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n",
- (codec->id & 0x2) ? (codec->id&1 ? "4th" : "Tertiary")
- : (codec->id&1 ? "Secondary": "Primary"));
- return 0;
- }
-
- /* probe for Modem Codec */
- codec->modem = ac97_check_modem(codec);
-
- /* enable SPDIF */
- f = codec->codec_read(codec, AC97_EXTENDED_STATUS);
- if((codec->codec_ops == &null_ops) && (f & 4))
- codec->codec_ops = &default_digital_ops;
-
- /* A device which thinks its a modem but isnt */
- if(codec->flags & AC97_DELUDED_MODEM)
- codec->modem = 0;
-
- if (codec->name == NULL)
- codec->name = "Unknown";
- printk(KERN_INFO "ac97_codec: AC97 %s codec, id: %s (%s)\n",
- codec->modem ? "Modem" : (audio ? "Audio" : ""),
- codec_id(id1, id2, cidbuf), codec->name);
-
- if(!ac97_init_mixer(codec))
- return 0;
-
- /*
- * Attach last so the caller can override the mixer
- * callbacks.
- */
-
- mutex_lock(&codec_mutex);
- list_add(&codec->list, &codecs);
-
- list_for_each(l, &codec_drivers) {
- d = list_entry(l, struct ac97_driver, list);
- if ((codec->model ^ d->codec_id) & d->codec_mask)
- continue;
- if(d->probe(codec, d) == 0)
- {
- codec->driver = d;
- break;
- }
- }
-
- mutex_unlock(&codec_mutex);
- return 1;
-}
-
-static int ac97_init_mixer(struct ac97_codec *codec)
-{
- u16 cap;
- int i;
-
- cap = codec->codec_read(codec, AC97_RESET);
-
- /* mixer masks */
- codec->supported_mixers = AC97_SUPPORTED_MASK;
- codec->stereo_mixers = AC97_STEREO_MASK;
- codec->record_sources = AC97_RECORD_MASK;
- if (!(cap & 0x04))
- codec->supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE);
- if (!(cap & 0x10))
- codec->supported_mixers &= ~SOUND_MASK_ALTPCM;
-
-
- /* detect bit resolution */
- codec->codec_write(codec, AC97_MASTER_VOL_STEREO, 0x2020);
- if(codec->codec_read(codec, AC97_MASTER_VOL_STEREO) == 0x2020)
- codec->bit_resolution = 6;
- else
- codec->bit_resolution = 5;
-
- /* generic OSS to AC97 wrapper */
- codec->read_mixer = ac97_read_mixer;
- codec->write_mixer = ac97_write_mixer;
- codec->recmask_io = ac97_recmask_io;
- codec->mixer_ioctl = ac97_mixer_ioctl;
-
- /* initialize mixer channel volumes */
- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
- struct mixer_defaults *md = &mixer_defaults[i];
- if (md->mixer == -1)
- break;
- if (!supported_mixer(codec, md->mixer))
- continue;
- ac97_set_mixer(codec, md->mixer, md->value);
- }
-
- /* codec specific initialization for 4-6 channel output or secondary codec stuff */
- if (codec->codec_ops->init != NULL) {
- codec->codec_ops->init(codec);
- }
-
- /*
- * Volume is MUTE only on this device. We have to initialise
- * it but its useless beyond that.
- */
- if(codec->flags & AC97_NO_PCM_VOLUME)
- {
- codec->supported_mixers &= ~SOUND_MASK_PCM;
- printk(KERN_WARNING "AC97 codec does not have proper volume support.\n");
- }
- return 1;
-}
-
-#define AC97_SIGMATEL_ANALOG 0x6c /* Analog Special */
-#define AC97_SIGMATEL_DAC2INVERT 0x6e
-#define AC97_SIGMATEL_BIAS1 0x70
-#define AC97_SIGMATEL_BIAS2 0x72
-#define AC97_SIGMATEL_MULTICHN 0x74 /* Multi-Channel programming */
-#define AC97_SIGMATEL_CIC1 0x76
-#define AC97_SIGMATEL_CIC2 0x78
-
-
-static int sigmatel_9708_init(struct ac97_codec * codec)
-{
- u16 codec72, codec6c;
-
- codec72 = codec->codec_read(codec, AC97_SIGMATEL_BIAS2) & 0x8000;
- codec6c = codec->codec_read(codec, AC97_SIGMATEL_ANALOG);
-
- if ((codec72==0) && (codec6c==0)) {
- codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
- codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1000);
- codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba);
- codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0007);
- } else if ((codec72==0x8000) && (codec6c==0)) {
- codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
- codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1001);
- codec->codec_write(codec, AC97_SIGMATEL_DAC2INVERT, 0x0008);
- } else if ((codec72==0x8000) && (codec6c==0x0080)) {
- /* nothing */
- }
- codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000);
- return 0;
-}
-
-
-static int sigmatel_9721_init(struct ac97_codec * codec)
-{
- /* Only set up secondary codec */
- if (codec->id == 0)
- return 0;
-
- codec->codec_write(codec, AC97_SURROUND_MASTER, 0L);
-
- /* initialize SigmaTel STAC9721/23 as secondary codec, decoding AC link
- sloc 3,4 = 0x01, slot 7,8 = 0x00, */
- codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x00);
-
- /* we don't have the crystal when we are on an AMR card, so use
- BIT_CLK as our clock source. Write the magic word ABBA and read
- back to enable register 0x78 */
- codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
- codec->codec_read(codec, AC97_SIGMATEL_CIC1);
-
- /* sync all the clocks*/
- codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x3802);
-
- return 0;
-}
-
-
-static int sigmatel_9744_init(struct ac97_codec * codec)
-{
- // patch for SigmaTel
- codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba);
- codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x0000); // is this correct? --jk
- codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba);
- codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0002);
- codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000);
- return 0;
-}
-
-static int cmedia_init(struct ac97_codec *codec)
-{
- /* Initialise the CMedia 9739 */
- /*
- We could set various options here
- Register 0x20 bit 0x100 sets mic as center bass
- Also do multi_channel_ctrl &=~0x3000 |=0x1000
-
- For now we set up the GPIO and PC beep
- */
-
- u16 v;
-
- /* MIC */
- codec->codec_write(codec, 0x64, 0x3000);
- v = codec->codec_read(codec, 0x64);
- v &= ~0x8000;
- codec->codec_write(codec, 0x64, v);
- codec->codec_write(codec, 0x70, 0x0100);
- codec->codec_write(codec, 0x72, 0x0020);
- return 0;
-}
-
-#define AC97_WM97XX_FMIXER_VOL 0x72
-#define AC97_WM97XX_RMIXER_VOL 0x74
-#define AC97_WM97XX_TEST 0x5a
-#define AC97_WM9704_RPCM_VOL 0x70
-#define AC97_WM9711_OUT3VOL 0x16
-
-static int wolfson_init03(struct ac97_codec * codec)
-{
- /* this is known to work for the ViewSonic ViewPad 1000 */
- codec->codec_write(codec, AC97_WM97XX_FMIXER_VOL, 0x0808);
- codec->codec_write(codec, AC97_GENERAL_PURPOSE, 0x8000);
- return 0;
-}
-
-static int wolfson_init04(struct ac97_codec * codec)
-{
- codec->codec_write(codec, AC97_WM97XX_FMIXER_VOL, 0x0808);
- codec->codec_write(codec, AC97_WM97XX_RMIXER_VOL, 0x0808);
-
- // patch for DVD noise
- codec->codec_write(codec, AC97_WM97XX_TEST, 0x0200);
-
- // init vol as PCM vol
- codec->codec_write(codec, AC97_WM9704_RPCM_VOL,
- codec->codec_read(codec, AC97_PCMOUT_VOL));
-
- /* set rear surround volume */
- codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000);
- return 0;
-}
-
-/* WM9705, WM9710 */
-static int wolfson_init05(struct ac97_codec * codec)
-{
- /* set front mixer volume */
- codec->codec_write(codec, AC97_WM97XX_FMIXER_VOL, 0x0808);
- return 0;
-}
-
-/* WM9711, WM9712 */
-static int wolfson_init11(struct ac97_codec * codec)
-{
- /* stop pop's during suspend/resume */
- codec->codec_write(codec, AC97_WM97XX_TEST,
- codec->codec_read(codec, AC97_WM97XX_TEST) & 0xffbf);
-
- /* set out3 volume */
- codec->codec_write(codec, AC97_WM9711_OUT3VOL, 0x0808);
- return 0;
-}
-
-/* WM9713 */
-static int wolfson_init13(struct ac97_codec * codec)
-{
- codec->codec_write(codec, AC97_RECORD_GAIN, 0x00a0);
- codec->codec_write(codec, AC97_POWER_CONTROL, 0x0000);
- codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0xDA00);
- codec->codec_write(codec, AC97_EXTEND_MODEM_STAT, 0x3810);
- codec->codec_write(codec, AC97_PHONE_VOL, 0x0808);
- codec->codec_write(codec, AC97_PCBEEP_VOL, 0x0808);
-
- return 0;
-}
-
-static int tritech_init(struct ac97_codec * codec)
-{
- codec->codec_write(codec, 0x26, 0x0300);
- codec->codec_write(codec, 0x26, 0x0000);
- codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000);
- codec->codec_write(codec, AC97_RESERVED_3A, 0x0000);
- return 0;
-}
-
-
-/* copied from drivers/sound/maestro.c */
-static int tritech_maestro_init(struct ac97_codec * codec)
-{
- /* no idea what this does */
- codec->codec_write(codec, 0x2A, 0x0001);
- codec->codec_write(codec, 0x2C, 0x0000);
- codec->codec_write(codec, 0x2C, 0XFFFF);
- return 0;
-}
-
-
-
-/*
- * Presario700 workaround
- * for Jack Sense/SPDIF Register mis-setting causing
- * no audible output
- * by Santiago Nullo 04/05/2002
- */
-
-#define AC97_AD1886_JACK_SENSE 0x72
-
-static int ad1886_init(struct ac97_codec * codec)
-{
- /* from AD1886 Specs */
- codec->codec_write(codec, AC97_AD1886_JACK_SENSE, 0x0010);
- return 0;
-}
-
-
-
-
-/*
- * This is basically standard AC97. It should work as a default for
- * almost all modern codecs. Note that some cards wire EAPD *backwards*
- * That side of it is up to the card driver not us to cope with.
- *
- */
-
-static int eapd_control(struct ac97_codec * codec, int on)
-{
- if(on)
- codec->codec_write(codec, AC97_POWER_CONTROL,
- codec->codec_read(codec, AC97_POWER_CONTROL)|0x8000);
- else
- codec->codec_write(codec, AC97_POWER_CONTROL,
- codec->codec_read(codec, AC97_POWER_CONTROL)&~0x8000);
- return 0;
-}
-
-static int generic_digital_control(struct ac97_codec *codec, int slots, int rate, int mode)
-{
- u16 reg;
-
- reg = codec->codec_read(codec, AC97_SPDIF_CONTROL);
-
- switch(rate)
- {
- /* Off by default */
- default:
- case 0:
- reg = codec->codec_read(codec, AC97_EXTENDED_STATUS);
- codec->codec_write(codec, AC97_EXTENDED_STATUS, (reg & ~AC97_EA_SPDIF));
- if(rate == 0)
- return 0;
- return -EINVAL;
- case 1:
- reg = (reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_48K;
- break;
- case 2:
- reg = (reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_44K;
- break;
- case 3:
- reg = (reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_32K;
- break;
- }
-
- reg &= ~AC97_SC_CC_MASK;
- reg |= (mode & AUDIO_CCMASK) << 6;
-
- if(mode & AUDIO_DIGITAL)
- reg |= 2;
- if(mode & AUDIO_PRO)
- reg |= 1;
- if(mode & AUDIO_DRS)
- reg |= 0x4000;
-
- codec->codec_write(codec, AC97_SPDIF_CONTROL, reg);
-
- reg = codec->codec_read(codec, AC97_EXTENDED_STATUS);
- reg &= (AC97_EA_SLOT_MASK);
- reg |= AC97_EA_VRA | AC97_EA_SPDIF | slots;
- codec->codec_write(codec, AC97_EXTENDED_STATUS, reg);
-
- reg = codec->codec_read(codec, AC97_EXTENDED_STATUS);
- if(!(reg & 0x0400))
- {
- codec->codec_write(codec, AC97_EXTENDED_STATUS, reg & ~ AC97_EA_SPDIF);
- return -EINVAL;
- }
- return 0;
-}
-
-/*
- * Crystal digital audio control (CS4299)
- */
-
-static int crystal_digital_control(struct ac97_codec *codec, int slots, int rate, int mode)
-{
- u16 cv;
-
- if(mode & AUDIO_DIGITAL)
- return -EINVAL;
-
- switch(rate)
- {
- case 0: cv = 0x0; break; /* SPEN off */
- case 48000: cv = 0x8004; break; /* 48KHz digital */
- case 44100: cv = 0x8104; break; /* 44.1KHz digital */
- case 32768: /* 32Khz */
- default:
- return -EINVAL;
- }
- codec->codec_write(codec, 0x68, cv);
- return 0;
-}
-
-/*
- * CMedia digital audio control
- * Needs more work.
- */
-
-static int cmedia_digital_control(struct ac97_codec *codec, int slots, int rate, int mode)
-{
- u16 cv;
-
- if(mode & AUDIO_DIGITAL)
- return -EINVAL;
-
- switch(rate)
- {
- case 0: cv = 0x0001; break; /* SPEN off */
- case 48000: cv = 0x0009; break; /* 48KHz digital */
- default:
- return -EINVAL;
- }
- codec->codec_write(codec, 0x2A, 0x05c4);
- codec->codec_write(codec, 0x6C, cv);
-
- /* Switch on mix to surround */
- cv = codec->codec_read(codec, 0x64);
- cv &= ~0x0200;
- if(mode)
- cv |= 0x0200;
- codec->codec_write(codec, 0x64, cv);
- return 0;
-}
-
-
-/* copied from drivers/sound/maestro.c */
-#if 0 /* there has been 1 person on the planet with a pt101 that we
- know of. If they care, they can put this back in :) */
-static int pt101_init(struct ac97_codec * codec)
-{
- printk(KERN_INFO "ac97_codec: PT101 Codec detected, initializing but _not_ installing mixer device.\n");
- /* who knows.. */
- codec->codec_write(codec, 0x2A, 0x0001);
- codec->codec_write(codec, 0x2C, 0x0000);
- codec->codec_write(codec, 0x2C, 0xFFFF);
- codec->codec_write(codec, 0x10, 0x9F1F);
- codec->codec_write(codec, 0x12, 0x0808);
- codec->codec_write(codec, 0x14, 0x9F1F);
- codec->codec_write(codec, 0x16, 0x9F1F);
- codec->codec_write(codec, 0x18, 0x0404);
- codec->codec_write(codec, 0x1A, 0x0000);
- codec->codec_write(codec, 0x1C, 0x0000);
- codec->codec_write(codec, 0x02, 0x0404);
- codec->codec_write(codec, 0x04, 0x0808);
- codec->codec_write(codec, 0x0C, 0x801F);
- codec->codec_write(codec, 0x0E, 0x801F);
- return 0;
-}
-#endif
-
-
-EXPORT_SYMBOL(ac97_read_proc);
-EXPORT_SYMBOL(ac97_probe_codec);
-
-/*
- * AC97 library support routines
- */
-
-/**
- * ac97_set_dac_rate - set codec rate adaption
- * @codec: ac97 code
- * @rate: rate in hertz
- *
- * Set the DAC rate. Assumes the codec supports VRA. The caller is
- * expected to have checked this little detail.
- */
-
-unsigned int ac97_set_dac_rate(struct ac97_codec *codec, unsigned int rate)
-{
- unsigned int new_rate = rate;
- u32 dacp;
- u32 mast_vol, phone_vol, mono_vol, pcm_vol;
- u32 mute_vol = 0x8000; /* The mute volume? */
-
- if(rate != codec->codec_read(codec, AC97_PCM_FRONT_DAC_RATE))
- {
- /* Mute several registers */
- mast_vol = codec->codec_read(codec, AC97_MASTER_VOL_STEREO);
- mono_vol = codec->codec_read(codec, AC97_MASTER_VOL_MONO);
- phone_vol = codec->codec_read(codec, AC97_HEADPHONE_VOL);
- pcm_vol = codec->codec_read(codec, AC97_PCMOUT_VOL);
- codec->codec_write(codec, AC97_MASTER_VOL_STEREO, mute_vol);
- codec->codec_write(codec, AC97_MASTER_VOL_MONO, mute_vol);
- codec->codec_write(codec, AC97_HEADPHONE_VOL, mute_vol);
- codec->codec_write(codec, AC97_PCMOUT_VOL, mute_vol);
-
- /* Power down the DAC */
- dacp=codec->codec_read(codec, AC97_POWER_CONTROL);
- codec->codec_write(codec, AC97_POWER_CONTROL, dacp|0x0200);
- /* Load the rate and read the effective rate */
- codec->codec_write(codec, AC97_PCM_FRONT_DAC_RATE, rate);
- new_rate=codec->codec_read(codec, AC97_PCM_FRONT_DAC_RATE);
- /* Power it back up */
- codec->codec_write(codec, AC97_POWER_CONTROL, dacp);
-
- /* Restore volumes */
- codec->codec_write(codec, AC97_MASTER_VOL_STEREO, mast_vol);
- codec->codec_write(codec, AC97_MASTER_VOL_MONO, mono_vol);
- codec->codec_write(codec, AC97_HEADPHONE_VOL, phone_vol);
- codec->codec_write(codec, AC97_PCMOUT_VOL, pcm_vol);
- }
- return new_rate;
-}
-
-EXPORT_SYMBOL(ac97_set_dac_rate);
-
-/**
- * ac97_set_adc_rate - set codec rate adaption
- * @codec: ac97 code
- * @rate: rate in hertz
- *
- * Set the ADC rate. Assumes the codec supports VRA. The caller is
- * expected to have checked this little detail.
- */
-
-unsigned int ac97_set_adc_rate(struct ac97_codec *codec, unsigned int rate)
-{
- unsigned int new_rate = rate;
- u32 dacp;
-
- if(rate != codec->codec_read(codec, AC97_PCM_LR_ADC_RATE))
- {
- /* Power down the ADC */
- dacp=codec->codec_read(codec, AC97_POWER_CONTROL);
- codec->codec_write(codec, AC97_POWER_CONTROL, dacp|0x0100);
- /* Load the rate and read the effective rate */
- codec->codec_write(codec, AC97_PCM_LR_ADC_RATE, rate);
- new_rate=codec->codec_read(codec, AC97_PCM_LR_ADC_RATE);
- /* Power it back up */
- codec->codec_write(codec, AC97_POWER_CONTROL, dacp);
- }
- return new_rate;
-}
-
-EXPORT_SYMBOL(ac97_set_adc_rate);
-
-static int swap_headphone(int remove_master)
-{
- struct list_head *l;
- struct ac97_codec *c;
-
- if (remove_master) {
- mutex_lock(&codec_mutex);
- list_for_each(l, &codecs)
- {
- c = list_entry(l, struct ac97_codec, list);
- if (supported_mixer(c, SOUND_MIXER_PHONEOUT))
- c->supported_mixers &= ~SOUND_MASK_PHONEOUT;
- }
- mutex_unlock(&codec_mutex);
- } else
- ac97_hw[SOUND_MIXER_PHONEOUT].offset = AC97_MASTER_VOL_STEREO;
-
- /* Scale values already match */
- ac97_hw[SOUND_MIXER_VOLUME].offset = AC97_MASTER_VOL_MONO;
- return 0;
-}
-
-static int apply_quirk(int quirk)
-{
- switch (quirk) {
- case AC97_TUNE_NONE:
- return 0;
- case AC97_TUNE_HP_ONLY:
- return swap_headphone(1);
- case AC97_TUNE_SWAP_HP:
- return swap_headphone(0);
- case AC97_TUNE_SWAP_SURROUND:
- return -ENOSYS; /* not yet implemented */
- case AC97_TUNE_AD_SHARING:
- return -ENOSYS; /* not yet implemented */
- case AC97_TUNE_ALC_JACK:
- return -ENOSYS; /* not yet implemented */
- }
- return -EINVAL;
-}
-
-/**
- * ac97_tune_hardware - tune up the hardware
- * @pdev: pci_dev pointer
- * @quirk: quirk list
- * @override: explicit quirk value (overrides if not AC97_TUNE_DEFAULT)
- *
- * Do some workaround for each pci device, such as renaming of the
- * headphone (true line-out) control as "Master".
- * The quirk-list must be terminated with a zero-filled entry.
- *
- * Returns zero if successful, or a negative error code on failure.
- */
-
-int ac97_tune_hardware(struct pci_dev *pdev, struct ac97_quirk *quirk, int override)
-{
- int result;
-
- if (!quirk)
- return -EINVAL;
-
- if (override != AC97_TUNE_DEFAULT) {
- result = apply_quirk(override);
- if (result < 0)
- printk(KERN_ERR "applying quirk type %d failed (%d)\n", override, result);
- return result;
- }
-
- for (; quirk->vendor; quirk++) {
- if (quirk->vendor != pdev->subsystem_vendor)
- continue;
- if ((! quirk->mask && quirk->device == pdev->subsystem_device) ||
- quirk->device == (quirk->mask & pdev->subsystem_device)) {
-#ifdef DEBUG
- printk("ac97 quirk for %s (%04x:%04x)\n", quirk->name, ac97->subsystem_vendor, pdev->subsystem_device);
-#endif
- result = apply_quirk(quirk->type);
- if (result < 0)
- printk(KERN_ERR "applying quirk type %d for %s failed (%d)\n", quirk->type, quirk->name, result);
- return result;
- }
- }
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ac97_tune_hardware);
-
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/ad1848.c b/sound/oss/ad1848.c
index 7cf9913a47b..ec1ee07df59 100644
--- a/sound/oss/ad1848.c
+++ b/sound/oss/ad1848.c
@@ -45,12 +45,11 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/stddef.h>
+#include <linux/slab.h>
#include <linux/isapnp.h>
#include <linux/pnp.h>
#include <linux/spinlock.h>
-#define DEB(x)
-#define DEB1(x)
#include "sound_config.h"
#include "ad1848.h"
@@ -118,9 +117,9 @@ ad1848_port_info;
static struct address_info cfg;
static int nr_ad1848_devs;
-static int deskpro_xl;
-static int deskpro_m;
-static int soundpro;
+static bool deskpro_xl;
+static bool deskpro_m;
+static bool soundpro;
static volatile signed char irq2dev[17] = {
-1, -1, -1, -1, -1, -1, -1, -1,
@@ -176,7 +175,7 @@ static struct {
#ifdef CONFIG_PNP
static int isapnp = 1;
static int isapnpjump;
-static int reverse;
+static bool reverse;
static int audio_activated;
#else
@@ -280,7 +279,7 @@ static void wait_for_calibration(ad1848_info * devc)
while (timeout > 0 && (ad_read(devc, 11) & 0x20))
timeout--;
if (ad_read(devc, 11) & 0x20)
- if ( (devc->model != MD_1845) || (devc->model != MD_1845_SSCAPE))
+ if ((devc->model != MD_1845) && (devc->model != MD_1845_SSCAPE))
printk(KERN_WARNING "ad1848: Auto calibration timed out(3).\n");
}
@@ -457,7 +456,7 @@ static int ad1848_set_recmask(ad1848_info * devc, int mask)
return mask;
}
-static void change_bits(ad1848_info * devc, unsigned char *regval,
+static void oss_change_bits(ad1848_info *devc, unsigned char *regval,
unsigned char *muteval, int dev, int chn, int newval)
{
unsigned char mask;
@@ -515,10 +514,10 @@ static void ad1848_mixer_set_channel(ad1848_info *devc, int dev, int value, int
if (muteregoffs != regoffs) {
muteval = ad_read(devc, muteregoffs);
- change_bits(devc, &val, &muteval, dev, channel, value);
+ oss_change_bits(devc, &val, &muteval, dev, channel, value);
}
else
- change_bits(devc, &val, &val, dev, channel, value);
+ oss_change_bits(devc, &val, &val, dev, channel, value);
spin_lock_irqsave(&devc->lock,flags);
ad_write(devc, regoffs, val);
@@ -715,7 +714,7 @@ static int ad1848_mixer_ioctl(int dev, unsigned int cmd, void __user *arg)
default:
if (get_user(val, (int __user *)arg))
- return -EFAULT;
+ return -EFAULT;
val = ad1848_mixer_set(devc, cmd & 0xff, val);
break;
}
@@ -1015,8 +1014,6 @@ static void ad1848_close(int dev)
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc;
- DEB(printk("ad1848_close(void)\n"));
-
devc->intr_active = 0;
ad1848_halt(dev);
@@ -2107,7 +2104,7 @@ int ad1848_control(int cmd, int arg)
switch (cmd)
{
case AD1848_SET_XTAL: /* Change clock frequency of AD1845 (only ) */
- if (devc->model != MD_1845 || devc->model != MD_1845_SSCAPE)
+ if (devc->model != MD_1845 && devc->model != MD_1845_SSCAPE)
return -EINVAL;
spin_lock_irqsave(&devc->lock,flags);
ad_enter_MCE(devc);
@@ -2863,7 +2860,7 @@ static struct {
{NULL}
};
-static struct isapnp_device_id id_table[] __devinitdata = {
+static struct isapnp_device_id id_table[] = {
{ ISAPNP_VENDOR('C','M','I'), ISAPNP_DEVICE(0x0001),
ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), 0 },
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,
diff --git a/sound/oss/aedsp16.c b/sound/oss/aedsp16.c
index 51e1fde62e8..35b5912cf3f 100644
--- a/sound/oss/aedsp16.c
+++ b/sound/oss/aedsp16.c
@@ -29,14 +29,6 @@
#include "sound_config.h"
/*
- * Sanity checks
- */
-
-#if defined(CONFIG_SOUND_AEDSP16_SBPRO) && defined(CONFIG_SOUND_AEDSP16_MSS)
-#error You have to enable only one of the MSS and SBPRO emulations.
-#endif
-
-/*
READ THIS
@@ -165,7 +157,7 @@
Started Fri Mar 17 16:13:18 MET 1995
- v0.1 (ALPHA, was an user-level program called AudioExcelDSP16.c)
+ v0.1 (ALPHA, was a user-level program called AudioExcelDSP16.c)
- Initial code.
v0.2 (ALPHA)
- Cleanups.
@@ -333,8 +325,9 @@
/*
* Size of character arrays that store name and version of sound card
*/
-#define CARDNAMELEN 15 /* Size of the card's name in chars */
-#define CARDVERLEN 2 /* Size of the card's version in chars */
+#define CARDNAMELEN 15 /* Size of the card's name in chars */
+#define CARDVERLEN 10 /* Size of the card's version in chars */
+#define CARDVERDIGITS 2 /* Number of digits in the version */
#if defined(CONFIG_SC6600)
/*
@@ -418,7 +411,7 @@
static int soft_cfg __initdata = 0; /* bitmapped config */
static int soft_cfg_mss __initdata = 0; /* bitmapped mss config */
-static int ver[CARDVERLEN] __initdata = {0, 0}; /* DSP Ver:
+static int ver[CARDVERDIGITS] __initdata = {0, 0}; /* DSP Ver:
hi->ver[0] lo->ver[1] */
#if defined(CONFIG_SC6600)
@@ -965,7 +958,7 @@ static int __init aedsp16_dsp_version(int port)
* string is finished.
*/
ver[len++] = ret;
- } while (len < CARDVERLEN);
+ } while (len < CARDVERDIGITS);
sprintf(DSPVersion, "%d.%d", ver[0], ver[1]);
DBG(("success.\n"));
diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c
deleted file mode 100644
index 23018a7c063..00000000000
--- a/sound/oss/au1550_ac97.c
+++ /dev/null
@@ -1,2129 +0,0 @@
-/*
- * au1550_ac97.c -- Sound driver for Alchemy Au1550 MIPS Internet Edge
- * Processor.
- *
- * Copyright 2004 Embedded Edge, LLC
- * dan@embeddededge.com
- *
- * Mostly copied from the au1000.c driver and some from the
- * PowerMac dbdma driver.
- * We assume the processor can do memory coherent DMA.
- *
- * Ported to 2.6 by Matt Porter <mporter@kernel.crashing.org>
- *
- * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#undef DEBUG
-
-#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/init.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/poll.h>
-#include <linux/bitops.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/ac97_codec.h>
-#include <linux/mutex.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/hardirq.h>
-#include <asm/mach-au1x00/au1xxx_psc.h>
-#include <asm/mach-au1x00/au1xxx_dbdma.h>
-#include <asm/mach-au1x00/au1xxx.h>
-
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-
-/* misc stuff */
-#define POLL_COUNT 0x50000
-#define AC97_EXT_DACS (AC97_EXTID_SDAC | AC97_EXTID_CDAC | AC97_EXTID_LDAC)
-
-/* The number of DBDMA ring descriptors to allocate. No sense making
- * this too large....if you can't keep up with a few you aren't likely
- * to be able to with lots of them, either.
- */
-#define NUM_DBDMA_DESCRIPTORS 4
-
-#define err(format, arg...) printk(KERN_ERR format "\n" , ## arg)
-
-/* Boot options
- * 0 = no VRA, 1 = use VRA if codec supports it
- */
-static int vra = 1;
-module_param(vra, bool, 0);
-MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it");
-
-static struct au1550_state {
- /* soundcore stuff */
- int dev_audio;
-
- struct ac97_codec *codec;
- unsigned codec_base_caps; /* AC'97 reg 00h, "Reset Register" */
- unsigned codec_ext_caps; /* AC'97 reg 28h, "Extended Audio ID" */
- int no_vra; /* do not use VRA */
-
- spinlock_t lock;
- struct mutex open_mutex;
- struct mutex sem;
- mode_t open_mode;
- wait_queue_head_t open_wait;
-
- struct dmabuf {
- u32 dmanr;
- unsigned sample_rate;
- unsigned src_factor;
- unsigned sample_size;
- int num_channels;
- int dma_bytes_per_sample;
- int user_bytes_per_sample;
- int cnt_factor;
-
- void *rawbuf;
- unsigned buforder;
- unsigned numfrag;
- unsigned fragshift;
- void *nextIn;
- void *nextOut;
- int count;
- unsigned total_bytes;
- unsigned error;
- wait_queue_head_t wait;
-
- /* redundant, but makes calculations easier */
- unsigned fragsize;
- unsigned dma_fragsize;
- unsigned dmasize;
- unsigned dma_qcount;
-
- /* OSS stuff */
- unsigned mapped:1;
- unsigned ready:1;
- unsigned stopped:1;
- unsigned ossfragshift;
- int ossmaxfrags;
- unsigned subdivision;
- } dma_dac, dma_adc;
-} au1550_state;
-
-static 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 void
-au1550_delay(int msec)
-{
- unsigned long tmo;
- signed long tmo2;
-
- if (in_interrupt())
- return;
-
- tmo = jiffies + (msec * HZ) / 1000;
- for (;;) {
- tmo2 = tmo - jiffies;
- if (tmo2 <= 0)
- break;
- schedule_timeout(tmo2);
- }
-}
-
-static u16
-rdcodec(struct ac97_codec *codec, u8 addr)
-{
- struct au1550_state *s = (struct au1550_state *)codec->private_data;
- unsigned long flags;
- u32 cmd, val;
- u16 data;
- int i;
-
- spin_lock_irqsave(&s->lock, flags);
-
- for (i = 0; i < POLL_COUNT; i++) {
- val = au_readl(PSC_AC97STAT);
- au_sync();
- if (!(val & PSC_AC97STAT_CP))
- break;
- }
- if (i == POLL_COUNT)
- err("rdcodec: codec cmd pending expired!");
-
- cmd = (u32)PSC_AC97CDC_INDX(addr);
- cmd |= PSC_AC97CDC_RD; /* read command */
- au_writel(cmd, PSC_AC97CDC);
- au_sync();
-
- /* now wait for the data
- */
- for (i = 0; i < POLL_COUNT; i++) {
- val = au_readl(PSC_AC97STAT);
- au_sync();
- if (!(val & PSC_AC97STAT_CP))
- break;
- }
- if (i == POLL_COUNT) {
- err("rdcodec: read poll expired!");
- data = 0;
- goto out;
- }
-
- /* wait for command done?
- */
- for (i = 0; i < POLL_COUNT; i++) {
- val = au_readl(PSC_AC97EVNT);
- au_sync();
- if (val & PSC_AC97EVNT_CD)
- break;
- }
- if (i == POLL_COUNT) {
- err("rdcodec: read cmdwait expired!");
- data = 0;
- goto out;
- }
-
- data = au_readl(PSC_AC97CDC) & 0xffff;
- au_sync();
-
- /* Clear command done event.
- */
- au_writel(PSC_AC97EVNT_CD, PSC_AC97EVNT);
- au_sync();
-
- out:
- spin_unlock_irqrestore(&s->lock, flags);
-
- return data;
-}
-
-
-static void
-wrcodec(struct ac97_codec *codec, u8 addr, u16 data)
-{
- struct au1550_state *s = (struct au1550_state *)codec->private_data;
- unsigned long flags;
- u32 cmd, val;
- int i;
-
- spin_lock_irqsave(&s->lock, flags);
-
- for (i = 0; i < POLL_COUNT; i++) {
- val = au_readl(PSC_AC97STAT);
- au_sync();
- if (!(val & PSC_AC97STAT_CP))
- break;
- }
- if (i == POLL_COUNT)
- err("wrcodec: codec cmd pending expired!");
-
- cmd = (u32)PSC_AC97CDC_INDX(addr);
- cmd |= (u32)data;
- au_writel(cmd, PSC_AC97CDC);
- au_sync();
-
- for (i = 0; i < POLL_COUNT; i++) {
- val = au_readl(PSC_AC97STAT);
- au_sync();
- if (!(val & PSC_AC97STAT_CP))
- break;
- }
- if (i == POLL_COUNT)
- err("wrcodec: codec cmd pending expired!");
-
- for (i = 0; i < POLL_COUNT; i++) {
- val = au_readl(PSC_AC97EVNT);
- au_sync();
- if (val & PSC_AC97EVNT_CD)
- break;
- }
- if (i == POLL_COUNT)
- err("wrcodec: read cmdwait expired!");
-
- /* Clear command done event.
- */
- au_writel(PSC_AC97EVNT_CD, PSC_AC97EVNT);
- au_sync();
-
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void
-waitcodec(struct ac97_codec *codec)
-{
- u16 temp;
- u32 val;
- int i;
-
- /* codec_wait is used to wait for a ready state after
- * an AC97C_RESET.
- */
- au1550_delay(10);
-
- /* first poll the CODEC_READY tag bit
- */
- for (i = 0; i < POLL_COUNT; i++) {
- val = au_readl(PSC_AC97STAT);
- au_sync();
- if (val & PSC_AC97STAT_CR)
- break;
- }
- if (i == POLL_COUNT) {
- err("waitcodec: CODEC_READY poll expired!");
- return;
- }
-
- /* get AC'97 powerdown control/status register
- */
- temp = rdcodec(codec, AC97_POWER_CONTROL);
-
- /* If anything is powered down, power'em up
- */
- if (temp & 0x7f00) {
- /* Power on
- */
- wrcodec(codec, AC97_POWER_CONTROL, 0);
- au1550_delay(100);
-
- /* Reread
- */
- temp = rdcodec(codec, AC97_POWER_CONTROL);
- }
-
- /* Check if Codec REF,ANL,DAC,ADC ready
- */
- if ((temp & 0x7f0f) != 0x000f)
- err("codec reg 26 status (0x%x) not ready!!", temp);
-}
-
-/* stop the ADC before calling */
-static void
-set_adc_rate(struct au1550_state *s, unsigned rate)
-{
- struct dmabuf *adc = &s->dma_adc;
- struct dmabuf *dac = &s->dma_dac;
- unsigned adc_rate, dac_rate;
- u16 ac97_extstat;
-
- if (s->no_vra) {
- /* calc SRC factor
- */
- adc->src_factor = ((96000 / rate) + 1) >> 1;
- adc->sample_rate = 48000 / adc->src_factor;
- return;
- }
-
- adc->src_factor = 1;
-
- ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS);
-
- rate = rate > 48000 ? 48000 : rate;
-
- /* enable VRA
- */
- wrcodec(s->codec, AC97_EXTENDED_STATUS,
- ac97_extstat | AC97_EXTSTAT_VRA);
-
- /* now write the sample rate
- */
- wrcodec(s->codec, AC97_PCM_LR_ADC_RATE, (u16) rate);
-
- /* read it back for actual supported rate
- */
- adc_rate = rdcodec(s->codec, AC97_PCM_LR_ADC_RATE);
-
- pr_debug("set_adc_rate: set to %d Hz\n", adc_rate);
-
- /* some codec's don't allow unequal DAC and ADC rates, in which case
- * writing one rate reg actually changes both.
- */
- dac_rate = rdcodec(s->codec, AC97_PCM_FRONT_DAC_RATE);
- if (dac->num_channels > 2)
- wrcodec(s->codec, AC97_PCM_SURR_DAC_RATE, dac_rate);
- if (dac->num_channels > 4)
- wrcodec(s->codec, AC97_PCM_LFE_DAC_RATE, dac_rate);
-
- adc->sample_rate = adc_rate;
- dac->sample_rate = dac_rate;
-}
-
-/* stop the DAC before calling */
-static void
-set_dac_rate(struct au1550_state *s, unsigned rate)
-{
- struct dmabuf *dac = &s->dma_dac;
- struct dmabuf *adc = &s->dma_adc;
- unsigned adc_rate, dac_rate;
- u16 ac97_extstat;
-
- if (s->no_vra) {
- /* calc SRC factor
- */
- dac->src_factor = ((96000 / rate) + 1) >> 1;
- dac->sample_rate = 48000 / dac->src_factor;
- return;
- }
-
- dac->src_factor = 1;
-
- ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS);
-
- rate = rate > 48000 ? 48000 : rate;
-
- /* enable VRA
- */
- wrcodec(s->codec, AC97_EXTENDED_STATUS,
- ac97_extstat | AC97_EXTSTAT_VRA);
-
- /* now write the sample rate
- */
- wrcodec(s->codec, AC97_PCM_FRONT_DAC_RATE, (u16) rate);
-
- /* I don't support different sample rates for multichannel,
- * so make these channels the same.
- */
- if (dac->num_channels > 2)
- wrcodec(s->codec, AC97_PCM_SURR_DAC_RATE, (u16) rate);
- if (dac->num_channels > 4)
- wrcodec(s->codec, AC97_PCM_LFE_DAC_RATE, (u16) rate);
- /* read it back for actual supported rate
- */
- dac_rate = rdcodec(s->codec, AC97_PCM_FRONT_DAC_RATE);
-
- pr_debug("set_dac_rate: set to %d Hz\n", dac_rate);
-
- /* some codec's don't allow unequal DAC and ADC rates, in which case
- * writing one rate reg actually changes both.
- */
- adc_rate = rdcodec(s->codec, AC97_PCM_LR_ADC_RATE);
-
- dac->sample_rate = dac_rate;
- adc->sample_rate = adc_rate;
-}
-
-static void
-stop_dac(struct au1550_state *s)
-{
- struct dmabuf *db = &s->dma_dac;
- u32 stat;
- unsigned long flags;
-
- if (db->stopped)
- return;
-
- spin_lock_irqsave(&s->lock, flags);
-
- au_writel(PSC_AC97PCR_TP, PSC_AC97PCR);
- au_sync();
-
- /* Wait for Transmit Busy to show disabled.
- */
- do {
- stat = au_readl(PSC_AC97STAT);
- au_sync();
- } while ((stat & PSC_AC97STAT_TB) != 0);
-
- au1xxx_dbdma_reset(db->dmanr);
-
- db->stopped = 1;
-
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void
-stop_adc(struct au1550_state *s)
-{
- struct dmabuf *db = &s->dma_adc;
- unsigned long flags;
- u32 stat;
-
- if (db->stopped)
- return;
-
- spin_lock_irqsave(&s->lock, flags);
-
- au_writel(PSC_AC97PCR_RP, PSC_AC97PCR);
- au_sync();
-
- /* Wait for Receive Busy to show disabled.
- */
- do {
- stat = au_readl(PSC_AC97STAT);
- au_sync();
- } while ((stat & PSC_AC97STAT_RB) != 0);
-
- au1xxx_dbdma_reset(db->dmanr);
-
- db->stopped = 1;
-
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-
-static void
-set_xmit_slots(int num_channels)
-{
- u32 ac97_config, stat;
-
- ac97_config = au_readl(PSC_AC97CFG);
- au_sync();
- ac97_config &= ~(PSC_AC97CFG_TXSLOT_MASK | PSC_AC97CFG_DE_ENABLE);
- au_writel(ac97_config, PSC_AC97CFG);
- au_sync();
-
- switch (num_channels) {
- case 6: /* stereo with surround and center/LFE,
- * slots 3,4,6,7,8,9
- */
- ac97_config |= PSC_AC97CFG_TXSLOT_ENA(6);
- ac97_config |= PSC_AC97CFG_TXSLOT_ENA(9);
-
- case 4: /* stereo with surround, slots 3,4,7,8 */
- ac97_config |= PSC_AC97CFG_TXSLOT_ENA(7);
- ac97_config |= PSC_AC97CFG_TXSLOT_ENA(8);
-
- case 2: /* stereo, slots 3,4 */
- case 1: /* mono */
- ac97_config |= PSC_AC97CFG_TXSLOT_ENA(3);
- ac97_config |= PSC_AC97CFG_TXSLOT_ENA(4);
- }
-
- au_writel(ac97_config, PSC_AC97CFG);
- au_sync();
-
- ac97_config |= PSC_AC97CFG_DE_ENABLE;
- au_writel(ac97_config, PSC_AC97CFG);
- au_sync();
-
- /* Wait for Device ready.
- */
- do {
- stat = au_readl(PSC_AC97STAT);
- au_sync();
- } while ((stat & PSC_AC97STAT_DR) == 0);
-}
-
-static void
-set_recv_slots(int num_channels)
-{
- u32 ac97_config, stat;
-
- ac97_config = au_readl(PSC_AC97CFG);
- au_sync();
- ac97_config &= ~(PSC_AC97CFG_RXSLOT_MASK | PSC_AC97CFG_DE_ENABLE);
- au_writel(ac97_config, PSC_AC97CFG);
- au_sync();
-
- /* Always enable slots 3 and 4 (stereo). Slot 6 is
- * optional Mic ADC, which we don't support yet.
- */
- ac97_config |= PSC_AC97CFG_RXSLOT_ENA(3);
- ac97_config |= PSC_AC97CFG_RXSLOT_ENA(4);
-
- au_writel(ac97_config, PSC_AC97CFG);
- au_sync();
-
- ac97_config |= PSC_AC97CFG_DE_ENABLE;
- au_writel(ac97_config, PSC_AC97CFG);
- au_sync();
-
- /* Wait for Device ready.
- */
- do {
- stat = au_readl(PSC_AC97STAT);
- au_sync();
- } while ((stat & PSC_AC97STAT_DR) == 0);
-}
-
-/* Hold spinlock for both start_dac() and start_adc() calls */
-static void
-start_dac(struct au1550_state *s)
-{
- struct dmabuf *db = &s->dma_dac;
-
- if (!db->stopped)
- return;
-
- set_xmit_slots(db->num_channels);
- au_writel(PSC_AC97PCR_TC, PSC_AC97PCR);
- au_sync();
- au_writel(PSC_AC97PCR_TS, PSC_AC97PCR);
- au_sync();
-
- au1xxx_dbdma_start(db->dmanr);
-
- db->stopped = 0;
-}
-
-static void
-start_adc(struct au1550_state *s)
-{
- struct dmabuf *db = &s->dma_adc;
- int i;
-
- if (!db->stopped)
- return;
-
- /* Put two buffers on the ring to get things started.
- */
- for (i=0; i<2; i++) {
- au1xxx_dbdma_put_dest(db->dmanr, db->nextIn, db->dma_fragsize);
-
- db->nextIn += db->dma_fragsize;
- if (db->nextIn >= db->rawbuf + db->dmasize)
- db->nextIn -= db->dmasize;
- }
-
- set_recv_slots(db->num_channels);
- au1xxx_dbdma_start(db->dmanr);
- au_writel(PSC_AC97PCR_RC, PSC_AC97PCR);
- au_sync();
- au_writel(PSC_AC97PCR_RS, PSC_AC97PCR);
- au_sync();
-
- db->stopped = 0;
-}
-
-static int
-prog_dmabuf(struct au1550_state *s, struct dmabuf *db)
-{
- unsigned user_bytes_per_sec;
- unsigned bufs;
- unsigned rate = db->sample_rate;
-
- if (!db->rawbuf) {
- db->ready = db->mapped = 0;
- db->buforder = 5; /* 32 * PAGE_SIZE */
- db->rawbuf = kmalloc((PAGE_SIZE << db->buforder), GFP_KERNEL);
- if (!db->rawbuf)
- return -ENOMEM;
- }
-
- db->cnt_factor = 1;
- if (db->sample_size == 8)
- db->cnt_factor *= 2;
- if (db->num_channels == 1)
- db->cnt_factor *= 2;
- db->cnt_factor *= db->src_factor;
-
- db->count = 0;
- db->dma_qcount = 0;
- db->nextIn = db->nextOut = db->rawbuf;
-
- db->user_bytes_per_sample = (db->sample_size>>3) * db->num_channels;
- db->dma_bytes_per_sample = 2 * ((db->num_channels == 1) ?
- 2 : db->num_channels);
-
- user_bytes_per_sec = rate * db->user_bytes_per_sample;
- bufs = PAGE_SIZE << db->buforder;
- if (db->ossfragshift) {
- if ((1000 << db->ossfragshift) < user_bytes_per_sec)
- db->fragshift = ld2(user_bytes_per_sec/1000);
- else
- db->fragshift = db->ossfragshift;
- } else {
- db->fragshift = ld2(user_bytes_per_sec / 100 /
- (db->subdivision ? db->subdivision : 1));
- if (db->fragshift < 3)
- db->fragshift = 3;
- }
-
- db->fragsize = 1 << db->fragshift;
- db->dma_fragsize = db->fragsize * db->cnt_factor;
- db->numfrag = bufs / db->dma_fragsize;
-
- while (db->numfrag < 4 && db->fragshift > 3) {
- db->fragshift--;
- db->fragsize = 1 << db->fragshift;
- db->dma_fragsize = db->fragsize * db->cnt_factor;
- db->numfrag = bufs / db->dma_fragsize;
- }
-
- if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
- db->numfrag = db->ossmaxfrags;
-
- db->dmasize = db->dma_fragsize * db->numfrag;
- memset(db->rawbuf, 0, bufs);
-
- pr_debug("prog_dmabuf: rate=%d, samplesize=%d, channels=%d\n",
- rate, db->sample_size, db->num_channels);
- pr_debug("prog_dmabuf: fragsize=%d, cnt_factor=%d, dma_fragsize=%d\n",
- db->fragsize, db->cnt_factor, db->dma_fragsize);
- pr_debug("prog_dmabuf: numfrag=%d, dmasize=%d\n", db->numfrag, db->dmasize);
-
- db->ready = 1;
- return 0;
-}
-
-static int
-prog_dmabuf_adc(struct au1550_state *s)
-{
- stop_adc(s);
- return prog_dmabuf(s, &s->dma_adc);
-
-}
-
-static int
-prog_dmabuf_dac(struct au1550_state *s)
-{
- stop_dac(s);
- return prog_dmabuf(s, &s->dma_dac);
-}
-
-
-static void dac_dma_interrupt(int irq, void *dev_id)
-{
- struct au1550_state *s = (struct au1550_state *) dev_id;
- struct dmabuf *db = &s->dma_dac;
- u32 ac97c_stat;
-
- spin_lock(&s->lock);
-
- ac97c_stat = au_readl(PSC_AC97STAT);
- if (ac97c_stat & (AC97C_XU | AC97C_XO | AC97C_TE))
- pr_debug("AC97C status = 0x%08x\n", ac97c_stat);
- db->dma_qcount--;
-
- if (db->count >= db->fragsize) {
- if (au1xxx_dbdma_put_source(db->dmanr, db->nextOut,
- db->fragsize) == 0) {
- err("qcount < 2 and no ring room!");
- }
- db->nextOut += db->fragsize;
- if (db->nextOut >= db->rawbuf + db->dmasize)
- db->nextOut -= db->dmasize;
- db->count -= db->fragsize;
- db->total_bytes += db->dma_fragsize;
- db->dma_qcount++;
- }
-
- /* wake up anybody listening */
- if (waitqueue_active(&db->wait))
- wake_up(&db->wait);
-
- spin_unlock(&s->lock);
-}
-
-
-static void adc_dma_interrupt(int irq, void *dev_id)
-{
- struct au1550_state *s = (struct au1550_state *)dev_id;
- struct dmabuf *dp = &s->dma_adc;
- u32 obytes;
- char *obuf;
-
- spin_lock(&s->lock);
-
- /* Pull the buffer from the dma queue.
- */
- au1xxx_dbdma_get_dest(dp->dmanr, (void *)(&obuf), &obytes);
-
- if ((dp->count + obytes) > dp->dmasize) {
- /* Overrun. Stop ADC and log the error
- */
- spin_unlock(&s->lock);
- stop_adc(s);
- dp->error++;
- err("adc overrun");
- return;
- }
-
- /* Put a new empty buffer on the destination DMA.
- */
- au1xxx_dbdma_put_dest(dp->dmanr, dp->nextIn, dp->dma_fragsize);
-
- dp->nextIn += dp->dma_fragsize;
- if (dp->nextIn >= dp->rawbuf + dp->dmasize)
- dp->nextIn -= dp->dmasize;
-
- dp->count += obytes;
- dp->total_bytes += obytes;
-
- /* wake up anybody listening
- */
- if (waitqueue_active(&dp->wait))
- wake_up(&dp->wait);
-
- spin_unlock(&s->lock);
-}
-
-static loff_t
-au1550_llseek(struct file *file, loff_t offset, int origin)
-{
- return -ESPIPE;
-}
-
-
-static int
-au1550_open_mixdev(struct inode *inode, struct file *file)
-{
- file->private_data = &au1550_state;
- return 0;
-}
-
-static int
-au1550_release_mixdev(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static int
-mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd,
- unsigned long arg)
-{
- return codec->mixer_ioctl(codec, cmd, arg);
-}
-
-static int
-au1550_ioctl_mixdev(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct au1550_state *s = (struct au1550_state *)file->private_data;
- struct ac97_codec *codec = s->codec;
-
- return mixdev_ioctl(codec, cmd, arg);
-}
-
-static /*const */ struct file_operations au1550_mixer_fops = {
- owner:THIS_MODULE,
- llseek:au1550_llseek,
- ioctl:au1550_ioctl_mixdev,
- open:au1550_open_mixdev,
- release:au1550_release_mixdev,
-};
-
-static int
-drain_dac(struct au1550_state *s, int nonblock)
-{
- unsigned long flags;
- int count, tmo;
-
- if (s->dma_dac.mapped || !s->dma_dac.ready || s->dma_dac.stopped)
- return 0;
-
- for (;;) {
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= s->dma_dac.fragsize)
- break;
- if (signal_pending(current))
- break;
- if (nonblock)
- return -EBUSY;
- tmo = 1000 * count / (s->no_vra ?
- 48000 : s->dma_dac.sample_rate);
- tmo /= s->dma_dac.dma_bytes_per_sample;
- au1550_delay(tmo);
- }
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-static inline u8 S16_TO_U8(s16 ch)
-{
- return (u8) (ch >> 8) + 0x80;
-}
-static inline s16 U8_TO_S16(u8 ch)
-{
- return (s16) (ch - 0x80) << 8;
-}
-
-/*
- * Translates user samples to dma buffer suitable for AC'97 DAC data:
- * If mono, copy left channel to right channel in dma buffer.
- * If 8 bit samples, cvt to 16-bit before writing to dma buffer.
- * If interpolating (no VRA), duplicate every audio frame src_factor times.
- */
-static int
-translate_from_user(struct dmabuf *db, char* dmabuf, char* userbuf,
- int dmacount)
-{
- int sample, i;
- int interp_bytes_per_sample;
- int num_samples;
- int mono = (db->num_channels == 1);
- char usersample[12];
- s16 ch, dmasample[6];
-
- if (db->sample_size == 16 && !mono && db->src_factor == 1) {
- /* no translation necessary, just copy
- */
- if (copy_from_user(dmabuf, userbuf, dmacount))
- return -EFAULT;
- return dmacount;
- }
-
- interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor;
- num_samples = dmacount / interp_bytes_per_sample;
-
- for (sample = 0; sample < num_samples; sample++) {
- if (copy_from_user(usersample, userbuf,
- db->user_bytes_per_sample)) {
- return -EFAULT;
- }
-
- for (i = 0; i < db->num_channels; i++) {
- if (db->sample_size == 8)
- ch = U8_TO_S16(usersample[i]);
- else
- ch = *((s16 *) (&usersample[i * 2]));
- dmasample[i] = ch;
- if (mono)
- dmasample[i + 1] = ch; /* right channel */
- }
-
- /* duplicate every audio frame src_factor times
- */
- for (i = 0; i < db->src_factor; i++)
- memcpy(dmabuf, dmasample, db->dma_bytes_per_sample);
-
- userbuf += db->user_bytes_per_sample;
- dmabuf += interp_bytes_per_sample;
- }
-
- return num_samples * interp_bytes_per_sample;
-}
-
-/*
- * Translates AC'97 ADC samples to user buffer:
- * If mono, send only left channel to user buffer.
- * If 8 bit samples, cvt from 16 to 8 bit before writing to user buffer.
- * If decimating (no VRA), skip over src_factor audio frames.
- */
-static int
-translate_to_user(struct dmabuf *db, char* userbuf, char* dmabuf,
- int dmacount)
-{
- int sample, i;
- int interp_bytes_per_sample;
- int num_samples;
- int mono = (db->num_channels == 1);
- char usersample[12];
-
- if (db->sample_size == 16 && !mono && db->src_factor == 1) {
- /* no translation necessary, just copy
- */
- if (copy_to_user(userbuf, dmabuf, dmacount))
- return -EFAULT;
- return dmacount;
- }
-
- interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor;
- num_samples = dmacount / interp_bytes_per_sample;
-
- for (sample = 0; sample < num_samples; sample++) {
- for (i = 0; i < db->num_channels; i++) {
- if (db->sample_size == 8)
- usersample[i] =
- S16_TO_U8(*((s16 *) (&dmabuf[i * 2])));
- else
- *((s16 *) (&usersample[i * 2])) =
- *((s16 *) (&dmabuf[i * 2]));
- }
-
- if (copy_to_user(userbuf, usersample,
- db->user_bytes_per_sample)) {
- return -EFAULT;
- }
-
- userbuf += db->user_bytes_per_sample;
- dmabuf += interp_bytes_per_sample;
- }
-
- return num_samples * interp_bytes_per_sample;
-}
-
-/*
- * Copy audio data to/from user buffer from/to dma buffer, taking care
- * that we wrap when reading/writing the dma buffer. Returns actual byte
- * count written to or read from the dma buffer.
- */
-static int
-copy_dmabuf_user(struct dmabuf *db, char* userbuf, int count, int to_user)
-{
- char *bufptr = to_user ? db->nextOut : db->nextIn;
- char *bufend = db->rawbuf + db->dmasize;
- int cnt, ret;
-
- if (bufptr + count > bufend) {
- int partial = (int) (bufend - bufptr);
- if (to_user) {
- if ((cnt = translate_to_user(db, userbuf,
- bufptr, partial)) < 0)
- return cnt;
- ret = cnt;
- if ((cnt = translate_to_user(db, userbuf + partial,
- db->rawbuf,
- count - partial)) < 0)
- return cnt;
- ret += cnt;
- } else {
- if ((cnt = translate_from_user(db, bufptr, userbuf,
- partial)) < 0)
- return cnt;
- ret = cnt;
- if ((cnt = translate_from_user(db, db->rawbuf,
- userbuf + partial,
- count - partial)) < 0)
- return cnt;
- ret += cnt;
- }
- } else {
- if (to_user)
- ret = translate_to_user(db, userbuf, bufptr, count);
- else
- ret = translate_from_user(db, bufptr, userbuf, count);
- }
-
- return ret;
-}
-
-
-static ssize_t
-au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
-{
- struct au1550_state *s = (struct au1550_state *)file->private_data;
- struct dmabuf *db = &s->dma_adc;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- int cnt, usercnt, avail;
-
- if (db->mapped)
- return -ENXIO;
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- ret = 0;
-
- count *= db->cnt_factor;
-
- mutex_lock(&s->sem);
- add_wait_queue(&db->wait, &wait);
-
- while (count > 0) {
- /* wait for samples in ADC dma buffer
- */
- do {
- spin_lock_irqsave(&s->lock, flags);
- if (db->stopped)
- start_adc(s);
- avail = db->count;
- if (avail <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&s->lock, flags);
- if (avail <= 0) {
- 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);
- }
- } while (avail <= 0);
-
- /* copy from nextOut to user
- */
- if ((cnt = copy_dmabuf_user(db, buffer,
- count > avail ?
- avail : count, 1)) < 0) {
- if (!ret)
- ret = -EFAULT;
- goto out;
- }
-
- spin_lock_irqsave(&s->lock, flags);
- db->count -= cnt;
- db->nextOut += cnt;
- if (db->nextOut >= db->rawbuf + db->dmasize)
- db->nextOut -= db->dmasize;
- spin_unlock_irqrestore(&s->lock, flags);
-
- count -= cnt;
- usercnt = cnt / db->cnt_factor;
- buffer += usercnt;
- ret += usercnt;
- } /* while (count > 0) */
-
-out:
- mutex_unlock(&s->sem);
-out2:
- remove_wait_queue(&db->wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-static ssize_t
-au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
-{
- struct au1550_state *s = (struct au1550_state *)file->private_data;
- struct dmabuf *db = &s->dma_dac;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret = 0;
- unsigned long flags;
- int cnt, usercnt, avail;
-
- pr_debug("write: count=%d\n", count);
-
- if (db->mapped)
- return -ENXIO;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
-
- count *= db->cnt_factor;
-
- mutex_lock(&s->sem);
- add_wait_queue(&db->wait, &wait);
-
- while (count > 0) {
- /* wait for space in playback buffer
- */
- do {
- spin_lock_irqsave(&s->lock, flags);
- avail = (int) db->dmasize - db->count;
- if (avail <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&s->lock, flags);
- if (avail <= 0) {
- 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);
- }
- } while (avail <= 0);
-
- /* copy from user to nextIn
- */
- if ((cnt = copy_dmabuf_user(db, (char *) buffer,
- count > avail ?
- avail : count, 0)) < 0) {
- if (!ret)
- ret = -EFAULT;
- goto out;
- }
-
- spin_lock_irqsave(&s->lock, flags);
- db->count += cnt;
- db->nextIn += cnt;
- if (db->nextIn >= db->rawbuf + db->dmasize)
- db->nextIn -= db->dmasize;
-
- /* If the data is available, we want to keep two buffers
- * on the dma queue. If the queue count reaches zero,
- * we know the dma has stopped.
- */
- while ((db->dma_qcount < 2) && (db->count >= db->fragsize)) {
- if (au1xxx_dbdma_put_source(db->dmanr, db->nextOut,
- db->fragsize) == 0) {
- err("qcount < 2 and no ring room!");
- }
- db->nextOut += db->fragsize;
- if (db->nextOut >= db->rawbuf + db->dmasize)
- db->nextOut -= db->dmasize;
- db->total_bytes += db->dma_fragsize;
- if (db->dma_qcount == 0)
- start_dac(s);
- db->dma_qcount++;
- }
- spin_unlock_irqrestore(&s->lock, flags);
-
- count -= cnt;
- usercnt = cnt / db->cnt_factor;
- buffer += usercnt;
- ret += usercnt;
- } /* while (count > 0) */
-
-out:
- mutex_unlock(&s->sem);
-out2:
- remove_wait_queue(&db->wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int
-au1550_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct au1550_state *s = (struct au1550_state *)file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- if (file->f_mode & FMODE_WRITE) {
- if (!s->dma_dac.ready)
- return 0;
- poll_wait(file, &s->dma_dac.wait, wait);
- }
- if (file->f_mode & FMODE_READ) {
- if (!s->dma_adc.ready)
- return 0;
- poll_wait(file, &s->dma_adc.wait, wait);
- }
-
- spin_lock_irqsave(&s->lock, flags);
-
- if (file->f_mode & FMODE_READ) {
- if (s->dma_adc.count >= (signed)s->dma_adc.dma_fragsize)
- mask |= POLLIN | POLLRDNORM;
- }
- if (file->f_mode & FMODE_WRITE) {
- if (s->dma_dac.mapped) {
- if (s->dma_dac.count >=
- (signed)s->dma_dac.dma_fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- if ((signed) s->dma_dac.dmasize >=
- s->dma_dac.count + (signed)s->dma_dac.dma_fragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return mask;
-}
-
-static int
-au1550_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct au1550_state *s = (struct au1550_state *)file->private_data;
- struct dmabuf *db;
- unsigned long size;
- int ret = 0;
-
- lock_kernel();
- mutex_lock(&s->sem);
- if (vma->vm_flags & VM_WRITE)
- db = &s->dma_dac;
- else if (vma->vm_flags & VM_READ)
- 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, page_to_pfn(virt_to_page(db->rawbuf)),
- size, vma->vm_page_prot)) {
- ret = -EAGAIN;
- goto out;
- }
- vma->vm_flags &= ~VM_IO;
- db->mapped = 1;
-out:
- mutex_unlock(&s->sem);
- unlock_kernel();
- return ret;
-}
-
-#ifdef DEBUG
-static struct ioctl_str_t {
- unsigned int cmd;
- const char *str;
-} ioctl_str[] = {
- {SNDCTL_DSP_RESET, "SNDCTL_DSP_RESET"},
- {SNDCTL_DSP_SYNC, "SNDCTL_DSP_SYNC"},
- {SNDCTL_DSP_SPEED, "SNDCTL_DSP_SPEED"},
- {SNDCTL_DSP_STEREO, "SNDCTL_DSP_STEREO"},
- {SNDCTL_DSP_GETBLKSIZE, "SNDCTL_DSP_GETBLKSIZE"},
- {SNDCTL_DSP_SAMPLESIZE, "SNDCTL_DSP_SAMPLESIZE"},
- {SNDCTL_DSP_CHANNELS, "SNDCTL_DSP_CHANNELS"},
- {SOUND_PCM_WRITE_CHANNELS, "SOUND_PCM_WRITE_CHANNELS"},
- {SOUND_PCM_WRITE_FILTER, "SOUND_PCM_WRITE_FILTER"},
- {SNDCTL_DSP_POST, "SNDCTL_DSP_POST"},
- {SNDCTL_DSP_SUBDIVIDE, "SNDCTL_DSP_SUBDIVIDE"},
- {SNDCTL_DSP_SETFRAGMENT, "SNDCTL_DSP_SETFRAGMENT"},
- {SNDCTL_DSP_GETFMTS, "SNDCTL_DSP_GETFMTS"},
- {SNDCTL_DSP_SETFMT, "SNDCTL_DSP_SETFMT"},
- {SNDCTL_DSP_GETOSPACE, "SNDCTL_DSP_GETOSPACE"},
- {SNDCTL_DSP_GETISPACE, "SNDCTL_DSP_GETISPACE"},
- {SNDCTL_DSP_NONBLOCK, "SNDCTL_DSP_NONBLOCK"},
- {SNDCTL_DSP_GETCAPS, "SNDCTL_DSP_GETCAPS"},
- {SNDCTL_DSP_GETTRIGGER, "SNDCTL_DSP_GETTRIGGER"},
- {SNDCTL_DSP_SETTRIGGER, "SNDCTL_DSP_SETTRIGGER"},
- {SNDCTL_DSP_GETIPTR, "SNDCTL_DSP_GETIPTR"},
- {SNDCTL_DSP_GETOPTR, "SNDCTL_DSP_GETOPTR"},
- {SNDCTL_DSP_MAPINBUF, "SNDCTL_DSP_MAPINBUF"},
- {SNDCTL_DSP_MAPOUTBUF, "SNDCTL_DSP_MAPOUTBUF"},
- {SNDCTL_DSP_SETSYNCRO, "SNDCTL_DSP_SETSYNCRO"},
- {SNDCTL_DSP_SETDUPLEX, "SNDCTL_DSP_SETDUPLEX"},
- {SNDCTL_DSP_GETODELAY, "SNDCTL_DSP_GETODELAY"},
- {SNDCTL_DSP_GETCHANNELMASK, "SNDCTL_DSP_GETCHANNELMASK"},
- {SNDCTL_DSP_BIND_CHANNEL, "SNDCTL_DSP_BIND_CHANNEL"},
- {OSS_GETVERSION, "OSS_GETVERSION"},
- {SOUND_PCM_READ_RATE, "SOUND_PCM_READ_RATE"},
- {SOUND_PCM_READ_CHANNELS, "SOUND_PCM_READ_CHANNELS"},
- {SOUND_PCM_READ_BITS, "SOUND_PCM_READ_BITS"},
- {SOUND_PCM_READ_FILTER, "SOUND_PCM_READ_FILTER"}
-};
-#endif
-
-static int
-dma_count_done(struct dmabuf *db)
-{
- if (db->stopped)
- return 0;
-
- return db->dma_fragsize - au1xxx_get_dma_residue(db->dmanr);
-}
-
-
-static int
-au1550_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct au1550_state *s = (struct au1550_state *)file->private_data;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int count;
- int val, mapped, ret, diff;
-
- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
-
-#ifdef DEBUG
- for (count = 0; count < ARRAY_SIZE(ioctl_str); count++) {
- if (ioctl_str[count].cmd == cmd)
- break;
- }
- if (count < ARRAY_SIZE(ioctl_str))
- pr_debug("ioctl %s, arg=0x%lxn", ioctl_str[count].str, arg);
- else
- pr_debug("ioctl 0x%x unknown, arg=0x%lx\n", cmd, arg);
-#endif
-
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, (int *) arg);
-
- case SNDCTL_DSP_SYNC:
- if (file->f_mode & FMODE_WRITE)
- return drain_dac(s, 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, (int *)arg);
-
- case SNDCTL_DSP_RESET:
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- synchronize_irq();
- s->dma_dac.count = s->dma_dac.total_bytes = 0;
- s->dma_dac.nextIn = s->dma_dac.nextOut =
- s->dma_dac.rawbuf;
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- synchronize_irq();
- s->dma_adc.count = s->dma_adc.total_bytes = 0;
- s->dma_adc.nextIn = s->dma_adc.nextOut =
- s->dma_adc.rawbuf;
- }
- return 0;
-
- case SNDCTL_DSP_SPEED:
- if (get_user(val, (int *) arg))
- return -EFAULT;
- if (val >= 0) {
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- set_adc_rate(s, val);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- set_dac_rate(s, val);
- }
- if (s->open_mode & FMODE_READ)
- if ((ret = prog_dmabuf_adc(s)))
- return ret;
- if (s->open_mode & FMODE_WRITE)
- if ((ret = prog_dmabuf_dac(s)))
- return ret;
- }
- return put_user((file->f_mode & FMODE_READ) ?
- s->dma_adc.sample_rate :
- s->dma_dac.sample_rate,
- (int *)arg);
-
- case SNDCTL_DSP_STEREO:
- if (get_user(val, (int *) arg))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.num_channels = val ? 2 : 1;
- if ((ret = prog_dmabuf_adc(s)))
- return ret;
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.num_channels = val ? 2 : 1;
- if (s->codec_ext_caps & AC97_EXT_DACS) {
- /* disable surround and center/lfe in AC'97
- */
- u16 ext_stat = rdcodec(s->codec,
- AC97_EXTENDED_STATUS);
- wrcodec(s->codec, AC97_EXTENDED_STATUS,
- ext_stat | (AC97_EXTSTAT_PRI |
- AC97_EXTSTAT_PRJ |
- AC97_EXTSTAT_PRK));
- }
- if ((ret = prog_dmabuf_dac(s)))
- return ret;
- }
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, (int *) arg))
- return -EFAULT;
- if (val != 0) {
- if (file->f_mode & FMODE_READ) {
- if (val < 0 || val > 2)
- return -EINVAL;
- stop_adc(s);
- s->dma_adc.num_channels = val;
- if ((ret = prog_dmabuf_adc(s)))
- return ret;
- }
- if (file->f_mode & FMODE_WRITE) {
- switch (val) {
- case 1:
- case 2:
- break;
- case 3:
- case 5:
- return -EINVAL;
- case 4:
- if (!(s->codec_ext_caps &
- AC97_EXTID_SDAC))
- return -EINVAL;
- break;
- case 6:
- if ((s->codec_ext_caps &
- AC97_EXT_DACS) != AC97_EXT_DACS)
- return -EINVAL;
- break;
- default:
- return -EINVAL;
- }
-
- stop_dac(s);
- if (val <= 2 &&
- (s->codec_ext_caps & AC97_EXT_DACS)) {
- /* disable surround and center/lfe
- * channels in AC'97
- */
- u16 ext_stat =
- rdcodec(s->codec,
- AC97_EXTENDED_STATUS);
- wrcodec(s->codec,
- AC97_EXTENDED_STATUS,
- ext_stat | (AC97_EXTSTAT_PRI |
- AC97_EXTSTAT_PRJ |
- AC97_EXTSTAT_PRK));
- } else if (val >= 4) {
- /* enable surround, center/lfe
- * channels in AC'97
- */
- u16 ext_stat =
- rdcodec(s->codec,
- AC97_EXTENDED_STATUS);
- ext_stat &= ~AC97_EXTSTAT_PRJ;
- if (val == 6)
- ext_stat &=
- ~(AC97_EXTSTAT_PRI |
- AC97_EXTSTAT_PRK);
- wrcodec(s->codec,
- AC97_EXTENDED_STATUS,
- ext_stat);
- }
-
- s->dma_dac.num_channels = val;
- if ((ret = prog_dmabuf_dac(s)))
- return ret;
- }
- }
- return put_user(val, (int *) arg);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(AFMT_S16_LE | AFMT_U8, (int *) arg);
-
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */
- if (get_user(val, (int *) arg))
- return -EFAULT;
- if (val != AFMT_QUERY) {
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- if (val == AFMT_S16_LE)
- s->dma_adc.sample_size = 16;
- else {
- val = AFMT_U8;
- s->dma_adc.sample_size = 8;
- }
- if ((ret = prog_dmabuf_adc(s)))
- return ret;
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- if (val == AFMT_S16_LE)
- s->dma_dac.sample_size = 16;
- else {
- val = AFMT_U8;
- s->dma_dac.sample_size = 8;
- }
- if ((ret = prog_dmabuf_dac(s)))
- return ret;
- }
- } else {
- if (file->f_mode & FMODE_READ)
- val = (s->dma_adc.sample_size == 16) ?
- AFMT_S16_LE : AFMT_U8;
- else
- val = (s->dma_dac.sample_size == 16) ?
- AFMT_S16_LE : AFMT_U8;
- }
- return put_user(val, (int *) arg);
-
- case SNDCTL_DSP_POST:
- return 0;
-
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
- spin_lock_irqsave(&s->lock, flags);
- if (file->f_mode & FMODE_READ && !s->dma_adc.stopped)
- val |= PCM_ENABLE_INPUT;
- if (file->f_mode & FMODE_WRITE && !s->dma_dac.stopped)
- val |= PCM_ENABLE_OUTPUT;
- spin_unlock_irqrestore(&s->lock, flags);
- return put_user(val, (int *) arg);
-
- case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, (int *) arg))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- if (val & PCM_ENABLE_INPUT) {
- spin_lock_irqsave(&s->lock, flags);
- start_adc(s);
- spin_unlock_irqrestore(&s->lock, flags);
- } else
- stop_adc(s);
- }
- if (file->f_mode & FMODE_WRITE) {
- if (val & PCM_ENABLE_OUTPUT) {
- spin_lock_irqsave(&s->lock, flags);
- start_dac(s);
- spin_unlock_irqrestore(&s->lock, flags);
- } else
- stop_dac(s);
- }
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- abinfo.fragsize = s->dma_dac.fragsize;
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac.count;
- count -= dma_count_done(&s->dma_dac);
- spin_unlock_irqrestore(&s->lock, flags);
- if (count < 0)
- count = 0;
- abinfo.bytes = (s->dma_dac.dmasize - count) /
- s->dma_dac.cnt_factor;
- abinfo.fragstotal = s->dma_dac.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
- pr_debug("ioctl SNDCTL_DSP_GETOSPACE: bytes=%d, fragments=%d\n", abinfo.bytes, abinfo.fragments);
- return copy_to_user((void *) arg, &abinfo,
- sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- abinfo.fragsize = s->dma_adc.fragsize;
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_adc.count;
- count += dma_count_done(&s->dma_adc);
- spin_unlock_irqrestore(&s->lock, flags);
- if (count < 0)
- count = 0;
- abinfo.bytes = count / s->dma_adc.cnt_factor;
- abinfo.fragstotal = s->dma_adc.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
- return copy_to_user((void *) arg, &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;
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac.count;
- count -= dma_count_done(&s->dma_dac);
- spin_unlock_irqrestore(&s->lock, flags);
- if (count < 0)
- count = 0;
- count /= s->dma_dac.cnt_factor;
- return put_user(count, (int *) arg);
-
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- spin_lock_irqsave(&s->lock, flags);
- cinfo.bytes = s->dma_adc.total_bytes;
- count = s->dma_adc.count;
- if (!s->dma_adc.stopped) {
- diff = dma_count_done(&s->dma_adc);
- count += diff;
- cinfo.bytes += diff;
- cinfo.ptr = virt_to_phys(s->dma_adc.nextIn) + diff -
- virt_to_phys(s->dma_adc.rawbuf);
- } else
- cinfo.ptr = virt_to_phys(s->dma_adc.nextIn) -
- virt_to_phys(s->dma_adc.rawbuf);
- if (s->dma_adc.mapped)
- s->dma_adc.count &= (s->dma_adc.dma_fragsize-1);
- spin_unlock_irqrestore(&s->lock, flags);
- if (count < 0)
- count = 0;
- cinfo.blocks = count >> s->dma_adc.fragshift;
- return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
-
- case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- spin_lock_irqsave(&s->lock, flags);
- cinfo.bytes = s->dma_dac.total_bytes;
- count = s->dma_dac.count;
- if (!s->dma_dac.stopped) {
- diff = dma_count_done(&s->dma_dac);
- count -= diff;
- cinfo.bytes += diff;
- cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) + diff -
- virt_to_phys(s->dma_dac.rawbuf);
- } else
- cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) -
- virt_to_phys(s->dma_dac.rawbuf);
- if (s->dma_dac.mapped)
- s->dma_dac.count &= (s->dma_dac.dma_fragsize-1);
- spin_unlock_irqrestore(&s->lock, flags);
- if (count < 0)
- count = 0;
- cinfo.blocks = count >> s->dma_dac.fragshift;
- return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
-
- case SNDCTL_DSP_GETBLKSIZE:
- if (file->f_mode & FMODE_WRITE)
- return put_user(s->dma_dac.fragsize, (int *) arg);
- else
- return put_user(s->dma_adc.fragsize, (int *) arg);
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, (int *) arg))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- 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 ((ret = prog_dmabuf_adc(s)))
- return ret;
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ossfragshift = val & 0xffff;
- s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_dac.ossfragshift < 4)
- s->dma_dac.ossfragshift = 4;
- if (s->dma_dac.ossfragshift > 15)
- s->dma_dac.ossfragshift = 15;
- if (s->dma_dac.ossmaxfrags < 4)
- s->dma_dac.ossmaxfrags = 4;
- if ((ret = prog_dmabuf_dac(s)))
- return ret;
- }
- return 0;
-
- case SNDCTL_DSP_SUBDIVIDE:
- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
- (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
- return -EINVAL;
- if (get_user(val, (int *) arg))
- return -EFAULT;
- if (val != 1 && val != 2 && val != 4)
- return -EINVAL;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.subdivision = val;
- if ((ret = prog_dmabuf_adc(s)))
- return ret;
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.subdivision = val;
- if ((ret = prog_dmabuf_dac(s)))
- return ret;
- }
- return 0;
-
- case SOUND_PCM_READ_RATE:
- return put_user((file->f_mode & FMODE_READ) ?
- s->dma_adc.sample_rate :
- s->dma_dac.sample_rate,
- (int *)arg);
-
- case SOUND_PCM_READ_CHANNELS:
- if (file->f_mode & FMODE_READ)
- return put_user(s->dma_adc.num_channels, (int *)arg);
- else
- return put_user(s->dma_dac.num_channels, (int *)arg);
-
- case SOUND_PCM_READ_BITS:
- if (file->f_mode & FMODE_READ)
- return put_user(s->dma_adc.sample_size, (int *)arg);
- else
- return put_user(s->dma_dac.sample_size, (int *)arg);
-
- 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
-au1550_open(struct inode *inode, struct file *file)
-{
- int minor = MINOR(inode->i_rdev);
- DECLARE_WAITQUEUE(wait, current);
- struct au1550_state *s = &au1550_state;
- int ret;
-
-#ifdef DEBUG
- if (file->f_flags & O_NONBLOCK)
- pr_debug("open: non-blocking\n");
- else
- pr_debug("open: blocking\n");
-#endif
-
- 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);
- }
-
- stop_dac(s);
- stop_adc(s);
-
- if (file->f_mode & FMODE_READ) {
- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags =
- s->dma_adc.subdivision = s->dma_adc.total_bytes = 0;
- s->dma_adc.num_channels = 1;
- s->dma_adc.sample_size = 8;
- set_adc_rate(s, 8000);
- if ((minor & 0xf) == SND_DEV_DSP16)
- s->dma_adc.sample_size = 16;
- }
-
- if (file->f_mode & FMODE_WRITE) {
- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags =
- s->dma_dac.subdivision = s->dma_dac.total_bytes = 0;
- s->dma_dac.num_channels = 1;
- s->dma_dac.sample_size = 8;
- set_dac_rate(s, 8000);
- if ((minor & 0xf) == SND_DEV_DSP16)
- s->dma_dac.sample_size = 16;
- }
-
- if (file->f_mode & FMODE_READ) {
- if ((ret = prog_dmabuf_adc(s)))
- return ret;
- }
- if (file->f_mode & FMODE_WRITE) {
- if ((ret = prog_dmabuf_dac(s)))
- return ret;
- }
-
- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
- mutex_unlock(&s->open_mutex);
- mutex_init(&s->sem);
- return 0;
-}
-
-static int
-au1550_release(struct inode *inode, struct file *file)
-{
- struct au1550_state *s = (struct au1550_state *)file->private_data;
-
- lock_kernel();
-
- if (file->f_mode & FMODE_WRITE) {
- unlock_kernel();
- drain_dac(s, file->f_flags & O_NONBLOCK);
- lock_kernel();
- }
-
- mutex_lock(&s->open_mutex);
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- kfree(s->dma_dac.rawbuf);
- s->dma_dac.rawbuf = NULL;
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- kfree(s->dma_adc.rawbuf);
- s->dma_adc.rawbuf = NULL;
- }
- 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 au1550_audio_fops = {
- owner: THIS_MODULE,
- llseek: au1550_llseek,
- read: au1550_read,
- write: au1550_write,
- poll: au1550_poll,
- ioctl: au1550_ioctl,
- mmap: au1550_mmap,
- open: au1550_open,
- release: au1550_release,
-};
-
-MODULE_AUTHOR("Advanced Micro Devices (AMD), dan@embeddededge.com");
-MODULE_DESCRIPTION("Au1550 AC97 Audio Driver");
-MODULE_LICENSE("GPL");
-
-
-static int __devinit
-au1550_probe(void)
-{
- struct au1550_state *s = &au1550_state;
- int val;
-
- memset(s, 0, sizeof(struct au1550_state));
-
- init_waitqueue_head(&s->dma_adc.wait);
- init_waitqueue_head(&s->dma_dac.wait);
- init_waitqueue_head(&s->open_wait);
- mutex_init(&s->open_mutex);
- spin_lock_init(&s->lock);
-
- s->codec = ac97_alloc_codec();
- if(s->codec == NULL) {
- err("Out of memory");
- return -1;
- }
- s->codec->private_data = s;
- s->codec->id = 0;
- s->codec->codec_read = rdcodec;
- s->codec->codec_write = wrcodec;
- s->codec->codec_wait = waitcodec;
-
- if (!request_mem_region(CPHYSADDR(AC97_PSC_SEL),
- 0x30, "Au1550 AC97")) {
- err("AC'97 ports in use");
- }
-
- /* Allocate the DMA Channels
- */
- if ((s->dma_dac.dmanr = au1xxx_dbdma_chan_alloc(DBDMA_MEM_CHAN,
- DBDMA_AC97_TX_CHAN, dac_dma_interrupt, (void *)s)) == 0) {
- err("Can't get DAC DMA");
- goto err_dma1;
- }
- au1xxx_dbdma_set_devwidth(s->dma_dac.dmanr, 16);
- if (au1xxx_dbdma_ring_alloc(s->dma_dac.dmanr,
- NUM_DBDMA_DESCRIPTORS) == 0) {
- err("Can't get DAC DMA descriptors");
- goto err_dma1;
- }
-
- if ((s->dma_adc.dmanr = au1xxx_dbdma_chan_alloc(DBDMA_AC97_RX_CHAN,
- DBDMA_MEM_CHAN, adc_dma_interrupt, (void *)s)) == 0) {
- err("Can't get ADC DMA");
- goto err_dma2;
- }
- au1xxx_dbdma_set_devwidth(s->dma_adc.dmanr, 16);
- if (au1xxx_dbdma_ring_alloc(s->dma_adc.dmanr,
- NUM_DBDMA_DESCRIPTORS) == 0) {
- err("Can't get ADC DMA descriptors");
- goto err_dma2;
- }
-
- pr_info("DAC: DMA%d, ADC: DMA%d", DBDMA_AC97_TX_CHAN, DBDMA_AC97_RX_CHAN);
-
- /* register devices */
-
- if ((s->dev_audio = register_sound_dsp(&au1550_audio_fops, -1)) < 0)
- goto err_dev1;
- if ((s->codec->dev_mixer =
- register_sound_mixer(&au1550_mixer_fops, -1)) < 0)
- goto err_dev2;
-
- /* The GPIO for the appropriate PSC was configured by the
- * board specific start up.
- *
- * configure PSC for AC'97
- */
- au_writel(0, AC97_PSC_CTRL); /* Disable PSC */
- au_sync();
- au_writel((PSC_SEL_CLK_SERCLK | PSC_SEL_PS_AC97MODE), AC97_PSC_SEL);
- au_sync();
-
- /* cold reset the AC'97
- */
- au_writel(PSC_AC97RST_RST, PSC_AC97RST);
- au_sync();
- au1550_delay(10);
- au_writel(0, PSC_AC97RST);
- au_sync();
-
- /* need to delay around 500msec(bleech) to give
- some CODECs enough time to wakeup */
- au1550_delay(500);
-
- /* warm reset the AC'97 to start the bitclk
- */
- au_writel(PSC_AC97RST_SNC, PSC_AC97RST);
- au_sync();
- udelay(100);
- au_writel(0, PSC_AC97RST);
- au_sync();
-
- /* Enable PSC
- */
- au_writel(PSC_CTRL_ENABLE, AC97_PSC_CTRL);
- au_sync();
-
- /* Wait for PSC ready.
- */
- do {
- val = au_readl(PSC_AC97STAT);
- au_sync();
- } while ((val & PSC_AC97STAT_SR) == 0);
-
- /* Configure AC97 controller.
- * Deep FIFO, 16-bit sample, DMA, make sure DMA matches fifo size.
- */
- val = PSC_AC97CFG_SET_LEN(16);
- val |= PSC_AC97CFG_RT_FIFO8 | PSC_AC97CFG_TT_FIFO8;
-
- /* Enable device so we can at least
- * talk over the AC-link.
- */
- au_writel(val, PSC_AC97CFG);
- au_writel(PSC_AC97MSK_ALLMASK, PSC_AC97MSK);
- au_sync();
- val |= PSC_AC97CFG_DE_ENABLE;
- au_writel(val, PSC_AC97CFG);
- au_sync();
-
- /* Wait for Device ready.
- */
- do {
- val = au_readl(PSC_AC97STAT);
- au_sync();
- } while ((val & PSC_AC97STAT_DR) == 0);
-
- /* codec init */
- if (!ac97_probe_codec(s->codec))
- goto err_dev3;
-
- s->codec_base_caps = rdcodec(s->codec, AC97_RESET);
- s->codec_ext_caps = rdcodec(s->codec, AC97_EXTENDED_ID);
- pr_info("AC'97 Base/Extended ID = %04x/%04x",
- s->codec_base_caps, s->codec_ext_caps);
-
- if (!(s->codec_ext_caps & AC97_EXTID_VRA)) {
- /* codec does not support VRA
- */
- s->no_vra = 1;
- } else if (!vra) {
- /* Boot option says disable VRA
- */
- u16 ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS);
- wrcodec(s->codec, AC97_EXTENDED_STATUS,
- ac97_extstat & ~AC97_EXTSTAT_VRA);
- s->no_vra = 1;
- }
- if (s->no_vra)
- pr_info("no VRA, interpolating and decimating");
-
- /* set mic to be the recording source */
- val = SOUND_MASK_MIC;
- mixdev_ioctl(s->codec, SOUND_MIXER_WRITE_RECSRC,
- (unsigned long) &val);
-
- return 0;
-
- err_dev3:
- unregister_sound_mixer(s->codec->dev_mixer);
- err_dev2:
- unregister_sound_dsp(s->dev_audio);
- err_dev1:
- au1xxx_dbdma_chan_free(s->dma_adc.dmanr);
- err_dma2:
- au1xxx_dbdma_chan_free(s->dma_dac.dmanr);
- err_dma1:
- release_mem_region(CPHYSADDR(AC97_PSC_SEL), 0x30);
-
- ac97_release_codec(s->codec);
- return -1;
-}
-
-static void __devinit
-au1550_remove(void)
-{
- struct au1550_state *s = &au1550_state;
-
- if (!s)
- return;
- synchronize_irq();
- au1xxx_dbdma_chan_free(s->dma_adc.dmanr);
- au1xxx_dbdma_chan_free(s->dma_dac.dmanr);
- release_mem_region(CPHYSADDR(AC97_PSC_SEL), 0x30);
- unregister_sound_dsp(s->dev_audio);
- unregister_sound_mixer(s->codec->dev_mixer);
- ac97_release_codec(s->codec);
-}
-
-static int __init
-init_au1550(void)
-{
- return au1550_probe();
-}
-
-static void __exit
-cleanup_au1550(void)
-{
- au1550_remove();
-}
-
-module_init(init_au1550);
-module_exit(cleanup_au1550);
-
-#ifndef MODULE
-
-static int __init
-au1550_setup(char *options)
-{
- char *this_opt;
-
- if (!options || !*options)
- return 0;
-
- while ((this_opt = strsep(&options, ","))) {
- if (!*this_opt)
- continue;
- if (!strncmp(this_opt, "vra", 3)) {
- vra = 1;
- }
- }
-
- return 1;
-}
-
-__setup("au1550_audio=", au1550_setup);
-
-#endif /* MODULE */
diff --git a/sound/oss/audio.c b/sound/oss/audio.c
index 89bd27a5e86..09c932f899b 100644
--- a/sound/oss/audio.c
+++ b/sound/oss/audio.c
@@ -354,7 +354,7 @@ int audio_read(int dev, struct file *file, char __user *buf, int count)
if(copy_to_user(&(buf)[p], fixit, l))
return -EFAULT;
- };
+ }
DMAbuf_rmchars(dev, buf_no, l);
@@ -433,7 +433,9 @@ int audio_ioctl(int dev, struct file *file, unsigned int cmd, void __user *arg)
return dma_ioctl(dev, cmd, arg);
case SNDCTL_DSP_NONBLOCK:
+ spin_lock(&file->f_lock);
file->f_flags |= O_NONBLOCK;
+ spin_unlock(&file->f_lock);
return 0;
case SNDCTL_DSP_GETCAPS:
@@ -512,7 +514,7 @@ int audio_ioctl(int dev, struct file *file, unsigned int cmd, void __user *arg)
count += dmap->bytes_in_use; /* Pointer wrap not handled yet */
count += dmap->byte_counter;
- /* Substract current count from the number of bytes written by app */
+ /* Subtract current count from the number of bytes written by app */
count = dmap->user_counter - count;
if (count < 0)
count = 0;
@@ -836,7 +838,7 @@ static int dma_ioctl(int dev, unsigned int cmd, void __user *arg)
if ((err = audio_devs[dev]->d->prepare_for_input(dev,
dmap_in->fragment_size, dmap_in->nbufs)) < 0) {
spin_unlock_irqrestore(&dmap_in->lock,flags);
- return -err;
+ return err;
}
dmap_in->dma_mode = DMODE_INPUT;
audio_devs[dev]->enable_bits |= PCM_ENABLE_INPUT;
@@ -929,7 +931,7 @@ static int dma_ioctl(int dev, unsigned int cmd, void __user *arg)
if (count < dmap_out->fragment_size && dmap_out->qhead != 0)
count += dmap_out->bytes_in_use; /* Pointer wrap not handled yet */
count += dmap_out->byte_counter;
- /* Substract current count from the number of bytes written by app */
+ /* Subtract current count from the number of bytes written by app */
count = dmap_out->user_counter - count;
if (count < 0)
count = 0;
diff --git a/sound/oss/btaudio.c b/sound/oss/btaudio.c
deleted file mode 100644
index 4d5cf05b892..00000000000
--- a/sound/oss/btaudio.c
+++ /dev/null
@@ -1,1139 +0,0 @@
-/*
- btaudio - bt878 audio dma driver for linux 2.4.x
-
- (c) 2000-2002 Gerd Knorr <kraxel@bytesex.org>
-
- 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.
-
-*/
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-#include <linux/slab.h>
-#include <linux/kdev_t.h>
-#include <linux/mutex.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-
-/* mmio access */
-#define btwrite(dat,adr) writel((dat), (bta->mmio+(adr)))
-#define btread(adr) readl(bta->mmio+(adr))
-
-#define btand(dat,adr) btwrite((dat) & btread(adr), adr)
-#define btor(dat,adr) btwrite((dat) | btread(adr), adr)
-#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
-
-/* registers (shifted because bta->mmio is long) */
-#define REG_INT_STAT (0x100 >> 2)
-#define REG_INT_MASK (0x104 >> 2)
-#define REG_GPIO_DMA_CTL (0x10c >> 2)
-#define REG_PACKET_LEN (0x110 >> 2)
-#define REG_RISC_STRT_ADD (0x114 >> 2)
-#define REG_RISC_COUNT (0x120 >> 2)
-
-/* IRQ bits - REG_INT_(STAT|MASK) */
-#define IRQ_SCERR (1 << 19)
-#define IRQ_OCERR (1 << 18)
-#define IRQ_PABORT (1 << 17)
-#define IRQ_RIPERR (1 << 16)
-#define IRQ_PPERR (1 << 15)
-#define IRQ_FDSR (1 << 14)
-#define IRQ_FTRGT (1 << 13)
-#define IRQ_FBUS (1 << 12)
-#define IRQ_RISCI (1 << 11)
-#define IRQ_OFLOW (1 << 3)
-
-#define IRQ_BTAUDIO (IRQ_SCERR | IRQ_OCERR | IRQ_PABORT | IRQ_RIPERR |\
- IRQ_PPERR | IRQ_FDSR | IRQ_FTRGT | IRQ_FBUS |\
- IRQ_RISCI)
-
-/* REG_GPIO_DMA_CTL bits */
-#define DMA_CTL_A_PWRDN (1 << 26)
-#define DMA_CTL_DA_SBR (1 << 14)
-#define DMA_CTL_DA_ES2 (1 << 13)
-#define DMA_CTL_ACAP_EN (1 << 4)
-#define DMA_CTL_RISC_EN (1 << 1)
-#define DMA_CTL_FIFO_EN (1 << 0)
-
-/* RISC instructions */
-#define RISC_WRITE (0x01 << 28)
-#define RISC_JUMP (0x07 << 28)
-#define RISC_SYNC (0x08 << 28)
-
-/* RISC bits */
-#define RISC_WR_SOL (1 << 27)
-#define RISC_WR_EOL (1 << 26)
-#define RISC_IRQ (1 << 24)
-#define RISC_SYNC_RESYNC (1 << 15)
-#define RISC_SYNC_FM1 0x06
-#define RISC_SYNC_VRO 0x0c
-
-#define HWBASE_AD (448000)
-
-/* -------------------------------------------------------------- */
-
-struct btaudio {
- /* linked list */
- struct btaudio *next;
-
- /* device info */
- int dsp_digital;
- int dsp_analog;
- int mixer_dev;
- struct pci_dev *pci;
- unsigned int irq;
- unsigned long mem;
- unsigned long __iomem *mmio;
-
- /* locking */
- int users;
- struct mutex lock;
-
- /* risc instructions */
- unsigned int risc_size;
- unsigned long *risc_cpu;
- dma_addr_t risc_dma;
-
- /* audio data */
- unsigned int buf_size;
- unsigned char *buf_cpu;
- dma_addr_t buf_dma;
-
- /* buffer setup */
- int line_bytes;
- int line_count;
- int block_bytes;
- int block_count;
-
- /* read fifo management */
- int recording;
- int dma_block;
- int read_offset;
- int read_count;
- wait_queue_head_t readq;
-
- /* settings */
- int gain[3];
- int source;
- int bits;
- int decimation;
- int mixcount;
- int sampleshift;
- int channels;
- int analog;
- int rate;
-};
-
-struct cardinfo {
- char *name;
- int rate;
-};
-
-static struct btaudio *btaudios;
-static unsigned int debug;
-static unsigned int irq_debug;
-
-/* -------------------------------------------------------------- */
-
-#define BUF_DEFAULT 128*1024
-#define BUF_MIN 8192
-
-static int alloc_buffer(struct btaudio *bta)
-{
- if (NULL == bta->buf_cpu) {
- for (bta->buf_size = BUF_DEFAULT; bta->buf_size >= BUF_MIN;
- bta->buf_size = bta->buf_size >> 1) {
- bta->buf_cpu = pci_alloc_consistent
- (bta->pci, bta->buf_size, &bta->buf_dma);
- if (NULL != bta->buf_cpu)
- break;
- }
- if (NULL == bta->buf_cpu)
- return -ENOMEM;
- memset(bta->buf_cpu,0,bta->buf_size);
- }
- if (NULL == bta->risc_cpu) {
- bta->risc_size = PAGE_SIZE;
- bta->risc_cpu = pci_alloc_consistent
- (bta->pci, bta->risc_size, &bta->risc_dma);
- if (NULL == bta->risc_cpu) {
- pci_free_consistent(bta->pci, bta->buf_size, bta->buf_cpu, bta->buf_dma);
- bta->buf_cpu = NULL;
- return -ENOMEM;
- }
- }
- return 0;
-}
-
-static void free_buffer(struct btaudio *bta)
-{
- if (NULL != bta->buf_cpu) {
- pci_free_consistent(bta->pci, bta->buf_size,
- bta->buf_cpu, bta->buf_dma);
- bta->buf_cpu = NULL;
- }
- if (NULL != bta->risc_cpu) {
- pci_free_consistent(bta->pci, bta->risc_size,
- bta->risc_cpu, bta->risc_dma);
- bta->risc_cpu = NULL;
- }
-}
-
-static int make_risc(struct btaudio *bta)
-{
- int rp, bp, line, block;
- unsigned long risc;
-
- bta->block_bytes = bta->buf_size >> 4;
- bta->block_count = 1 << 4;
- bta->line_bytes = bta->block_bytes;
- bta->line_count = bta->block_count;
- while (bta->line_bytes > 4095) {
- bta->line_bytes >>= 1;
- bta->line_count <<= 1;
- }
- if (bta->line_count > 255)
- return -EINVAL;
- if (debug)
- printk(KERN_DEBUG
- "btaudio: bufsize=%d - bs=%d bc=%d - ls=%d, lc=%d\n",
- bta->buf_size,bta->block_bytes,bta->block_count,
- bta->line_bytes,bta->line_count);
- rp = 0; bp = 0;
- block = 0;
- bta->risc_cpu[rp++] = cpu_to_le32(RISC_SYNC|RISC_SYNC_FM1);
- bta->risc_cpu[rp++] = cpu_to_le32(0);
- for (line = 0; line < bta->line_count; line++) {
- risc = RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL;
- risc |= bta->line_bytes;
- if (0 == (bp & (bta->block_bytes-1))) {
- risc |= RISC_IRQ;
- risc |= (block & 0x0f) << 16;
- risc |= (~block & 0x0f) << 20;
- block++;
- }
- bta->risc_cpu[rp++] = cpu_to_le32(risc);
- bta->risc_cpu[rp++] = cpu_to_le32(bta->buf_dma + bp);
- bp += bta->line_bytes;
- }
- bta->risc_cpu[rp++] = cpu_to_le32(RISC_SYNC|RISC_SYNC_VRO);
- bta->risc_cpu[rp++] = cpu_to_le32(0);
- bta->risc_cpu[rp++] = cpu_to_le32(RISC_JUMP);
- bta->risc_cpu[rp++] = cpu_to_le32(bta->risc_dma);
- return 0;
-}
-
-static int start_recording(struct btaudio *bta)
-{
- int ret;
-
- if (0 != (ret = alloc_buffer(bta)))
- return ret;
- if (0 != (ret = make_risc(bta)))
- return ret;
-
- btwrite(bta->risc_dma, REG_RISC_STRT_ADD);
- btwrite((bta->line_count << 16) | bta->line_bytes,
- REG_PACKET_LEN);
- btwrite(IRQ_BTAUDIO, REG_INT_MASK);
- if (bta->analog) {
- btwrite(DMA_CTL_ACAP_EN |
- DMA_CTL_RISC_EN |
- DMA_CTL_FIFO_EN |
- DMA_CTL_DA_ES2 |
- ((bta->bits == 8) ? DMA_CTL_DA_SBR : 0) |
- (bta->gain[bta->source] << 28) |
- (bta->source << 24) |
- (bta->decimation << 8),
- REG_GPIO_DMA_CTL);
- } else {
- btwrite(DMA_CTL_ACAP_EN |
- DMA_CTL_RISC_EN |
- DMA_CTL_FIFO_EN |
- DMA_CTL_DA_ES2 |
- DMA_CTL_A_PWRDN |
- (1 << 6) |
- ((bta->bits == 8) ? DMA_CTL_DA_SBR : 0) |
- (bta->gain[bta->source] << 28) |
- (bta->source << 24) |
- (bta->decimation << 8),
- REG_GPIO_DMA_CTL);
- }
- bta->dma_block = 0;
- bta->read_offset = 0;
- bta->read_count = 0;
- bta->recording = 1;
- if (debug)
- printk(KERN_DEBUG "btaudio: recording started\n");
- return 0;
-}
-
-static void stop_recording(struct btaudio *bta)
-{
- btand(~15, REG_GPIO_DMA_CTL);
- bta->recording = 0;
- if (debug)
- printk(KERN_DEBUG "btaudio: recording stopped\n");
-}
-
-
-/* -------------------------------------------------------------- */
-
-static int btaudio_mixer_open(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct btaudio *bta;
-
- for (bta = btaudios; bta != NULL; bta = bta->next)
- if (bta->mixer_dev == minor)
- break;
- if (NULL == bta)
- return -ENODEV;
-
- if (debug)
- printk("btaudio: open mixer [%d]\n",minor);
- file->private_data = bta;
- return 0;
-}
-
-static int btaudio_mixer_release(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static int btaudio_mixer_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct btaudio *bta = file->private_data;
- int ret,val=0,i=0;
- void __user *argp = (void __user *)arg;
-
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- memset(&info,0,sizeof(info));
- strlcpy(info.id,"bt878",sizeof(info.id));
- strlcpy(info.name,"Brooktree Bt878 audio",sizeof(info.name));
- info.modify_counter = bta->mixcount;
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == SOUND_OLD_MIXER_INFO) {
- _old_mixer_info info;
- memset(&info,0,sizeof(info));
- strlcpy(info.id, "bt878", sizeof(info.id));
- strlcpy(info.name,"Brooktree Bt878 audio",sizeof(info.name));
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, (int __user *)argp);
-
- /* read */
- if (_SIOC_DIR(cmd) & _SIOC_WRITE)
- if (get_user(val, (int __user *)argp))
- return -EFAULT;
-
- switch (cmd) {
- case MIXER_READ(SOUND_MIXER_CAPS):
- ret = SOUND_CAP_EXCL_INPUT;
- break;
- case MIXER_READ(SOUND_MIXER_STEREODEVS):
- ret = 0;
- break;
- case MIXER_READ(SOUND_MIXER_RECMASK):
- case MIXER_READ(SOUND_MIXER_DEVMASK):
- ret = SOUND_MASK_LINE1|SOUND_MASK_LINE2|SOUND_MASK_LINE3;
- break;
-
- case MIXER_WRITE(SOUND_MIXER_RECSRC):
- if (val & SOUND_MASK_LINE1 && bta->source != 0)
- bta->source = 0;
- else if (val & SOUND_MASK_LINE2 && bta->source != 1)
- bta->source = 1;
- else if (val & SOUND_MASK_LINE3 && bta->source != 2)
- bta->source = 2;
- btaor((bta->gain[bta->source] << 28) |
- (bta->source << 24),
- 0x0cffffff, REG_GPIO_DMA_CTL);
- case MIXER_READ(SOUND_MIXER_RECSRC):
- switch (bta->source) {
- case 0: ret = SOUND_MASK_LINE1; break;
- case 1: ret = SOUND_MASK_LINE2; break;
- case 2: ret = SOUND_MASK_LINE3; break;
- default: ret = 0;
- }
- break;
-
- case MIXER_WRITE(SOUND_MIXER_LINE1):
- case MIXER_WRITE(SOUND_MIXER_LINE2):
- case MIXER_WRITE(SOUND_MIXER_LINE3):
- if (MIXER_WRITE(SOUND_MIXER_LINE1) == cmd)
- i = 0;
- if (MIXER_WRITE(SOUND_MIXER_LINE2) == cmd)
- i = 1;
- if (MIXER_WRITE(SOUND_MIXER_LINE3) == cmd)
- i = 2;
- bta->gain[i] = (val & 0xff) * 15 / 100;
- if (bta->gain[i] > 15) bta->gain[i] = 15;
- if (bta->gain[i] < 0) bta->gain[i] = 0;
- if (i == bta->source)
- btaor((bta->gain[bta->source]<<28),
- 0x0fffffff, REG_GPIO_DMA_CTL);
- ret = bta->gain[i] * 100 / 15;
- ret |= ret << 8;
- break;
-
- case MIXER_READ(SOUND_MIXER_LINE1):
- case MIXER_READ(SOUND_MIXER_LINE2):
- case MIXER_READ(SOUND_MIXER_LINE3):
- if (MIXER_READ(SOUND_MIXER_LINE1) == cmd)
- i = 0;
- if (MIXER_READ(SOUND_MIXER_LINE2) == cmd)
- i = 1;
- if (MIXER_READ(SOUND_MIXER_LINE3) == cmd)
- i = 2;
- ret = bta->gain[i] * 100 / 15;
- ret |= ret << 8;
- break;
-
- default:
- return -EINVAL;
- }
- if (put_user(ret, (int __user *)argp))
- return -EFAULT;
- return 0;
-}
-
-static const struct file_operations btaudio_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .open = btaudio_mixer_open,
- .release = btaudio_mixer_release,
- .ioctl = btaudio_mixer_ioctl,
-};
-
-/* -------------------------------------------------------------- */
-
-static int btaudio_dsp_open(struct inode *inode, struct file *file,
- struct btaudio *bta, int analog)
-{
- mutex_lock(&bta->lock);
- if (bta->users)
- goto busy;
- bta->users++;
- file->private_data = bta;
-
- bta->analog = analog;
- bta->dma_block = 0;
- bta->read_offset = 0;
- bta->read_count = 0;
- bta->sampleshift = 0;
-
- mutex_unlock(&bta->lock);
- return 0;
-
- busy:
- mutex_unlock(&bta->lock);
- return -EBUSY;
-}
-
-static int btaudio_dsp_open_digital(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct btaudio *bta;
-
- for (bta = btaudios; bta != NULL; bta = bta->next)
- if (bta->dsp_digital == minor)
- break;
- if (NULL == bta)
- return -ENODEV;
-
- if (debug)
- printk("btaudio: open digital dsp [%d]\n",minor);
- return btaudio_dsp_open(inode,file,bta,0);
-}
-
-static int btaudio_dsp_open_analog(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct btaudio *bta;
-
- for (bta = btaudios; bta != NULL; bta = bta->next)
- if (bta->dsp_analog == minor)
- break;
- if (NULL == bta)
- return -ENODEV;
-
- if (debug)
- printk("btaudio: open analog dsp [%d]\n",minor);
- return btaudio_dsp_open(inode,file,bta,1);
-}
-
-static int btaudio_dsp_release(struct inode *inode, struct file *file)
-{
- struct btaudio *bta = file->private_data;
-
- mutex_lock(&bta->lock);
- if (bta->recording)
- stop_recording(bta);
- bta->users--;
- mutex_unlock(&bta->lock);
- return 0;
-}
-
-static ssize_t btaudio_dsp_read(struct file *file, char __user *buffer,
- size_t swcount, loff_t *ppos)
-{
- struct btaudio *bta = file->private_data;
- int hwcount = swcount << bta->sampleshift;
- int nsrc, ndst, err, ret = 0;
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(&bta->readq, &wait);
- mutex_lock(&bta->lock);
- while (swcount > 0) {
- if (0 == bta->read_count) {
- if (!bta->recording) {
- if (0 != (err = start_recording(bta))) {
- if (0 == ret)
- ret = err;
- break;
- }
- }
- if (file->f_flags & O_NONBLOCK) {
- if (0 == ret)
- ret = -EAGAIN;
- break;
- }
- mutex_unlock(&bta->lock);
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- mutex_lock(&bta->lock);
- if(signal_pending(current)) {
- if (0 == ret)
- ret = -EINTR;
- break;
- }
- }
- nsrc = (bta->read_count < hwcount) ? bta->read_count : hwcount;
- if (nsrc > bta->buf_size - bta->read_offset)
- nsrc = bta->buf_size - bta->read_offset;
- ndst = nsrc >> bta->sampleshift;
-
- if ((bta->analog && 0 == bta->sampleshift) ||
- (!bta->analog && 2 == bta->channels)) {
- /* just copy */
- if (copy_to_user(buffer + ret, bta->buf_cpu + bta->read_offset, nsrc)) {
- if (0 == ret)
- ret = -EFAULT;
- break;
- }
-
- } else if (!bta->analog) {
- /* stereo => mono (digital audio) */
- __s16 *src = (__s16*)(bta->buf_cpu + bta->read_offset);
- __s16 __user *dst = (__s16 __user *)(buffer + ret);
- __s16 avg;
- int n = ndst>>1;
- if (!access_ok(VERIFY_WRITE, dst, ndst)) {
- if (0 == ret)
- ret = -EFAULT;
- break;
- }
- for (; n; n--, dst++) {
- avg = (__s16)le16_to_cpu(*src) / 2; src++;
- avg += (__s16)le16_to_cpu(*src) / 2; src++;
- __put_user(cpu_to_le16(avg),dst);
- }
-
- } else if (8 == bta->bits) {
- /* copy + byte downsampling (audio A/D) */
- __u8 *src = bta->buf_cpu + bta->read_offset;
- __u8 __user *dst = buffer + ret;
- int n = ndst;
- if (!access_ok(VERIFY_WRITE, dst, ndst)) {
- if (0 == ret)
- ret = -EFAULT;
- break;
- }
- for (; n; n--, src += (1 << bta->sampleshift), dst++)
- __put_user(*src, dst);
-
- } else {
- /* copy + word downsampling (audio A/D) */
- __u16 *src = (__u16*)(bta->buf_cpu + bta->read_offset);
- __u16 __user *dst = (__u16 __user *)(buffer + ret);
- int n = ndst>>1;
- if (!access_ok(VERIFY_WRITE,dst,ndst)) {
- if (0 == ret)
- ret = -EFAULT;
- break;
- }
- for (; n; n--, src += (1 << bta->sampleshift), dst++)
- __put_user(*src, dst);
- }
-
- ret += ndst;
- swcount -= ndst;
- hwcount -= nsrc;
- bta->read_count -= nsrc;
- bta->read_offset += nsrc;
- if (bta->read_offset == bta->buf_size)
- bta->read_offset = 0;
- }
- mutex_unlock(&bta->lock);
- remove_wait_queue(&bta->readq, &wait);
- current->state = TASK_RUNNING;
- return ret;
-}
-
-static ssize_t btaudio_dsp_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *ppos)
-{
- return -EINVAL;
-}
-
-static int btaudio_dsp_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct btaudio *bta = file->private_data;
- int s, i, ret, val = 0;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, p);
- case SNDCTL_DSP_GETCAPS:
- return 0;
-
- case SNDCTL_DSP_SPEED:
- if (get_user(val, p))
- return -EFAULT;
- if (bta->analog) {
- for (s = 0; s < 16; s++)
- if (val << s >= HWBASE_AD*4/15)
- break;
- for (i = 15; i >= 5; i--)
- if (val << s <= HWBASE_AD*4/i)
- break;
- bta->sampleshift = s;
- bta->decimation = i;
- if (debug)
- printk(KERN_DEBUG "btaudio: rate: req=%d "
- "dec=%d shift=%d hwrate=%d swrate=%d\n",
- val,i,s,(HWBASE_AD*4/i),(HWBASE_AD*4/i)>>s);
- } else {
- bta->sampleshift = (bta->channels == 2) ? 0 : 1;
- bta->decimation = 0;
- }
- if (bta->recording) {
- mutex_lock(&bta->lock);
- stop_recording(bta);
- start_recording(bta);
- mutex_unlock(&bta->lock);
- }
- /* fall through */
- case SOUND_PCM_READ_RATE:
- if (bta->analog) {
- return put_user(HWBASE_AD*4/bta->decimation>>bta->sampleshift, p);
- } else {
- return put_user(bta->rate, p);
- }
-
- case SNDCTL_DSP_STEREO:
- if (!bta->analog) {
- if (get_user(val, p))
- return -EFAULT;
- bta->channels = (val > 0) ? 2 : 1;
- bta->sampleshift = (bta->channels == 2) ? 0 : 1;
- if (debug)
- printk(KERN_INFO
- "btaudio: stereo=%d channels=%d\n",
- val,bta->channels);
- } else {
- if (val == 1)
- return -EFAULT;
- else {
- bta->channels = 1;
- if (debug)
- printk(KERN_INFO
- "btaudio: stereo=0 channels=1\n");
- }
- }
- return put_user((bta->channels)-1, p);
-
- case SNDCTL_DSP_CHANNELS:
- if (!bta->analog) {
- if (get_user(val, p))
- return -EFAULT;
- bta->channels = (val > 1) ? 2 : 1;
- bta->sampleshift = (bta->channels == 2) ? 0 : 1;
- if (debug)
- printk(KERN_DEBUG
- "btaudio: val=%d channels=%d\n",
- val,bta->channels);
- }
- /* fall through */
- case SOUND_PCM_READ_CHANNELS:
- return put_user(bta->channels, p);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- if (bta->analog)
- return put_user(AFMT_S16_LE|AFMT_S8, p);
- else
- return put_user(AFMT_S16_LE, p);
-
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- if (get_user(val, p))
- return -EFAULT;
- if (val != AFMT_QUERY) {
- if (bta->analog)
- bta->bits = (val == AFMT_S8) ? 8 : 16;
- else
- bta->bits = 16;
- if (bta->recording) {
- mutex_lock(&bta->lock);
- stop_recording(bta);
- start_recording(bta);
- mutex_unlock(&bta->lock);
- }
- }
- if (debug)
- printk(KERN_DEBUG "btaudio: fmt: bits=%d\n",bta->bits);
- return put_user((bta->bits==16) ? AFMT_S16_LE : AFMT_S8,
- p);
- break;
- case SOUND_PCM_READ_BITS:
- return put_user(bta->bits, p);
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_RESET:
- if (bta->recording) {
- mutex_lock(&bta->lock);
- stop_recording(bta);
- mutex_unlock(&bta->lock);
- }
- return 0;
- case SNDCTL_DSP_GETBLKSIZE:
- if (!bta->recording) {
- if (0 != (ret = alloc_buffer(bta)))
- return ret;
- if (0 != (ret = make_risc(bta)))
- return ret;
- }
- return put_user(bta->block_bytes>>bta->sampleshift,p);
-
- case SNDCTL_DSP_SYNC:
- /* NOP */
- return 0;
- case SNDCTL_DSP_GETISPACE:
- {
- audio_buf_info info;
- if (!bta->recording)
- return -EINVAL;
- info.fragsize = bta->block_bytes>>bta->sampleshift;
- info.fragstotal = bta->block_count;
- info.bytes = bta->read_count;
- info.fragments = info.bytes / info.fragsize;
- if (debug)
- printk(KERN_DEBUG "btaudio: SNDCTL_DSP_GETISPACE "
- "returns %d/%d/%d/%d\n",
- info.fragsize, info.fragstotal,
- info.bytes, info.fragments);
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
-#if 0 /* TODO */
- case SNDCTL_DSP_GETTRIGGER:
- case SNDCTL_DSP_SETTRIGGER:
- case SNDCTL_DSP_SETFRAGMENT:
-#endif
- default:
- return -EINVAL;
- }
-}
-
-static unsigned int btaudio_dsp_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct btaudio *bta = file->private_data;
- unsigned int mask = 0;
-
- poll_wait(file, &bta->readq, wait);
-
- if (0 != bta->read_count)
- mask |= (POLLIN | POLLRDNORM);
-
- return mask;
-}
-
-static const struct file_operations btaudio_digital_dsp_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .open = btaudio_dsp_open_digital,
- .release = btaudio_dsp_release,
- .read = btaudio_dsp_read,
- .write = btaudio_dsp_write,
- .ioctl = btaudio_dsp_ioctl,
- .poll = btaudio_dsp_poll,
-};
-
-static const struct file_operations btaudio_analog_dsp_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .open = btaudio_dsp_open_analog,
- .release = btaudio_dsp_release,
- .read = btaudio_dsp_read,
- .write = btaudio_dsp_write,
- .ioctl = btaudio_dsp_ioctl,
- .poll = btaudio_dsp_poll,
-};
-
-/* -------------------------------------------------------------- */
-
-static char *irq_name[] = { "", "", "", "OFLOW", "", "", "", "", "", "", "",
- "RISCI", "FBUS", "FTRGT", "FDSR", "PPERR",
- "RIPERR", "PABORT", "OCERR", "SCERR" };
-
-static irqreturn_t btaudio_irq(int irq, void *dev_id)
-{
- int count = 0;
- u32 stat,astat;
- struct btaudio *bta = dev_id;
- int handled = 0;
-
- for (;;) {
- count++;
- stat = btread(REG_INT_STAT);
- astat = stat & btread(REG_INT_MASK);
- if (!astat)
- return IRQ_RETVAL(handled);
- handled = 1;
- btwrite(astat,REG_INT_STAT);
-
- if (irq_debug) {
- int i;
- printk(KERN_DEBUG "btaudio: irq loop=%d risc=%x, bits:",
- count, stat>>28);
- for (i = 0; i < (sizeof(irq_name)/sizeof(char*)); i++) {
- if (stat & (1 << i))
- printk(" %s",irq_name[i]);
- if (astat & (1 << i))
- printk("*");
- }
- printk("\n");
- }
- if (stat & IRQ_RISCI) {
- int blocks;
- blocks = (stat >> 28) - bta->dma_block;
- if (blocks < 0)
- blocks += bta->block_count;
- bta->dma_block = stat >> 28;
- if (bta->read_count + 2*bta->block_bytes > bta->buf_size) {
- stop_recording(bta);
- printk(KERN_INFO "btaudio: buffer overrun\n");
- }
- if (blocks > 0) {
- bta->read_count += blocks * bta->block_bytes;
- wake_up_interruptible(&bta->readq);
- }
- }
- if (count > 10) {
- printk(KERN_WARNING
- "btaudio: Oops - irq mask cleared\n");
- btwrite(0, REG_INT_MASK);
- }
- }
- return IRQ_NONE;
-}
-
-/* -------------------------------------------------------------- */
-
-static unsigned int dsp1 = -1;
-static unsigned int dsp2 = -1;
-static unsigned int mixer = -1;
-static int latency = -1;
-static int digital = 1;
-static int analog = 1;
-static int rate;
-
-#define BTA_OSPREY200 1
-
-static struct cardinfo cards[] = {
- [0] = {
- .name = "default",
- .rate = 32000,
- },
- [BTA_OSPREY200] = {
- .name = "Osprey 200",
- .rate = 44100,
- },
-};
-
-static int __devinit btaudio_probe(struct pci_dev *pci_dev,
- const struct pci_device_id *pci_id)
-{
- struct btaudio *bta;
- struct cardinfo *card = &cards[pci_id->driver_data];
- unsigned char revision,lat;
- int rc = -EBUSY;
-
- if (pci_enable_device(pci_dev))
- return -EIO;
- if (!request_mem_region(pci_resource_start(pci_dev,0),
- pci_resource_len(pci_dev,0),
- "btaudio")) {
- return -EBUSY;
- }
-
- bta = kzalloc(sizeof(*bta),GFP_ATOMIC);
- if (!bta) {
- rc = -ENOMEM;
- goto fail0;
- }
-
- bta->pci = pci_dev;
- bta->irq = pci_dev->irq;
- bta->mem = pci_resource_start(pci_dev,0);
- bta->mmio = ioremap(pci_resource_start(pci_dev,0),
- pci_resource_len(pci_dev,0));
-
- bta->source = 1;
- bta->bits = 8;
- bta->channels = 1;
- if (bta->analog) {
- bta->decimation = 15;
- } else {
- bta->decimation = 0;
- bta->sampleshift = 1;
- }
-
- /* sample rate */
- bta->rate = card->rate;
- if (rate)
- bta->rate = rate;
-
- mutex_init(&bta->lock);
- init_waitqueue_head(&bta->readq);
-
- if (-1 != latency) {
- printk(KERN_INFO "btaudio: setting pci latency timer to %d\n",
- latency);
- pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency);
- }
- pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
- pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &lat);
- printk(KERN_INFO "btaudio: Bt%x (rev %d) at %02x:%02x.%x, ",
- pci_dev->device,revision,pci_dev->bus->number,
- PCI_SLOT(pci_dev->devfn),PCI_FUNC(pci_dev->devfn));
- printk("irq: %d, latency: %d, mmio: 0x%lx\n",
- bta->irq, lat, bta->mem);
- printk("btaudio: using card config \"%s\"\n", card->name);
-
- /* init hw */
- btwrite(0, REG_GPIO_DMA_CTL);
- btwrite(0, REG_INT_MASK);
- btwrite(~0U, REG_INT_STAT);
- pci_set_master(pci_dev);
-
- if ((rc = request_irq(bta->irq, btaudio_irq, IRQF_SHARED|IRQF_DISABLED,
- "btaudio",(void *)bta)) < 0) {
- printk(KERN_WARNING
- "btaudio: can't request irq (rc=%d)\n",rc);
- goto fail1;
- }
-
- /* register devices */
- if (digital) {
- rc = bta->dsp_digital =
- register_sound_dsp(&btaudio_digital_dsp_fops,dsp1);
- if (rc < 0) {
- printk(KERN_WARNING
- "btaudio: can't register digital dsp (rc=%d)\n",rc);
- goto fail2;
- }
- printk(KERN_INFO "btaudio: registered device dsp%d [digital]\n",
- bta->dsp_digital >> 4);
- }
- if (analog) {
- rc = bta->dsp_analog =
- register_sound_dsp(&btaudio_analog_dsp_fops,dsp2);
- if (rc < 0) {
- printk(KERN_WARNING
- "btaudio: can't register analog dsp (rc=%d)\n",rc);
- goto fail3;
- }
- printk(KERN_INFO "btaudio: registered device dsp%d [analog]\n",
- bta->dsp_analog >> 4);
- rc = bta->mixer_dev = register_sound_mixer(&btaudio_mixer_fops,mixer);
- if (rc < 0) {
- printk(KERN_WARNING
- "btaudio: can't register mixer (rc=%d)\n",rc);
- goto fail4;
- }
- printk(KERN_INFO "btaudio: registered device mixer%d\n",
- bta->mixer_dev >> 4);
- }
-
- /* hook into linked list */
- bta->next = btaudios;
- btaudios = bta;
-
- pci_set_drvdata(pci_dev,bta);
- return 0;
-
- fail4:
- unregister_sound_dsp(bta->dsp_analog);
- fail3:
- if (digital)
- unregister_sound_dsp(bta->dsp_digital);
- fail2:
- free_irq(bta->irq,bta);
- fail1:
- iounmap(bta->mmio);
- kfree(bta);
- fail0:
- release_mem_region(pci_resource_start(pci_dev,0),
- pci_resource_len(pci_dev,0));
- return rc;
-}
-
-static void __devexit btaudio_remove(struct pci_dev *pci_dev)
-{
- struct btaudio *bta = pci_get_drvdata(pci_dev);
- struct btaudio *walk;
-
- /* turn off all DMA / IRQs */
- btand(~15, REG_GPIO_DMA_CTL);
- btwrite(0, REG_INT_MASK);
- btwrite(~0U, REG_INT_STAT);
-
- /* unregister devices */
- if (digital) {
- unregister_sound_dsp(bta->dsp_digital);
- }
- if (analog) {
- unregister_sound_dsp(bta->dsp_analog);
- unregister_sound_mixer(bta->mixer_dev);
- }
-
- /* free resources */
- free_buffer(bta);
- free_irq(bta->irq,bta);
- release_mem_region(pci_resource_start(pci_dev,0),
- pci_resource_len(pci_dev,0));
- iounmap(bta->mmio);
-
- /* remove from linked list */
- if (bta == btaudios) {
- btaudios = NULL;
- } else {
- for (walk = btaudios; walk->next != bta; walk = walk->next)
- ; /* if (NULL == walk->next) BUG(); */
- walk->next = bta->next;
- }
-
- pci_set_drvdata(pci_dev, NULL);
- kfree(bta);
- return;
-}
-
-/* -------------------------------------------------------------- */
-
-static struct pci_device_id btaudio_pci_tbl[] = {
- {
- .vendor = PCI_VENDOR_ID_BROOKTREE,
- .device = 0x0878,
- .subvendor = 0x0070,
- .subdevice = 0xff01,
- .driver_data = BTA_OSPREY200,
- },{
- .vendor = PCI_VENDOR_ID_BROOKTREE,
- .device = 0x0878,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },{
- .vendor = PCI_VENDOR_ID_BROOKTREE,
- .device = 0x0878,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },{
- /* --- end of list --- */
- }
-};
-
-static struct pci_driver btaudio_pci_driver = {
- .name = "btaudio",
- .id_table = btaudio_pci_tbl,
- .probe = btaudio_probe,
- .remove = __devexit_p(btaudio_remove),
-};
-
-static int btaudio_init_module(void)
-{
- printk(KERN_INFO "btaudio: driver version 0.7 loaded [%s%s%s]\n",
- digital ? "digital" : "",
- analog && digital ? "+" : "",
- analog ? "analog" : "");
- return pci_register_driver(&btaudio_pci_driver);
-}
-
-static void btaudio_cleanup_module(void)
-{
- pci_unregister_driver(&btaudio_pci_driver);
- return;
-}
-
-module_init(btaudio_init_module);
-module_exit(btaudio_cleanup_module);
-
-module_param(dsp1, int, S_IRUGO);
-module_param(dsp2, int, S_IRUGO);
-module_param(mixer, int, S_IRUGO);
-module_param(debug, int, S_IRUGO | S_IWUSR);
-module_param(irq_debug, int, S_IRUGO | S_IWUSR);
-module_param(digital, int, S_IRUGO);
-module_param(analog, int, S_IRUGO);
-module_param(rate, int, S_IRUGO);
-module_param(latency, int, S_IRUGO);
-MODULE_PARM_DESC(latency,"pci latency timer");
-
-MODULE_DEVICE_TABLE(pci, btaudio_pci_tbl);
-MODULE_DESCRIPTION("bt878 audio dma driver");
-MODULE_AUTHOR("Gerd Knorr");
-MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/sound/oss/coproc.h b/sound/oss/coproc.h
index 7306346e9ac..7bec21bbdd8 100644
--- a/sound/oss/coproc.h
+++ b/sound/oss/coproc.h
@@ -4,7 +4,7 @@
*/
/*
- * Coprocessor access types
+ * Coprocessor access types
*/
#define COPR_CUSTOM 0x0001 /* Custom applications */
#define COPR_MIDI 0x0002 /* MIDI (MPU-401) emulation */
diff --git a/sound/oss/cs4232.c b/sound/oss/cs4232.c
deleted file mode 100644
index de40e21bf27..00000000000
--- a/sound/oss/cs4232.c
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * cs4232.c
- *
- * The low level driver for Crystal CS4232 based cards. The CS4232 is
- * a PnP compatible chip which contains a CS4231A codec, SB emulation,
- * a MPU401 compatible MIDI port, joystick and synthesizer and IDE CD-ROM
- * interfaces. This is just a temporary driver until full PnP support
- * gets implemented. Just the WSS codec, FM synth and the MIDI ports are
- * supported. Other interfaces are left uninitialized.
- *
- * ifdef ...WAVEFRONT...
- *
- * Support is provided for initializing the WaveFront synth
- * interface as well, which is logical device #4. Note that if
- * you have a Tropez+ card, you probably don't need to setup
- * the CS4232-supported MIDI interface, since it corresponds to
- * the internal 26-pin header that's hard to access. Using this
- * requires an additional IRQ, a resource none too plentiful in
- * this environment. Just don't set module parameters mpuio and
- * mpuirq, and the MIDI port will be left uninitialized. You can
- * still use the ICS2115 hosted MIDI interface which corresponds
- * to the 9-pin D connector on the back of the card.
- *
- * endif ...WAVEFRONT...
- *
- * Supported chips are:
- * CS4232
- * CS4236
- * CS4236B
- *
- * Note: You will need a PnP config setup to initialise some CS4232 boards
- * anyway.
- *
- * Changes
- * John Rood Added Bose Sound System Support.
- * Toshio Spoor
- * Alan Cox Modularisation, Basic cleanups.
- * Paul Barton-Davis Separated MPU configuration, added
- * Tropez+ (WaveFront) support
- * Christoph Hellwig Adapted to module_init/module_exit,
- * simple cleanups
- * Arnaldo C. de Melo got rid of attach_uart401
- * Bartlomiej Zolnierkiewicz
- * Added some __init/__initdata/__exit
- * Marcus Meissner Added ISA PnP support.
- */
-
-#include <linux/pnp.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include "sound_config.h"
-
-#include "ad1848.h"
-#include "mpu401.h"
-
-#define KEY_PORT 0x279 /* Same as LPT1 status port */
-#define CSN_NUM 0x99 /* Just a random number */
-#define INDEX_ADDRESS 0x00 /* (R0) Index Address Register */
-#define INDEX_DATA 0x01 /* (R1) Indexed Data Register */
-#define PIN_CONTROL 0x0a /* (I10) Pin Control */
-#define ENABLE_PINS 0xc0 /* XCTRL0/XCTRL1 enable */
-
-static void CS_OUT(unsigned char a)
-{
- outb(a, KEY_PORT);
-}
-
-#define CS_OUT2(a, b) {CS_OUT(a);CS_OUT(b);}
-#define CS_OUT3(a, b, c) {CS_OUT(a);CS_OUT(b);CS_OUT(c);}
-
-static int __initdata bss = 0;
-static int mpu_base, mpu_irq;
-static int synth_base, synth_irq;
-static int mpu_detected;
-
-static int probe_cs4232_mpu(struct address_info *hw_config)
-{
- /*
- * Just write down the config values.
- */
-
- mpu_base = hw_config->io_base;
- mpu_irq = hw_config->irq;
-
- return 1;
-}
-
-static unsigned char crystal_key[] = /* A 32 byte magic key sequence */
-{
- 0x96, 0x35, 0x9a, 0xcd, 0xe6, 0xf3, 0x79, 0xbc,
- 0x5e, 0xaf, 0x57, 0x2b, 0x15, 0x8a, 0xc5, 0xe2,
- 0xf1, 0xf8, 0x7c, 0x3e, 0x9f, 0x4f, 0x27, 0x13,
- 0x09, 0x84, 0x42, 0xa1, 0xd0, 0x68, 0x34, 0x1a
-};
-
-static void sleep(unsigned howlong)
-{
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(howlong);
-}
-
-static void enable_xctrl(int baseio)
-{
- unsigned char regd;
-
- /*
- * Some IBM Aptiva's have the Bose Sound System. By default
- * the Bose Amplifier is disabled. The amplifier will be
- * activated, by setting the XCTRL0 and XCTRL1 bits.
- * Volume of the monitor bose speakers/woofer, can then
- * be set by changing the PCM volume.
- *
- */
-
- printk("cs4232: enabling Bose Sound System Amplifier.\n");
-
- /* Switch to Pin Control Address */
- regd = inb(baseio + INDEX_ADDRESS) & 0xe0;
- outb(((unsigned char) (PIN_CONTROL | regd)), baseio + INDEX_ADDRESS );
-
- /* Activate the XCTRL0 and XCTRL1 Pins */
- regd = inb(baseio + INDEX_DATA);
- outb(((unsigned char) (ENABLE_PINS | regd)), baseio + INDEX_DATA );
-}
-
-static int __init probe_cs4232(struct address_info *hw_config, int isapnp_configured)
-{
- int i, n;
- int base = hw_config->io_base, irq = hw_config->irq;
- int dma1 = hw_config->dma, dma2 = hw_config->dma2;
- struct resource *ports;
-
- if (base == -1 || irq == -1 || dma1 == -1) {
- printk(KERN_ERR "cs4232: dma, irq and io must be set.\n");
- return 0;
- }
-
- /*
- * Verify that the I/O port range is free.
- */
-
- ports = request_region(base, 4, "ad1848");
- if (!ports) {
- printk(KERN_ERR "cs4232.c: I/O port 0x%03x not free\n", base);
- return 0;
- }
- if (ad1848_detect(ports, NULL, hw_config->osp)) {
- goto got_it; /* The card is already active */
- }
- if (isapnp_configured) {
- printk(KERN_ERR "cs4232.c: ISA PnP configured, but not detected?\n");
- goto fail;
- }
-
- /*
- * This version of the driver doesn't use the PnP method when configuring
- * the card but a simplified method defined by Crystal. This means that
- * just one CS4232 compatible device can exist on the system. Also this
- * method conflicts with possible PnP support in the OS. For this reason
- * driver is just a temporary kludge.
- *
- * Also the Cirrus/Crystal method doesn't always work. Try ISA PnP first ;)
- */
-
- /*
- * Repeat initialization few times since it doesn't always succeed in
- * first time.
- */
-
- for (n = 0; n < 4; n++)
- {
- /*
- * Wake up the card by sending a 32 byte Crystal key to the key port.
- */
-
- for (i = 0; i < 32; i++)
- CS_OUT(crystal_key[i]);
-
- sleep(HZ / 10);
-
- /*
- * Now set the CSN (Card Select Number).
- */
-
- CS_OUT2(0x06, CSN_NUM);
-
- /*
- * Then set some config bytes. First logical device 0
- */
-
- CS_OUT2(0x15, 0x00); /* Select logical device 0 (WSS/SB/FM) */
- CS_OUT3(0x47, (base >> 8) & 0xff, base & 0xff); /* WSS base */
-
- if (!request_region(0x388, 4, "FM")) /* Not free */
- CS_OUT3(0x48, 0x00, 0x00) /* FM base off */
- else {
- release_region(0x388, 4);
- CS_OUT3(0x48, 0x03, 0x88); /* FM base 0x388 */
- }
-
- CS_OUT3(0x42, 0x00, 0x00); /* SB base off */
- CS_OUT2(0x22, irq); /* SB+WSS IRQ */
- CS_OUT2(0x2a, dma1); /* SB+WSS DMA */
-
- if (dma2 != -1)
- CS_OUT2(0x25, dma2) /* WSS DMA2 */
- else
- CS_OUT2(0x25, 4); /* No WSS DMA2 */
-
- CS_OUT2(0x33, 0x01); /* Activate logical dev 0 */
-
- sleep(HZ / 10);
-
- /*
- * Initialize logical device 3 (MPU)
- */
-
- if (mpu_base != 0 && mpu_irq != 0)
- {
- CS_OUT2(0x15, 0x03); /* Select logical device 3 (MPU) */
- CS_OUT3(0x47, (mpu_base >> 8) & 0xff, mpu_base & 0xff); /* MPU base */
- CS_OUT2(0x22, mpu_irq); /* MPU IRQ */
- CS_OUT2(0x33, 0x01); /* Activate logical dev 3 */
- }
-
- if(synth_base != 0)
- {
- CS_OUT2 (0x15, 0x04); /* logical device 4 (WaveFront) */
- CS_OUT3 (0x47, (synth_base >> 8) & 0xff,
- synth_base & 0xff); /* base */
- CS_OUT2 (0x22, synth_irq); /* IRQ */
- CS_OUT2 (0x33, 0x01); /* Activate logical dev 4 */
- }
-
- /*
- * Finally activate the chip
- */
-
- CS_OUT(0x79);
-
- sleep(HZ / 5);
-
- /*
- * Then try to detect the codec part of the chip
- */
-
- if (ad1848_detect(ports, NULL, hw_config->osp))
- goto got_it;
-
- sleep(HZ);
- }
-fail:
- release_region(base, 4);
- return 0;
-
-got_it:
- if (dma2 == -1)
- dma2 = dma1;
-
- hw_config->slots[0] = ad1848_init("Crystal audio controller", ports,
- irq,
- dma1, /* Playback DMA */
- dma2, /* Capture DMA */
- 0,
- hw_config->osp,
- THIS_MODULE);
-
- if (hw_config->slots[0] != -1 &&
- audio_devs[hw_config->slots[0]]->mixer_dev!=-1)
- {
- /* Assume the mixer map is as suggested in the CS4232 databook */
- AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE);
- AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD);
- AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* FM synth */
- }
- if (mpu_base != 0 && mpu_irq != 0)
- {
- static struct address_info hw_config2 = {
- 0
- }; /* Ensure it's initialized */
-
- hw_config2.io_base = mpu_base;
- hw_config2.irq = mpu_irq;
- hw_config2.dma = -1;
- hw_config2.dma2 = -1;
- hw_config2.always_detect = 0;
- hw_config2.name = NULL;
- hw_config2.driver_use_1 = 0;
- hw_config2.driver_use_2 = 0;
- hw_config2.card_subtype = 0;
-
- if (probe_uart401(&hw_config2, THIS_MODULE))
- {
- mpu_detected = 1;
- }
- else
- {
- mpu_base = mpu_irq = 0;
- }
- hw_config->slots[1] = hw_config2.slots[1];
- }
-
- if (bss)
- enable_xctrl(base);
-
- return 1;
-}
-
-static void __devexit unload_cs4232(struct address_info *hw_config)
-{
- int base = hw_config->io_base, irq = hw_config->irq;
- int dma1 = hw_config->dma, dma2 = hw_config->dma2;
-
- if (dma2 == -1)
- dma2 = dma1;
-
- ad1848_unload(base,
- irq,
- dma1, /* Playback DMA */
- dma2, /* Capture DMA */
- 0);
-
- sound_unload_audiodev(hw_config->slots[0]);
- if (mpu_base != 0 && mpu_irq != 0 && mpu_detected)
- {
- static struct address_info hw_config2 =
- {
- 0
- }; /* Ensure it's initialized */
-
- hw_config2.io_base = mpu_base;
- hw_config2.irq = mpu_irq;
- hw_config2.dma = -1;
- hw_config2.dma2 = -1;
- hw_config2.always_detect = 0;
- hw_config2.name = NULL;
- hw_config2.driver_use_1 = 0;
- hw_config2.driver_use_2 = 0;
- hw_config2.card_subtype = 0;
- hw_config2.slots[1] = hw_config->slots[1];
-
- unload_uart401(&hw_config2);
- }
-}
-
-static struct address_info cfg;
-static struct address_info cfg_mpu;
-
-static int __initdata io = -1;
-static int __initdata irq = -1;
-static int __initdata dma = -1;
-static int __initdata dma2 = -1;
-static int __initdata mpuio = -1;
-static int __initdata mpuirq = -1;
-static int __initdata synthio = -1;
-static int __initdata synthirq = -1;
-static int __initdata isapnp = 1;
-
-static unsigned int cs4232_devices;
-
-MODULE_DESCRIPTION("CS4232 based soundcard driver");
-MODULE_AUTHOR("Hannu Savolainen, Paul Barton-Davis");
-MODULE_LICENSE("GPL");
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io,"base I/O port for AD1848");
-module_param(irq, int, 0);
-MODULE_PARM_DESC(irq,"IRQ for AD1848 chip");
-module_param(dma, int, 0);
-MODULE_PARM_DESC(dma,"8 bit DMA for AD1848 chip");
-module_param(dma2, int, 0);
-MODULE_PARM_DESC(dma2,"16 bit DMA for AD1848 chip");
-module_param(mpuio, int, 0);
-MODULE_PARM_DESC(mpuio,"MPU 401 base address");
-module_param(mpuirq, int, 0);
-MODULE_PARM_DESC(mpuirq,"MPU 401 IRQ");
-module_param(synthio, int, 0);
-MODULE_PARM_DESC(synthio,"Maui WaveTable base I/O port");
-module_param(synthirq, int, 0);
-MODULE_PARM_DESC(synthirq,"Maui WaveTable IRQ");
-module_param(isapnp, bool, 0);
-MODULE_PARM_DESC(isapnp,"Enable ISAPnP probing (default 1)");
-module_param(bss, bool, 0);
-MODULE_PARM_DESC(bss,"Enable Bose Sound System Support (default 0)");
-
-/*
- * Install a CS4232 based card. Need to have ad1848 and mpu401
- * loaded ready.
- */
-
-/* All cs4232 based cards have the main ad1848 card either as CSC0000 or
- * CSC0100. */
-static const struct pnp_device_id cs4232_pnp_table[] = {
- { .id = "CSC0100", .driver_data = 0 },
- { .id = "CSC0000", .driver_data = 0 },
- /* Guillemot Turtlebeach something appears to be cs4232 compatible
- * (untested) */
- { .id = "GIM0100", .driver_data = 0 },
- { .id = ""}
-};
-
-MODULE_DEVICE_TABLE(pnp, cs4232_pnp_table);
-
-static int __init cs4232_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
-{
- struct address_info *isapnpcfg;
-
- isapnpcfg = kmalloc(sizeof(*isapnpcfg),GFP_KERNEL);
- if (!isapnpcfg)
- return -ENOMEM;
-
- isapnpcfg->irq = pnp_irq(dev, 0);
- isapnpcfg->dma = pnp_dma(dev, 0);
- isapnpcfg->dma2 = pnp_dma(dev, 1);
- isapnpcfg->io_base = pnp_port_start(dev, 0);
- if (probe_cs4232(isapnpcfg,TRUE) == 0) {
- printk(KERN_ERR "cs4232: ISA PnP card found, but not detected?\n");
- kfree(isapnpcfg);
- return -ENODEV;
- }
- pnp_set_drvdata(dev,isapnpcfg);
- cs4232_devices++;
- return 0;
-}
-
-static void __devexit cs4232_pnp_remove(struct pnp_dev *dev)
-{
- struct address_info *cfg = pnp_get_drvdata(dev);
- if (cfg) {
- unload_cs4232(cfg);
- kfree(cfg);
- }
-}
-
-static struct pnp_driver cs4232_driver = {
- .name = "cs4232",
- .id_table = cs4232_pnp_table,
- .probe = cs4232_pnp_probe,
- .remove = __devexit_p(cs4232_pnp_remove),
-};
-
-static int __init init_cs4232(void)
-{
-#ifdef CONFIG_SOUND_WAVEFRONT_MODULE
- if(synthio == -1)
- printk(KERN_INFO "cs4232: set synthio and synthirq to use the wavefront facilities.\n");
- else {
- synth_base = synthio;
- synth_irq = synthirq;
- }
-#else
- if(synthio != -1)
- printk(KERN_WARNING "cs4232: wavefront support not enabled in this driver.\n");
-#endif
- cfg.irq = -1;
-
- if (isapnp) {
- pnp_register_driver(&cs4232_driver);
- if (cs4232_devices)
- return 0;
- }
-
- if(io==-1||irq==-1||dma==-1)
- {
- printk(KERN_ERR "cs4232: Must set io, irq and dma.\n");
- return -ENODEV;
- }
-
- cfg.io_base = io;
- cfg.irq = irq;
- cfg.dma = dma;
- cfg.dma2 = dma2;
-
- cfg_mpu.io_base = -1;
- cfg_mpu.irq = -1;
-
- if (mpuio != -1 && mpuirq != -1) {
- cfg_mpu.io_base = mpuio;
- cfg_mpu.irq = mpuirq;
- probe_cs4232_mpu(&cfg_mpu); /* Bug always returns 0 not OK -- AC */
- }
-
- if (probe_cs4232(&cfg,FALSE) == 0)
- return -ENODEV;
-
- return 0;
-}
-
-static void __exit cleanup_cs4232(void)
-{
- pnp_unregister_driver(&cs4232_driver);
- if (cfg.irq != -1)
- unload_cs4232(&cfg); /* Unloads global MPU as well, if needed */
-}
-
-module_init(init_cs4232);
-module_exit(cleanup_cs4232);
-
-#ifndef MODULE
-static int __init setup_cs4232(char *str)
-{
- /* io, irq, dma, dma2 mpuio, mpuirq*/
- int ints[7];
-
- /* If we have isapnp cards, no need for options */
- pnp_register_driver(&cs4232_driver);
- if (cs4232_devices)
- return 1;
-
- str = get_options(str, ARRAY_SIZE(ints), ints);
-
- io = ints[1];
- irq = ints[2];
- dma = ints[3];
- dma2 = ints[4];
- mpuio = ints[5];
- mpuirq = ints[6];
-
- return 1;
-}
-
-__setup("cs4232=", setup_cs4232);
-#endif
diff --git a/sound/oss/dev_table.c b/sound/oss/dev_table.c
index 08274c995d0..d8cf3e58dc7 100644
--- a/sound/oss/dev_table.c
+++ b/sound/oss/dev_table.c
@@ -67,20 +67,20 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
return -(EBUSY);
}
d = (struct audio_driver *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct audio_driver)));
+ sound_nblocks++;
+ if (sound_nblocks >= MAX_MEM_BLOCKS)
+ sound_nblocks = MAX_MEM_BLOCKS - 1;
- if (sound_nblocks < 1024)
- sound_nblocks++;
+ op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vzalloc(sizeof(struct audio_operations)));
+ sound_nblocks++;
+ if (sound_nblocks >= MAX_MEM_BLOCKS)
+ sound_nblocks = MAX_MEM_BLOCKS - 1;
- op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct audio_operations)));
-
- if (sound_nblocks < 1024)
- sound_nblocks++;
if (d == NULL || op == NULL) {
printk(KERN_ERR "Sound: Can't allocate driver for (%s)\n", name);
sound_unload_audiodev(num);
return -(ENOMEM);
}
- memset((char *) op, 0, sizeof(struct audio_operations));
init_waitqueue_head(&op->in_sleeper);
init_waitqueue_head(&op->out_sleeper);
init_waitqueue_head(&op->poll_sleeper);
@@ -127,15 +127,15 @@ int sound_install_mixer(int vers, char *name, struct mixer_operations *driver,
/* FIXME: This leaks a mixer_operations struct every time its called
until you unload sound! */
- op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct mixer_operations)));
+ op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vzalloc(sizeof(struct mixer_operations)));
+ sound_nblocks++;
+ if (sound_nblocks >= MAX_MEM_BLOCKS)
+ sound_nblocks = MAX_MEM_BLOCKS - 1;
- if (sound_nblocks < 1024)
- sound_nblocks++;
if (op == NULL) {
printk(KERN_ERR "Sound: Can't allocate mixer driver for (%s)\n", name);
return -ENOMEM;
}
- memset((char *) op, 0, sizeof(struct mixer_operations));
memcpy((char *) op, (char *) driver, driver_size);
strlcpy(op->name, name, sizeof(op->name));
diff --git a/sound/oss/dev_table.h b/sound/oss/dev_table.h
index b7617bee638..0199a317c5a 100644
--- a/sound/oss/dev_table.h
+++ b/sound/oss/dev_table.h
@@ -271,7 +271,7 @@ struct synth_operations
void (*reset) (int dev);
void (*hw_control) (int dev, unsigned char *event);
int (*load_patch) (int dev, int format, const char __user *addr,
- int offs, int count, int pmgr_flag);
+ int count, int pmgr_flag);
void (*aftertouch) (int dev, int voice, int pressure);
void (*controller) (int dev, int voice, int ctrl_num, int value);
void (*panning) (int dev, int voice, int value);
diff --git a/sound/oss/dmabuf.c b/sound/oss/dmabuf.c
index eaf69971bf9..e3f29132d3a 100644
--- a/sound/oss/dmabuf.c
+++ b/sound/oss/dmabuf.c
@@ -26,7 +26,9 @@
#define SAMPLE_ROUNDUP 0
#include <linux/mm.h>
+#include <linux/gfp.h>
#include "sound_config.h"
+#include "sleep.h"
#define DMAP_FREE_ON_CLOSE 0
#define DMAP_KEEP_ON_CLOSE 1
@@ -113,7 +115,7 @@ static int sound_alloc_dmap(struct dma_buffparms *dmap)
}
}
dmap->raw_buf = start_addr;
- dmap->raw_buf_phys = virt_to_bus(start_addr);
+ dmap->raw_buf_phys = dma_map_single(NULL, start_addr, dmap->buffsize, DMA_BIDIRECTIONAL);
for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++)
SetPageReserved(page);
@@ -138,6 +140,7 @@ static void sound_free_dmap(struct dma_buffparms *dmap)
for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++)
ClearPageReserved(page);
+ dma_unmap_single(NULL, dmap->raw_buf_phys, dmap->buffsize, DMA_BIDIRECTIONAL);
free_pages((unsigned long) dmap->raw_buf, sz);
dmap->raw_buf = NULL;
}
@@ -349,8 +352,7 @@ static void dma_reset_output(int dev)
if (!signal_pending(current) && adev->dmap_out->qlen &&
adev->dmap_out->underrun_count == 0){
spin_unlock_irqrestore(&dmap->lock,flags);
- interruptible_sleep_on_timeout(&adev->out_sleeper,
- dmabuf_timeout(dmap));
+ oss_broken_sleep_on(&adev->out_sleeper, dmabuf_timeout(dmap));
spin_lock_irqsave(&dmap->lock,flags);
}
adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE);
@@ -439,12 +441,12 @@ int DMAbuf_sync(int dev)
DMAbuf_launch_output(dev, dmap);
adev->dmap_out->flags |= DMA_SYNCING;
adev->dmap_out->underrun_count = 0;
- while (!signal_pending(current) && n++ <= adev->dmap_out->nbufs &&
+ while (!signal_pending(current) && n++ < adev->dmap_out->nbufs &&
adev->dmap_out->qlen && adev->dmap_out->underrun_count == 0) {
long t = dmabuf_timeout(dmap);
spin_unlock_irqrestore(&dmap->lock,flags);
/* FIXME: not safe may miss events */
- t = interruptible_sleep_on_timeout(&adev->out_sleeper, t);
+ t = oss_broken_sleep_on(&adev->out_sleeper, t);
spin_lock_irqsave(&dmap->lock,flags);
if (!t) {
adev->dmap_out->flags &= ~DMA_SYNCING;
@@ -464,7 +466,7 @@ int DMAbuf_sync(int dev)
while (!signal_pending(current) &&
adev->d->local_qlen(dev)){
spin_unlock_irqrestore(&dmap->lock,flags);
- interruptible_sleep_on_timeout(&adev->out_sleeper,
+ oss_broken_sleep_on(&adev->out_sleeper,
dmabuf_timeout(dmap));
spin_lock_irqsave(&dmap->lock,flags);
}
@@ -555,7 +557,6 @@ int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock)
unsigned long flags;
int err = 0, n = 0;
struct dma_buffparms *dmap = adev->dmap_in;
- int go;
if (!(adev->open_mode & OPEN_READ))
return -EIO;
@@ -582,12 +583,11 @@ int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock)
spin_unlock_irqrestore(&dmap->lock,flags);
return -EAGAIN;
}
- if ((go = adev->go))
+ if (adev->go)
timeout = dmabuf_timeout(dmap);
spin_unlock_irqrestore(&dmap->lock,flags);
- timeout = interruptible_sleep_on_timeout(&adev->in_sleeper,
- timeout);
+ timeout = oss_broken_sleep_on(&adev->in_sleeper, timeout);
if (!timeout) {
/* FIXME: include device name */
err = -EIO;
@@ -767,8 +767,7 @@ static int output_sleep(int dev, int dontblock)
timeout_value = dmabuf_timeout(dmap);
else
timeout_value = MAX_SCHEDULE_TIMEOUT;
- timeout_value = interruptible_sleep_on_timeout(&adev->out_sleeper,
- timeout_value);
+ timeout_value = oss_broken_sleep_on(&adev->out_sleeper, timeout_value);
if (timeout != MAX_SCHEDULE_TIMEOUT && !timeout_value) {
printk(KERN_WARNING "Sound: DMA (output) timed out - IRQ/DRQ config error?\n");
dma_reset_output(dev);
@@ -795,9 +794,9 @@ static int find_output_space(int dev, char **buf, int *size)
#ifdef BE_CONSERVATIVE
active_offs = dmap->byte_counter + dmap->qhead * dmap->fragment_size;
#else
- active_offs = DMAbuf_get_buffer_pointer(dev, dmap, DMODE_OUTPUT);
+ active_offs = max(DMAbuf_get_buffer_pointer(dev, dmap, DMODE_OUTPUT), 0);
/* Check for pointer wrapping situation */
- if (active_offs < 0 || active_offs >= dmap->bytes_in_use)
+ if (active_offs >= dmap->bytes_in_use)
active_offs = 0;
active_offs += dmap->byte_counter;
#endif
diff --git a/sound/oss/dmasound/Kconfig b/sound/oss/dmasound/Kconfig
index 71b313479f8..f456574a964 100644
--- a/sound/oss/dmasound/Kconfig
+++ b/sound/oss/dmasound/Kconfig
@@ -14,7 +14,7 @@ config DMASOUND_ATARI
config DMASOUND_PAULA
tristate "Amiga DMA sound support"
- depends on (AMIGA || APUS) && SOUND
+ depends on AMIGA && SOUND
select DMASOUND
help
If you want to use the internal audio of your Amiga in Linux, answer
@@ -42,3 +42,4 @@ config DMASOUND_Q40
config DMASOUND
tristate
+ select SOUND_OSS_CORE
diff --git a/sound/oss/dmasound/Makefile b/sound/oss/dmasound/Makefile
index 4611636b1a8..3c1531652d1 100644
--- a/sound/oss/dmasound/Makefile
+++ b/sound/oss/dmasound/Makefile
@@ -2,12 +2,6 @@
# Makefile for the DMA sound driver
#
-dmasound_pmac-y += dmasound_awacs.o \
- trans_16.o dac3550a.o tas_common.o \
- tas3001c.o tas3001c_tables.o \
- tas3004.o tas3004_tables.o
-
obj-$(CONFIG_DMASOUND_ATARI) += dmasound_core.o dmasound_atari.o
-obj-$(CONFIG_DMASOUND_PMAC) += dmasound_core.o dmasound_pmac.o
obj-$(CONFIG_DMASOUND_PAULA) += dmasound_core.o dmasound_paula.o
obj-$(CONFIG_DMASOUND_Q40) += dmasound_core.o dmasound_q40.o
diff --git a/sound/oss/dmasound/awacs_defs.h b/sound/oss/dmasound/awacs_defs.h
deleted file mode 100644
index 2194f46b046..00000000000
--- a/sound/oss/dmasound/awacs_defs.h
+++ /dev/null
@@ -1,251 +0,0 @@
-/*********************************************************/
-/* This file was written by someone, somewhere, sometime */
-/* And is released into the Public Domain */
-/*********************************************************/
-
-#ifndef _AWACS_DEFS_H_
-#define _AWACS_DEFS_H_
-
-/*******************************/
-/* AWACs Audio Register Layout */
-/*******************************/
-
-struct awacs_regs {
- unsigned control; /* Audio control register */
- unsigned pad0[3];
- unsigned codec_ctrl; /* Codec control register */
- unsigned pad1[3];
- unsigned codec_stat; /* Codec status register */
- unsigned pad2[3];
- unsigned clip_count; /* Clipping count register */
- unsigned pad3[3];
- unsigned byteswap; /* Data is little-endian if 1 */
-};
-
-/*******************/
-/* Audio Bit Masks */
-/*******************/
-
-/* Audio Control Reg Bit Masks */
-/* ----- ------- --- --- ----- */
-#define MASK_ISFSEL (0xf) /* Input SubFrame Select */
-#define MASK_OSFSEL (0xf << 4) /* Output SubFrame Select */
-#define MASK_RATE (0x7 << 8) /* Sound Rate */
-#define MASK_CNTLERR (0x1 << 11) /* Error */
-#define MASK_PORTCHG (0x1 << 12) /* Port Change */
-#define MASK_IEE (0x1 << 13) /* Enable Interrupt on Error */
-#define MASK_IEPC (0x1 << 14) /* Enable Interrupt on Port Change */
-#define MASK_SSFSEL (0x3 << 15) /* Status SubFrame Select */
-
-/* Audio Codec Control Reg Bit Masks */
-/* ----- ----- ------- --- --- ----- */
-#define MASK_NEWECMD (0x1 << 24) /* Lock: don't write to reg when 1 */
-#define MASK_EMODESEL (0x3 << 22) /* Send info out on which frame? */
-#define MASK_EXMODEADDR (0x3ff << 12) /* Extended Mode Address -- 10 bits */
-#define MASK_EXMODEDATA (0xfff) /* Extended Mode Data -- 12 bits */
-
-/* Audio Codec Control Address Values / Masks */
-/* ----- ----- ------- ------- ------ - ----- */
-#define MASK_ADDR0 (0x0 << 12) /* Expanded Data Mode Address 0 */
-#define MASK_ADDR_MUX MASK_ADDR0 /* Mux Control */
-#define MASK_ADDR_GAIN MASK_ADDR0
-
-#define MASK_ADDR1 (0x1 << 12) /* Expanded Data Mode Address 1 */
-#define MASK_ADDR_MUTE MASK_ADDR1
-#define MASK_ADDR_RATE MASK_ADDR1
-
-#define MASK_ADDR2 (0x2 << 12) /* Expanded Data Mode Address 2 */
-#define MASK_ADDR_VOLA MASK_ADDR2 /* Volume Control A -- Headphones */
-#define MASK_ADDR_VOLHD MASK_ADDR2
-
-#define MASK_ADDR4 (0x4 << 12) /* Expanded Data Mode Address 4 */
-#define MASK_ADDR_VOLC MASK_ADDR4 /* Volume Control C -- Speaker */
-#define MASK_ADDR_VOLSPK MASK_ADDR4
-
-/* additional registers of screamer */
-#define MASK_ADDR5 (0x5 << 12) /* Expanded Data Mode Address 5 */
-#define MASK_ADDR6 (0x6 << 12) /* Expanded Data Mode Address 6 */
-#define MASK_ADDR7 (0x7 << 12) /* Expanded Data Mode Address 7 */
-
-/* Address 0 Bit Masks & Macros */
-/* ------- - --- ----- - ------ */
-#define MASK_GAINRIGHT (0xf) /* Gain Right Mask */
-#define MASK_GAINLEFT (0xf << 4) /* Gain Left Mask */
-#define MASK_GAINLINE (0x1 << 8) /* Disable Mic preamp */
-#define MASK_GAINMIC (0x0 << 8) /* Enable Mic preamp */
-
-#define MASK_MUX_CD (0x1 << 9) /* Select CD in MUX */
-#define MASK_MUX_MIC (0x1 << 10) /* Select Mic in MUX */
-#define MASK_MUX_AUDIN (0x1 << 11) /* Select Audio In in MUX */
-#define MASK_MUX_LINE MASK_MUX_AUDIN
-
-#define GAINRIGHT(x) ((x) & MASK_GAINRIGHT)
-#define GAINLEFT(x) (((x) << 4) & MASK_GAINLEFT)
-
-#define DEF_CD_GAIN 0x00bb
-#define DEF_MIC_GAIN 0x00cc
-
-/* Address 1 Bit Masks */
-/* ------- - --- ----- */
-#define MASK_ADDR1RES1 (0x3) /* Reserved */
-#define MASK_RECALIBRATE (0x1 << 2) /* Recalibrate */
-#define MASK_SAMPLERATE (0x7 << 3) /* Sample Rate: */
-#define MASK_LOOPTHRU (0x1 << 6) /* Loopthrough Enable */
-#define MASK_CMUTE (0x1 << 7) /* Output C (Speaker) Mute when 1 */
-#define MASK_SPKMUTE MASK_CMUTE
-#define MASK_ADDR1RES2 (0x1 << 8) /* Reserved */
-#define MASK_AMUTE (0x1 << 9) /* Output A (Headphone) Mute when 1 */
-#define MASK_HDMUTE MASK_AMUTE
-#define MASK_PAROUT0 (0x1 << 10) /* Parallel Output 0 */
-#define MASK_PAROUT1 (0x2 << 10) /* Parallel Output 1 */
-
-#define MASK_MIC_BOOST (0x4) /* screamer mic boost */
-
-#define SAMPLERATE_48000 (0x0 << 3) /* 48 or 44.1 kHz */
-#define SAMPLERATE_32000 (0x1 << 3) /* 32 or 29.4 kHz */
-#define SAMPLERATE_24000 (0x2 << 3) /* 24 or 22.05 kHz */
-#define SAMPLERATE_19200 (0x3 << 3) /* 19.2 or 17.64 kHz */
-#define SAMPLERATE_16000 (0x4 << 3) /* 16 or 14.7 kHz */
-#define SAMPLERATE_12000 (0x5 << 3) /* 12 or 11.025 kHz */
-#define SAMPLERATE_9600 (0x6 << 3) /* 9.6 or 8.82 kHz */
-#define SAMPLERATE_8000 (0x7 << 3) /* 8 or 7.35 kHz */
-
-/* Address 2 & 4 Bit Masks & Macros */
-/* ------- - - - --- ----- - ------ */
-#define MASK_OUTVOLRIGHT (0xf) /* Output Right Volume */
-#define MASK_ADDR2RES1 (0x2 << 4) /* Reserved */
-#define MASK_ADDR4RES1 MASK_ADDR2RES1
-#define MASK_OUTVOLLEFT (0xf << 6) /* Output Left Volume */
-#define MASK_ADDR2RES2 (0x2 << 10) /* Reserved */
-#define MASK_ADDR4RES2 MASK_ADDR2RES2
-
-#define VOLRIGHT(x) (((~(x)) & MASK_OUTVOLRIGHT))
-#define VOLLEFT(x) (((~(x)) << 6) & MASK_OUTVOLLEFT)
-
-/* Audio Codec Status Reg Bit Masks */
-/* ----- ----- ------ --- --- ----- */
-#define MASK_EXTEND (0x1 << 23) /* Extend */
-#define MASK_VALID (0x1 << 22) /* Valid Data? */
-#define MASK_OFLEFT (0x1 << 21) /* Overflow Left */
-#define MASK_OFRIGHT (0x1 << 20) /* Overflow Right */
-#define MASK_ERRCODE (0xf << 16) /* Error Code */
-#define MASK_REVISION (0xf << 12) /* Revision Number */
-#define MASK_MFGID (0xf << 8) /* Mfg. ID */
-#define MASK_CODSTATRES (0xf << 4) /* bits 4 - 7 reserved */
-#define MASK_INPPORT (0xf) /* Input Port */
-#define MASK_HDPCONN 8 /* headphone plugged in */
-
-/* Clipping Count Reg Bit Masks */
-/* -------- ----- --- --- ----- */
-#define MASK_CLIPLEFT (0xff << 7) /* Clipping Count, Left Channel */
-#define MASK_CLIPRIGHT (0xff) /* Clipping Count, Right Channel */
-
-/* DBDMA ChannelStatus Bit Masks */
-/* ----- ------------- --- ----- */
-#define MASK_CSERR (0x1 << 7) /* Error */
-#define MASK_EOI (0x1 << 6) /* End of Input -- only for Input Channel */
-#define MASK_CSUNUSED (0x1f << 1) /* bits 1-5 not used */
-#define MASK_WAIT (0x1) /* Wait */
-
-/* Various Rates */
-/* ------- ----- */
-#define RATE_48000 (0x0 << 8) /* 48 kHz */
-#define RATE_44100 (0x0 << 8) /* 44.1 kHz */
-#define RATE_32000 (0x1 << 8) /* 32 kHz */
-#define RATE_29400 (0x1 << 8) /* 29.4 kHz */
-#define RATE_24000 (0x2 << 8) /* 24 kHz */
-#define RATE_22050 (0x2 << 8) /* 22.05 kHz */
-#define RATE_19200 (0x3 << 8) /* 19.2 kHz */
-#define RATE_17640 (0x3 << 8) /* 17.64 kHz */
-#define RATE_16000 (0x4 << 8) /* 16 kHz */
-#define RATE_14700 (0x4 << 8) /* 14.7 kHz */
-#define RATE_12000 (0x5 << 8) /* 12 kHz */
-#define RATE_11025 (0x5 << 8) /* 11.025 kHz */
-#define RATE_9600 (0x6 << 8) /* 9.6 kHz */
-#define RATE_8820 (0x6 << 8) /* 8.82 kHz */
-#define RATE_8000 (0x7 << 8) /* 8 kHz */
-#define RATE_7350 (0x7 << 8) /* 7.35 kHz */
-
-#define RATE_LOW 1 /* HIGH = 48kHz, etc; LOW = 44.1kHz, etc. */
-
-/*******************/
-/* Burgundy values */
-/*******************/
-
-#define MASK_ADDR_BURGUNDY_INPSEL21 (0x11 << 12)
-#define MASK_ADDR_BURGUNDY_INPSEL3 (0x12 << 12)
-
-#define MASK_ADDR_BURGUNDY_GAINCH1 (0x13 << 12)
-#define MASK_ADDR_BURGUNDY_GAINCH2 (0x14 << 12)
-#define MASK_ADDR_BURGUNDY_GAINCH3 (0x15 << 12)
-#define MASK_ADDR_BURGUNDY_GAINCH4 (0x16 << 12)
-
-#define MASK_ADDR_BURGUNDY_VOLCH1 (0x20 << 12)
-#define MASK_ADDR_BURGUNDY_VOLCH2 (0x21 << 12)
-#define MASK_ADDR_BURGUNDY_VOLCH3 (0x22 << 12)
-#define MASK_ADDR_BURGUNDY_VOLCH4 (0x23 << 12)
-
-#define MASK_ADDR_BURGUNDY_OUTPUTSELECTS (0x2B << 12)
-#define MASK_ADDR_BURGUNDY_OUTPUTENABLES (0x2F << 12)
-
-#define MASK_ADDR_BURGUNDY_MASTER_VOLUME (0x30 << 12)
-
-#define MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES (0x60 << 12)
-
-#define MASK_ADDR_BURGUNDY_ATTENSPEAKER (0x62 << 12)
-#define MASK_ADDR_BURGUNDY_ATTENLINEOUT (0x63 << 12)
-#define MASK_ADDR_BURGUNDY_ATTENHP (0x64 << 12)
-
-#define MASK_ADDR_BURGUNDY_VOLCD (MASK_ADDR_BURGUNDY_VOLCH1)
-#define MASK_ADDR_BURGUNDY_VOLLINE (MASK_ADDR_BURGUNDY_VOLCH2)
-#define MASK_ADDR_BURGUNDY_VOLMIC (MASK_ADDR_BURGUNDY_VOLCH3)
-#define MASK_ADDR_BURGUNDY_VOLMODEM (MASK_ADDR_BURGUNDY_VOLCH4)
-
-#define MASK_ADDR_BURGUNDY_GAINCD (MASK_ADDR_BURGUNDY_GAINCH1)
-#define MASK_ADDR_BURGUNDY_GAINLINE (MASK_ADDR_BURGUNDY_GAINCH2)
-#define MASK_ADDR_BURGUNDY_GAINMIC (MASK_ADDR_BURGUNDY_GAINCH3)
-#define MASK_ADDR_BURGUNDY_GAINMODEM (MASK_ADDR_BURGUNDY_VOLCH4)
-
-
-/* These are all default values for the burgundy */
-#define DEF_BURGUNDY_INPSEL21 (0xAA)
-#define DEF_BURGUNDY_INPSEL3 (0x0A)
-
-#define DEF_BURGUNDY_GAINCD (0x33)
-#define DEF_BURGUNDY_GAINLINE (0x44)
-#define DEF_BURGUNDY_GAINMIC (0x44)
-#define DEF_BURGUNDY_GAINMODEM (0x06)
-
-/* Remember: lowest volume here is 0x9b */
-#define DEF_BURGUNDY_VOLCD (0xCCCCCCCC)
-#define DEF_BURGUNDY_VOLLINE (0x00000000)
-#define DEF_BURGUNDY_VOLMIC (0x00000000)
-#define DEF_BURGUNDY_VOLMODEM (0xCCCCCCCC)
-
-#define DEF_BURGUNDY_OUTPUTSELECTS (0x010f010f)
-#define DEF_BURGUNDY_OUTPUTENABLES (0x0A)
-
-#define DEF_BURGUNDY_MASTER_VOLUME (0xFFFFFFFF)
-
-#define DEF_BURGUNDY_MORE_OUTPUTENABLES (0x7E)
-
-#define DEF_BURGUNDY_ATTENSPEAKER (0x44)
-#define DEF_BURGUNDY_ATTENLINEOUT (0xCC)
-#define DEF_BURGUNDY_ATTENHP (0xCC)
-
-/*********************/
-/* i2s layout values */
-/*********************/
-
-#define I2S_REG_INT_CTL 0x00
-#define I2S_REG_SERIAL_FORMAT 0x10
-#define I2S_REG_CODEC_MSG_OUT 0x20
-#define I2S_REG_CODEC_MSG_IN 0x30
-#define I2S_REG_FRAME_COUNT 0x40
-#define I2S_REG_FRAME_MATCH 0x50
-#define I2S_REG_DATAWORD_SIZES 0x60
-#define I2S_REG_PEAKLEVEL_SEL 0x70
-#define I2S_REG_PEAKLEVEL_IN0 0x80
-#define I2S_REG_PEAKLEVEL_IN1 0x90
-
-#endif /* _AWACS_DEFS_H_ */
diff --git a/sound/oss/dmasound/dac3550a.c b/sound/oss/dmasound/dac3550a.c
deleted file mode 100644
index 0f0d03a55da..00000000000
--- a/sound/oss/dmasound/dac3550a.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Driver for the i2c/i2s based DAC3550a sound chip used
- * on some Apple iBooks. Also known as "DACA".
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/proc_fs.h>
-#include <linux/ioport.h>
-#include <linux/sysctl.h>
-#include <linux/types.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <asm/uaccess.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-
-#include "dmasound.h"
-
-/* FYI: This code was derived from the tas3001c.c Texas/Tumbler mixer
- * control code, as well as info derived from the AppleDACAAudio driver
- * from Darwin CVS (main thing I derived being register numbers and
- * values, as well as when to make the calls). */
-
-#define I2C_DRIVERID_DACA (0xFDCB)
-
-#define DACA_VERSION "0.1"
-#define DACA_DATE "20010930"
-
-static int cur_left_vol;
-static int cur_right_vol;
-static struct i2c_client *daca_client;
-
-static int daca_attach_adapter(struct i2c_adapter *adapter);
-static int daca_detect_client(struct i2c_adapter *adapter, int address);
-static int daca_detach_client(struct i2c_client *client);
-
-struct i2c_driver daca_driver = {
- .driver = {
- .name = "DAC3550A driver V " DACA_VERSION,
- },
- .id = I2C_DRIVERID_DACA,
- .attach_adapter = daca_attach_adapter,
- .detach_client = daca_detach_client,
-};
-
-#define VOL_MAX ((1<<20) - 1)
-
-void daca_get_volume(uint * left_vol, uint *right_vol)
-{
- *left_vol = cur_left_vol >> 5;
- *right_vol = cur_right_vol >> 5;
-}
-
-int daca_set_volume(uint left_vol, uint right_vol)
-{
- unsigned short voldata;
-
- if (!daca_client)
- return -1;
-
- /* Derived from experience, not from any specific values */
- left_vol <<= 5;
- right_vol <<= 5;
-
- if (left_vol > VOL_MAX)
- left_vol = VOL_MAX;
- if (right_vol > VOL_MAX)
- right_vol = VOL_MAX;
-
- voldata = ((left_vol >> 14) & 0x3f) << 8;
- voldata |= (right_vol >> 14) & 0x3f;
-
- if (i2c_smbus_write_word_data(daca_client, 2, voldata) < 0) {
- printk("daca: failed to set volume \n");
- return -1;
- }
-
- cur_left_vol = left_vol;
- cur_right_vol = right_vol;
-
- return 0;
-}
-
-int daca_leave_sleep(void)
-{
- if (!daca_client)
- return -1;
-
- /* Do a short sleep, just to make sure I2C bus is awake and paying
- * attention to us
- */
- msleep(20);
- /* Write the sample rate reg the value it needs */
- i2c_smbus_write_byte_data(daca_client, 1, 8);
- daca_set_volume(cur_left_vol >> 5, cur_right_vol >> 5);
- /* Another short delay, just to make sure the other I2C bus writes
- * have taken...
- */
- msleep(20);
- /* Write the global config reg - invert right power amp,
- * DAC on, use 5-volt mode */
- i2c_smbus_write_byte_data(daca_client, 3, 0x45);
-
- return 0;
-}
-
-int daca_enter_sleep(void)
-{
- if (!daca_client)
- return -1;
-
- i2c_smbus_write_byte_data(daca_client, 1, 8);
- daca_set_volume(cur_left_vol >> 5, cur_right_vol >> 5);
-
- /* Write the global config reg - invert right power amp,
- * DAC on, enter low-power mode, use 5-volt mode
- */
- i2c_smbus_write_byte_data(daca_client, 3, 0x65);
-
- return 0;
-}
-
-static int daca_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!strncmp(adapter->name, "mac-io", 6))
- daca_detect_client(adapter, 0x4d);
- return 0;
-}
-
-static int daca_init_client(struct i2c_client * new_client)
-{
- /*
- * Probe is not working with the current i2c-keywest
- * driver. We try to use addr 0x4d on each adapters
- * instead, by setting the format register.
- *
- * FIXME: I'm sure that can be obtained from the
- * device-tree. --BenH.
- */
-
- /* Write the global config reg - invert right power amp,
- * DAC on, use 5-volt mode
- */
- if (i2c_smbus_write_byte_data(new_client, 3, 0x45))
- return -1;
-
- i2c_smbus_write_byte_data(new_client, 1, 8);
- daca_client = new_client;
- daca_set_volume(15000, 15000);
-
- return 0;
-}
-
-static int daca_detect_client(struct i2c_adapter *adapter, int address)
-{
- const char *client_name = "DAC 3550A Digital Equalizer";
- struct i2c_client *new_client;
- int rc = -ENODEV;
-
- new_client = kzalloc(sizeof(*new_client), GFP_KERNEL);
- if (!new_client)
- return -ENOMEM;
-
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &daca_driver;
- new_client->flags = 0;
- strcpy(new_client->name, client_name);
-
- if (daca_init_client(new_client))
- goto bail;
-
- /* Tell the i2c layer a new client has arrived */
- if (i2c_attach_client(new_client))
- goto bail;
-
- return 0;
- bail:
- kfree(new_client);
- return rc;
-}
-
-
-static int daca_detach_client(struct i2c_client *client)
-{
- if (client == daca_client)
- daca_client = NULL;
-
- i2c_detach_client(client);
- kfree(client);
- return 0;
-}
-
-void daca_cleanup(void)
-{
- i2c_del_driver(&daca_driver);
-}
-
-int daca_init(void)
-{
- printk("dac3550a driver version %s (%s)\n",DACA_VERSION,DACA_DATE);
- return i2c_add_driver(&daca_driver);
-}
diff --git a/sound/oss/dmasound/dmasound.h b/sound/oss/dmasound/dmasound.h
index 25dd5a318eb..01019f06fa9 100644
--- a/sound/oss/dmasound/dmasound.h
+++ b/sound/oss/dmasound/dmasound.h
@@ -59,7 +59,6 @@ static inline int ioctl_return(int __user *addr, int value)
*/
#undef HAS_8BIT_TABLES
-#undef HAS_RECORD
#if defined(CONFIG_DMASOUND_ATARI) || defined(CONFIG_DMASOUND_ATARI_MODULE) ||\
defined(CONFIG_DMASOUND_PAULA) || defined(CONFIG_DMASOUND_PAULA_MODULE) ||\
@@ -83,10 +82,6 @@ static inline int ioctl_return(int __user *addr, int value)
#define DEFAULT_N_BUFFERS 4
#define DEFAULT_BUFF_SIZE (1<<15)
-#if defined(CONFIG_DMASOUND_PMAC) || defined(CONFIG_DMASOUND_PMAC_MODULE)
-#define HAS_RECORD
-#endif
-
/*
* Initialization
*/
@@ -134,7 +129,7 @@ typedef struct {
int (*mixer_ioctl)(u_int, u_long); /* optional */
int (*write_sq_setup)(void); /* optional */
int (*read_sq_setup)(void); /* optional */
- int (*sq_open)(mode_t); /* optional */
+ int (*sq_open)(fmode_t); /* optional */
int (*state_info)(char *, size_t); /* optional */
void (*abort_read)(void); /* optional */
int min_dsp_speed;
@@ -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) */
@@ -243,21 +235,15 @@ struct sound_queue {
*/
int active;
wait_queue_head_t action_queue, open_queue, sync_queue;
- int open_mode;
+ int non_blocking;
int busy, syncing, xruns, died;
};
-#define SLEEP(queue) interruptible_sleep_on_timeout(&queue, HZ)
#define WAKE_UP(queue) (wake_up_interruptible(&queue))
extern struct sound_queue dmasound_write_sq;
#define write_sq dmasound_write_sq
-#ifdef HAS_RECORD
-extern struct sound_queue dmasound_read_sq;
-#define read_sq dmasound_read_sq
-#endif
-
extern int dmasound_catchRadius;
#define catchRadius dmasound_catchRadius
diff --git a/sound/oss/dmasound/dmasound_atari.c b/sound/oss/dmasound/dmasound_atari.c
index 285239d64b8..13c214466d3 100644
--- a/sound/oss/dmasound/dmasound_atari.c
+++ b/sound/oss/dmasound/dmasound_atari.c
@@ -143,7 +143,7 @@ static int AtaMixerIoctl(u_int cmd, u_long arg);
static int TTMixerIoctl(u_int cmd, u_long arg);
static int FalconMixerIoctl(u_int cmd, u_long arg);
static int AtaWriteSqSetup(void);
-static int AtaSqOpen(mode_t mode);
+static int AtaSqOpen(fmode_t mode);
static int TTStateInfo(char *buffer, size_t space);
static int FalconStateInfo(char *buffer, size_t space);
@@ -847,22 +847,23 @@ static int __init AtaIrqInit(void)
of events. So all we need to keep the music playing is
to provide the sound hardware with new data upon
an interrupt from timer A. */
- mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */
- mfp.tim_dt_a = 1; /* Cause interrupt after first event. */
- mfp.tim_ct_a = 8; /* Turn on event counting. */
+ st_mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */
+ st_mfp.tim_dt_a = 1; /* Cause interrupt after first event. */
+ st_mfp.tim_ct_a = 8; /* Turn on event counting. */
/* Register interrupt handler. */
- request_irq(IRQ_MFP_TIMA, AtaInterrupt, IRQ_TYPE_SLOW, "DMA sound",
- AtaInterrupt);
- mfp.int_en_a |= 0x20; /* Turn interrupt on. */
- mfp.int_mk_a |= 0x20;
+ if (request_irq(IRQ_MFP_TIMA, AtaInterrupt, IRQ_TYPE_SLOW, "DMA sound",
+ AtaInterrupt))
+ return 0;
+ st_mfp.int_en_a |= 0x20; /* Turn interrupt on. */
+ st_mfp.int_mk_a |= 0x20;
return 1;
}
#ifdef MODULE
static void AtaIrqCleanUp(void)
{
- mfp.tim_ct_a = 0; /* stop timer */
- mfp.int_en_a &= ~0x20; /* turn interrupt off */
+ st_mfp.tim_ct_a = 0; /* stop timer */
+ st_mfp.int_en_a &= ~0x20; /* turn interrupt off */
free_irq(IRQ_MFP_TIMA, AtaInterrupt);
}
#endif /* MODULE */
@@ -1276,7 +1277,7 @@ static irqreturn_t AtaInterrupt(int irq, void *dummy)
* (almost) like on the TT.
*/
write_sq_ignore_int = 0;
- return IRQ_HANDLED;
+ goto out;
}
if (!write_sq.active) {
@@ -1284,7 +1285,7 @@ static irqreturn_t AtaInterrupt(int irq, void *dummy)
* the sq variables, so better don't do anything here.
*/
WAKE_UP(write_sq.sync_queue);
- return IRQ_HANDLED;
+ goto out;
}
/* Probably ;) one frame is finished. Well, in fact it may be that a
@@ -1321,6 +1322,7 @@ static irqreturn_t AtaInterrupt(int irq, void *dummy)
/* We are not playing after AtaPlay(), so there
is nothing to play any more. Wake up a process
waiting for audio output to drain. */
+out:
spin_unlock(&dmasound.lock);
return IRQ_HANDLED;
}
@@ -1461,7 +1463,7 @@ static int AtaWriteSqSetup(void)
return 0 ;
}
-static int AtaSqOpen(mode_t mode)
+static int AtaSqOpen(fmode_t mode)
{
write_sq_ignore_int = 1;
return 0 ;
@@ -1523,7 +1525,7 @@ static SETTINGS def_soft = {
.speed = 8000
} ;
-static MACHINE machTT = {
+static __initdata MACHINE machTT = {
.name = "Atari",
.name2 = "TT",
.owner = THIS_MODULE,
@@ -1552,7 +1554,7 @@ static MACHINE machTT = {
.capabilities = DSP_CAP_BATCH /* As per SNDCTL_DSP_GETCAPS */
};
-static MACHINE machFalcon = {
+static __initdata MACHINE machFalcon = {
.name = "Atari",
.name2 = "FALCON",
.dma_alloc = AtaAlloc,
@@ -1598,7 +1600,7 @@ static int __init dmasound_atari_init(void)
is_falcon = 0;
} else
return -ENODEV;
- if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0)
+ if ((st_mfp.int_en_a & st_mfp.int_mk_a & 0x20) == 0)
return dmasound_init();
else {
printk("DMA sound driver: Timer A interrupt already in use\n");
diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c
deleted file mode 100644
index 8f6388004f4..00000000000
--- a/sound/oss/dmasound/dmasound_awacs.c
+++ /dev/null
@@ -1,3215 +0,0 @@
-/*
- * linux/sound/oss/dmasound/dmasound_awacs.c
- *
- * PowerMac `AWACS' and `Burgundy' DMA Sound Driver
- * with some limited support for DACA & Tumbler
- *
- * See linux/sound/oss/dmasound/dmasound_core.c for copyright and
- * history prior to 2001/01/26.
- *
- * 26/01/2001 ed 0.1 Iain Sandoe
- * - added version info.
- * - moved dbdma command buffer allocation to PMacXXXSqSetup()
- * - fixed up beep dbdma cmd buffers
- *
- * 08/02/2001 [0.2]
- * - make SNDCTL_DSP_GETFMTS return the correct info for the h/w
- * - move soft format translations to a separate file
- * - [0.3] make SNDCTL_DSP_GETCAPS return correct info.
- * - [0.4] more informative machine name strings.
- * - [0.5]
- * - record changes.
- * - made the default_hard/soft entries.
- * 04/04/2001 [0.6]
- * - minor correction to bit assignments in awacs_defs.h
- * - incorporate mixer changes from 2.2.x back-port.
- * - take out passthru as a rec input (it isn't).
- * - make Input Gain slider work the 'right way up'.
- * - try to make the mixer sliders more logical - so now the
- * input selectors are just two-state (>50% == ON) and the
- * Input Gain slider handles the rest of the gain issues.
- * - try to pick slider representations that most closely match
- * the actual use - e.g. IGain for input gain...
- * - first stab at over/under-run detection.
- * - minor cosmetic changes to IRQ identification.
- * - fix bug where rates > max would be reported as supported.
- * - first stab at over/under-run detection.
- * - make use of i2c for mixer settings conditional on perch
- * rather than cuda (some machines without perch have cuda).
- * - fix bug where TX stops when dbdma status comes up "DEAD"
- * so far only reported on PowerComputing clones ... but.
- * - put in AWACS/Screamer register write timeouts.
- * - part way to partitioning the init() stuff
- * - first pass at 'tumbler' stuff (not support - just an attempt
- * to allow the driver to load on new G4s).
- * 01/02/2002 [0.7] - BenH
- * - all sort of minor bits went in since the latest update, I
- * bumped the version number for that reason
- *
- * 07/26/2002 [0.8] - BenH
- * - More minor bits since last changelog (I should be more careful
- * with those)
- * - Support for snapper & better tumbler integration by Toby Sargeant
- * - Headphone detect for scremer by Julien Blache
- * - More tumbler fixed by Andreas Schwab
- * 11/29/2003 [0.8.1] - Renzo Davoli (King Enzo)
- * - Support for Snapper line in
- * - snapper input resampling (for rates < 44100)
- * - software line gain control
- */
-
-/* GENERAL FIXME/TODO: check that the assumptions about what is written to
- mac-io is valid for DACA & Tumbler.
-
- This driver is in bad need of a rewrite. The dbdma code has to be split,
- some proper device-tree parsing code has to be written, etc...
-*/
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/soundcard.h>
-#include <linux/adb.h>
-#include <linux/nvram.h>
-#include <linux/tty.h>
-#include <linux/vt_kern.h>
-#include <linux/spinlock.h>
-#include <linux/kmod.h>
-#include <linux/interrupt.h>
-#include <linux/input.h>
-#include <linux/mutex.h>
-#ifdef CONFIG_ADB_CUDA
-#include <linux/cuda.h>
-#endif
-#ifdef CONFIG_ADB_PMU
-#include <linux/pmu.h>
-#endif
-
-#include <asm/uaccess.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/io.h>
-#include <asm/dbdma.h>
-#include <asm/pmac_feature.h>
-#include <asm/irq.h>
-#include <asm/nvram.h>
-
-#include "awacs_defs.h"
-#include "dmasound.h"
-#include "tas3001c.h"
-#include "tas3004.h"
-#include "tas_common.h"
-
-#define DMASOUND_AWACS_REVISION 0
-#define DMASOUND_AWACS_EDITION 7
-
-#define AWACS_SNAPPER 110 /* fake revision # for snapper */
-#define AWACS_BURGUNDY 100 /* fake revision # for burgundy */
-#define AWACS_TUMBLER 90 /* fake revision # for tumbler */
-#define AWACS_DACA 80 /* fake revision # for daca (ibook) */
-#define AWACS_AWACS 2 /* holding revision for AWACS */
-#define AWACS_SCREAMER 3 /* holding revision for Screamer */
-/*
- * Interrupt numbers and addresses, & info obtained from the device tree.
- */
-static int awacs_irq, awacs_tx_irq, awacs_rx_irq;
-static volatile struct awacs_regs __iomem *awacs;
-static volatile u32 __iomem *i2s;
-static volatile struct dbdma_regs __iomem *awacs_txdma, *awacs_rxdma;
-static int awacs_rate_index;
-static int awacs_subframe;
-static struct device_node* awacs_node;
-static struct device_node* i2s_node;
-static struct resource awacs_rsrc[3];
-
-static char awacs_name[64];
-static int awacs_revision;
-static int awacs_sleeping;
-static DEFINE_MUTEX(dmasound_mutex);
-
-static int sound_device_id; /* exists after iMac revA */
-static int hw_can_byteswap = 1 ; /* most pmac sound h/w can */
-
-/* model info */
-/* To be replaced with better interaction with pmac_feature.c */
-static int is_pbook_3X00;
-static int is_pbook_g3;
-
-/* expansion info */
-static int has_perch;
-static int has_ziva;
-
-/* for earlier powerbooks which need fiddling with mac-io to enable
- * cd etc.
-*/
-static unsigned char __iomem *latch_base;
-static unsigned char __iomem *macio_base;
-
-/*
- * Space for the DBDMA command blocks.
- */
-static void *awacs_tx_cmd_space;
-static volatile struct dbdma_cmd *awacs_tx_cmds;
-static int number_of_tx_cmd_buffers;
-
-static void *awacs_rx_cmd_space;
-static volatile struct dbdma_cmd *awacs_rx_cmds;
-static int number_of_rx_cmd_buffers;
-
-/*
- * Cached values of AWACS registers (we can't read them).
- * Except on the burgundy (and screamer). XXX
- */
-
-int awacs_reg[8];
-int awacs_reg1_save;
-
-/* tracking values for the mixer contents
-*/
-
-static int spk_vol;
-static int line_vol;
-static int passthru_vol;
-
-static int ip_gain; /* mic preamp settings */
-static int rec_lev = 0x4545 ; /* default CD gain 69 % */
-static int mic_lev;
-static int cd_lev = 0x6363 ; /* 99 % */
-static int line_lev;
-
-static int hdp_connected;
-
-/*
- * Stuff for outputting a beep. The values range from -327 to +327
- * so we can multiply by an amplitude in the range 0..100 to get a
- * signed short value to put in the output buffer.
- */
-static short beep_wform[256] = {
- 0, 40, 79, 117, 153, 187, 218, 245,
- 269, 288, 304, 316, 323, 327, 327, 324,
- 318, 310, 299, 288, 275, 262, 249, 236,
- 224, 213, 204, 196, 190, 186, 183, 182,
- 182, 183, 186, 189, 192, 196, 200, 203,
- 206, 208, 209, 209, 209, 207, 204, 201,
- 197, 193, 188, 183, 179, 174, 170, 166,
- 163, 161, 160, 159, 159, 160, 161, 162,
- 164, 166, 168, 169, 171, 171, 171, 170,
- 169, 167, 163, 159, 155, 150, 144, 139,
- 133, 128, 122, 117, 113, 110, 107, 105,
- 103, 103, 103, 103, 104, 104, 105, 105,
- 105, 103, 101, 97, 92, 86, 78, 68,
- 58, 45, 32, 18, 3, -11, -26, -41,
- -55, -68, -79, -88, -95, -100, -102, -102,
- -99, -93, -85, -75, -62, -48, -33, -16,
- 0, 16, 33, 48, 62, 75, 85, 93,
- 99, 102, 102, 100, 95, 88, 79, 68,
- 55, 41, 26, 11, -3, -18, -32, -45,
- -58, -68, -78, -86, -92, -97, -101, -103,
- -105, -105, -105, -104, -104, -103, -103, -103,
- -103, -105, -107, -110, -113, -117, -122, -128,
- -133, -139, -144, -150, -155, -159, -163, -167,
- -169, -170, -171, -171, -171, -169, -168, -166,
- -164, -162, -161, -160, -159, -159, -160, -161,
- -163, -166, -170, -174, -179, -183, -188, -193,
- -197, -201, -204, -207, -209, -209, -209, -208,
- -206, -203, -200, -196, -192, -189, -186, -183,
- -182, -182, -183, -186, -190, -196, -204, -213,
- -224, -236, -249, -262, -275, -288, -299, -310,
- -318, -324, -327, -327, -323, -316, -304, -288,
- -269, -245, -218, -187, -153, -117, -79, -40,
-};
-
-/* beep support */
-#define BEEP_SRATE 22050 /* 22050 Hz sample rate */
-#define BEEP_BUFLEN 512
-#define BEEP_VOLUME 15 /* 0 - 100 */
-
-static int beep_vol = BEEP_VOLUME;
-static int beep_playing;
-static int awacs_beep_state;
-static short *beep_buf;
-static void *beep_dbdma_cmd_space;
-static volatile struct dbdma_cmd *beep_dbdma_cmd;
-
-/* Burgundy functions */
-static void awacs_burgundy_wcw(unsigned addr,unsigned newval);
-static unsigned awacs_burgundy_rcw(unsigned addr);
-static void awacs_burgundy_write_volume(unsigned address, int volume);
-static int awacs_burgundy_read_volume(unsigned address);
-static void awacs_burgundy_write_mvolume(unsigned address, int volume);
-static int awacs_burgundy_read_mvolume(unsigned address);
-
-/* we will allocate a single 'emergency' dbdma cmd block to use if the
- tx status comes up "DEAD". This happens on some PowerComputing Pmac
- clones, either owing to a bug in dbdma or some interaction between
- IDE and sound. However, this measure would deal with DEAD status if
- if appeared elsewhere.
-
- for the sake of memory efficiency we'll allocate this cmd as part of
- the beep cmd stuff.
-*/
-
-static volatile struct dbdma_cmd *emergency_dbdma_cmd;
-
-#ifdef CONFIG_PM
-/*
- * Stuff for restoring after a sleep.
- */
-static void awacs_sleep_notify(struct pmu_sleep_notifier *self, int when);
-struct pmu_sleep_notifier awacs_sleep_notifier = {
- awacs_sleep_notify, SLEEP_LEVEL_SOUND,
-};
-#endif /* CONFIG_PM */
-
-/* for (soft) sample rate translations */
-int expand_bal; /* Balance factor for expanding (not volume!) */
-int expand_read_bal; /* Balance factor for expanding reads (not volume!) */
-
-/*** Low level stuff *********************************************************/
-
-static void *PMacAlloc(unsigned int size, gfp_t flags);
-static void PMacFree(void *ptr, unsigned int size);
-static int PMacIrqInit(void);
-#ifdef MODULE
-static void PMacIrqCleanup(void);
-#endif
-static void PMacSilence(void);
-static void PMacInit(void);
-static int PMacSetFormat(int format);
-static int PMacSetVolume(int volume);
-static void PMacPlay(void);
-static void PMacRecord(void);
-static irqreturn_t pmac_awacs_tx_intr(int irq, void *devid);
-static irqreturn_t pmac_awacs_rx_intr(int irq, void *devid);
-static irqreturn_t pmac_awacs_intr(int irq, void *devid);
-static void awacs_write(int val);
-static int awacs_get_volume(int reg, int lshift);
-static int awacs_volume_setter(int volume, int n, int mute, int lshift);
-
-
-/*** Mid level stuff **********************************************************/
-
-static int PMacMixerIoctl(u_int cmd, u_long arg);
-static int PMacWriteSqSetup(void);
-static int PMacReadSqSetup(void);
-static void PMacAbortRead(void);
-
-extern TRANS transAwacsNormal ;
-extern TRANS transAwacsExpand ;
-extern TRANS transAwacsNormalRead ;
-extern TRANS transAwacsExpandRead ;
-
-extern int daca_init(void);
-extern void daca_cleanup(void);
-extern int daca_set_volume(uint left_vol, uint right_vol);
-extern void daca_get_volume(uint * left_vol, uint *right_vol);
-extern int daca_enter_sleep(void);
-extern int daca_leave_sleep(void);
-
-#define TRY_LOCK() \
- if ((rc = mutex_lock_interruptible(&dmasound_mutex)) != 0) \
- return rc;
-#define LOCK() mutex_lock(&dmasound_mutex);
-
-#define UNLOCK() mutex_unlock(&dmasound_mutex);
-
-/* We use different versions that the ones provided in dmasound.h
- *
- * FIXME: Use different names ;)
- */
-#undef IOCTL_IN
-#undef IOCTL_OUT
-
-#define IOCTL_IN(arg, ret) \
- rc = get_user(ret, (int __user *)(arg)); \
- if (rc) break;
-#define IOCTL_OUT(arg, ret) \
- ioctl_return2((int __user *)(arg), ret)
-
-static inline int ioctl_return2(int __user *addr, int value)
-{
- return value < 0 ? value : put_user(value, addr);
-}
-
-
-/*** AE - TUMBLER / SNAPPER START ************************************************/
-
-
-int gpio_audio_reset, gpio_audio_reset_pol;
-int gpio_amp_mute, gpio_amp_mute_pol;
-int gpio_headphone_mute, gpio_headphone_mute_pol;
-int gpio_headphone_detect, gpio_headphone_detect_pol;
-int gpio_headphone_irq;
-
-int
-setup_audio_gpio(const char *name, const char* compatible, int *gpio_addr, int* gpio_pol)
-{
- struct device_node *gpiop;
- struct device_node *np;
- const u32* pp;
- int ret = -ENODEV;
-
- gpiop = of_find_node_by_name(NULL, "gpio");
- if (!gpiop)
- goto done;
-
- np = of_get_next_child(gpiop, NULL);
- while(np != 0) {
- if (name) {
- const char *property =
- of_get_property(np,"audio-gpio",NULL);
- if (property != 0 && strcmp(property,name) == 0)
- break;
- } else if (compatible && of_device_is_compatible(np, compatible))
- break;
- np = of_get_next_child(gpiop, np);
- }
- if (!np)
- goto done;
- pp = of_get_property(np, "AAPL,address", NULL);
- if (!pp)
- goto done;
- *gpio_addr = (*pp) & 0x0000ffff;
- pp = of_get_property(np, "audio-gpio-active-state", NULL);
- if (pp)
- *gpio_pol = *pp;
- else
- *gpio_pol = 1;
- ret = irq_of_parse_and_map(np, 0);
-done:
- of_node_put(np);
- of_node_put(gpiop);
- return ret;
-}
-
-static inline void
-write_audio_gpio(int gpio_addr, int data)
-{
- if (!gpio_addr)
- return;
- pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, gpio_addr, data ? 0x05 : 0x04);
-}
-
-static inline int
-read_audio_gpio(int gpio_addr)
-{
- if (!gpio_addr)
- return 0;
- return ((pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio_addr, 0) & 0x02) !=0);
-}
-
-/*
- * Headphone interrupt via GPIO (Tumbler, Snapper, DACA)
- */
-static irqreturn_t
-headphone_intr(int irq, void *devid)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&dmasound.lock, flags);
- if (read_audio_gpio(gpio_headphone_detect) == gpio_headphone_detect_pol) {
- printk(KERN_INFO "Audio jack plugged, muting speakers.\n");
- write_audio_gpio(gpio_headphone_mute, !gpio_headphone_mute_pol);
- write_audio_gpio(gpio_amp_mute, gpio_amp_mute_pol);
- tas_output_device_change(sound_device_id,TAS_OUTPUT_HEADPHONES,0);
- } else {
- printk(KERN_INFO "Audio jack unplugged, enabling speakers.\n");
- write_audio_gpio(gpio_amp_mute, !gpio_amp_mute_pol);
- write_audio_gpio(gpio_headphone_mute, gpio_headphone_mute_pol);
- tas_output_device_change(sound_device_id,TAS_OUTPUT_INTERNAL_SPKR,0);
- }
- spin_unlock_irqrestore(&dmasound.lock, flags);
- return IRQ_HANDLED;
-}
-
-
-/* Initialize tumbler */
-
-static int
-tas_dmasound_init(void)
-{
- setup_audio_gpio(
- "audio-hw-reset",
- NULL,
- &gpio_audio_reset,
- &gpio_audio_reset_pol);
- setup_audio_gpio(
- "amp-mute",
- NULL,
- &gpio_amp_mute,
- &gpio_amp_mute_pol);
- setup_audio_gpio("headphone-mute",
- NULL,
- &gpio_headphone_mute,
- &gpio_headphone_mute_pol);
- gpio_headphone_irq = setup_audio_gpio(
- "headphone-detect",
- NULL,
- &gpio_headphone_detect,
- &gpio_headphone_detect_pol);
- /* Fix some broken OF entries in desktop machines */
- if (!gpio_headphone_irq)
- gpio_headphone_irq = setup_audio_gpio(
- NULL,
- "keywest-gpio15",
- &gpio_headphone_detect,
- &gpio_headphone_detect_pol);
-
- write_audio_gpio(gpio_audio_reset, gpio_audio_reset_pol);
- msleep(100);
- write_audio_gpio(gpio_audio_reset, !gpio_audio_reset_pol);
- msleep(100);
- if (gpio_headphone_irq) {
- if (request_irq(gpio_headphone_irq,headphone_intr,0,"Headphone detect",NULL) < 0) {
- printk(KERN_ERR "tumbler: Can't request headphone interrupt\n");
- gpio_headphone_irq = 0;
- } else {
- u8 val;
- /* Activate headphone status interrupts */
- val = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio_headphone_detect, 0);
- pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, gpio_headphone_detect, val | 0x80);
- /* Trigger it */
- headphone_intr(0, NULL);
- }
- }
- if (!gpio_headphone_irq) {
- /* Some machine enter this case ? */
- printk(KERN_WARNING "tumbler: Headphone detect IRQ not found, enabling all outputs !\n");
- write_audio_gpio(gpio_amp_mute, !gpio_amp_mute_pol);
- write_audio_gpio(gpio_headphone_mute, !gpio_headphone_mute_pol);
- }
- return 0;
-}
-
-
-static int
-tas_dmasound_cleanup(void)
-{
- if (gpio_headphone_irq)
- free_irq(gpio_headphone_irq, NULL);
- return 0;
-}
-
-/* We don't support 48k yet */
-static int tas_freqs[1] = { 44100 } ;
-static int tas_freqs_ok[1] = { 1 } ;
-
-/* don't know what to do really - just have to leave it where
- * OF left things
-*/
-
-static int
-tas_set_frame_rate(void)
-{
- if (i2s) {
- out_le32(i2s + (I2S_REG_SERIAL_FORMAT >> 2), 0x41190000);
- out_le32(i2s + (I2S_REG_DATAWORD_SIZES >> 2), 0x02000200);
- }
- dmasound.hard.speed = 44100 ;
- awacs_rate_index = 0 ;
- return 44100 ;
-}
-
-static int
-tas_mixer_ioctl(u_int cmd, u_long arg)
-{
- int __user *argp = (int __user *)arg;
- int data;
- int rc;
-
- rc=tas_device_ioctl(cmd, arg);
- if (rc != -EINVAL) {
- return rc;
- }
-
- if ((cmd & ~0xff) == MIXER_WRITE(0) &&
- tas_supported_mixers() & (1<<(cmd & 0xff))) {
- rc = get_user(data, argp);
- if (rc<0) return rc;
- tas_set_mixer_level(cmd & 0xff, data);
- tas_get_mixer_level(cmd & 0xff, &data);
- return ioctl_return2(argp, data);
- }
- if ((cmd & ~0xff) == MIXER_READ(0) &&
- tas_supported_mixers() & (1<<(cmd & 0xff))) {
- tas_get_mixer_level(cmd & 0xff, &data);
- return ioctl_return2(argp, data);
- }
-
- switch(cmd) {
- case SOUND_MIXER_READ_DEVMASK:
- data = tas_supported_mixers() | SOUND_MASK_SPEAKER;
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_READ_STEREODEVS:
- data = tas_stereo_mixers();
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_READ_CAPS:
- rc = IOCTL_OUT(arg, 0);
- break;
- case SOUND_MIXER_READ_RECMASK:
- // XXX FIXME: find a way to check what is really available */
- data = SOUND_MASK_LINE | SOUND_MASK_MIC;
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_READ_RECSRC:
- if (awacs_reg[0] & MASK_MUX_AUDIN)
- data |= SOUND_MASK_LINE;
- if (awacs_reg[0] & MASK_MUX_MIC)
- data |= SOUND_MASK_MIC;
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_WRITE_RECSRC:
- IOCTL_IN(arg, data);
- data =0;
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_WRITE_SPEAKER: /* really bell volume */
- IOCTL_IN(arg, data);
- beep_vol = data & 0xff;
- /* fall through */
- case SOUND_MIXER_READ_SPEAKER:
- rc = IOCTL_OUT(arg, (beep_vol<<8) | beep_vol);
- break;
- case SOUND_MIXER_OUTMASK:
- case SOUND_MIXER_OUTSRC:
- default:
- rc = -EINVAL;
- }
-
- return rc;
-}
-
-static void __init
-tas_init_frame_rates(const unsigned int *prop, unsigned int l)
-{
- int i ;
- if (prop) {
- for (i=0; i<1; i++)
- tas_freqs_ok[i] = 0;
- for (l /= sizeof(int); l > 0; --l) {
- unsigned int r = *prop++;
- /* Apple 'Fixed' format */
- if (r >= 0x10000)
- r >>= 16;
- for (i = 0; i < 1; ++i) {
- if (r == tas_freqs[i]) {
- tas_freqs_ok[i] = 1;
- break;
- }
- }
- }
- }
- /* else we assume that all the rates are available */
-}
-
-
-/*** AE - TUMBLER / SNAPPER END ************************************************/
-
-
-
-/*** Low level stuff *********************************************************/
-
-/*
- * PCI PowerMac, with AWACS, Screamer, Burgundy, DACA or Tumbler and DBDMA.
- */
-static void *PMacAlloc(unsigned int size, gfp_t flags)
-{
- return kmalloc(size, flags);
-}
-
-static void PMacFree(void *ptr, unsigned int size)
-{
- kfree(ptr);
-}
-
-static int __init PMacIrqInit(void)
-{
- if (awacs)
- if (request_irq(awacs_irq, pmac_awacs_intr, 0, "Built-in Sound misc", NULL))
- return 0;
- if (request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "Built-in Sound out", NULL)
- || request_irq(awacs_rx_irq, pmac_awacs_rx_intr, 0, "Built-in Sound in", NULL))
- return 0;
- return 1;
-}
-
-#ifdef MODULE
-static void PMacIrqCleanup(void)
-{
- /* turn off input & output dma */
- DBDMA_DO_STOP(awacs_txdma);
- DBDMA_DO_STOP(awacs_rxdma);
-
- if (awacs)
- /* disable interrupts from awacs interface */
- out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);
-
- /* Switch off the sound clock */
- pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 0);
- /* Make sure proper bits are set on pismo & tipb */
- if ((machine_is_compatible("PowerBook3,1") ||
- machine_is_compatible("PowerBook3,2")) && awacs) {
- awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1;
- awacs_write(MASK_ADDR1 | awacs_reg[1]);
- msleep(200);
- }
- if (awacs)
- free_irq(awacs_irq, NULL);
- free_irq(awacs_tx_irq, NULL);
- free_irq(awacs_rx_irq, NULL);
-
- if (awacs)
- iounmap(awacs);
- if (i2s)
- iounmap(i2s);
- iounmap(awacs_txdma);
- iounmap(awacs_rxdma);
-
- release_mem_region(awacs_rsrc[0].start,
- awacs_rsrc[0].end - awacs_rsrc[0].start + 1);
- release_mem_region(awacs_rsrc[1].start,
- awacs_rsrc[1].end - awacs_rsrc[1].start + 1);
- release_mem_region(awacs_rsrc[2].start,
- awacs_rsrc[2].end - awacs_rsrc[2].start + 1);
-
- kfree(awacs_tx_cmd_space);
- kfree(awacs_rx_cmd_space);
- kfree(beep_dbdma_cmd_space);
- kfree(beep_buf);
-#ifdef CONFIG_PM
- pmu_unregister_sleep_notifier(&awacs_sleep_notifier);
-#endif
-}
-#endif /* MODULE */
-
-static void PMacSilence(void)
-{
- /* turn off output dma */
- DBDMA_DO_STOP(awacs_txdma);
-}
-
-/* don't know what to do really - just have to leave it where
- * OF left things
-*/
-
-static int daca_set_frame_rate(void)
-{
- if (i2s) {
- out_le32(i2s + (I2S_REG_SERIAL_FORMAT >> 2), 0x41190000);
- out_le32(i2s + (I2S_REG_DATAWORD_SIZES >> 2), 0x02000200);
- }
- dmasound.hard.speed = 44100 ;
- awacs_rate_index = 0 ;
- return 44100 ;
-}
-
-static int awacs_freqs[8] = {
- 44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350
-};
-static int awacs_freqs_ok[8] = { 1, 1, 1, 1, 1, 1, 1, 1 };
-
-static int
-awacs_set_frame_rate(int desired, int catch_r)
-{
- int tolerance, i = 8 ;
- /*
- * If we have a sample rate which is within catchRadius percent
- * of the requested value, we don't have to expand the samples.
- * Otherwise choose the next higher rate.
- * N.B.: burgundy awacs only works at 44100 Hz.
- */
- do {
- tolerance = catch_r * awacs_freqs[--i] / 100;
- if (awacs_freqs_ok[i]
- && dmasound.soft.speed <= awacs_freqs[i] + tolerance)
- break;
- } while (i > 0);
- dmasound.hard.speed = awacs_freqs[i];
- awacs_rate_index = i;
-
- out_le32(&awacs->control, MASK_IEPC | (i << 8) | 0x11 );
- awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) | (i << 3);
- awacs_write(awacs_reg[1] | MASK_ADDR1);
- return dmasound.hard.speed;
-}
-
-static int
-burgundy_set_frame_rate(void)
-{
- awacs_rate_index = 0 ;
- awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) ;
- /* XXX disable error interrupt on burgundy for now */
- out_le32(&awacs->control, MASK_IEPC | 0 | 0x11 | MASK_IEE);
- return 44100 ;
-}
-
-static int
-set_frame_rate(int desired, int catch_r)
-{
- switch (awacs_revision) {
- case AWACS_BURGUNDY:
- dmasound.hard.speed = burgundy_set_frame_rate();
- break ;
- case AWACS_TUMBLER:
- case AWACS_SNAPPER:
- dmasound.hard.speed = tas_set_frame_rate();
- break ;
- case AWACS_DACA:
- dmasound.hard.speed =
- daca_set_frame_rate();
- break ;
- default:
- dmasound.hard.speed = awacs_set_frame_rate(desired,
- catch_r);
- break ;
- }
- return dmasound.hard.speed ;
-}
-
-static void
-awacs_recalibrate(void)
-{
- /* Sorry for the horrible delays... I hope to get that improved
- * by making the whole PM process asynchronous in a future version
- */
- msleep(750);
- awacs_reg[1] |= MASK_CMUTE | MASK_AMUTE;
- awacs_write(awacs_reg[1] | MASK_RECALIBRATE | MASK_ADDR1);
- msleep(1000);
- awacs_write(awacs_reg[1] | MASK_ADDR1);
-}
-
-static void PMacInit(void)
-{
- int tolerance;
-
- switch (dmasound.soft.format) {
- case AFMT_S16_LE:
- case AFMT_U16_LE:
- if (hw_can_byteswap)
- dmasound.hard.format = AFMT_S16_LE;
- else
- dmasound.hard.format = AFMT_S16_BE;
- break;
- default:
- dmasound.hard.format = AFMT_S16_BE;
- break;
- }
- dmasound.hard.stereo = 1;
- dmasound.hard.size = 16;
-
- /* set dmasound.hard.speed - on the basis of what we want (soft)
- * and the tolerance we'll allow.
- */
- set_frame_rate(dmasound.soft.speed, catchRadius) ;
-
- tolerance = (catchRadius * dmasound.hard.speed) / 100;
- if (dmasound.soft.speed >= dmasound.hard.speed - tolerance) {
- dmasound.trans_write = &transAwacsNormal;
- dmasound.trans_read = &transAwacsNormalRead;
- } else {
- dmasound.trans_write = &transAwacsExpand;
- dmasound.trans_read = &transAwacsExpandRead;
- }
-
- if (awacs) {
- if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE))
- out_le32(&awacs->byteswap, BS_VAL);
- else
- out_le32(&awacs->byteswap, 0);
- }
-
- expand_bal = -dmasound.soft.speed;
- expand_read_bal = -dmasound.soft.speed;
-}
-
-static int PMacSetFormat(int format)
-{
- int size;
- int req_format = format;
-
- switch (format) {
- case AFMT_QUERY:
- return dmasound.soft.format;
- case AFMT_MU_LAW:
- case AFMT_A_LAW:
- case AFMT_U8:
- case AFMT_S8:
- size = 8;
- break;
- case AFMT_S16_LE:
- if(!hw_can_byteswap)
- format = AFMT_S16_BE;
- case AFMT_S16_BE:
- size = 16;
- break;
- case AFMT_U16_LE:
- if(!hw_can_byteswap)
- format = AFMT_U16_BE;
- case AFMT_U16_BE:
- size = 16;
- break;
- default: /* :-) */
- printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n",
- format);
- size = 8;
- format = AFMT_U8;
- }
-
- if (req_format == format) {
- dmasound.soft.format = format;
- dmasound.soft.size = size;
- if (dmasound.minDev == SND_DEV_DSP) {
- dmasound.dsp.format = format;
- dmasound.dsp.size = size;
- }
- }
-
- return format;
-}
-
-#define AWACS_VOLUME_TO_MASK(x) (15 - ((((x) - 1) * 15) / 99))
-#define AWACS_MASK_TO_VOLUME(y) (100 - ((y) * 99 / 15))
-
-static int awacs_get_volume(int reg, int lshift)
-{
- int volume;
-
- volume = AWACS_MASK_TO_VOLUME((reg >> lshift) & 0xf);
- volume |= AWACS_MASK_TO_VOLUME(reg & 0xf) << 8;
- return volume;
-}
-
-static int awacs_volume_setter(int volume, int n, int mute, int lshift)
-{
- int r1, rn;
-
- if (mute && volume == 0) {
- r1 = awacs_reg[1] | mute;
- } else {
- r1 = awacs_reg[1] & ~mute;
- rn = awacs_reg[n] & ~(0xf | (0xf << lshift));
- rn |= ((AWACS_VOLUME_TO_MASK(volume & 0xff) & 0xf) << lshift);
- rn |= AWACS_VOLUME_TO_MASK((volume >> 8) & 0xff) & 0xf;
- awacs_reg[n] = rn;
- awacs_write((n << 12) | rn);
- volume = awacs_get_volume(rn, lshift);
- }
- if (r1 != awacs_reg[1]) {
- awacs_reg[1] = r1;
- awacs_write(r1 | MASK_ADDR1);
- }
- return volume;
-}
-
-static int PMacSetVolume(int volume)
-{
- printk(KERN_WARNING "Bogus call to PMacSetVolume !\n");
- return 0;
-}
-
-static void awacs_setup_for_beep(int speed)
-{
- out_le32(&awacs->control,
- (in_le32(&awacs->control) & ~0x1f00)
- | ((speed > 0 ? speed : awacs_rate_index) << 8));
-
- if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE) && speed == -1)
- out_le32(&awacs->byteswap, BS_VAL);
- else
- out_le32(&awacs->byteswap, 0);
-}
-
-/* CHECK: how much of this *really* needs IRQs masked? */
-static void __PMacPlay(void)
-{
- volatile struct dbdma_cmd *cp;
- int next_frg, count;
-
- count = 300 ; /* > two cycles at the lowest sample rate */
-
- /* what we want to send next */
- next_frg = (write_sq.front + write_sq.active) % write_sq.max_count;
-
- if (awacs_beep_state) {
- /* sound takes precedence over beeps */
- /* stop the dma channel */
- out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
- while ( (in_le32(&awacs_txdma->status) & RUN) && count--)
- udelay(1);
- if (awacs)
- awacs_setup_for_beep(-1);
- out_le32(&awacs_txdma->cmdptr,
- virt_to_bus(&(awacs_tx_cmds[next_frg])));
-
- beep_playing = 0;
- awacs_beep_state = 0;
- }
- /* this won't allow more than two frags to be in the output queue at
- once. (or one, if the max frags is 2 - because count can't exceed
- 2 in that case)
- */
- while (write_sq.active < 2 && write_sq.active < write_sq.count) {
- count = (write_sq.count == write_sq.active + 1) ?
- write_sq.rear_size:write_sq.block_size ;
- if (count < write_sq.block_size) {
- if (!write_sq.syncing) /* last block not yet filled,*/
- break; /* and we're not syncing or POST-ed */
- else {
- /* pretend the block is full to force a new
- block to be started on the next write */
- write_sq.rear_size = write_sq.block_size ;
- write_sq.syncing &= ~2 ; /* clear POST */
- }
- }
- cp = &awacs_tx_cmds[next_frg];
- st_le16(&cp->req_count, count);
- st_le16(&cp->xfer_status, 0);
- st_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS);
- /* put a STOP at the end of the queue - but only if we have
- space for it. This means that, if we under-run and we only
- have two fragments, we might re-play sound from an existing
- queued frag. I guess the solution to that is not to set two
- frags if you are likely to under-run...
- */
- if (write_sq.count < write_sq.max_count) {
- if (++next_frg >= write_sq.max_count)
- next_frg = 0 ; /* wrap */
- /* if we get here then we've underrun so we will stop*/
- st_le16(&awacs_tx_cmds[next_frg].command, DBDMA_STOP);
- }
- /* set the dbdma controller going, if it is not already */
- if (write_sq.active == 0)
- out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp));
- (void)in_le32(&awacs_txdma->status);
- out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
- ++write_sq.active;
- }
-}
-
-static void PMacPlay(void)
-{
- LOCK();
- if (!awacs_sleeping) {
- unsigned long flags;
-
- spin_lock_irqsave(&dmasound.lock, flags);
- __PMacPlay();
- spin_unlock_irqrestore(&dmasound.lock, flags);
- }
- UNLOCK();
-}
-
-static void PMacRecord(void)
-{
- unsigned long flags;
-
- if (read_sq.active)
- return;
-
- spin_lock_irqsave(&dmasound.lock, flags);
-
- /* This is all we have to do......Just start it up.
- */
- out_le32(&awacs_rxdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
- read_sq.active = 1;
-
- spin_unlock_irqrestore(&dmasound.lock, flags);
-}
-
-/* if the TX status comes up "DEAD" - reported on some Power Computing machines
- we need to re-start the dbdma - but from a different physical start address
- and with a different transfer length. It would get very messy to do this
- with the normal dbdma_cmd blocks - we would have to re-write the buffer start
- addresses each time. So, we will keep a single dbdma_cmd block which can be
- fiddled with.
- When DEAD status is first reported the content of the faulted dbdma block is
- copied into the emergency buffer and we note that the buffer is in use.
- we then bump the start physical address by the amount that was successfully
- output before it died.
- On any subsequent DEAD result we just do the bump-ups (we know that we are
- already using the emergency dbdma_cmd).
- CHECK: this just tries to "do it". It is possible that we should abandon
- xfers when the number of residual bytes gets below a certain value - I can
- see that this might cause a loop-forever if too small a transfer causes
- DEAD status. However this is a TODO for now - we'll see what gets reported.
- When we get a successful transfer result with the emergency buffer we just
- pretend that it completed using the original dmdma_cmd and carry on. The
- 'next_cmd' field will already point back to the original loop of blocks.
-*/
-
-static irqreturn_t
-pmac_awacs_tx_intr(int irq, void *devid)
-{
- int i = write_sq.front;
- int stat;
- int i_nowrap = write_sq.front;
- volatile struct dbdma_cmd *cp;
- /* != 0 when we are dealing with a DEAD xfer */
- static int emergency_in_use;
-
- spin_lock(&dmasound.lock);
- while (write_sq.active > 0) { /* we expect to have done something*/
- if (emergency_in_use) /* we are dealing with DEAD xfer */
- cp = emergency_dbdma_cmd ;
- else
- cp = &awacs_tx_cmds[i];
- stat = ld_le16(&cp->xfer_status);
- if (stat & DEAD) {
- unsigned short req, res ;
- unsigned int phy ;
-#ifdef DEBUG_DMASOUND
-printk("dmasound_pmac: tx-irq: xfer died - patching it up...\n") ;
-#endif
- /* to clear DEAD status we must first clear RUN
- set it to quiescent to be on the safe side */
- (void)in_le32(&awacs_txdma->status);
- out_le32(&awacs_txdma->control,
- (RUN|PAUSE|FLUSH|WAKE) << 16);
- write_sq.died++ ;
- if (!emergency_in_use) { /* new problem */
- memcpy((void *)emergency_dbdma_cmd, (void *)cp,
- sizeof(struct dbdma_cmd));
- emergency_in_use = 1;
- cp = emergency_dbdma_cmd;
- }
- /* now bump the values to reflect the amount
- we haven't yet shifted */
- req = ld_le16(&cp->req_count);
- res = ld_le16(&cp->res_count);
- phy = ld_le32(&cp->phy_addr);
- phy += (req - res);
- st_le16(&cp->req_count, res);
- st_le16(&cp->res_count, 0);
- st_le16(&cp->xfer_status, 0);
- st_le32(&cp->phy_addr, phy);
- st_le32(&cp->cmd_dep, virt_to_bus(&awacs_tx_cmds[(i+1)%write_sq.max_count]));
- st_le16(&cp->command, OUTPUT_MORE | BR_ALWAYS | INTR_ALWAYS);
-
- /* point at our patched up command block */
- out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp));
- /* we must re-start the controller */
- (void)in_le32(&awacs_txdma->status);
- /* should complete clearing the DEAD status */
- out_le32(&awacs_txdma->control,
- ((RUN|WAKE) << 16) + (RUN|WAKE));
- break; /* this block is still going */
- }
- if ((stat & ACTIVE) == 0)
- break; /* this frame is still going */
- if (emergency_in_use)
- emergency_in_use = 0 ; /* done that */
- --write_sq.count;
- --write_sq.active;
- i_nowrap++;
- if (++i >= write_sq.max_count)
- i = 0;
- }
-
- /* if we stopped and we were not sync-ing - then we under-ran */
- if( write_sq.syncing == 0 ){
- stat = in_le32(&awacs_txdma->status) ;
- /* we hit the dbdma_stop */
- if( (stat & ACTIVE) == 0 ) write_sq.xruns++ ;
- }
-
- /* if we used some data up then wake the writer to supply some more*/
- if (i_nowrap != write_sq.front)
- WAKE_UP(write_sq.action_queue);
- write_sq.front = i;
-
- /* but make sure we funnel what we've already got */\
- if (!awacs_sleeping)
- __PMacPlay();
-
- /* make the wake-on-empty conditional on syncing */
- if (!write_sq.active && (write_sq.syncing & 1))
- WAKE_UP(write_sq.sync_queue); /* any time we're empty */
- spin_unlock(&dmasound.lock);
- return IRQ_HANDLED;
-}
-
-
-static irqreturn_t
-pmac_awacs_rx_intr(int irq, void *devid)
-{
- int stat ;
- /* For some reason on my PowerBook G3, I get one interrupt
- * when the interrupt vector is installed (like something is
- * pending). This happens before the dbdma is initialized by
- * us, so I just check the command pointer and if it is zero,
- * just blow it off.
- */
- if (in_le32(&awacs_rxdma->cmdptr) == 0)
- return IRQ_HANDLED;
-
- /* We also want to blow 'em off when shutting down.
- */
- if (read_sq.active == 0)
- return IRQ_HANDLED;
-
- spin_lock(&dmasound.lock);
- /* Check multiple buffers in case we were held off from
- * interrupt processing for a long time. Geeze, I really hope
- * this doesn't happen.
- */
- while ((stat=awacs_rx_cmds[read_sq.rear].xfer_status)) {
-
- /* if we got a "DEAD" status then just log it for now.
- and try to restart dma.
- TODO: figure out how best to fix it up
- */
- if (stat & DEAD){
-#ifdef DEBUG_DMASOUND
-printk("dmasound_pmac: rx-irq: DIED - attempting resurection\n");
-#endif
- /* to clear DEAD status we must first clear RUN
- set it to quiescent to be on the safe side */
- (void)in_le32(&awacs_txdma->status);
- out_le32(&awacs_txdma->control,
- (RUN|PAUSE|FLUSH|WAKE) << 16);
- awacs_rx_cmds[read_sq.rear].xfer_status = 0;
- awacs_rx_cmds[read_sq.rear].res_count = 0;
- read_sq.died++ ;
- (void)in_le32(&awacs_txdma->status);
- /* re-start the same block */
- out_le32(&awacs_rxdma->cmdptr,
- virt_to_bus(&awacs_rx_cmds[read_sq.rear]));
- /* we must re-start the controller */
- (void)in_le32(&awacs_rxdma->status);
- /* should complete clearing the DEAD status */
- out_le32(&awacs_rxdma->control,
- ((RUN|WAKE) << 16) + (RUN|WAKE));
- spin_unlock(&dmasound.lock);
- return IRQ_HANDLED; /* try this block again */
- }
- /* Clear status and move on to next buffer.
- */
- awacs_rx_cmds[read_sq.rear].xfer_status = 0;
- read_sq.rear++;
-
- /* Wrap the buffer ring.
- */
- if (read_sq.rear >= read_sq.max_active)
- read_sq.rear = 0;
-
- /* If we have caught up to the front buffer, bump it.
- * This will cause weird (but not fatal) results if the
- * read loop is currently using this buffer. The user is
- * behind in this case anyway, so weird things are going
- * to happen.
- */
- if (read_sq.rear == read_sq.front) {
- read_sq.front++;
- read_sq.xruns++ ; /* we overan */
- if (read_sq.front >= read_sq.max_active)
- read_sq.front = 0;
- }
- }
-
- WAKE_UP(read_sq.action_queue);
- spin_unlock(&dmasound.lock);
- return IRQ_HANDLED;
-}
-
-
-static irqreturn_t
-pmac_awacs_intr(int irq, void *devid)
-{
- int ctrl;
- int status;
- int r1;
-
- spin_lock(&dmasound.lock);
- ctrl = in_le32(&awacs->control);
- status = in_le32(&awacs->codec_stat);
-
- if (ctrl & MASK_PORTCHG) {
- /* tested on Screamer, should work on others too */
- if (awacs_revision == AWACS_SCREAMER) {
- if (((status & MASK_HDPCONN) >> 3) && (hdp_connected == 0)) {
- hdp_connected = 1;
-
- r1 = awacs_reg[1] | MASK_SPKMUTE;
- awacs_reg[1] = r1;
- awacs_write(r1 | MASK_ADDR_MUTE);
- } else if (((status & MASK_HDPCONN) >> 3 == 0) && (hdp_connected == 1)) {
- hdp_connected = 0;
-
- r1 = awacs_reg[1] & ~MASK_SPKMUTE;
- awacs_reg[1] = r1;
- awacs_write(r1 | MASK_ADDR_MUTE);
- }
- }
- }
- if (ctrl & MASK_CNTLERR) {
- int err = (in_le32(&awacs->codec_stat) & MASK_ERRCODE) >> 16;
- /* CHECK: we just swallow burgundy errors at the moment..*/
- if (err != 0 && awacs_revision != AWACS_BURGUNDY)
- printk(KERN_ERR "dmasound_pmac: error %x\n", err);
- }
- /* Writing 1s to the CNTLERR and PORTCHG bits clears them... */
- out_le32(&awacs->control, ctrl);
- spin_unlock(&dmasound.lock);
- return IRQ_HANDLED;
-}
-
-static void
-awacs_write(int val)
-{
- int count = 300 ;
- if (awacs_revision >= AWACS_DACA || !awacs)
- return ;
-
- while ((in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) && count--)
- udelay(1) ; /* timeout is > 2 samples at lowest rate */
- out_le32(&awacs->codec_ctrl, val | (awacs_subframe << 22));
- (void)in_le32(&awacs->byteswap);
-}
-
-/* this is called when the beep timer expires... it will be called even
- if the beep has been overidden by other sound output.
-*/
-static void awacs_nosound(unsigned long xx)
-{
- unsigned long flags;
- int count = 600 ; /* > four samples at lowest rate */
-
- spin_lock_irqsave(&dmasound.lock, flags);
- if (beep_playing) {
- st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
- out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
- while ((in_le32(&awacs_txdma->status) & RUN) && count--)
- udelay(1);
- if (awacs)
- awacs_setup_for_beep(-1);
- beep_playing = 0;
- }
- spin_unlock_irqrestore(&dmasound.lock, flags);
-}
-
-/*
- * We generate the beep with a single dbdma command that loops a buffer
- * forever - without generating interrupts.
- *
- * So, to stop it you have to stop dma output as per awacs_nosound.
- */
-static int awacs_beep_event(struct input_dev *dev, unsigned int type,
- unsigned int code, int hz)
-{
- unsigned long flags;
- int beep_speed = 0;
- int srate;
- int period, ncycles, nsamples;
- int i, j, f;
- short *p;
- static int beep_hz_cache;
- static int beep_nsamples_cache;
- static int beep_volume_cache;
-
- if (type != EV_SND)
- return -1;
- switch (code) {
- case SND_BELL:
- if (hz)
- hz = 1000;
- break;
- case SND_TONE:
- break;
- default:
- return -1;
- }
-
- if (beep_buf == NULL)
- return -1;
-
- /* quick-hack fix for DACA, Burgundy & Tumbler */
-
- if (awacs_revision >= AWACS_DACA){
- srate = 44100 ;
- } else {
- for (i = 0; i < 8 && awacs_freqs[i] >= BEEP_SRATE; ++i)
- if (awacs_freqs_ok[i])
- beep_speed = i;
- srate = awacs_freqs[beep_speed];
- }
-
- if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) {
- /* cancel beep currently playing */
- awacs_nosound(0);
- return 0;
- }
-
- spin_lock_irqsave(&dmasound.lock, flags);
- if (beep_playing || write_sq.active || beep_buf == NULL) {
- spin_unlock_irqrestore(&dmasound.lock, flags);
- return -1; /* too hard, sorry :-( */
- }
- beep_playing = 1;
- st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS);
- spin_unlock_irqrestore(&dmasound.lock, flags);
-
- if (hz == beep_hz_cache && beep_vol == beep_volume_cache) {
- nsamples = beep_nsamples_cache;
- } else {
- period = srate * 256 / hz; /* fixed point */
- ncycles = BEEP_BUFLEN * 256 / period;
- nsamples = (period * ncycles) >> 8;
- f = ncycles * 65536 / nsamples;
- j = 0;
- p = beep_buf;
- for (i = 0; i < nsamples; ++i, p += 2) {
- p[0] = p[1] = beep_wform[j >> 8] * beep_vol;
- j = (j + f) & 0xffff;
- }
- beep_hz_cache = hz;
- beep_volume_cache = beep_vol;
- beep_nsamples_cache = nsamples;
- }
-
- st_le16(&beep_dbdma_cmd->req_count, nsamples*4);
- st_le16(&beep_dbdma_cmd->xfer_status, 0);
- st_le32(&beep_dbdma_cmd->cmd_dep, virt_to_bus(beep_dbdma_cmd));
- st_le32(&beep_dbdma_cmd->phy_addr, virt_to_bus(beep_buf));
- awacs_beep_state = 1;
-
- spin_lock_irqsave(&dmasound.lock, flags);
- if (beep_playing) { /* i.e. haven't been terminated already */
- int count = 300 ;
- out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
- while ((in_le32(&awacs_txdma->status) & RUN) && count--)
- udelay(1); /* timeout > 2 samples at lowest rate*/
- if (awacs)
- awacs_setup_for_beep(beep_speed);
- out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
- (void)in_le32(&awacs_txdma->status);
- out_le32(&awacs_txdma->control, RUN | (RUN << 16));
- }
- spin_unlock_irqrestore(&dmasound.lock, flags);
-
- return 0;
-}
-
-/* used in init and for wake-up */
-
-static void
-load_awacs(void)
-{
- awacs_write(awacs_reg[0] + MASK_ADDR0);
- awacs_write(awacs_reg[1] + MASK_ADDR1);
- awacs_write(awacs_reg[2] + MASK_ADDR2);
- awacs_write(awacs_reg[4] + MASK_ADDR4);
-
- if (awacs_revision == AWACS_SCREAMER) {
- awacs_write(awacs_reg[5] + MASK_ADDR5);
- msleep(100);
- awacs_write(awacs_reg[6] + MASK_ADDR6);
- msleep(2);
- awacs_write(awacs_reg[1] + MASK_ADDR1);
- awacs_write(awacs_reg[7] + MASK_ADDR7);
- }
- if (awacs) {
- if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE))
- out_le32(&awacs->byteswap, BS_VAL);
- else
- out_le32(&awacs->byteswap, 0);
- }
-}
-
-#ifdef CONFIG_PM
-/*
- * Save state when going to sleep, restore it afterwards.
- */
-/* FIXME: sort out disabling/re-enabling of read stuff as well */
-static void awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
-{
- unsigned long flags;
-
- switch (when) {
- case PBOOK_SLEEP_NOW:
- LOCK();
- awacs_sleeping = 1;
- /* Tell the rest of the driver we are now going to sleep */
- mb();
- if (awacs_revision == AWACS_SCREAMER ||
- awacs_revision == AWACS_AWACS) {
- awacs_reg1_save = awacs_reg[1];
- awacs_reg[1] |= MASK_AMUTE | MASK_CMUTE;
- awacs_write(MASK_ADDR1 | awacs_reg[1]);
- }
-
- PMacSilence();
- /* stop rx - if going - a bit of a daft user... but */
- out_le32(&awacs_rxdma->control, (RUN|WAKE|FLUSH << 16));
- /* deny interrupts */
- if (awacs)
- disable_irq(awacs_irq);
- disable_irq(awacs_tx_irq);
- disable_irq(awacs_rx_irq);
- /* Chip specific sleep code */
- switch (awacs_revision) {
- case AWACS_TUMBLER:
- case AWACS_SNAPPER:
- write_audio_gpio(gpio_headphone_mute, gpio_headphone_mute_pol);
- write_audio_gpio(gpio_amp_mute, gpio_amp_mute_pol);
- tas_enter_sleep();
- write_audio_gpio(gpio_audio_reset, gpio_audio_reset_pol);
- break ;
- case AWACS_DACA:
- daca_enter_sleep();
- break ;
- case AWACS_BURGUNDY:
- break ;
- case AWACS_SCREAMER:
- case AWACS_AWACS:
- default:
- out_le32(&awacs->control, 0x11) ;
- break ;
- }
- /* Disable sound clock */
- pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 0);
- /* According to Darwin, we do that after turning off the sound
- * chip clock. All this will have to be cleaned up once we properly
- * parse the OF sound-objects
- */
- if ((machine_is_compatible("PowerBook3,1") ||
- machine_is_compatible("PowerBook3,2")) && awacs) {
- awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1;
- awacs_write(MASK_ADDR1 | awacs_reg[1]);
- msleep(200);
- }
- break;
- case PBOOK_WAKE:
- /* Enable sound clock */
- pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 1);
- if ((machine_is_compatible("PowerBook3,1") ||
- machine_is_compatible("PowerBook3,2")) && awacs) {
- msleep(100);
- awacs_reg[1] &= ~(MASK_PAROUT0 | MASK_PAROUT1);
- awacs_write(MASK_ADDR1 | awacs_reg[1]);
- msleep(300);
- } else
- msleep(1000);
- /* restore settings */
- switch (awacs_revision) {
- case AWACS_TUMBLER:
- case AWACS_SNAPPER:
- write_audio_gpio(gpio_headphone_mute, gpio_headphone_mute_pol);
- write_audio_gpio(gpio_amp_mute, gpio_amp_mute_pol);
- write_audio_gpio(gpio_audio_reset, gpio_audio_reset_pol);
- msleep(100);
- write_audio_gpio(gpio_audio_reset, !gpio_audio_reset_pol);
- msleep(150);
- tas_leave_sleep(); /* Stub for now */
- headphone_intr(0, NULL);
- break;
- case AWACS_DACA:
- msleep(10); /* Check this !!! */
- daca_leave_sleep();
- break ; /* dont know how yet */
- case AWACS_BURGUNDY:
- break ;
- case AWACS_SCREAMER:
- case AWACS_AWACS:
- default:
- load_awacs() ;
- break ;
- }
- /* Recalibrate chip */
- if (awacs_revision == AWACS_SCREAMER && awacs)
- awacs_recalibrate();
- /* Make sure dma is stopped */
- PMacSilence();
- if (awacs)
- enable_irq(awacs_irq);
- enable_irq(awacs_tx_irq);
- enable_irq(awacs_rx_irq);
- if (awacs) {
- /* OK, allow ints back again */
- out_le32(&awacs->control, MASK_IEPC
- | (awacs_rate_index << 8) | 0x11
- | (awacs_revision < AWACS_DACA ? MASK_IEE: 0));
- }
- if (macio_base && is_pbook_g3) {
- /* FIXME: should restore the setup we had...*/
- out_8(macio_base + 0x37, 3);
- } else if (is_pbook_3X00) {
- in_8(latch_base + 0x190);
- }
- /* Remove mute */
- if (awacs_revision == AWACS_SCREAMER ||
- awacs_revision == AWACS_AWACS) {
- awacs_reg[1] = awacs_reg1_save;
- awacs_write(MASK_ADDR1 | awacs_reg[1]);
- }
- awacs_sleeping = 0;
- /* Resume pending sounds. */
- /* we don't try to restart input... */
- spin_lock_irqsave(&dmasound.lock, flags);
- __PMacPlay();
- spin_unlock_irqrestore(&dmasound.lock, flags);
- UNLOCK();
- }
-}
-#endif /* CONFIG_PM */
-
-
-/* All the burgundy functions: */
-
-/* Waits for busy flag to clear */
-static inline void
-awacs_burgundy_busy_wait(void)
-{
- int count = 50; /* > 2 samples at 44k1 */
- while ((in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) && count--)
- udelay(1) ;
-}
-
-static inline void
-awacs_burgundy_extend_wait(void)
-{
- int count = 50 ; /* > 2 samples at 44k1 */
- while ((!(in_le32(&awacs->codec_stat) & MASK_EXTEND)) && count--)
- udelay(1) ;
- count = 50;
- while ((in_le32(&awacs->codec_stat) & MASK_EXTEND) && count--)
- udelay(1);
-}
-
-static void
-awacs_burgundy_wcw(unsigned addr, unsigned val)
-{
- out_le32(&awacs->codec_ctrl, addr + 0x200c00 + (val & 0xff));
- awacs_burgundy_busy_wait();
- out_le32(&awacs->codec_ctrl, addr + 0x200d00 +((val>>8) & 0xff));
- awacs_burgundy_busy_wait();
- out_le32(&awacs->codec_ctrl, addr + 0x200e00 +((val>>16) & 0xff));
- awacs_burgundy_busy_wait();
- out_le32(&awacs->codec_ctrl, addr + 0x200f00 +((val>>24) & 0xff));
- awacs_burgundy_busy_wait();
-}
-
-static unsigned
-awacs_burgundy_rcw(unsigned addr)
-{
- unsigned val = 0;
- unsigned long flags;
-
- /* should have timeouts here */
- spin_lock_irqsave(&dmasound.lock, flags);
-
- out_le32(&awacs->codec_ctrl, addr + 0x100000);
- awacs_burgundy_busy_wait();
- awacs_burgundy_extend_wait();
- val += (in_le32(&awacs->codec_stat) >> 4) & 0xff;
-
- out_le32(&awacs->codec_ctrl, addr + 0x100100);
- awacs_burgundy_busy_wait();
- awacs_burgundy_extend_wait();
- val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<8;
-
- out_le32(&awacs->codec_ctrl, addr + 0x100200);
- awacs_burgundy_busy_wait();
- awacs_burgundy_extend_wait();
- val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<16;
-
- out_le32(&awacs->codec_ctrl, addr + 0x100300);
- awacs_burgundy_busy_wait();
- awacs_burgundy_extend_wait();
- val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<24;
-
- spin_unlock_irqrestore(&dmasound.lock, flags);
-
- return val;
-}
-
-
-static void
-awacs_burgundy_wcb(unsigned addr, unsigned val)
-{
- out_le32(&awacs->codec_ctrl, addr + 0x300000 + (val & 0xff));
- awacs_burgundy_busy_wait();
-}
-
-static unsigned
-awacs_burgundy_rcb(unsigned addr)
-{
- unsigned val = 0;
- unsigned long flags;
-
- /* should have timeouts here */
- spin_lock_irqsave(&dmasound.lock, flags);
-
- out_le32(&awacs->codec_ctrl, addr + 0x100000);
- awacs_burgundy_busy_wait();
- awacs_burgundy_extend_wait();
- val += (in_le32(&awacs->codec_stat) >> 4) & 0xff;
-
- spin_unlock_irqrestore(&dmasound.lock, flags);
-
- return val;
-}
-
-static int
-awacs_burgundy_check(void)
-{
- /* Checks to see the chip is alive and kicking */
- int error = in_le32(&awacs->codec_ctrl) & MASK_ERRCODE;
-
- return error == 0xf0000;
-}
-
-static int
-awacs_burgundy_init(void)
-{
- if (awacs_burgundy_check()) {
- printk(KERN_WARNING "dmasound_pmac: burgundy not working :-(\n");
- return 1;
- }
-
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_OUTPUTENABLES,
- DEF_BURGUNDY_OUTPUTENABLES);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
- DEF_BURGUNDY_MORE_OUTPUTENABLES);
- awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_OUTPUTSELECTS,
- DEF_BURGUNDY_OUTPUTSELECTS);
-
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL21,
- DEF_BURGUNDY_INPSEL21);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL3,
- DEF_BURGUNDY_INPSEL3);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINCD,
- DEF_BURGUNDY_GAINCD);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINLINE,
- DEF_BURGUNDY_GAINLINE);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMIC,
- DEF_BURGUNDY_GAINMIC);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMODEM,
- DEF_BURGUNDY_GAINMODEM);
-
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER,
- DEF_BURGUNDY_ATTENSPEAKER);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENLINEOUT,
- DEF_BURGUNDY_ATTENLINEOUT);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENHP,
- DEF_BURGUNDY_ATTENHP);
-
- awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_MASTER_VOLUME,
- DEF_BURGUNDY_MASTER_VOLUME);
- awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLCD,
- DEF_BURGUNDY_VOLCD);
- awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLLINE,
- DEF_BURGUNDY_VOLLINE);
- awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLMIC,
- DEF_BURGUNDY_VOLMIC);
- return 0;
-}
-
-static void
-awacs_burgundy_write_volume(unsigned address, int volume)
-{
- int hardvolume,lvolume,rvolume;
-
- lvolume = (volume & 0xff) ? (volume & 0xff) + 155 : 0;
- rvolume = ((volume >>8)&0xff) ? ((volume >> 8)&0xff ) + 155 : 0;
-
- hardvolume = lvolume + (rvolume << 16);
-
- awacs_burgundy_wcw(address, hardvolume);
-}
-
-static int
-awacs_burgundy_read_volume(unsigned address)
-{
- int softvolume,wvolume;
-
- wvolume = awacs_burgundy_rcw(address);
-
- softvolume = (wvolume & 0xff) - 155;
- softvolume += (((wvolume >> 16) & 0xff) - 155)<<8;
-
- return softvolume > 0 ? softvolume : 0;
-}
-
-static int
-awacs_burgundy_read_mvolume(unsigned address)
-{
- int lvolume,rvolume,wvolume;
-
- wvolume = awacs_burgundy_rcw(address);
-
- wvolume &= 0xffff;
-
- rvolume = (wvolume & 0xff) - 155;
- lvolume = ((wvolume & 0xff00)>>8) - 155;
-
- return lvolume + (rvolume << 8);
-}
-
-static void
-awacs_burgundy_write_mvolume(unsigned address, int volume)
-{
- int lvolume,rvolume,hardvolume;
-
- lvolume = (volume &0xff) ? (volume & 0xff) + 155 :0;
- rvolume = ((volume >>8) & 0xff) ? (volume >> 8) + 155 :0;
-
- hardvolume = lvolume + (rvolume << 8);
- hardvolume += (hardvolume << 16);
-
- awacs_burgundy_wcw(address, hardvolume);
-}
-
-/* End burgundy functions */
-
-/* Set up output volumes on machines with the 'perch/whisper' extension card.
- * this has an SGS i2c chip (7433) which is accessed using the cuda.
- *
- * TODO: split this out and make use of the other parts of the SGS chip to
- * do Bass, Treble etc.
- */
-
-static void
-awacs_enable_amp(int spkr_vol)
-{
-#ifdef CONFIG_ADB_CUDA
- struct adb_request req;
-
- if (sys_ctrler != SYS_CTRLER_CUDA)
- return;
-
- /* turn on headphones */
- cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
- 0x8a, 4, 0);
- while (!req.complete) cuda_poll();
- cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
- 0x8a, 6, 0);
- while (!req.complete) cuda_poll();
-
- /* turn on speaker */
- cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
- 0x8a, 3, (100 - (spkr_vol & 0xff)) * 32 / 100);
- while (!req.complete) cuda_poll();
- cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
- 0x8a, 5, (100 - ((spkr_vol >> 8) & 0xff)) * 32 / 100);
- while (!req.complete) cuda_poll();
-
- cuda_request(&req, NULL, 5, CUDA_PACKET,
- CUDA_GET_SET_IIC, 0x8a, 1, 0x29);
- while (!req.complete) cuda_poll();
-#endif /* CONFIG_ADB_CUDA */
-}
-
-
-/*** Mid level stuff *********************************************************/
-
-
-/*
- * /dev/mixer abstraction
- */
-
-static void do_line_lev(int data)
-{
- line_lev = data ;
- awacs_reg[0] &= ~MASK_MUX_AUDIN;
- if ((data & 0xff) >= 50)
- awacs_reg[0] |= MASK_MUX_AUDIN;
- awacs_write(MASK_ADDR0 | awacs_reg[0]);
-}
-
-static void do_ip_gain(int data)
-{
- ip_gain = data ;
- data &= 0xff;
- awacs_reg[0] &= ~MASK_GAINLINE;
- if (awacs_revision == AWACS_SCREAMER) {
- awacs_reg[6] &= ~MASK_MIC_BOOST ;
- if (data >= 33) {
- awacs_reg[0] |= MASK_GAINLINE;
- if( data >= 66)
- awacs_reg[6] |= MASK_MIC_BOOST ;
- }
- awacs_write(MASK_ADDR6 | awacs_reg[6]) ;
- } else {
- if (data >= 50)
- awacs_reg[0] |= MASK_GAINLINE;
- }
- awacs_write(MASK_ADDR0 | awacs_reg[0]);
-}
-
-static void do_mic_lev(int data)
-{
- mic_lev = data ;
- data &= 0xff;
- awacs_reg[0] &= ~MASK_MUX_MIC;
- if (data >= 50)
- awacs_reg[0] |= MASK_MUX_MIC;
- awacs_write(MASK_ADDR0 | awacs_reg[0]);
-}
-
-static void do_cd_lev(int data)
-{
- cd_lev = data ;
- awacs_reg[0] &= ~MASK_MUX_CD;
- if ((data & 0xff) >= 50)
- awacs_reg[0] |= MASK_MUX_CD;
- awacs_write(MASK_ADDR0 | awacs_reg[0]);
-}
-
-static void do_rec_lev(int data)
-{
- int left, right ;
- rec_lev = data ;
- /* need to fudge this to use the volume setter routine */
- left = 100 - (data & 0xff) ; if( left < 0 ) left = 0 ;
- right = 100 - ((data >> 8) & 0xff) ; if( right < 0 ) right = 0 ;
- left |= (right << 8 );
- left = awacs_volume_setter(left, 0, 0, 4);
-}
-
-static void do_passthru_vol(int data)
-{
- passthru_vol = data ;
- awacs_reg[1] &= ~MASK_LOOPTHRU;
- if (awacs_revision == AWACS_SCREAMER) {
- if( data ) { /* switch it on for non-zero */
- awacs_reg[1] |= MASK_LOOPTHRU;
- awacs_write(MASK_ADDR1 | awacs_reg[1]);
- }
- data = awacs_volume_setter(data, 5, 0, 6) ;
- } else {
- if ((data & 0xff) >= 50)
- awacs_reg[1] |= MASK_LOOPTHRU;
- awacs_write(MASK_ADDR1 | awacs_reg[1]);
- data = (awacs_reg[1] & MASK_LOOPTHRU)? 100: 0;
- }
-}
-
-static int awacs_mixer_ioctl(u_int cmd, u_long arg)
-{
- int data;
- int rc;
-
- switch (cmd) {
- case SOUND_MIXER_READ_CAPS:
- /* say we will allow multiple inputs? prob. wrong
- so I'm switching it to single */
- return IOCTL_OUT(arg, 1);
- case SOUND_MIXER_READ_DEVMASK:
- data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
- | SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD
- | SOUND_MASK_IGAIN | SOUND_MASK_RECLEV
- | SOUND_MASK_ALTPCM
- | SOUND_MASK_MONITOR;
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_READ_RECMASK:
- data = SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD;
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_READ_RECSRC:
- data = 0;
- if (awacs_reg[0] & MASK_MUX_AUDIN)
- data |= SOUND_MASK_LINE;
- if (awacs_reg[0] & MASK_MUX_MIC)
- data |= SOUND_MASK_MIC;
- if (awacs_reg[0] & MASK_MUX_CD)
- data |= SOUND_MASK_CD;
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_WRITE_RECSRC:
- IOCTL_IN(arg, data);
- data &= (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD);
- awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC
- | MASK_MUX_AUDIN);
- if (data & SOUND_MASK_LINE)
- awacs_reg[0] |= MASK_MUX_AUDIN;
- if (data & SOUND_MASK_MIC)
- awacs_reg[0] |= MASK_MUX_MIC;
- if (data & SOUND_MASK_CD)
- awacs_reg[0] |= MASK_MUX_CD;
- awacs_write(awacs_reg[0] | MASK_ADDR0);
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_READ_STEREODEVS:
- data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER| SOUND_MASK_RECLEV ;
- if (awacs_revision == AWACS_SCREAMER)
- data |= SOUND_MASK_MONITOR ;
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_WRITE_VOLUME:
- IOCTL_IN(arg, data);
- line_vol = data ;
- awacs_volume_setter(data, 2, 0, 6);
- /* fall through */
- case SOUND_MIXER_READ_VOLUME:
- rc = IOCTL_OUT(arg, line_vol);
- break;
- case SOUND_MIXER_WRITE_SPEAKER:
- IOCTL_IN(arg, data);
- spk_vol = data ;
- if (has_perch)
- awacs_enable_amp(data);
- else
- (void)awacs_volume_setter(data, 4, MASK_CMUTE, 6);
- /* fall though */
- case SOUND_MIXER_READ_SPEAKER:
- rc = IOCTL_OUT(arg, spk_vol);
- break;
- case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */
- IOCTL_IN(arg, data);
- beep_vol = data & 0xff;
- /* fall through */
- case SOUND_MIXER_READ_ALTPCM:
- rc = IOCTL_OUT(arg, beep_vol);
- break;
- case SOUND_MIXER_WRITE_LINE:
- IOCTL_IN(arg, data);
- do_line_lev(data) ;
- /* fall through */
- case SOUND_MIXER_READ_LINE:
- rc = IOCTL_OUT(arg, line_lev);
- break;
- case SOUND_MIXER_WRITE_IGAIN:
- IOCTL_IN(arg, data);
- do_ip_gain(data) ;
- /* fall through */
- case SOUND_MIXER_READ_IGAIN:
- rc = IOCTL_OUT(arg, ip_gain);
- break;
- case SOUND_MIXER_WRITE_MIC:
- IOCTL_IN(arg, data);
- do_mic_lev(data);
- /* fall through */
- case SOUND_MIXER_READ_MIC:
- rc = IOCTL_OUT(arg, mic_lev);
- break;
- case SOUND_MIXER_WRITE_CD:
- IOCTL_IN(arg, data);
- do_cd_lev(data);
- /* fall through */
- case SOUND_MIXER_READ_CD:
- rc = IOCTL_OUT(arg, cd_lev);
- break;
- case SOUND_MIXER_WRITE_RECLEV:
- IOCTL_IN(arg, data);
- do_rec_lev(data) ;
- /* fall through */
- case SOUND_MIXER_READ_RECLEV:
- rc = IOCTL_OUT(arg, rec_lev);
- break;
- case MIXER_WRITE(SOUND_MIXER_MONITOR):
- IOCTL_IN(arg, data);
- do_passthru_vol(data) ;
- /* fall through */
- case MIXER_READ(SOUND_MIXER_MONITOR):
- rc = IOCTL_OUT(arg, passthru_vol);
- break;
- default:
- rc = -EINVAL;
- }
-
- return rc;
-}
-
-static void awacs_mixer_init(void)
-{
- awacs_volume_setter(line_vol, 2, 0, 6);
- if (has_perch)
- awacs_enable_amp(spk_vol);
- else
- (void)awacs_volume_setter(spk_vol, 4, MASK_CMUTE, 6);
- do_line_lev(line_lev) ;
- do_ip_gain(ip_gain) ;
- do_mic_lev(mic_lev) ;
- do_cd_lev(cd_lev) ;
- do_rec_lev(rec_lev) ;
- do_passthru_vol(passthru_vol) ;
-}
-
-static int burgundy_mixer_ioctl(u_int cmd, u_long arg)
-{
- int data;
- int rc;
-
- /* We are, we are, we are... Burgundy or better */
- switch(cmd) {
- case SOUND_MIXER_READ_DEVMASK:
- data = SOUND_MASK_VOLUME | SOUND_MASK_CD |
- SOUND_MASK_LINE | SOUND_MASK_MIC |
- SOUND_MASK_SPEAKER | SOUND_MASK_ALTPCM;
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_READ_RECMASK:
- data = SOUND_MASK_LINE | SOUND_MASK_MIC
- | SOUND_MASK_CD;
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_READ_RECSRC:
- data = 0;
- if (awacs_reg[0] & MASK_MUX_AUDIN)
- data |= SOUND_MASK_LINE;
- if (awacs_reg[0] & MASK_MUX_MIC)
- data |= SOUND_MASK_MIC;
- if (awacs_reg[0] & MASK_MUX_CD)
- data |= SOUND_MASK_CD;
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_WRITE_RECSRC:
- IOCTL_IN(arg, data);
- data &= (SOUND_MASK_LINE
- | SOUND_MASK_MIC | SOUND_MASK_CD);
- awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC
- | MASK_MUX_AUDIN);
- if (data & SOUND_MASK_LINE)
- awacs_reg[0] |= MASK_MUX_AUDIN;
- if (data & SOUND_MASK_MIC)
- awacs_reg[0] |= MASK_MUX_MIC;
- if (data & SOUND_MASK_CD)
- awacs_reg[0] |= MASK_MUX_CD;
- awacs_write(awacs_reg[0] | MASK_ADDR0);
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_READ_STEREODEVS:
- data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
- | SOUND_MASK_RECLEV | SOUND_MASK_CD
- | SOUND_MASK_LINE;
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_READ_CAPS:
- rc = IOCTL_OUT(arg, 0);
- break;
- case SOUND_MIXER_WRITE_VOLUME:
- IOCTL_IN(arg, data);
- awacs_burgundy_write_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME, data);
- /* Fall through */
- case SOUND_MIXER_READ_VOLUME:
- rc = IOCTL_OUT(arg, awacs_burgundy_read_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME));
- break;
- case SOUND_MIXER_WRITE_SPEAKER:
- IOCTL_IN(arg, data);
- if (!(data & 0xff)) {
- /* Mute the left speaker */
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
- awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x2);
- } else {
- /* Unmute the left speaker */
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
- awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x2);
- }
- if (!(data & 0xff00)) {
- /* Mute the right speaker */
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
- awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x4);
- } else {
- /* Unmute the right speaker */
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
- awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x4);
- }
-
- data = (((data&0xff)*16)/100 > 0xf ? 0xf :
- (((data&0xff)*16)/100)) +
- ((((data>>8)*16)/100 > 0xf ? 0xf :
- ((((data>>8)*16)/100)))<<4);
-
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER, ~data);
- /* Fall through */
- case SOUND_MIXER_READ_SPEAKER:
- data = awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER);
- data = (((data & 0xf)*100)/16) + ((((data>>4)*100)/16)<<8);
- rc = IOCTL_OUT(arg, (~data) & 0x0000ffff);
- break;
- case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */
- IOCTL_IN(arg, data);
- beep_vol = data & 0xff;
- /* fall through */
- case SOUND_MIXER_READ_ALTPCM:
- rc = IOCTL_OUT(arg, beep_vol);
- break;
- case SOUND_MIXER_WRITE_LINE:
- IOCTL_IN(arg, data);
- awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLLINE, data);
-
- /* fall through */
- case SOUND_MIXER_READ_LINE:
- data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLLINE);
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_WRITE_MIC:
- IOCTL_IN(arg, data);
- /* Mic is mono device */
- data = (data << 8) + (data << 24);
- awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLMIC, data);
- /* fall through */
- case SOUND_MIXER_READ_MIC:
- data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLMIC);
- data <<= 24;
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_WRITE_CD:
- IOCTL_IN(arg, data);
- awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLCD, data);
- /* fall through */
- case SOUND_MIXER_READ_CD:
- data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLCD);
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_WRITE_RECLEV:
- IOCTL_IN(arg, data);
- data = awacs_volume_setter(data, 0, 0, 4);
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_READ_RECLEV:
- data = awacs_get_volume(awacs_reg[0], 4);
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_OUTMASK:
- case SOUND_MIXER_OUTSRC:
- default:
- rc = -EINVAL;
- }
-
- return rc;
-}
-
-static int daca_mixer_ioctl(u_int cmd, u_long arg)
-{
- int data;
- int rc;
-
- /* And the DACA's no genius either! */
-
- switch(cmd) {
- case SOUND_MIXER_READ_DEVMASK:
- data = SOUND_MASK_VOLUME;
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_READ_RECMASK:
- data = 0;
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_READ_RECSRC:
- data = 0;
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_WRITE_RECSRC:
- IOCTL_IN(arg, data);
- data =0;
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_READ_STEREODEVS:
- data = SOUND_MASK_VOLUME;
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_READ_CAPS:
- rc = IOCTL_OUT(arg, 0);
- break;
- case SOUND_MIXER_WRITE_VOLUME:
- IOCTL_IN(arg, data);
- daca_set_volume(data, data);
- /* Fall through */
- case SOUND_MIXER_READ_VOLUME:
- daca_get_volume(& data, &data);
- rc = IOCTL_OUT(arg, data);
- break;
- case SOUND_MIXER_OUTMASK:
- case SOUND_MIXER_OUTSRC:
- default:
- rc = -EINVAL;
- }
- return rc;
-}
-
-static int PMacMixerIoctl(u_int cmd, u_long arg)
-{
- int rc;
-
- /* Different IOCTLS for burgundy and, eventually, DACA & Tumbler */
-
- TRY_LOCK();
-
- switch (awacs_revision){
- case AWACS_BURGUNDY:
- rc = burgundy_mixer_ioctl(cmd, arg);
- break ;
- case AWACS_DACA:
- rc = daca_mixer_ioctl(cmd, arg);
- break;
- case AWACS_TUMBLER:
- case AWACS_SNAPPER:
- rc = tas_mixer_ioctl(cmd, arg);
- break ;
- default: /* ;-)) */
- rc = awacs_mixer_ioctl(cmd, arg);
- }
-
- UNLOCK();
-
- return rc;
-}
-
-static void PMacMixerInit(void)
-{
- switch (awacs_revision) {
- case AWACS_TUMBLER:
- printk("AE-Init tumbler mixer\n");
- break ;
- case AWACS_SNAPPER:
- printk("AE-Init snapper mixer\n");
- break ;
- case AWACS_DACA:
- case AWACS_BURGUNDY:
- break ; /* don't know yet */
- case AWACS_AWACS:
- case AWACS_SCREAMER:
- default:
- awacs_mixer_init() ;
- break ;
- }
-}
-
-/* Write/Read sq setup functions:
- Check to see if we have enough (or any) dbdma cmd buffers for the
- user's fragment settings. If not, allocate some. If this fails we will
- point at the beep buffer - as an emergency provision - to stop dma tromping
- on some random bit of memory (if someone lets it go anyway).
- The command buffers are then set up to point to the fragment buffers
- (allocated elsewhere). We need n+1 commands the last of which holds
- a NOP + loop to start.
-*/
-
-static int PMacWriteSqSetup(void)
-{
- int i, count = 600 ;
- volatile struct dbdma_cmd *cp;
-
- LOCK();
-
- /* stop the controller from doing any output - if it isn't already.
- it _should_ be before this is called anyway */
-
- out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
- while ((in_le32(&awacs_txdma->status) & RUN) && count--)
- udelay(1);
-#ifdef DEBUG_DMASOUND
-if (count <= 0)
- printk("dmasound_pmac: write sq setup: timeout waiting for dma to stop\n");
-#endif
-
- if ((write_sq.max_count + 1) > number_of_tx_cmd_buffers) {
- kfree(awacs_tx_cmd_space);
- number_of_tx_cmd_buffers = 0;
-
- /* we need nbufs + 1 (for the loop) and we should request + 1
- again because the DBDMA_ALIGN might pull the start up by up
- to sizeof(struct dbdma_cmd) - 4.
- */
-
- awacs_tx_cmd_space = kmalloc
- ((write_sq.max_count + 1 + 1) * sizeof(struct dbdma_cmd),
- GFP_KERNEL);
- if (awacs_tx_cmd_space == NULL) {
- /* don't leave it dangling - nasty but better than a
- random address */
- out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
- printk(KERN_ERR
- "dmasound_pmac: can't allocate dbdma cmd buffers"
- ", driver disabled\n");
- UNLOCK();
- return -ENOMEM;
- }
- awacs_tx_cmds = (volatile struct dbdma_cmd *)
- DBDMA_ALIGN(awacs_tx_cmd_space);
- number_of_tx_cmd_buffers = write_sq.max_count + 1;
- }
-
- cp = awacs_tx_cmds;
- memset((void *)cp, 0, (write_sq.max_count+1) * sizeof(struct dbdma_cmd));
- for (i = 0; i < write_sq.max_count; ++i, ++cp) {
- st_le32(&cp->phy_addr, virt_to_bus(write_sq.buffers[i]));
- }
- st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
- st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds));
- /* point the controller at the command stack - ready to go */
- out_le32(&awacs_txdma->cmdptr, virt_to_bus(awacs_tx_cmds));
- UNLOCK();
- return 0;
-}
-
-static int PMacReadSqSetup(void)
-{
- int i, count = 600;
- volatile struct dbdma_cmd *cp;
-
- LOCK();
-
- /* stop the controller from doing any input - if it isn't already.
- it _should_ be before this is called anyway */
-
- out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
- while ((in_le32(&awacs_rxdma->status) & RUN) && count--)
- udelay(1);
-#ifdef DEBUG_DMASOUND
-if (count <= 0)
- printk("dmasound_pmac: read sq setup: timeout waiting for dma to stop\n");
-#endif
-
- if ((read_sq.max_count+1) > number_of_rx_cmd_buffers ) {
- kfree(awacs_rx_cmd_space);
- number_of_rx_cmd_buffers = 0;
-
- /* we need nbufs + 1 (for the loop) and we should request + 1 again
- because the DBDMA_ALIGN might pull the start up by up to
- sizeof(struct dbdma_cmd) - 4 (assuming kmalloc aligns 32 bits).
- */
-
- awacs_rx_cmd_space = kmalloc
- ((read_sq.max_count + 1 + 1) * sizeof(struct dbdma_cmd),
- GFP_KERNEL);
- if (awacs_rx_cmd_space == NULL) {
- /* don't leave it dangling - nasty but better than a
- random address */
- out_le32(&awacs_rxdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
- printk(KERN_ERR
- "dmasound_pmac: can't allocate dbdma cmd buffers"
- ", driver disabled\n");
- UNLOCK();
- return -ENOMEM;
- }
- awacs_rx_cmds = (volatile struct dbdma_cmd *)
- DBDMA_ALIGN(awacs_rx_cmd_space);
- number_of_rx_cmd_buffers = read_sq.max_count + 1 ;
- }
- cp = awacs_rx_cmds;
- memset((void *)cp, 0, (read_sq.max_count+1) * sizeof(struct dbdma_cmd));
-
- /* Set dma buffers up in a loop */
- for (i = 0; i < read_sq.max_count; i++,cp++) {
- st_le32(&cp->phy_addr, virt_to_bus(read_sq.buffers[i]));
- st_le16(&cp->command, INPUT_MORE + INTR_ALWAYS);
- st_le16(&cp->req_count, read_sq.block_size);
- st_le16(&cp->xfer_status, 0);
- }
-
- /* The next two lines make the thing loop around.
- */
- st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
- st_le32(&cp->cmd_dep, virt_to_bus(awacs_rx_cmds));
- /* point the controller at the command stack - ready to go */
- out_le32(&awacs_rxdma->cmdptr, virt_to_bus(awacs_rx_cmds));
-
- UNLOCK();
- return 0;
-}
-
-/* TODO: this needs work to guarantee that when it returns DMA has stopped
- but in a more elegant way than is done here....
-*/
-
-static void PMacAbortRead(void)
-{
- int i;
- volatile struct dbdma_cmd *cp;
-
- LOCK();
- /* give it a chance to update the output and provide the IRQ
- that is expected.
- */
-
- out_le32(&awacs_rxdma->control, ((FLUSH) << 16) + FLUSH );
-
- cp = awacs_rx_cmds;
- for (i = 0; i < read_sq.max_count; i++,cp++)
- st_le16(&cp->command, DBDMA_STOP);
- /*
- * We should probably wait for the thing to stop before we
- * release the memory.
- */
-
- msleep(100) ; /* give it a (small) chance to act */
-
- /* apply the sledgehammer approach - just stop it now */
-
- out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
- UNLOCK();
-}
-
-extern char *get_afmt_string(int);
-static int PMacStateInfo(char *b, size_t sp)
-{
- int i, len = 0;
- len = sprintf(b,"HW rates: ");
- switch (awacs_revision){
- case AWACS_DACA:
- case AWACS_BURGUNDY:
- len += sprintf(b,"44100 ") ;
- break ;
- case AWACS_TUMBLER:
- case AWACS_SNAPPER:
- for (i=0; i<1; i++){
- if (tas_freqs_ok[i])
- len += sprintf(b+len,"%d ", tas_freqs[i]) ;
- }
- break ;
- case AWACS_AWACS:
- case AWACS_SCREAMER:
- default:
- for (i=0; i<8; i++){
- if (awacs_freqs_ok[i])
- len += sprintf(b+len,"%d ", awacs_freqs[i]) ;
- }
- break ;
- }
- len += sprintf(b+len,"s/sec\n") ;
- if (len < sp) {
- len += sprintf(b+len,"HW AFMTS: ");
- i = AFMT_U16_BE ;
- while (i) {
- if (i & dmasound.mach.hardware_afmts)
- len += sprintf(b+len,"%s ",
- get_afmt_string(i & dmasound.mach.hardware_afmts));
- i >>= 1 ;
- }
- len += sprintf(b+len,"\n") ;
- }
- return len ;
-}
-
-/*** Machine definitions *****************************************************/
-
-static SETTINGS def_hard = {
- .format = AFMT_S16_BE,
- .stereo = 1,
- .size = 16,
- .speed = 44100
-} ;
-
-static SETTINGS def_soft = {
- .format = AFMT_S16_BE,
- .stereo = 1,
- .size = 16,
- .speed = 44100
-} ;
-
-static MACHINE machPMac = {
- .name = awacs_name,
- .name2 = "PowerMac Built-in Sound",
- .owner = THIS_MODULE,
- .dma_alloc = PMacAlloc,
- .dma_free = PMacFree,
- .irqinit = PMacIrqInit,
-#ifdef MODULE
- .irqcleanup = PMacIrqCleanup,
-#endif /* MODULE */
- .init = PMacInit,
- .silence = PMacSilence,
- .setFormat = PMacSetFormat,
- .setVolume = PMacSetVolume,
- .play = PMacPlay,
- .record = NULL, /* default to no record */
- .mixer_init = PMacMixerInit,
- .mixer_ioctl = PMacMixerIoctl,
- .write_sq_setup = PMacWriteSqSetup,
- .read_sq_setup = PMacReadSqSetup,
- .state_info = PMacStateInfo,
- .abort_read = PMacAbortRead,
- .min_dsp_speed = 7350,
- .max_dsp_speed = 44100,
- .version = ((DMASOUND_AWACS_REVISION<<8) + DMASOUND_AWACS_EDITION)
-};
-
-
-/*** Config & Setup **********************************************************/
-
-/* Check for pmac models that we care about in terms of special actions.
-*/
-
-void __init
-set_model(void)
-{
- /* portables/lap-tops */
-
- if (machine_is_compatible("AAPL,3400/2400") ||
- machine_is_compatible("AAPL,3500")) {
- is_pbook_3X00 = 1 ;
- }
- if (machine_is_compatible("PowerBook1,1") || /* lombard */
- machine_is_compatible("AAPL,PowerBook1998")){ /* wallstreet */
- is_pbook_g3 = 1 ;
- return ;
- }
-}
-
-/* Get the OF node that tells us about the registers, interrupts etc. to use
- for sound IO.
-
- On most machines the sound IO OF node is the 'davbus' node. On newer pmacs
- with DACA (& Tumbler) the node to use is i2s-a. On much older machines i.e.
- before 9500 there is no davbus node and we have to use the 'awacs' property.
-
- In the latter case we signal this by setting the codec value - so that the
- code that looks for chip properties knows how to go about it.
-*/
-
-static struct device_node* __init
-get_snd_io_node(void)
-{
- struct device_node *np;
-
- /* set up awacs_node for early OF which doesn't have a full set of
- * properties on davbus
- */
- awacs_node = of_find_node_by_name(NULL, "awacs");
- if (awacs_node)
- awacs_revision = AWACS_AWACS;
-
- /* powermac models after 9500 (other than those which use DACA or
- * Tumbler) have a node called "davbus".
- */
- np = of_find_node_by_name(NULL, "davbus");
- /*
- * if we didn't find a davbus device, try 'i2s-a' since
- * this seems to be what iBooks (& Tumbler) have.
- */
- if (np == NULL) {
- i2s_node = of_find_node_by_name(NULL, "i2s-a");
- np = of_node_get(i2s_node);
- }
-
- /* if we didn't find this - perhaps we are on an early model
- * which _only_ has an 'awacs' node
- */
- if (np == NULL && awacs_node)
- np = of_node_get(awacs_node);
-
- /* if we failed all these return null - this will cause the
- * driver to give up...
- */
- return np ;
-}
-
-/* Get the OF node that contains the info about the sound chip, inputs s-rates
- etc.
- This node does not exist (or contains much reduced info) on earlier machines
- we have to deduce the info other ways for these.
-*/
-
-static struct device_node* __init
-get_snd_info_node(struct device_node *io)
-{
- struct device_node *info;
-
- for_each_node_by_name(info, "sound")
- if (info->parent == io)
- break;
- return info;
-}
-
-/* Find out what type of codec we have.
-*/
-
-static int __init
-get_codec_type(struct device_node *info)
-{
- /* already set if pre-davbus model and info will be NULL */
- int codec = awacs_revision ;
-
- if (info) {
- /* must do awacs first to allow screamer to overide it */
- if (of_device_is_compatible(info, "awacs"))
- codec = AWACS_AWACS ;
- if (of_device_is_compatible(info, "screamer"))
- codec = AWACS_SCREAMER;
- if (of_device_is_compatible(info, "burgundy"))
- codec = AWACS_BURGUNDY ;
- if (of_device_is_compatible(info, "daca"))
- codec = AWACS_DACA;
- if (of_device_is_compatible(info, "tumbler"))
- codec = AWACS_TUMBLER;
- if (of_device_is_compatible(info, "snapper"))
- codec = AWACS_SNAPPER;
- }
- return codec ;
-}
-
-/* find out what type, if any, of expansion card we have
-*/
-static void __init
-get_expansion_type(void)
-{
- struct device_node *dn;
-
- dn = of_find_node_by_name(NULL, "perch");
- if (dn != NULL)
- has_perch = 1;
- of_node_put(dn);
-
- dn = of_find_node_by_name(NULL, "pb-ziva-pc");
- if (dn != NULL)
- has_ziva = 1;
- of_node_put(dn);
- /* need to work out how we deal with iMac SRS module */
-}
-
-/* set up frame rates.
- * I suspect that these routines don't quite go about it the right way:
- * - where there is more than one rate - I think that the first property
- * value is the number of rates.
- * TODO: check some more device trees and modify accordingly
- * Set dmasound.mach.max_dsp_rate on the basis of these routines.
-*/
-
-static void __init
-awacs_init_frame_rates(const unsigned int *prop, unsigned int l)
-{
- int i ;
- if (prop) {
- for (i=0; i<8; i++)
- awacs_freqs_ok[i] = 0 ;
- for (l /= sizeof(int); l > 0; --l) {
- unsigned int r = *prop++;
- /* Apple 'Fixed' format */
- if (r >= 0x10000)
- r >>= 16;
- for (i = 0; i < 8; ++i) {
- if (r == awacs_freqs[i]) {
- awacs_freqs_ok[i] = 1;
- break;
- }
- }
- }
- }
- /* else we assume that all the rates are available */
-}
-
-static void __init
-burgundy_init_frame_rates(const unsigned int *prop, unsigned int l)
-{
- int temp[9] ;
- int i = 0 ;
- if (prop) {
- for (l /= sizeof(int); l > 0; --l) {
- unsigned int r = *prop++;
- /* Apple 'Fixed' format */
- if (r >= 0x10000)
- r >>= 16;
- temp[i] = r ;
- i++ ; if(i>=9) i=8;
- }
- }
-#ifdef DEBUG_DMASOUND
-if (i > 1){
- int j;
- printk("dmasound_pmac: burgundy with multiple frame rates\n");
- for(j=0; j<i; j++)
- printk("%d ", temp[j]) ;
- printk("\n") ;
-}
-#endif
-}
-
-static void __init
-daca_init_frame_rates(const unsigned int *prop, unsigned int l)
-{
- int temp[9] ;
- int i = 0 ;
- if (prop) {
- for (l /= sizeof(int); l > 0; --l) {
- unsigned int r = *prop++;
- /* Apple 'Fixed' format */
- if (r >= 0x10000)
- r >>= 16;
- temp[i] = r ;
- i++ ; if(i>=9) i=8;
-
- }
- }
-#ifdef DEBUG_DMASOUND
-if (i > 1){
- int j;
- printk("dmasound_pmac: DACA with multiple frame rates\n");
- for(j=0; j<i; j++)
- printk("%d ", temp[j]) ;
- printk("\n") ;
-}
-#endif
-}
-
-static void __init
-init_frame_rates(const unsigned int *prop, unsigned int l)
-{
- switch (awacs_revision) {
- case AWACS_TUMBLER:
- case AWACS_SNAPPER:
- tas_init_frame_rates(prop, l);
- break ;
- case AWACS_DACA:
- daca_init_frame_rates(prop, l);
- break ;
- case AWACS_BURGUNDY:
- burgundy_init_frame_rates(prop, l);
- break ;
- default:
- awacs_init_frame_rates(prop, l);
- break ;
- }
-}
-
-/* find things/machines that can't do mac-io byteswap
-*/
-
-static void __init
-set_hw_byteswap(struct device_node *io)
-{
- struct device_node *mio ;
- unsigned int kl = 0 ;
-
- /* if seems that Keylargo can't byte-swap */
-
- for (mio = io->parent; mio ; mio = mio->parent) {
- if (strcmp(mio->name, "mac-io") == 0) {
- if (of_device_is_compatible(mio, "Keylargo"))
- kl = 1;
- break;
- }
- }
- hw_can_byteswap = !kl;
-}
-
-/* Allocate the resources necessary for beep generation. This cannot be (quite)
- done statically (yet) because we cannot do virt_to_bus() on static vars when
- the code is loaded as a module.
-
- for the sake of saving the possibility that two allocations will incur the
- overhead of two pull-ups in DBDMA_ALIGN() we allocate the 'emergency' dmdma
- command here as well... even tho' it is not part of the beep process.
-*/
-
-int32_t
-__init setup_beep(void)
-{
- /* Initialize beep stuff */
- /* want one cmd buffer for beeps, and a second one for emergencies
- - i.e. dbdma error conditions.
- ask for three to allow for pull up in DBDMA_ALIGN().
- */
- beep_dbdma_cmd_space =
- kmalloc((2 + 1) * sizeof(struct dbdma_cmd), GFP_KERNEL);
- if(beep_dbdma_cmd_space == NULL) {
- printk(KERN_ERR "dmasound_pmac: no beep dbdma cmd space\n") ;
- return -ENOMEM ;
- }
- beep_dbdma_cmd = (volatile struct dbdma_cmd *)
- DBDMA_ALIGN(beep_dbdma_cmd_space);
- /* set up emergency dbdma cmd */
- emergency_dbdma_cmd = beep_dbdma_cmd+1 ;
- beep_buf = kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
- if (beep_buf == NULL) {
- printk(KERN_ERR "dmasound_pmac: no memory for beep buffer\n");
- kfree(beep_dbdma_cmd_space) ;
- return -ENOMEM ;
- }
- return 0 ;
-}
-
-static struct input_dev *awacs_beep_dev;
-
-int __init dmasound_awacs_init(void)
-{
- struct device_node *io = NULL, *info = NULL;
- int vol, res;
-
- if (!machine_is(powermac))
- return -ENODEV;
-
- awacs_subframe = 0;
- awacs_revision = 0;
- hw_can_byteswap = 1 ; /* most can */
-
- /* look for models we need to handle specially */
- set_model() ;
-
- /* find the OF node that tells us about the dbdma stuff
- */
- io = get_snd_io_node();
- if (io == NULL) {
-#ifdef DEBUG_DMASOUND
-printk("dmasound_pmac: couldn't find sound io OF node\n");
-#endif
- goto no_device;
- }
-
- /* find the OF node that tells us about the sound sub-system
- * this doesn't exist on pre-davbus machines (earlier than 9500)
- */
- if (awacs_revision != AWACS_AWACS) { /* set for pre-davbus */
- info = get_snd_info_node(io) ;
- if (info == NULL){
-#ifdef DEBUG_DMASOUND
-printk("dmasound_pmac: couldn't find 'sound' OF node\n");
-#endif
- goto no_device;
- }
- }
-
- awacs_revision = get_codec_type(info) ;
- if (awacs_revision == 0) {
-#ifdef DEBUG_DMASOUND
-printk("dmasound_pmac: couldn't find a Codec we can handle\n");
-#endif
- goto no_device; /* we don't know this type of h/w */
- }
-
- /* set up perch, ziva, SRS or whatever else we have as sound
- * expansion.
- */
- get_expansion_type();
-
- /* we've now got enough information to make up the audio topology.
- * we will map the sound part of mac-io now so that we can probe for
- * other info if necessary (early AWACS we want to read chip ids)
- */
-
- if (of_get_address(io, 2, NULL, NULL) == NULL) {
- /* OK - maybe we need to use the 'awacs' node (on earlier
- * machines).
- */
- if (awacs_node) {
- of_node_put(io);
- io = of_node_get(awacs_node);
- if (of_get_address(io, 2, NULL, NULL) == NULL) {
- printk("dmasound_pmac: can't use %s\n",
- io->full_name);
- goto no_device;
- }
- } else
- printk("dmasound_pmac: can't use %s\n", io->full_name);
- }
-
- if (of_address_to_resource(io, 0, &awacs_rsrc[0]) ||
- request_mem_region(awacs_rsrc[0].start,
- awacs_rsrc[0].end - awacs_rsrc[0].start + 1,
- " (IO)") == NULL) {
- printk(KERN_ERR "dmasound: can't request IO resource !\n");
- goto no_device;
- }
- if (of_address_to_resource(io, 1, &awacs_rsrc[1]) ||
- request_mem_region(awacs_rsrc[1].start,
- awacs_rsrc[1].end - awacs_rsrc[1].start + 1,
- " (tx dma)") == NULL) {
- release_mem_region(awacs_rsrc[0].start,
- awacs_rsrc[0].end - awacs_rsrc[0].start + 1);
- printk(KERN_ERR "dmasound: can't request Tx DMA resource !\n");
- goto no_device;
- }
- if (of_address_to_resource(io, 2, &awacs_rsrc[2]) ||
- request_mem_region(awacs_rsrc[2].start,
- awacs_rsrc[2].end - awacs_rsrc[2].start + 1,
- " (rx dma)") == NULL) {
- release_mem_region(awacs_rsrc[0].start,
- awacs_rsrc[0].end - awacs_rsrc[0].start + 1);
- release_mem_region(awacs_rsrc[1].start,
- awacs_rsrc[1].end - awacs_rsrc[1].start + 1);
- printk(KERN_ERR "dmasound: can't request Rx DMA resource !\n");
- goto no_device;
- }
-
- awacs_beep_dev = input_allocate_device();
- if (!awacs_beep_dev) {
- release_mem_region(awacs_rsrc[0].start,
- awacs_rsrc[0].end - awacs_rsrc[0].start + 1);
- release_mem_region(awacs_rsrc[1].start,
- awacs_rsrc[1].end - awacs_rsrc[1].start + 1);
- release_mem_region(awacs_rsrc[2].start,
- awacs_rsrc[2].end - awacs_rsrc[2].start + 1);
- printk(KERN_ERR "dmasound: can't allocate input device !\n");
- goto no_device;
- }
-
- awacs_beep_dev->name = "dmasound beeper";
- awacs_beep_dev->phys = "macio/input0";
- awacs_beep_dev->id.bustype = BUS_HOST;
- awacs_beep_dev->event = awacs_beep_event;
- awacs_beep_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
- awacs_beep_dev->evbit[0] = BIT(EV_SND);
-
- /* all OF versions I've seen use this value */
- if (i2s_node)
- i2s = ioremap(awacs_rsrc[0].start, 0x1000);
- else
- awacs = ioremap(awacs_rsrc[0].start, 0x1000);
- awacs_txdma = ioremap(awacs_rsrc[1].start, 0x100);
- awacs_rxdma = ioremap(awacs_rsrc[2].start, 0x100);
-
- /* first of all make sure that the chip is powered up....*/
- pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, io, 0, 1);
- if (awacs_revision == AWACS_SCREAMER && awacs)
- awacs_recalibrate();
-
- awacs_irq = irq_of_parse_and_map(io, 0);
- awacs_tx_irq = irq_of_parse_and_map(io, 1);
- awacs_rx_irq = irq_of_parse_and_map(io, 2);
-
- /* Hack for legacy crap that will be killed someday */
- of_node_put(awacs_node);
- awacs_node = of_node_get(io);
-
- /* if we have an awacs or screamer - probe the chip to make
- * sure we have the right revision.
- */
-
- if (awacs_revision <= AWACS_SCREAMER){
- uint32_t temp, rev, mfg ;
- /* find out the awacs revision from the chip */
- temp = in_le32(&awacs->codec_stat);
- rev = (temp >> 12) & 0xf;
- mfg = (temp >> 8) & 0xf;
-#ifdef DEBUG_DMASOUND
-printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev);
-#endif
- if (rev >= AWACS_SCREAMER)
- awacs_revision = AWACS_SCREAMER ;
- else
- awacs_revision = rev ;
- }
-
- dmasound.mach = machPMac;
-
- /* find out other bits & pieces from OF, these may be present
- only on some models ... so be careful.
- */
-
- /* in the absence of a frame rates property we will use the defaults
- */
-
- if (info) {
- const unsigned int *prop;
- unsigned int l;
-
- sound_device_id = 0;
- /* device ID appears post g3 b&w */
- prop = of_get_property(info, "device-id", NULL);
- if (prop != 0)
- sound_device_id = *prop;
-
- /* look for a property saying what sample rates
- are available */
-
- prop = of_get_property(info, "sample-rates", &l);
- if (prop == 0)
- prop = of_get_property(info, "output-frame-rates", &l);
-
- /* if it's there use it to set up frame rates */
- init_frame_rates(prop, l) ;
- of_node_put(info);
- info = NULL;
- }
-
- if (awacs)
- out_le32(&awacs->control, 0x11); /* set everything quiesent */
-
- set_hw_byteswap(io) ; /* figure out if the h/w can do it */
-
-#ifdef CONFIG_NVRAM
- /* get default volume from nvram */
- vol = ((pmac_xpram_read( 8 ) & 7 ) << 1 );
-#else
- vol = 0;
-#endif
-
- /* set up tracking values */
- spk_vol = vol * 100 ;
- spk_vol /= 7 ; /* get set value to a percentage */
- spk_vol |= (spk_vol << 8) ; /* equal left & right */
- line_vol = passthru_vol = spk_vol ;
-
- /* fill regs that are shared between AWACS & Burgundy */
-
- awacs_reg[2] = vol + (vol << 6);
- awacs_reg[4] = vol + (vol << 6);
- awacs_reg[5] = vol + (vol << 6); /* screamer has loopthru vol control */
- awacs_reg[6] = 0; /* maybe should be vol << 3 for PCMCIA speaker */
- awacs_reg[7] = 0;
-
- awacs_reg[0] = MASK_MUX_CD;
- awacs_reg[1] = MASK_LOOPTHRU;
-
- /* FIXME: Only machines with external SRS module need MASK_PAROUT */
- if (has_perch || sound_device_id == 0x5
- || /*sound_device_id == 0x8 ||*/ sound_device_id == 0xb)
- awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1;
-
- switch (awacs_revision) {
- case AWACS_TUMBLER:
- tas_register_driver(&tas3001c_hooks);
- tas_init(I2C_DRIVERID_TAS3001C, I2C_DRIVERNAME_TAS3001C);
- tas_dmasound_init();
- tas_post_init();
- break ;
- case AWACS_SNAPPER:
- tas_register_driver(&tas3004_hooks);
- tas_init(I2C_DRIVERID_TAS3004,I2C_DRIVERNAME_TAS3004);
- tas_dmasound_init();
- tas_post_init();
- break;
- case AWACS_DACA:
- daca_init();
- break;
- case AWACS_BURGUNDY:
- awacs_burgundy_init();
- break ;
- case AWACS_SCREAMER:
- case AWACS_AWACS:
- default:
- load_awacs();
- break ;
- }
-
- /* enable/set-up external modules - when we know how */
-
- if (has_perch)
- awacs_enable_amp(100 * 0x101);
-
- /* Reset dbdma channels */
- out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16);
- while (in_le32(&awacs_txdma->status) & RUN)
- udelay(1);
- out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16);
- while (in_le32(&awacs_rxdma->status) & RUN)
- udelay(1);
-
- /* Initialize beep stuff */
- if ((res=setup_beep()))
- return res ;
-
-#ifdef CONFIG_PM
- pmu_register_sleep_notifier(&awacs_sleep_notifier);
-#endif /* CONFIG_PM */
-
- /* Powerbooks have odd ways of enabling inputs such as
- an expansion-bay CD or sound from an internal modem
- or a PC-card modem. */
- if (is_pbook_3X00) {
- /*
- * Enable CD and PC-card sound inputs.
- * This is done by reading from address
- * f301a000, + 0x10 to enable the expansion-bay
- * CD sound input, + 0x80 to enable the PC-card
- * sound input. The 0x100 enables the SCSI bus
- * terminator power.
- */
- latch_base = ioremap (0xf301a000, 0x1000);
- in_8(latch_base + 0x190);
-
- } else if (is_pbook_g3) {
- struct device_node* mio;
- macio_base = NULL;
- for (mio = io->parent; mio; mio = mio->parent) {
- if (strcmp(mio->name, "mac-io") == 0) {
- struct resource r;
- if (of_address_to_resource(mio, 0, &r) == 0)
- macio_base = ioremap(r.start, 0x40);
- break;
- }
- }
- /*
- * Enable CD sound input.
- * The relevant bits for writing to this byte are 0x8f.
- * I haven't found out what the 0x80 bit does.
- * For the 0xf bits, writing 3 or 7 enables the CD
- * input, any other value disables it. Values
- * 1, 3, 5, 7 enable the microphone. Values 0, 2,
- * 4, 6, 8 - f enable the input from the modem.
- * -- paulus.
- */
- if (macio_base)
- out_8(macio_base + 0x37, 3);
- }
-
- if (hw_can_byteswap)
- dmasound.mach.hardware_afmts = (AFMT_S16_BE | AFMT_S16_LE) ;
- else
- dmasound.mach.hardware_afmts = AFMT_S16_BE ;
-
- /* shut out chips that do output only.
- * may need to extend this to machines which have no inputs - even tho'
- * they use screamer - IIRC one of the powerbooks is like this.
- */
-
- if (awacs_revision != AWACS_DACA) {
- dmasound.mach.capabilities = DSP_CAP_DUPLEX ;
- dmasound.mach.record = PMacRecord ;
- }
-
- dmasound.mach.default_hard = def_hard ;
- dmasound.mach.default_soft = def_soft ;
-
- switch (awacs_revision) {
- case AWACS_BURGUNDY:
- sprintf(awacs_name, "PowerMac Burgundy ") ;
- break ;
- case AWACS_DACA:
- sprintf(awacs_name, "PowerMac DACA ") ;
- break ;
- case AWACS_TUMBLER:
- sprintf(awacs_name, "PowerMac Tumbler ") ;
- break ;
- case AWACS_SNAPPER:
- sprintf(awacs_name, "PowerMac Snapper ") ;
- break ;
- case AWACS_SCREAMER:
- sprintf(awacs_name, "PowerMac Screamer ") ;
- break ;
- case AWACS_AWACS:
- default:
- sprintf(awacs_name, "PowerMac AWACS rev %d ", awacs_revision) ;
- break ;
- }
-
- /*
- * XXX: we should handle errors here, but that would mean
- * rewriting the whole init code. later..
- */
- input_register_device(awacs_beep_dev);
-
- of_node_put(io);
-
- return dmasound_init();
-
-no_device:
- of_node_put(info);
- of_node_put(awacs_node);
- of_node_put(i2s_node);
- of_node_put(io);
- return -ENODEV ;
-}
-
-static void __exit dmasound_awacs_cleanup(void)
-{
- input_unregister_device(awacs_beep_dev);
-
- switch (awacs_revision) {
- case AWACS_TUMBLER:
- case AWACS_SNAPPER:
- tas_dmasound_cleanup();
- tas_cleanup();
- break ;
- case AWACS_DACA:
- daca_cleanup();
- break;
- }
- dmasound_deinit();
-
- of_node_put(awacs_node);
- of_node_put(i2s_node);
-}
-
-MODULE_DESCRIPTION("PowerMac built-in audio driver.");
-MODULE_LICENSE("GPL");
-
-module_init(dmasound_awacs_init);
-module_exit(dmasound_awacs_cleanup);
diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c
index f4056a9c371..f4ee85a4c42 100644
--- a/sound/oss/dmasound/dmasound_core.c
+++ b/sound/oss/dmasound/dmasound_core.c
@@ -181,7 +181,7 @@
#include <linux/init.h>
#include <linux/soundcard.h>
#include <linux/poll.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
@@ -194,6 +194,7 @@
* Declarations
*/
+static DEFINE_MUTEX(dmasound_core_mutex);
int dmasound_catchRadius = 0;
module_param(dmasound_catchRadius, int, 0);
@@ -202,13 +203,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
@@ -218,19 +212,17 @@ static int state_unit = -1;
static int irq_installed;
#endif /* MODULE */
-/* software implemented recording volume! */
-uint software_input_volume = SW_INPUT_VOLUME_SCALE * SW_INPUT_VOLUME_DEFAULT;
-EXPORT_SYMBOL(software_input_volume);
-
/* control over who can modify resources shared between play/record */
-static mode_t shared_resource_owner;
+static fmode_t shared_resource_owner;
static int shared_resources_initialised;
/*
* Mid level stuff
*/
-struct sound_settings dmasound = { .lock = SPIN_LOCK_UNLOCKED };
+struct sound_settings dmasound = {
+ .lock = __SPIN_LOCK_UNLOCKED(dmasound.lock)
+};
static inline void sound_silence(void)
{
@@ -332,22 +324,26 @@ static struct {
static int mixer_open(struct inode *inode, struct file *file)
{
- if (!try_module_get(dmasound.mach.owner))
+ mutex_lock(&dmasound_core_mutex);
+ if (!try_module_get(dmasound.mach.owner)) {
+ mutex_unlock(&dmasound_core_mutex);
return -ENODEV;
+ }
mixer.busy = 1;
+ mutex_unlock(&dmasound_core_mutex);
return 0;
}
static int mixer_release(struct inode *inode, struct file *file)
{
- lock_kernel();
+ mutex_lock(&dmasound_core_mutex);
mixer.busy = 0;
module_put(dmasound.mach.owner);
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return 0;
}
-static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg)
+
+static int mixer_ioctl(struct file *file, u_int cmd, u_long arg)
{
if (_SIOC_DIR(cmd) & _SIOC_WRITE)
mixer.modify_counter++;
@@ -371,11 +367,22 @@ static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
return -EINVAL;
}
+static long mixer_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
+{
+ int ret;
+
+ mutex_lock(&dmasound_core_mutex);
+ ret = mixer_ioctl(file, cmd, arg);
+ mutex_unlock(&dmasound_core_mutex);
+
+ return ret;
+}
+
static const struct file_operations mixer_fops =
{
.owner = THIS_MODULE,
.llseek = no_llseek,
- .ioctl = mixer_ioctl,
+ .unlocked_ioctl = mixer_unlocked_ioctl,
.open = mixer_open,
.release = mixer_release,
};
@@ -403,10 +410,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 +533,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 ;
@@ -622,15 +619,27 @@ static ssize_t sq_write(struct file *file, const char __user *src, size_t uLeft,
}
while (uLeft) {
+ DEFINE_WAIT(wait);
+
while (write_sq.count >= write_sq.max_active) {
+ prepare_to_wait(&write_sq.action_queue, &wait, TASK_INTERRUPTIBLE);
sq_play();
- if (write_sq.open_mode & O_NONBLOCK)
+ if (write_sq.non_blocking) {
+ finish_wait(&write_sq.action_queue, &wait);
return uWritten > 0 ? uWritten : -EAGAIN;
- SLEEP(write_sq.action_queue);
- if (signal_pending(current))
+ }
+ if (write_sq.count < write_sq.max_active)
+ break;
+
+ schedule_timeout(HZ);
+ if (signal_pending(current)) {
+ finish_wait(&write_sq.action_queue, &wait);
return uWritten > 0 ? uWritten : -EINTR;
+ }
}
+ finish_wait(&write_sq.action_queue, &wait);
+
/* Here, we can avoid disabling the interrupt by first
* copying and translating the data, and then updating
* the write_sq variables. Until this is done, the interrupt
@@ -672,13 +681,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 +688,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);
@@ -791,7 +698,7 @@ static inline void sq_init_waitqueue(struct sound_queue *sq)
#if 0 /* blocking open() */
static inline void sq_wake_up(struct sound_queue *sq, struct file *file,
- mode_t mode)
+ fmode_t mode)
{
if (file->f_mode & mode) {
sq->busy = 0; /* CHECK: IS THIS OK??? */
@@ -800,7 +707,7 @@ static inline void sq_wake_up(struct sound_queue *sq, struct file *file,
}
#endif
-static int sq_open2(struct sound_queue *sq, struct file *file, mode_t mode,
+static int sq_open2(struct sound_queue *sq, struct file *file, fmode_t mode,
int numbufs, int bufsize)
{
int rc = 0;
@@ -812,11 +719,8 @@ static int sq_open2(struct sound_queue *sq, struct file *file, mode_t mode,
if (file->f_flags & O_NONBLOCK)
return rc;
rc = -EINTR;
- while (sq->busy) {
- SLEEP(sq->open_queue);
- if (signal_pending(current))
- return rc;
- }
+ if (wait_event_interruptible(sq->open_queue, !sq->busy))
+ return rc;
rc = 0;
#else
/* OSS manual says we will return EBUSY regardless
@@ -841,7 +745,7 @@ static int sq_open2(struct sound_queue *sq, struct file *file, mode_t mode,
return rc;
}
- sq->open_mode = file->f_mode;
+ sq->non_blocking = file->f_flags & O_NONBLOCK;
}
return rc;
}
@@ -854,52 +758,24 @@ 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;
- if (!try_module_get(dmasound.mach.owner))
+ mutex_lock(&dmasound_core_mutex);
+ if (!try_module_get(dmasound.mach.owner)) {
+ mutex_unlock(&dmasound_core_mutex);
return -ENODEV;
+ }
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);
@@ -933,10 +809,11 @@ static int sq_open(struct inode *inode, struct file *file)
sound_set_format(AFMT_MU_LAW);
}
#endif
-
+ mutex_unlock(&dmasound_core_mutex);
return 0;
out:
module_put(dmasound.mach.owner);
+ mutex_unlock(&dmasound_core_mutex);
return rc;
}
@@ -956,43 +833,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
*/
@@ -1001,7 +844,7 @@ static void sq_reset(void)
shared_resources_initialised = 0 ;
}
-static int sq_fsync(struct file *filp, struct dentry *dentry)
+static int sq_fsync(void)
{
int rc = 0;
int timeout = 5;
@@ -1010,7 +853,8 @@ static int sq_fsync(struct file *filp, struct dentry *dentry)
sq_play(); /* there may be an incomplete frame waiting */
while (write_sq.active) {
- SLEEP(write_sq.sync_queue);
+ wait_event_interruptible_timeout(write_sq.sync_queue,
+ !write_sq.active, HZ);
if (signal_pending(current)) {
/* While waiting for audio output to drain, an
* interrupt occurred. Stop audio output immediately
@@ -1036,22 +880,11 @@ static int sq_release(struct inode *inode, struct file *file)
{
int rc = 0;
- 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
+ mutex_lock(&dmasound_core_mutex);
if (file->f_mode & FMODE_WRITE) {
if (write_sq.busy)
- rc = sq_fsync(file, file->f_path.dentry);
+ rc = sq_fsync();
sq_reset_output() ; /* make sure dma is stopped and all is quiet */
write_sq_release_buffers();
@@ -1078,7 +911,7 @@ static int sq_release(struct inode *inode, struct file *file)
write_sq_wake_up(file); /* checks f_mode */
#endif /* blocking open() */
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return rc;
}
@@ -1090,10 +923,10 @@ static int sq_release(struct inode *inode, struct file *file)
is the owner - if we have problems.
*/
-static int shared_resources_are_mine(mode_t md)
+static int shared_resources_are_mine(fmode_t md)
{
if (shared_resource_owner)
- return (shared_resource_owner & md ) ;
+ return (shared_resource_owner & md) != 0;
else {
shared_resource_owner = md ;
return 1 ;
@@ -1105,11 +938,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 ;
@@ -1157,8 +985,7 @@ printk("dmasound_core: tried to set_queue_frags on a locked queue\n") ;
return 0 ;
}
-static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg)
+static int sq_ioctl(struct file *file, u_int cmd, u_long arg)
{
int val, result;
u_long fmt;
@@ -1185,13 +1012,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) ;
@@ -1211,13 +1031,11 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
case SNDCTL_DSP_SYNC:
/* This call, effectively, has the same behaviour as SNDCTL_DSP_RESET
except that it waits for output to finish before resetting
- everything - read, however, is killed imediately.
+ everything - read, however, is killed immediately.
*/
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);
+ result = sq_fsync();
sq_reset_output() ;
}
/* if we are the shared resource owner then release them */
@@ -1294,13 +1112,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)
@@ -1332,35 +1143,32 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
return IOCTL_OUT(arg,val);
default:
- return mixer_ioctl(inode, file, cmd, arg);
+ return mixer_ioctl(file, cmd, arg);
}
return -EINVAL;
}
-static const struct file_operations sq_fops =
+static long sq_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
{
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = sq_write,
- .poll = sq_poll,
- .ioctl = sq_ioctl,
- .open = sq_open,
- .release = sq_release,
-};
+ int ret;
+
+ mutex_lock(&dmasound_core_mutex);
+ ret = sq_ioctl(file, cmd, arg);
+ mutex_unlock(&dmasound_core_mutex);
+
+ return ret;
+}
-#ifdef HAS_RECORD
-static const struct file_operations sq_fops_record =
+static const struct file_operations sq_fops =
{
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = sq_write,
.poll = sq_poll,
- .ioctl = sq_ioctl,
+ .unlocked_ioctl = sq_unlocked_ioctl,
.open = sq_open,
.release = sq_release,
- .read = sq_read,
};
-#endif
static int sq_init(void)
{
@@ -1369,10 +1177,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 +1184,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 +1209,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>).
@@ -1427,7 +1226,7 @@ static struct {
/* publish this function for use by low-level code, if required */
-char *get_afmt_string(int afmt)
+static char *get_afmt_string(int afmt)
{
switch(afmt) {
case AFMT_MU_LAW:
@@ -1467,12 +1266,17 @@ static int state_open(struct inode *inode, struct file *file)
{
char *buffer = state.buf;
int len = 0;
+ int ret;
+ mutex_lock(&dmasound_core_mutex);
+ ret = -EBUSY;
if (state.busy)
- return -EBUSY;
+ goto out;
+ ret = -ENODEV;
if (!try_module_get(dmasound.mach.owner))
- return -ENODEV;
+ goto out;
+
state.ptr = 0;
state.busy = 1;
@@ -1518,11 +1322,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 +1330,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
@@ -1547,15 +1338,18 @@ printk("dmasound: stat buffer used %d bytes\n", len) ;
printk(KERN_ERR "dmasound_core: stat buffer overflowed!\n");
state.len = len;
- return 0;
+ ret = 0;
+out:
+ mutex_unlock(&dmasound_core_mutex);
+ return ret;
}
static int state_release(struct inode *inode, struct file *file)
{
- lock_kernel();
+ mutex_lock(&dmasound_core_mutex);
state.busy = 0;
module_put(dmasound.mach.owner);
- unlock_kernel();
+ mutex_unlock(&dmasound_core_mutex);
return 0;
}
@@ -1638,13 +1432,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 +1446,6 @@ void dmasound_deinit(void)
}
write_sq_release_buffers();
- read_sq_release_buffers();
if (mixer_unit >= 0)
unregister_sound_mixer(mixer_unit);
@@ -1684,36 +1470,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,12 +1592,8 @@ 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);
EXPORT_SYMBOL(dmasound_alaw2dma8);
#endif
-EXPORT_SYMBOL(get_afmt_string) ;
diff --git a/sound/oss/dmasound/dmasound_paula.c b/sound/oss/dmasound/dmasound_paula.c
index 90fc058e115..c2d45a5848b 100644
--- a/sound/oss/dmasound/dmasound_paula.c
+++ b/sound/oss/dmasound/dmasound_paula.c
@@ -21,6 +21,7 @@
#include <linux/ioport.h>
#include <linux/soundcard.h>
#include <linux/interrupt.h>
+#include <linux/platform_device.h>
#include <asm/uaccess.h>
#include <asm/setup.h>
@@ -91,10 +92,6 @@ static irqreturn_t AmiInterrupt(int irq, void *dummy);
* power LED are controlled by the same line.
*/
-#ifdef CONFIG_APUS
-#define mach_heartbeat ppc_md.heartbeat
-#endif
-
static void (*saved_heartbeat)(int) = NULL;
static inline void disable_heartbeat(void)
@@ -661,7 +658,7 @@ static int AmiStateInfo(char *buffer, size_t space)
len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n",
dmasound.volume_right);
if (len >= space) {
- printk(KERN_ERR "dmasound_paula: overlowed state buffer alloc.\n") ;
+ printk(KERN_ERR "dmasound_paula: overflowed state buffer alloc.\n") ;
len = space ;
}
return len;
@@ -714,31 +711,29 @@ static MACHINE machAmiga = {
/*** Config & Setup **********************************************************/
-int __init dmasound_paula_init(void)
+static int __init amiga_audio_probe(struct platform_device *pdev)
{
- int err;
-
- if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_AUDIO)) {
- if (!request_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40,
- "dmasound [Paula]"))
- return -EBUSY;
- dmasound.mach = machAmiga;
- dmasound.mach.default_hard = def_hard ;
- dmasound.mach.default_soft = def_soft ;
- err = dmasound_init();
- if (err)
- release_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40);
- return err;
- } else
- return -ENODEV;
+ dmasound.mach = machAmiga;
+ dmasound.mach.default_hard = def_hard ;
+ dmasound.mach.default_soft = def_soft ;
+ return dmasound_init();
}
-static void __exit dmasound_paula_cleanup(void)
+static int __exit amiga_audio_remove(struct platform_device *pdev)
{
dmasound_deinit();
- release_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40);
+ return 0;
}
-module_init(dmasound_paula_init);
-module_exit(dmasound_paula_cleanup);
+static struct platform_driver amiga_audio_driver = {
+ .remove = __exit_p(amiga_audio_remove),
+ .driver = {
+ .name = "amiga-audio",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver_probe(amiga_audio_driver, amiga_audio_probe);
+
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:amiga-audio");
diff --git a/sound/oss/dmasound/dmasound_q40.c b/sound/oss/dmasound/dmasound_q40.c
index b3379dd7ca5..99bcb21c228 100644
--- a/sound/oss/dmasound/dmasound_q40.c
+++ b/sound/oss/dmasound/dmasound_q40.c
@@ -371,8 +371,9 @@ static void Q40Free(void *ptr, unsigned int size)
static int __init Q40IrqInit(void)
{
/* Register interrupt handler. */
- request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0,
- "DMA sound", Q40Interrupt);
+ if (request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0,
+ "DMA sound", Q40Interrupt))
+ return 0;
return(1);
}
@@ -401,6 +402,7 @@ static void Q40PlayNextFrame(int index)
u_char *start;
u_long size;
u_char speed;
+ int error;
/* used by Q40Play() if all doubts whether there really is something
* to be played are already wiped out.
@@ -419,11 +421,13 @@ static void Q40PlayNextFrame(int index)
master_outb( 0,SAMPLE_ENABLE_REG);
free_irq(Q40_IRQ_SAMPLE, Q40Interrupt);
if (dmasound.soft.stereo)
- request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0,
- "Q40 sound", Q40Interrupt);
+ error = request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0,
+ "Q40 sound", Q40Interrupt);
else
- request_irq(Q40_IRQ_SAMPLE, Q40MonoInterrupt, 0,
- "Q40 sound", Q40Interrupt);
+ error = request_irq(Q40_IRQ_SAMPLE, Q40MonoInterrupt, 0,
+ "Q40 sound", Q40Interrupt);
+ if (error && printk_ratelimit())
+ pr_err("Couldn't register sound interrupt\n");
master_outb( speed, SAMPLE_RATE_REG);
master_outb( 1,SAMPLE_CLEAR_REG);
@@ -611,7 +615,7 @@ static MACHINE machQ40 = {
/*** Config & Setup **********************************************************/
-int __init dmasound_q40_init(void)
+static int __init dmasound_q40_init(void)
{
if (MACH_IS_Q40) {
dmasound.mach = machQ40;
diff --git a/sound/oss/dmasound/tas3001c.c b/sound/oss/dmasound/tas3001c.c
deleted file mode 100644
index 4b7dbdd2a43..00000000000
--- a/sound/oss/dmasound/tas3001c.c
+++ /dev/null
@@ -1,849 +0,0 @@
-/*
- * Driver for the i2c/i2s based TA3004 sound chip used
- * on some Apple hardware. Also known as "snapper".
- *
- * Tobias Sargeant <tobias.sargeant@bigpond.com>
- * Based upon, tas3001c.c by Christopher C. Chimelis <chris@debian.org>:
- *
- * TODO:
- * -----
- * * Enable control over input line 2 (is this connected?)
- * * Implement sleep support (at least mute everything and
- * * set gains to minimum during sleep)
- * * Look into some of Darwin's tweaks regarding the mute
- * * lines (delays & different behaviour on some HW)
- *
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/proc_fs.h>
-#include <linux/ioport.h>
-#include <linux/sysctl.h>
-#include <linux/types.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/soundcard.h>
-#include <linux/workqueue.h>
-#include <asm/uaccess.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-
-#include "dmasound.h"
-#include "tas_common.h"
-#include "tas3001c.h"
-
-#include "tas_ioctl.h"
-
-#define TAS3001C_BIQUAD_FILTER_COUNT 6
-#define TAS3001C_BIQUAD_CHANNEL_COUNT 2
-
-#define VOL_DEFAULT (100 * 4 / 5)
-#define INPUT_DEFAULT (100 * 4 / 5)
-#define BASS_DEFAULT (100 / 2)
-#define TREBLE_DEFAULT (100 / 2)
-
-struct tas3001c_data_t {
- struct tas_data_t super;
- int device_id;
- int output_id;
- int speaker_id;
- struct tas_drce_t drce_state;
- struct work_struct change;
-};
-
-
-static const union tas_biquad_t
-tas3001c_eq_unity={
- .buf = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 }
-};
-
-
-static inline unsigned char db_to_regval(short db) {
- int r=0;
-
- r=(db+0x59a0) / 0x60;
-
- if (r < 0x91) return 0x91;
- if (r > 0xef) return 0xef;
- return r;
-}
-
-static inline short quantize_db(short db) {
- return db_to_regval(db) * 0x60 - 0x59a0;
-}
-
-
-static inline int
-register_width(enum tas3001c_reg_t r)
-{
- switch(r) {
- case TAS3001C_REG_MCR:
- case TAS3001C_REG_TREBLE:
- case TAS3001C_REG_BASS:
- return 1;
-
- case TAS3001C_REG_DRC:
- return 2;
-
- case TAS3001C_REG_MIXER1:
- case TAS3001C_REG_MIXER2:
- return 3;
-
- case TAS3001C_REG_VOLUME:
- return 6;
-
- case TAS3001C_REG_LEFT_BIQUAD0:
- case TAS3001C_REG_LEFT_BIQUAD1:
- case TAS3001C_REG_LEFT_BIQUAD2:
- case TAS3001C_REG_LEFT_BIQUAD3:
- case TAS3001C_REG_LEFT_BIQUAD4:
- case TAS3001C_REG_LEFT_BIQUAD5:
- case TAS3001C_REG_LEFT_BIQUAD6:
-
- case TAS3001C_REG_RIGHT_BIQUAD0:
- case TAS3001C_REG_RIGHT_BIQUAD1:
- case TAS3001C_REG_RIGHT_BIQUAD2:
- case TAS3001C_REG_RIGHT_BIQUAD3:
- case TAS3001C_REG_RIGHT_BIQUAD4:
- case TAS3001C_REG_RIGHT_BIQUAD5:
- case TAS3001C_REG_RIGHT_BIQUAD6:
- return 15;
-
- default:
- return 0;
- }
-}
-
-static int
-tas3001c_write_register( struct tas3001c_data_t *self,
- enum tas3001c_reg_t reg_num,
- char *data,
- uint write_mode)
-{
- if (reg_num==TAS3001C_REG_MCR ||
- reg_num==TAS3001C_REG_BASS ||
- reg_num==TAS3001C_REG_TREBLE) {
- return tas_write_byte_register(&self->super,
- (uint)reg_num,
- *data,
- write_mode);
- } else {
- return tas_write_register(&self->super,
- (uint)reg_num,
- register_width(reg_num),
- data,
- write_mode);
- }
-}
-
-static int
-tas3001c_sync_register( struct tas3001c_data_t *self,
- enum tas3001c_reg_t reg_num)
-{
- if (reg_num==TAS3001C_REG_MCR ||
- reg_num==TAS3001C_REG_BASS ||
- reg_num==TAS3001C_REG_TREBLE) {
- return tas_sync_byte_register(&self->super,
- (uint)reg_num,
- register_width(reg_num));
- } else {
- return tas_sync_register(&self->super,
- (uint)reg_num,
- register_width(reg_num));
- }
-}
-
-static int
-tas3001c_read_register( struct tas3001c_data_t *self,
- enum tas3001c_reg_t reg_num,
- char *data,
- uint write_mode)
-{
- return tas_read_register(&self->super,
- (uint)reg_num,
- register_width(reg_num),
- data);
-}
-
-static inline int
-tas3001c_fast_load(struct tas3001c_data_t *self, int fast)
-{
- if (fast)
- self->super.shadow[TAS3001C_REG_MCR][0] |= 0x80;
- else
- self->super.shadow[TAS3001C_REG_MCR][0] &= 0x7f;
- return tas3001c_sync_register(self,TAS3001C_REG_MCR);
-}
-
-static uint
-tas3001c_supported_mixers(struct tas3001c_data_t *self)
-{
- return SOUND_MASK_VOLUME |
- SOUND_MASK_PCM |
- SOUND_MASK_ALTPCM |
- SOUND_MASK_TREBLE |
- SOUND_MASK_BASS;
-}
-
-static int
-tas3001c_mixer_is_stereo(struct tas3001c_data_t *self,int mixer)
-{
- switch(mixer) {
- case SOUND_MIXER_VOLUME:
- return 1;
- default:
- return 0;
- }
-}
-
-static uint
-tas3001c_stereo_mixers(struct tas3001c_data_t *self)
-{
- uint r=tas3001c_supported_mixers(self);
- uint i;
-
- for (i=1; i<SOUND_MIXER_NRDEVICES; i++)
- if (r&(1<<i) && !tas3001c_mixer_is_stereo(self,i))
- r &= ~(1<<i);
- return r;
-}
-
-static int
-tas3001c_get_mixer_level(struct tas3001c_data_t *self,int mixer,uint *level)
-{
- if (!self)
- return -1;
-
- *level=self->super.mixer[mixer];
-
- return 0;
-}
-
-static int
-tas3001c_set_mixer_level(struct tas3001c_data_t *self,int mixer,uint level)
-{
- int rc;
- tas_shadow_t *shadow;
-
- uint temp;
- uint offset=0;
-
- if (!self)
- return -1;
-
- shadow=self->super.shadow;
-
- if (!tas3001c_mixer_is_stereo(self,mixer))
- level = tas_mono_to_stereo(level);
-
- switch(mixer) {
- case SOUND_MIXER_VOLUME:
- temp = tas3001c_gain.master[level&0xff];
- shadow[TAS3001C_REG_VOLUME][0] = (temp >> 16) & 0xff;
- shadow[TAS3001C_REG_VOLUME][1] = (temp >> 8) & 0xff;
- shadow[TAS3001C_REG_VOLUME][2] = (temp >> 0) & 0xff;
- temp = tas3001c_gain.master[(level>>8)&0xff];
- shadow[TAS3001C_REG_VOLUME][3] = (temp >> 16) & 0xff;
- shadow[TAS3001C_REG_VOLUME][4] = (temp >> 8) & 0xff;
- shadow[TAS3001C_REG_VOLUME][5] = (temp >> 0) & 0xff;
- rc = tas3001c_sync_register(self,TAS3001C_REG_VOLUME);
- break;
- case SOUND_MIXER_ALTPCM:
- /* tas3001c_fast_load(self, 1); */
- level = tas_mono_to_stereo(level);
- temp = tas3001c_gain.mixer[level&0xff];
- shadow[TAS3001C_REG_MIXER2][offset+0] = (temp >> 16) & 0xff;
- shadow[TAS3001C_REG_MIXER2][offset+1] = (temp >> 8) & 0xff;
- shadow[TAS3001C_REG_MIXER2][offset+2] = (temp >> 0) & 0xff;
- rc = tas3001c_sync_register(self,TAS3001C_REG_MIXER2);
- /* tas3001c_fast_load(self, 0); */
- break;
- case SOUND_MIXER_PCM:
- /* tas3001c_fast_load(self, 1); */
- level = tas_mono_to_stereo(level);
- temp = tas3001c_gain.mixer[level&0xff];
- shadow[TAS3001C_REG_MIXER1][offset+0] = (temp >> 16) & 0xff;
- shadow[TAS3001C_REG_MIXER1][offset+1] = (temp >> 8) & 0xff;
- shadow[TAS3001C_REG_MIXER1][offset+2] = (temp >> 0) & 0xff;
- rc = tas3001c_sync_register(self,TAS3001C_REG_MIXER1);
- /* tas3001c_fast_load(self, 0); */
- break;
- case SOUND_MIXER_TREBLE:
- temp = tas3001c_gain.treble[level&0xff];
- shadow[TAS3001C_REG_TREBLE][0]=temp&0xff;
- rc = tas3001c_sync_register(self,TAS3001C_REG_TREBLE);
- break;
- case SOUND_MIXER_BASS:
- temp = tas3001c_gain.bass[level&0xff];
- shadow[TAS3001C_REG_BASS][0]=temp&0xff;
- rc = tas3001c_sync_register(self,TAS3001C_REG_BASS);
- break;
- default:
- rc = -1;
- break;
- }
- if (rc < 0)
- return rc;
- self->super.mixer[mixer]=level;
- return 0;
-}
-
-static int
-tas3001c_leave_sleep(struct tas3001c_data_t *self)
-{
- unsigned char mcr = (1<<6)+(2<<4)+(2<<2);
-
- if (!self)
- return -1;
-
- /* Make sure something answers on the i2c bus */
- if (tas3001c_write_register(self, TAS3001C_REG_MCR, &mcr,
- WRITE_NORMAL|FORCE_WRITE) < 0)
- return -1;
-
- tas3001c_fast_load(self, 1);
-
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD0);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD1);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD2);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD3);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD4);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD5);
-
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD0);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD1);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD2);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD3);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD4);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD5);
-
- tas3001c_fast_load(self, 0);
-
- (void)tas3001c_sync_register(self,TAS3001C_REG_BASS);
- (void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE);
- (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1);
- (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2);
- (void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME);
-
- return 0;
-}
-
-static int
-tas3001c_enter_sleep(struct tas3001c_data_t *self)
-{
- /* Stub for now, but I have the details on low-power mode */
- if (!self)
- return -1;
- return 0;
-}
-
-static int
-tas3001c_sync_biquad( struct tas3001c_data_t *self,
- u_int channel,
- u_int filter)
-{
- enum tas3001c_reg_t reg;
-
- if (channel >= TAS3001C_BIQUAD_CHANNEL_COUNT ||
- filter >= TAS3001C_BIQUAD_FILTER_COUNT) return -EINVAL;
-
- reg=( channel ? TAS3001C_REG_RIGHT_BIQUAD0 : TAS3001C_REG_LEFT_BIQUAD0 ) + filter;
-
- return tas3001c_sync_register(self,reg);
-}
-
-static int
-tas3001c_write_biquad_shadow( struct tas3001c_data_t *self,
- u_int channel,
- u_int filter,
- const union tas_biquad_t *biquad)
-{
- tas_shadow_t *shadow=self->super.shadow;
- enum tas3001c_reg_t reg;
-
- if (channel >= TAS3001C_BIQUAD_CHANNEL_COUNT ||
- filter >= TAS3001C_BIQUAD_FILTER_COUNT) return -EINVAL;
-
- reg=( channel ? TAS3001C_REG_RIGHT_BIQUAD0 : TAS3001C_REG_LEFT_BIQUAD0 ) + filter;
-
- SET_4_20(shadow[reg], 0,biquad->coeff.b0);
- SET_4_20(shadow[reg], 3,biquad->coeff.b1);
- SET_4_20(shadow[reg], 6,biquad->coeff.b2);
- SET_4_20(shadow[reg], 9,biquad->coeff.a1);
- SET_4_20(shadow[reg],12,biquad->coeff.a2);
-
- return 0;
-}
-
-static int
-tas3001c_write_biquad( struct tas3001c_data_t *self,
- u_int channel,
- u_int filter,
- const union tas_biquad_t *biquad)
-{
- int rc;
-
- rc=tas3001c_write_biquad_shadow(self, channel, filter, biquad);
- if (rc < 0) return rc;
-
- return tas3001c_sync_biquad(self, channel, filter);
-}
-
-static int
-tas3001c_write_biquad_list( struct tas3001c_data_t *self,
- u_int filter_count,
- u_int flags,
- struct tas_biquad_ctrl_t *biquads)
-{
- int i;
- int rc;
-
- if (flags & TAS_BIQUAD_FAST_LOAD) tas3001c_fast_load(self,1);
-
- for (i=0; i<filter_count; i++) {
- rc=tas3001c_write_biquad(self,
- biquads[i].channel,
- biquads[i].filter,
- &biquads[i].data);
- if (rc < 0) break;
- }
-
- if (flags & TAS_BIQUAD_FAST_LOAD) {
- tas3001c_fast_load(self,0);
-
- (void)tas3001c_sync_register(self,TAS3001C_REG_BASS);
- (void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE);
- (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1);
- (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2);
- (void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME);
- }
-
- return rc;
-}
-
-static int
-tas3001c_read_biquad( struct tas3001c_data_t *self,
- u_int channel,
- u_int filter,
- union tas_biquad_t *biquad)
-{
- tas_shadow_t *shadow=self->super.shadow;
- enum tas3001c_reg_t reg;
-
- if (channel >= TAS3001C_BIQUAD_CHANNEL_COUNT ||
- filter >= TAS3001C_BIQUAD_FILTER_COUNT) return -EINVAL;
-
- reg=( channel ? TAS3001C_REG_RIGHT_BIQUAD0 : TAS3001C_REG_LEFT_BIQUAD0 ) + filter;
-
- biquad->coeff.b0=GET_4_20(shadow[reg], 0);
- biquad->coeff.b1=GET_4_20(shadow[reg], 3);
- biquad->coeff.b2=GET_4_20(shadow[reg], 6);
- biquad->coeff.a1=GET_4_20(shadow[reg], 9);
- biquad->coeff.a2=GET_4_20(shadow[reg],12);
-
- return 0;
-}
-
-static int
-tas3001c_eq_rw( struct tas3001c_data_t *self,
- u_int cmd,
- u_long arg)
-{
- int rc;
- struct tas_biquad_ctrl_t biquad;
- void __user *argp = (void __user *)arg;
-
- if (copy_from_user(&biquad, argp, sizeof(struct tas_biquad_ctrl_t))) {
- return -EFAULT;
- }
-
- if (cmd & SIOC_IN) {
- rc=tas3001c_write_biquad(self, biquad.channel, biquad.filter, &biquad.data);
- if (rc != 0) return rc;
- }
-
- if (cmd & SIOC_OUT) {
- rc=tas3001c_read_biquad(self, biquad.channel, biquad.filter, &biquad.data);
- if (rc != 0) return rc;
-
- if (copy_to_user(argp, &biquad, sizeof(struct tas_biquad_ctrl_t))) {
- return -EFAULT;
- }
-
- }
- return 0;
-}
-
-static int
-tas3001c_eq_list_rw( struct tas3001c_data_t *self,
- u_int cmd,
- u_long arg)
-{
- int rc;
- int filter_count;
- int flags;
- int i,j;
- char sync_required[2][6];
- struct tas_biquad_ctrl_t biquad;
- struct tas_biquad_ctrl_list_t __user *argp = (void __user *)arg;
-
- memset(sync_required,0,sizeof(sync_required));
-
- if (copy_from_user(&filter_count, &argp->filter_count, sizeof(int)))
- return -EFAULT;
-
- if (copy_from_user(&flags, &argp->flags, sizeof(int)))
- return -EFAULT;
-
- if (cmd & SIOC_IN) {
- }
-
- for (i=0; i < filter_count; i++) {
- if (copy_from_user(&biquad, &argp->biquads[i],
- sizeof(struct tas_biquad_ctrl_t))) {
- return -EFAULT;
- }
-
- if (cmd & SIOC_IN) {
- sync_required[biquad.channel][biquad.filter]=1;
- rc=tas3001c_write_biquad_shadow(self, biquad.channel, biquad.filter, &biquad.data);
- if (rc != 0) return rc;
- }
-
- if (cmd & SIOC_OUT) {
- rc=tas3001c_read_biquad(self, biquad.channel, biquad.filter, &biquad.data);
- if (rc != 0) return rc;
-
- if (copy_to_user(&argp->biquads[i], &biquad,
- sizeof(struct tas_biquad_ctrl_t))) {
- return -EFAULT;
- }
- }
- }
-
- if (cmd & SIOC_IN) {
- if (flags & TAS_BIQUAD_FAST_LOAD) tas3001c_fast_load(self,1);
- for (i=0; i<2; i++) {
- for (j=0; j<6; j++) {
- if (sync_required[i][j]) {
- rc=tas3001c_sync_biquad(self, i, j);
- if (rc < 0) return rc;
- }
- }
- }
- if (flags & TAS_BIQUAD_FAST_LOAD) {
- tas3001c_fast_load(self,0);
- /* now we need to set up the mixers again,
- because leaving fast mode resets them. */
- (void)tas3001c_sync_register(self,TAS3001C_REG_BASS);
- (void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE);
- (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1);
- (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2);
- (void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME);
- }
- }
-
- return 0;
-}
-
-static int
-tas3001c_update_drce( struct tas3001c_data_t *self,
- int flags,
- struct tas_drce_t *drce)
-{
- tas_shadow_t *shadow;
- shadow=self->super.shadow;
-
- shadow[TAS3001C_REG_DRC][1] = 0xc1;
-
- if (flags & TAS_DRCE_THRESHOLD) {
- self->drce_state.threshold=quantize_db(drce->threshold);
- shadow[TAS3001C_REG_DRC][2] = db_to_regval(self->drce_state.threshold);
- }
-
- if (flags & TAS_DRCE_ENABLE) {
- self->drce_state.enable = drce->enable;
- }
-
- if (!self->drce_state.enable) {
- shadow[TAS3001C_REG_DRC][0] = 0xf0;
- }
-
-#ifdef DEBUG_DRCE
- printk("DRCE IOCTL: set [ ENABLE:%x THRESH:%x\n",
- self->drce_state.enable,
- self->drce_state.threshold);
-
- printk("DRCE IOCTL: reg [ %02x %02x ]\n",
- (unsigned char)shadow[TAS3001C_REG_DRC][0],
- (unsigned char)shadow[TAS3001C_REG_DRC][1]);
-#endif
-
- return tas3001c_sync_register(self, TAS3001C_REG_DRC);
-}
-
-static int
-tas3001c_drce_rw( struct tas3001c_data_t *self,
- u_int cmd,
- u_long arg)
-{
- int rc;
- struct tas_drce_ctrl_t drce_ctrl;
- void __user *argp = (void __user *)arg;
-
- if (copy_from_user(&drce_ctrl, argp, sizeof(struct tas_drce_ctrl_t)))
- return -EFAULT;
-
-#ifdef DEBUG_DRCE
- printk("DRCE IOCTL: input [ FLAGS:%x ENABLE:%x THRESH:%x\n",
- drce_ctrl.flags,
- drce_ctrl.data.enable,
- drce_ctrl.data.threshold);
-#endif
-
- if (cmd & SIOC_IN) {
- rc = tas3001c_update_drce(self, drce_ctrl.flags, &drce_ctrl.data);
- if (rc < 0)
- return rc;
- }
-
- if (cmd & SIOC_OUT) {
- if (drce_ctrl.flags & TAS_DRCE_ENABLE)
- drce_ctrl.data.enable = self->drce_state.enable;
-
- if (drce_ctrl.flags & TAS_DRCE_THRESHOLD)
- drce_ctrl.data.threshold = self->drce_state.threshold;
-
- if (copy_to_user(argp, &drce_ctrl,
- sizeof(struct tas_drce_ctrl_t))) {
- return -EFAULT;
- }
- }
-
- return 0;
-}
-
-static void
-tas3001c_update_device_parameters(struct tas3001c_data_t *self)
-{
- int i,j;
-
- if (!self) return;
-
- if (self->output_id == TAS_OUTPUT_HEADPHONES) {
- tas3001c_fast_load(self, 1);
-
- for (i=0; i<TAS3001C_BIQUAD_CHANNEL_COUNT; i++) {
- for (j=0; j<TAS3001C_BIQUAD_FILTER_COUNT; j++) {
- tas3001c_write_biquad(self, i, j, &tas3001c_eq_unity);
- }
- }
-
- tas3001c_fast_load(self, 0);
-
- (void)tas3001c_sync_register(self,TAS3001C_REG_BASS);
- (void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE);
- (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1);
- (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2);
- (void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME);
-
- return;
- }
-
- for (i=0; tas3001c_eq_prefs[i]; i++) {
- struct tas_eq_pref_t *eq = tas3001c_eq_prefs[i];
-
- if (eq->device_id == self->device_id &&
- (eq->output_id == 0 || eq->output_id == self->output_id) &&
- (eq->speaker_id == 0 || eq->speaker_id == self->speaker_id)) {
-
- tas3001c_update_drce(self, TAS_DRCE_ALL, eq->drce);
- tas3001c_write_biquad_list(self, eq->filter_count, TAS_BIQUAD_FAST_LOAD, eq->biquads);
-
- break;
- }
- }
-}
-
-static void
-tas3001c_device_change_handler(struct work_struct *work)
-{
- struct tas3001c_data_t *self;
- self = container_of(work, struct tas3001c_data_t, change);
- tas3001c_update_device_parameters(self);
-}
-
-static int
-tas3001c_output_device_change( struct tas3001c_data_t *self,
- int device_id,
- int output_id,
- int speaker_id)
-{
- self->device_id=device_id;
- self->output_id=output_id;
- self->speaker_id=speaker_id;
-
- schedule_work(&self->change);
- return 0;
-}
-
-static int
-tas3001c_device_ioctl( struct tas3001c_data_t *self,
- u_int cmd,
- u_long arg)
-{
- uint __user *argp = (void __user *)arg;
- switch (cmd) {
- case TAS_READ_EQ:
- case TAS_WRITE_EQ:
- return tas3001c_eq_rw(self, cmd, arg);
-
- case TAS_READ_EQ_LIST:
- case TAS_WRITE_EQ_LIST:
- return tas3001c_eq_list_rw(self, cmd, arg);
-
- case TAS_READ_EQ_FILTER_COUNT:
- put_user(TAS3001C_BIQUAD_FILTER_COUNT, argp);
- return 0;
-
- case TAS_READ_EQ_CHANNEL_COUNT:
- put_user(TAS3001C_BIQUAD_CHANNEL_COUNT, argp);
- return 0;
-
- case TAS_READ_DRCE:
- case TAS_WRITE_DRCE:
- return tas3001c_drce_rw(self, cmd, arg);
-
- case TAS_READ_DRCE_CAPS:
- put_user(TAS_DRCE_ENABLE | TAS_DRCE_THRESHOLD, argp);
- return 0;
-
- case TAS_READ_DRCE_MIN:
- case TAS_READ_DRCE_MAX: {
- struct tas_drce_ctrl_t drce_ctrl;
-
- if (copy_from_user(&drce_ctrl, argp,
- sizeof(struct tas_drce_ctrl_t))) {
- return -EFAULT;
- }
-
- if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) {
- if (cmd == TAS_READ_DRCE_MIN) {
- drce_ctrl.data.threshold=-36<<8;
- } else {
- drce_ctrl.data.threshold=-6<<8;
- }
- }
-
- if (copy_to_user(argp, &drce_ctrl,
- sizeof(struct tas_drce_ctrl_t))) {
- return -EFAULT;
- }
- }
- }
-
- return -EINVAL;
-}
-
-static int
-tas3001c_init_mixer(struct tas3001c_data_t *self)
-{
- unsigned char mcr = (1<<6)+(2<<4)+(2<<2);
-
- /* Make sure something answers on the i2c bus */
- if (tas3001c_write_register(self, TAS3001C_REG_MCR, &mcr,
- WRITE_NORMAL|FORCE_WRITE) < 0)
- return -1;
-
- tas3001c_fast_load(self, 1);
-
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD0);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD1);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD2);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD3);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD4);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD5);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD6);
-
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD0);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD1);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD2);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD3);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD4);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD5);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD6);
-
- tas3001c_fast_load(self, 0);
-
- tas3001c_set_mixer_level(self, SOUND_MIXER_VOLUME, VOL_DEFAULT<<8 | VOL_DEFAULT);
- tas3001c_set_mixer_level(self, SOUND_MIXER_PCM, INPUT_DEFAULT<<8 | INPUT_DEFAULT);
- tas3001c_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0);
-
- tas3001c_set_mixer_level(self, SOUND_MIXER_BASS, BASS_DEFAULT);
- tas3001c_set_mixer_level(self, SOUND_MIXER_TREBLE, TREBLE_DEFAULT);
-
- return 0;
-}
-
-static int
-tas3001c_uninit_mixer(struct tas3001c_data_t *self)
-{
- tas3001c_set_mixer_level(self, SOUND_MIXER_VOLUME, 0);
- tas3001c_set_mixer_level(self, SOUND_MIXER_PCM, 0);
- tas3001c_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0);
-
- tas3001c_set_mixer_level(self, SOUND_MIXER_BASS, 0);
- tas3001c_set_mixer_level(self, SOUND_MIXER_TREBLE, 0);
-
- return 0;
-}
-
-static int
-tas3001c_init(struct i2c_client *client)
-{
- struct tas3001c_data_t *self;
- size_t sz = sizeof(*self) + (TAS3001C_REG_MAX*sizeof(tas_shadow_t));
- int i, j;
-
- self = kzalloc(sz, GFP_KERNEL);
- if (!self)
- return -ENOMEM;
-
- self->super.client = client;
- self->super.shadow = (tas_shadow_t *)(self+1);
- self->output_id = TAS_OUTPUT_HEADPHONES;
-
- dev_set_drvdata(&client->dev, self);
-
- for (i = 0; i < TAS3001C_BIQUAD_CHANNEL_COUNT; i++)
- for (j = 0; j < TAS3001C_BIQUAD_FILTER_COUNT; j++)
- tas3001c_write_biquad_shadow(self, i, j,
- &tas3001c_eq_unity);
-
- INIT_WORK(&self->change, tas3001c_device_change_handler);
- return 0;
-}
-
-static void
-tas3001c_uninit(struct tas3001c_data_t *self)
-{
- tas3001c_uninit_mixer(self);
- kfree(self);
-}
-
-struct tas_driver_hooks_t tas3001c_hooks = {
- .init = (tas_hook_init_t)tas3001c_init,
- .post_init = (tas_hook_post_init_t)tas3001c_init_mixer,
- .uninit = (tas_hook_uninit_t)tas3001c_uninit,
- .get_mixer_level = (tas_hook_get_mixer_level_t)tas3001c_get_mixer_level,
- .set_mixer_level = (tas_hook_set_mixer_level_t)tas3001c_set_mixer_level,
- .enter_sleep = (tas_hook_enter_sleep_t)tas3001c_enter_sleep,
- .leave_sleep = (tas_hook_leave_sleep_t)tas3001c_leave_sleep,
- .supported_mixers = (tas_hook_supported_mixers_t)tas3001c_supported_mixers,
- .mixer_is_stereo = (tas_hook_mixer_is_stereo_t)tas3001c_mixer_is_stereo,
- .stereo_mixers = (tas_hook_stereo_mixers_t)tas3001c_stereo_mixers,
- .output_device_change = (tas_hook_output_device_change_t)tas3001c_output_device_change,
- .device_ioctl = (tas_hook_device_ioctl_t)tas3001c_device_ioctl
-};
diff --git a/sound/oss/dmasound/tas3001c.h b/sound/oss/dmasound/tas3001c.h
deleted file mode 100644
index 3660da33a2d..00000000000
--- a/sound/oss/dmasound/tas3001c.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Header file for the i2c/i2s based TA3001c sound chip used
- * on some Apple hardware. Also known as "tumbler".
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- *
- * Written by Christopher C. Chimelis <chris@debian.org>
- */
-
-#ifndef _TAS3001C_H_
-#define _TAS3001C_H_
-
-#include <linux/types.h>
-
-#include "tas_common.h"
-#include "tas_eq_prefs.h"
-
-/*
- * Macros that correspond to the registers that we write to
- * when setting the various values.
- */
-
-#define TAS3001C_VERSION "0.3"
-#define TAS3001C_DATE "20011214"
-
-#define I2C_DRIVERNAME_TAS3001C "TAS3001c driver V " TAS3001C_VERSION
-#define I2C_DRIVERID_TAS3001C (I2C_DRIVERID_TAS_BASE+0)
-
-extern struct tas_driver_hooks_t tas3001c_hooks;
-extern struct tas_gain_t tas3001c_gain;
-extern struct tas_eq_pref_t *tas3001c_eq_prefs[];
-
-enum tas3001c_reg_t {
- TAS3001C_REG_MCR = 0x01,
- TAS3001C_REG_DRC = 0x02,
-
- TAS3001C_REG_VOLUME = 0x04,
- TAS3001C_REG_TREBLE = 0x05,
- TAS3001C_REG_BASS = 0x06,
- TAS3001C_REG_MIXER1 = 0x07,
- TAS3001C_REG_MIXER2 = 0x08,
-
- TAS3001C_REG_LEFT_BIQUAD0 = 0x0a,
- TAS3001C_REG_LEFT_BIQUAD1 = 0x0b,
- TAS3001C_REG_LEFT_BIQUAD2 = 0x0c,
- TAS3001C_REG_LEFT_BIQUAD3 = 0x0d,
- TAS3001C_REG_LEFT_BIQUAD4 = 0x0e,
- TAS3001C_REG_LEFT_BIQUAD5 = 0x0f,
- TAS3001C_REG_LEFT_BIQUAD6 = 0x10,
-
- TAS3001C_REG_RIGHT_BIQUAD0 = 0x13,
- TAS3001C_REG_RIGHT_BIQUAD1 = 0x14,
- TAS3001C_REG_RIGHT_BIQUAD2 = 0x15,
- TAS3001C_REG_RIGHT_BIQUAD3 = 0x16,
- TAS3001C_REG_RIGHT_BIQUAD4 = 0x17,
- TAS3001C_REG_RIGHT_BIQUAD5 = 0x18,
- TAS3001C_REG_RIGHT_BIQUAD6 = 0x19,
-
- TAS3001C_REG_MAX = 0x20
-};
-
-#endif /* _TAS3001C_H_ */
diff --git a/sound/oss/dmasound/tas3001c_tables.c b/sound/oss/dmasound/tas3001c_tables.c
deleted file mode 100644
index 1768fa95f25..00000000000
--- a/sound/oss/dmasound/tas3001c_tables.c
+++ /dev/null
@@ -1,375 +0,0 @@
-#include "tas_common.h"
-#include "tas_eq_prefs.h"
-
-static struct tas_drce_t eqp_0e_2_1_drce = {
- .enable = 1,
- .above = { .val = 3.0 * (1<<8), .expand = 0 },
- .below = { .val = 1.0 * (1<<8), .expand = 0 },
- .threshold = -15.33 * (1<<8),
- .energy = 2.4 * (1<<12),
- .attack = 0.013 * (1<<12),
- .decay = 0.212 * (1<<12),
-};
-
-static struct tas_biquad_ctrl_t eqp_0e_2_1_biquads[]={
- { .channel = 0, .filter = 0, .data = { .coeff = { 0x0FCAD3, 0xE06A58, 0x0FCAD3, 0xE06B09, 0x0F9657 } } },
- { .channel = 0, .filter = 1, .data = { .coeff = { 0x041731, 0x082E63, 0x041731, 0xFD8D08, 0x02CFBD } } },
- { .channel = 0, .filter = 2, .data = { .coeff = { 0x0FFDC7, 0xE0524C, 0x0FBFAA, 0xE0524C, 0x0FBD72 } } },
- { .channel = 0, .filter = 3, .data = { .coeff = { 0x0F3D35, 0xE228CA, 0x0EC7B2, 0xE228CA, 0x0E04E8 } } },
- { .channel = 0, .filter = 4, .data = { .coeff = { 0x0FCEBF, 0xE181C2, 0x0F2656, 0xE181C2, 0x0EF516 } } },
- { .channel = 0, .filter = 5, .data = { .coeff = { 0x0EC417, 0x073E22, 0x0B0633, 0x073E22, 0x09CA4A } } },
-
- { .channel = 1, .filter = 0, .data = { .coeff = { 0x0FCAD3, 0xE06A58, 0x0FCAD3, 0xE06B09, 0x0F9657 } } },
- { .channel = 1, .filter = 1, .data = { .coeff = { 0x041731, 0x082E63, 0x041731, 0xFD8D08, 0x02CFBD } } },
- { .channel = 1, .filter = 2, .data = { .coeff = { 0x0FFDC7, 0xE0524C, 0x0FBFAA, 0xE0524C, 0x0FBD72 } } },
- { .channel = 1, .filter = 3, .data = { .coeff = { 0x0F3D35, 0xE228CA, 0x0EC7B2, 0xE228CA, 0x0E04E8 } } },
- { .channel = 1, .filter = 4, .data = { .coeff = { 0x0FCEBF, 0xE181C2, 0x0F2656, 0xE181C2, 0x0EF516 } } },
- { .channel = 1, .filter = 5, .data = { .coeff = { 0x0EC417, 0x073E22, 0x0B0633, 0x073E22, 0x09CA4A } } },
-};
-
-static struct tas_eq_pref_t eqp_0e_2_1 = {
- .sample_rate = 44100,
- .device_id = 0x0e,
- .output_id = TAS_OUTPUT_EXTERNAL_SPKR,
- .speaker_id = 0x01,
-
- .drce = &eqp_0e_2_1_drce,
-
- .filter_count = 12,
- .biquads = eqp_0e_2_1_biquads
-};
-
-/* ======================================================================== */
-
-static struct tas_drce_t eqp_10_1_0_drce={
- .enable = 1,
- .above = { .val = 3.0 * (1<<8), .expand = 0 },
- .below = { .val = 1.0 * (1<<8), .expand = 0 },
- .threshold = -12.46 * (1<<8),
- .energy = 2.4 * (1<<12),
- .attack = 0.013 * (1<<12),
- .decay = 0.212 * (1<<12),
-};
-
-static struct tas_biquad_ctrl_t eqp_10_1_0_biquads[]={
- { .channel = 0, .filter = 0, .data = { .coeff = { 0x0F4A12, 0xE16BDA, 0x0F4A12, 0xE173F0, 0x0E9C3A } } },
- { .channel = 0, .filter = 1, .data = { .coeff = { 0x02DD54, 0x05BAA8, 0x02DD54, 0xF8001D, 0x037532 } } },
- { .channel = 0, .filter = 2, .data = { .coeff = { 0x0E2FC7, 0xE4D5DC, 0x0D7477, 0xE4D5DC, 0x0BA43F } } },
- { .channel = 0, .filter = 3, .data = { .coeff = { 0x0E7899, 0xE67CCA, 0x0D0E93, 0xE67CCA, 0x0B872D } } },
- { .channel = 0, .filter = 4, .data = { .coeff = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } },
- { .channel = 0, .filter = 5, .data = { .coeff = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } },
-
- { .channel = 1, .filter = 0, .data = { .coeff = { 0x0F4A12, 0xE16BDA, 0x0F4A12, 0xE173F0, 0x0E9C3A } } },
- { .channel = 1, .filter = 1, .data = { .coeff = { 0x02DD54, 0x05BAA8, 0x02DD54, 0xF8001D, 0x037532 } } },
- { .channel = 1, .filter = 2, .data = { .coeff = { 0x0E2FC7, 0xE4D5DC, 0x0D7477, 0xE4D5DC, 0x0BA43F } } },
- { .channel = 1, .filter = 3, .data = { .coeff = { 0x0E7899, 0xE67CCA, 0x0D0E93, 0xE67CCA, 0x0B872D } } },
- { .channel = 1, .filter = 4, .data = { .coeff = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } },
- { .channel = 1, .filter = 5, .data = { .coeff = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } },
-};
-
-static struct tas_eq_pref_t eqp_10_1_0 = {
- .sample_rate = 44100,
- .device_id = 0x10,
- .output_id = TAS_OUTPUT_INTERNAL_SPKR,
- .speaker_id = 0x00,
-
- .drce = &eqp_10_1_0_drce,
-
- .filter_count = 12,
- .biquads = eqp_10_1_0_biquads
-};
-
-/* ======================================================================== */
-
-static struct tas_drce_t eqp_15_2_1_drce={
- .enable = 1,
- .above = { .val = 3.0 * (1<<8), .expand = 0 },
- .below = { .val = 1.0 * (1<<8), .expand = 0 },
- .threshold = -15.33 * (1<<8),
- .energy = 2.4 * (1<<12),
- .attack = 0.013 * (1<<12),
- .decay = 0.212 * (1<<12),
-};
-
-static struct tas_biquad_ctrl_t eqp_15_2_1_biquads[]={
- { .channel = 0, .filter = 0, .data = { .coeff = { 0x0FE143, 0xE05204, 0x0FCCC5, 0xE05266, 0x0FAE6B } } },
- { .channel = 0, .filter = 1, .data = { .coeff = { 0x102383, 0xE03A03, 0x0FA325, 0xE03A03, 0x0FC6A8 } } },
- { .channel = 0, .filter = 2, .data = { .coeff = { 0x0FF2AB, 0xE06285, 0x0FB20A, 0xE06285, 0x0FA4B5 } } },
- { .channel = 0, .filter = 3, .data = { .coeff = { 0x0F544D, 0xE35971, 0x0D8F3A, 0xE35971, 0x0CE388 } } },
- { .channel = 0, .filter = 4, .data = { .coeff = { 0x13E1D3, 0xF3ECB5, 0x042227, 0xF3ECB5, 0x0803FA } } },
- { .channel = 0, .filter = 5, .data = { .coeff = { 0x0AC119, 0x034181, 0x078AB1, 0x034181, 0x024BCA } } },
-
- { .channel = 1, .filter = 0, .data = { .coeff = { 0x0FE143, 0xE05204, 0x0FCCC5, 0xE05266, 0x0FAE6B } } },
- { .channel = 1, .filter = 1, .data = { .coeff = { 0x102383, 0xE03A03, 0x0FA325, 0xE03A03, 0x0FC6A8 } } },
- { .channel = 1, .filter = 2, .data = { .coeff = { 0x0FF2AB, 0xE06285, 0x0FB20A, 0xE06285, 0x0FA4B5 } } },
- { .channel = 1, .filter = 3, .data = { .coeff = { 0x0F544D, 0xE35971, 0x0D8F3A, 0xE35971, 0x0CE388 } } },
- { .channel = 1, .filter = 4, .data = { .coeff = { 0x13E1D3, 0xF3ECB5, 0x042227, 0xF3ECB5, 0x0803FA } } },
- { .channel = 1, .filter = 5, .data = { .coeff = { 0x0AC119, 0x034181, 0x078AB1, 0x034181, 0x024BCA } } },
-};
-
-static struct tas_eq_pref_t eqp_15_2_1 = {
- .sample_rate = 44100,
- .device_id = 0x15,
- .output_id = TAS_OUTPUT_EXTERNAL_SPKR,
- .speaker_id = 0x01,
-
- .drce = &eqp_15_2_1_drce,
-
- .filter_count = 12,
- .biquads = eqp_15_2_1_biquads
-};
-
-/* ======================================================================== */
-
-static struct tas_drce_t eqp_15_1_0_drce={
- .enable = 1,
- .above = { .val = 3.0 * (1<<8), .expand = 0 },
- .below = { .val = 1.0 * (1<<8), .expand = 0 },
- .threshold = 0.0 * (1<<8),
- .energy = 2.4 * (1<<12),
- .attack = 0.013 * (1<<12),
- .decay = 0.212 * (1<<12),
-};
-
-static struct tas_biquad_ctrl_t eqp_15_1_0_biquads[]={
- { .channel = 0, .filter = 0, .data = { .coeff = { 0x0FAD08, 0xE0A5EF, 0x0FAD08, 0xE0A79D, 0x0F5BBE } } },
- { .channel = 0, .filter = 1, .data = { .coeff = { 0x04B38D, 0x09671B, 0x04B38D, 0x000F71, 0x02BEC5 } } },
- { .channel = 0, .filter = 2, .data = { .coeff = { 0x0FDD32, 0xE0A56F, 0x0F8A69, 0xE0A56F, 0x0F679C } } },
- { .channel = 0, .filter = 3, .data = { .coeff = { 0x0FD284, 0xE135FB, 0x0F2161, 0xE135FB, 0x0EF3E5 } } },
- { .channel = 0, .filter = 4, .data = { .coeff = { 0x0E81B1, 0xE6283F, 0x0CE49D, 0xE6283F, 0x0B664F } } },
- { .channel = 0, .filter = 5, .data = { .coeff = { 0x0F2D62, 0xE98797, 0x0D1E19, 0xE98797, 0x0C4B7B } } },
-
- { .channel = 1, .filter = 0, .data = { .coeff = { 0x0FAD08, 0xE0A5EF, 0x0FAD08, 0xE0A79D, 0x0F5BBE } } },
- { .channel = 1, .filter = 1, .data = { .coeff = { 0x04B38D, 0x09671B, 0x04B38D, 0x000F71, 0x02BEC5 } } },
- { .channel = 1, .filter = 2, .data = { .coeff = { 0x0FDD32, 0xE0A56F, 0x0F8A69, 0xE0A56F, 0x0F679C } } },
- { .channel = 1, .filter = 3, .data = { .coeff = { 0x0FD284, 0xE135FB, 0x0F2161, 0xE135FB, 0x0EF3E5 } } },
- { .channel = 1, .filter = 4, .data = { .coeff = { 0x0E81B1, 0xE6283F, 0x0CE49D, 0xE6283F, 0x0B664F } } },
- { .channel = 1, .filter = 5, .data = { .coeff = { 0x0F2D62, 0xE98797, 0x0D1E19, 0xE98797, 0x0C4B7B } } },
-};
-
-static struct tas_eq_pref_t eqp_15_1_0 = {
- .sample_rate = 44100,
- .device_id = 0x15,
- .output_id = TAS_OUTPUT_INTERNAL_SPKR,
- .speaker_id = 0x00,
-
- .drce = &eqp_15_1_0_drce,
-
- .filter_count = 12,
- .biquads = eqp_15_1_0_biquads
-};
-
-/* ======================================================================== */
-
-static struct tas_drce_t eqp_0f_2_1_drce={
- .enable = 1,
- .above = { .val = 3.0 * (1<<8), .expand = 0 },
- .below = { .val = 1.0 * (1<<8), .expand = 0 },
- .threshold = -15.33 * (1<<8),
- .energy = 2.4 * (1<<12),
- .attack = 0.013 * (1<<12),
- .decay = 0.212 * (1<<12),
-};
-
-static struct tas_biquad_ctrl_t eqp_0f_2_1_biquads[]={
- { .channel = 0, .filter = 0, .data = { .coeff = { 0x0FE143, 0xE05204, 0x0FCCC5, 0xE05266, 0x0FAE6B } } },
- { .channel = 0, .filter = 1, .data = { .coeff = { 0x102383, 0xE03A03, 0x0FA325, 0xE03A03, 0x0FC6A8 } } },
- { .channel = 0, .filter = 2, .data = { .coeff = { 0x0FF2AB, 0xE06285, 0x0FB20A, 0xE06285, 0x0FA4B5 } } },
- { .channel = 0, .filter = 3, .data = { .coeff = { 0x0F544D, 0xE35971, 0x0D8F3A, 0xE35971, 0x0CE388 } } },
- { .channel = 0, .filter = 4, .data = { .coeff = { 0x13E1D3, 0xF3ECB5, 0x042227, 0xF3ECB5, 0x0803FA } } },
- { .channel = 0, .filter = 5, .data = { .coeff = { 0x0AC119, 0x034181, 0x078AB1, 0x034181, 0x024BCA } } },
-
- { .channel = 1, .filter = 0, .data = { .coeff = { 0x0FE143, 0xE05204, 0x0FCCC5, 0xE05266, 0x0FAE6B } } },
- { .channel = 1, .filter = 1, .data = { .coeff = { 0x102383, 0xE03A03, 0x0FA325, 0xE03A03, 0x0FC6A8 } } },
- { .channel = 1, .filter = 2, .data = { .coeff = { 0x0FF2AB, 0xE06285, 0x0FB20A, 0xE06285, 0x0FA4B5 } } },
- { .channel = 1, .filter = 3, .data = { .coeff = { 0x0F544D, 0xE35971, 0x0D8F3A, 0xE35971, 0x0CE388 } } },
- { .channel = 1, .filter = 4, .data = { .coeff = { 0x13E1D3, 0xF3ECB5, 0x042227, 0xF3ECB5, 0x0803FA } } },
- { .channel = 1, .filter = 5, .data = { .coeff = { 0x0AC119, 0x034181, 0x078AB1, 0x034181, 0x024BCA } } },
-};
-
-static struct tas_eq_pref_t eqp_0f_2_1 = {
- .sample_rate = 44100,
- .device_id = 0x0f,
- .output_id = TAS_OUTPUT_EXTERNAL_SPKR,
- .speaker_id = 0x01,
-
- .drce = &eqp_0f_2_1_drce,
-
- .filter_count = 12,
- .biquads = eqp_0f_2_1_biquads
-};
-
-/* ======================================================================== */
-
-static struct tas_drce_t eqp_0f_1_0_drce={
- .enable = 1,
- .above = { .val = 3.0 * (1<<8), .expand = 0 },
- .below = { .val = 1.0 * (1<<8), .expand = 0 },
- .threshold = -15.33 * (1<<8),
- .energy = 2.4 * (1<<12),
- .attack = 0.013 * (1<<12),
- .decay = 0.212 * (1<<12),
-};
-
-static struct tas_biquad_ctrl_t eqp_0f_1_0_biquads[]={
- { .channel = 0, .filter = 0, .data = { .coeff = { 0x0FCAD3, 0xE06A58, 0x0FCAD3, 0xE06B09, 0x0F9657 } } },
- { .channel = 0, .filter = 1, .data = { .coeff = { 0x041731, 0x082E63, 0x041731, 0xFD8D08, 0x02CFBD } } },
- { .channel = 0, .filter = 2, .data = { .coeff = { 0x0FFDC7, 0xE0524C, 0x0FBFAA, 0xE0524C, 0x0FBD72 } } },
- { .channel = 0, .filter = 3, .data = { .coeff = { 0x0F3D35, 0xE228CA, 0x0EC7B2, 0xE228CA, 0x0E04E8 } } },
- { .channel = 0, .filter = 4, .data = { .coeff = { 0x0FCEBF, 0xE181C2, 0x0F2656, 0xE181C2, 0x0EF516 } } },
- { .channel = 0, .filter = 5, .data = { .coeff = { 0x0EC417, 0x073E22, 0x0B0633, 0x073E22, 0x09CA4A } } },
-
- { .channel = 1, .filter = 0, .data = { .coeff = { 0x0FCAD3, 0xE06A58, 0x0FCAD3, 0xE06B09, 0x0F9657 } } },
- { .channel = 1, .filter = 1, .data = { .coeff = { 0x041731, 0x082E63, 0x041731, 0xFD8D08, 0x02CFBD } } },
- { .channel = 1, .filter = 2, .data = { .coeff = { 0x0FFDC7, 0xE0524C, 0x0FBFAA, 0xE0524C, 0x0FBD72 } } },
- { .channel = 1, .filter = 3, .data = { .coeff = { 0x0F3D35, 0xE228CA, 0x0EC7B2, 0xE228CA, 0x0E04E8 } } },
- { .channel = 1, .filter = 4, .data = { .coeff = { 0x0FCEBF, 0xE181C2, 0x0F2656, 0xE181C2, 0x0EF516 } } },
- { .channel = 1, .filter = 5, .data = { .coeff = { 0x0EC417, 0x073E22, 0x0B0633, 0x073E22, 0x09CA4A } } },
-};
-
-static struct tas_eq_pref_t eqp_0f_1_0 = {
- .sample_rate = 44100,
- .device_id = 0x0f,
- .output_id = TAS_OUTPUT_INTERNAL_SPKR,
- .speaker_id = 0x00,
-
- .drce = &eqp_0f_1_0_drce,
-
- .filter_count = 12,
- .biquads = eqp_0f_1_0_biquads
-};
-
-/* ======================================================================== */
-
-static uint tas3001c_master_tab[]={
- 0x0, 0x75, 0x9c, 0xbb,
- 0xdb, 0xfb, 0x11e, 0x143,
- 0x16b, 0x196, 0x1c3, 0x1f5,
- 0x229, 0x263, 0x29f, 0x2e1,
- 0x328, 0x373, 0x3c5, 0x41b,
- 0x478, 0x4dc, 0x547, 0x5b8,
- 0x633, 0x6b5, 0x740, 0x7d5,
- 0x873, 0x91c, 0x9d2, 0xa92,
- 0xb5e, 0xc39, 0xd22, 0xe19,
- 0xf20, 0x1037, 0x1161, 0x129e,
- 0x13ed, 0x1551, 0x16ca, 0x185d,
- 0x1a08, 0x1bcc, 0x1dac, 0x1fa7,
- 0x21c1, 0x23fa, 0x2655, 0x28d6,
- 0x2b7c, 0x2e4a, 0x3141, 0x3464,
- 0x37b4, 0x3b35, 0x3ee9, 0x42d3,
- 0x46f6, 0x4b53, 0x4ff0, 0x54ce,
- 0x59f2, 0x5f5f, 0x6519, 0x6b24,
- 0x7183, 0x783c, 0x7f53, 0x86cc,
- 0x8ead, 0x96fa, 0x9fba, 0xa8f2,
- 0xb2a7, 0xbce1, 0xc7a5, 0xd2fa,
- 0xdee8, 0xeb75, 0xf8aa, 0x1068e,
- 0x1152a, 0x12487, 0x134ad, 0x145a5,
- 0x1577b, 0x16a37, 0x17df5, 0x192bd,
- 0x1a890, 0x1bf7b, 0x1d78d, 0x1f0d1,
- 0x20b55, 0x22727, 0x24456, 0x262f2,
- 0x2830b
-};
-
-static uint tas3001c_mixer_tab[]={
- 0x0, 0x748, 0x9be, 0xbaf,
- 0xda4, 0xfb1, 0x11de, 0x1431,
- 0x16ad, 0x1959, 0x1c37, 0x1f4b,
- 0x2298, 0x2628, 0x29fb, 0x2e12,
- 0x327d, 0x3734, 0x3c47, 0x41b4,
- 0x4787, 0x4dbe, 0x546d, 0x5b86,
- 0x632e, 0x6b52, 0x7400, 0x7d54,
- 0x873b, 0x91c6, 0x9d1a, 0xa920,
- 0xb5e5, 0xc38c, 0xd21b, 0xe18f,
- 0xf1f5, 0x1036a, 0x1160f, 0x129d6,
- 0x13ed0, 0x1550c, 0x16ca0, 0x185c9,
- 0x1a07b, 0x1bcc3, 0x1dab9, 0x1fa75,
- 0x21c0f, 0x23fa3, 0x26552, 0x28d64,
- 0x2b7c9, 0x2e4a2, 0x31411, 0x3463b,
- 0x37b44, 0x3b353, 0x3ee94, 0x42d30,
- 0x46f55, 0x4b533, 0x4fefc, 0x54ce5,
- 0x59f25, 0x5f5f6, 0x65193, 0x6b23c,
- 0x71835, 0x783c3, 0x7f52c, 0x86cc0,
- 0x8eacc, 0x96fa5, 0x9fba0, 0xa8f1a,
- 0xb2a71, 0xbce0a, 0xc7a4a, 0xd2fa0,
- 0xdee7b, 0xeb752, 0xf8a9f, 0x1068e4,
- 0x1152a3, 0x12486a, 0x134ac8, 0x145a55,
- 0x1577ac, 0x16a370, 0x17df51, 0x192bc2,
- 0x1a88f8, 0x1bf7b7, 0x1d78c9, 0x1f0d04,
- 0x20b542, 0x227268, 0x244564, 0x262f26,
- 0x2830af
-};
-
-static uint tas3001c_treble_tab[]={
- 0x96, 0x95, 0x95, 0x94,
- 0x93, 0x92, 0x92, 0x91,
- 0x90, 0x90, 0x8f, 0x8e,
- 0x8d, 0x8d, 0x8c, 0x8b,
- 0x8a, 0x8a, 0x89, 0x88,
- 0x88, 0x87, 0x86, 0x85,
- 0x85, 0x84, 0x83, 0x83,
- 0x82, 0x81, 0x80, 0x80,
- 0x7f, 0x7e, 0x7e, 0x7d,
- 0x7c, 0x7b, 0x7b, 0x7a,
- 0x79, 0x78, 0x78, 0x77,
- 0x76, 0x76, 0x75, 0x74,
- 0x73, 0x73, 0x72, 0x71,
- 0x71, 0x70, 0x6e, 0x6d,
- 0x6d, 0x6c, 0x6b, 0x6a,
- 0x69, 0x68, 0x67, 0x66,
- 0x65, 0x63, 0x62, 0x62,
- 0x60, 0x5f, 0x5d, 0x5c,
- 0x5a, 0x58, 0x56, 0x55,
- 0x53, 0x51, 0x4f, 0x4c,
- 0x4a, 0x48, 0x45, 0x43,
- 0x40, 0x3d, 0x3a, 0x37,
- 0x35, 0x32, 0x2e, 0x2a,
- 0x27, 0x22, 0x1e, 0x1a,
- 0x15, 0x11, 0xc, 0x7,
- 0x1
-};
-
-static uint tas3001c_bass_tab[]={
- 0x86, 0x83, 0x81, 0x7f,
- 0x7d, 0x7b, 0x79, 0x78,
- 0x76, 0x75, 0x74, 0x72,
- 0x71, 0x6f, 0x6e, 0x6d,
- 0x6c, 0x6b, 0x69, 0x67,
- 0x65, 0x64, 0x61, 0x60,
- 0x5e, 0x5d, 0x5c, 0x5b,
- 0x5a, 0x59, 0x58, 0x57,
- 0x56, 0x55, 0x55, 0x54,
- 0x53, 0x52, 0x50, 0x4f,
- 0x4d, 0x4c, 0x4b, 0x49,
- 0x47, 0x45, 0x44, 0x42,
- 0x41, 0x3f, 0x3e, 0x3d,
- 0x3c, 0x3b, 0x39, 0x38,
- 0x37, 0x36, 0x35, 0x34,
- 0x33, 0x31, 0x30, 0x2f,
- 0x2e, 0x2c, 0x2b, 0x2b,
- 0x29, 0x28, 0x27, 0x26,
- 0x25, 0x24, 0x22, 0x21,
- 0x20, 0x1e, 0x1c, 0x19,
- 0x18, 0x18, 0x17, 0x16,
- 0x15, 0x14, 0x13, 0x12,
- 0x11, 0x10, 0xf, 0xe,
- 0xd, 0xb, 0xa, 0x9,
- 0x8, 0x6, 0x4, 0x2,
- 0x1
-};
-
-struct tas_gain_t tas3001c_gain = {
- .master = tas3001c_master_tab,
- .treble = tas3001c_treble_tab,
- .bass = tas3001c_bass_tab,
- .mixer = tas3001c_mixer_tab
-};
-
-struct tas_eq_pref_t *tas3001c_eq_prefs[]={
- &eqp_0e_2_1,
- &eqp_10_1_0,
- &eqp_15_2_1,
- &eqp_15_1_0,
- &eqp_0f_2_1,
- &eqp_0f_1_0,
- NULL
-};
diff --git a/sound/oss/dmasound/tas3004.c b/sound/oss/dmasound/tas3004.c
deleted file mode 100644
index 678bf0ff6da..00000000000
--- a/sound/oss/dmasound/tas3004.c
+++ /dev/null
@@ -1,1138 +0,0 @@
-/*
- * Driver for the i2c/i2s based TA3004 sound chip used
- * on some Apple hardware. Also known as "snapper".
- *
- * Tobias Sargeant <tobias.sargeant@bigpond.com>
- * Based upon tas3001c.c by Christopher C. Chimelis <chris@debian.org>:
- *
- * Input support by Renzo Davoli <renzo@cs.unibo.it>
- *
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/proc_fs.h>
-#include <linux/ioport.h>
-#include <linux/sysctl.h>
-#include <linux/types.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/soundcard.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-
-#include <asm/uaccess.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-
-#include "dmasound.h"
-#include "tas_common.h"
-#include "tas3004.h"
-
-#include "tas_ioctl.h"
-
-/* #define DEBUG_DRCE */
-
-#define TAS3004_BIQUAD_FILTER_COUNT 7
-#define TAS3004_BIQUAD_CHANNEL_COUNT 2
-
-#define VOL_DEFAULT (100 * 4 / 5)
-#define INPUT_DEFAULT (100 * 4 / 5)
-#define BASS_DEFAULT (100 / 2)
-#define TREBLE_DEFAULT (100 / 2)
-
-struct tas3004_data_t {
- struct tas_data_t super;
- int device_id;
- int output_id;
- int speaker_id;
- struct tas_drce_t drce_state;
- struct work_struct change;
-};
-
-#define MAKE_TIME(sec,usec) (((sec)<<12) + (50000+(usec/10)*(1<<12))/100000)
-
-#define MAKE_RATIO(i,f) (((i)<<8) + ((500+(f)*(1<<8))/1000))
-
-
-static const union tas_biquad_t tas3004_eq_unity = {
- .buf = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 },
-};
-
-
-static const struct tas_drce_t tas3004_drce_min = {
- .enable = 1,
- .above = { .val = MAKE_RATIO(16,0), .expand = 0 },
- .below = { .val = MAKE_RATIO(2,0), .expand = 0 },
- .threshold = -0x59a0,
- .energy = MAKE_TIME(0, 1700),
- .attack = MAKE_TIME(0, 1700),
- .decay = MAKE_TIME(0, 1700),
-};
-
-
-static const struct tas_drce_t tas3004_drce_max = {
- .enable = 1,
- .above = { .val = MAKE_RATIO(1,500), .expand = 1 },
- .below = { .val = MAKE_RATIO(2,0), .expand = 1 },
- .threshold = -0x0,
- .energy = MAKE_TIME(2,400000),
- .attack = MAKE_TIME(2,400000),
- .decay = MAKE_TIME(2,400000),
-};
-
-
-static const unsigned short time_constants[]={
- MAKE_TIME(0, 1700),
- MAKE_TIME(0, 3500),
- MAKE_TIME(0, 6700),
- MAKE_TIME(0, 13000),
- MAKE_TIME(0, 26000),
- MAKE_TIME(0, 53000),
- MAKE_TIME(0,106000),
- MAKE_TIME(0,212000),
- MAKE_TIME(0,425000),
- MAKE_TIME(0,850000),
- MAKE_TIME(1,700000),
- MAKE_TIME(2,400000),
-};
-
-static const unsigned short above_threshold_compression_ratio[]={
- MAKE_RATIO( 1, 70),
- MAKE_RATIO( 1,140),
- MAKE_RATIO( 1,230),
- MAKE_RATIO( 1,330),
- MAKE_RATIO( 1,450),
- MAKE_RATIO( 1,600),
- MAKE_RATIO( 1,780),
- MAKE_RATIO( 2, 0),
- MAKE_RATIO( 2,290),
- MAKE_RATIO( 2,670),
- MAKE_RATIO( 3,200),
- MAKE_RATIO( 4, 0),
- MAKE_RATIO( 5,330),
- MAKE_RATIO( 8, 0),
- MAKE_RATIO(16, 0),
-};
-
-static const unsigned short above_threshold_expansion_ratio[]={
- MAKE_RATIO(1, 60),
- MAKE_RATIO(1,130),
- MAKE_RATIO(1,190),
- MAKE_RATIO(1,250),
- MAKE_RATIO(1,310),
- MAKE_RATIO(1,380),
- MAKE_RATIO(1,440),
- MAKE_RATIO(1,500)
-};
-
-static const unsigned short below_threshold_compression_ratio[]={
- MAKE_RATIO(1, 70),
- MAKE_RATIO(1,140),
- MAKE_RATIO(1,230),
- MAKE_RATIO(1,330),
- MAKE_RATIO(1,450),
- MAKE_RATIO(1,600),
- MAKE_RATIO(1,780),
- MAKE_RATIO(2, 0)
-};
-
-static const unsigned short below_threshold_expansion_ratio[]={
- MAKE_RATIO(1, 60),
- MAKE_RATIO(1,130),
- MAKE_RATIO(1,190),
- MAKE_RATIO(1,250),
- MAKE_RATIO(1,310),
- MAKE_RATIO(1,380),
- MAKE_RATIO(1,440),
- MAKE_RATIO(1,500),
- MAKE_RATIO(1,560),
- MAKE_RATIO(1,630),
- MAKE_RATIO(1,690),
- MAKE_RATIO(1,750),
- MAKE_RATIO(1,810),
- MAKE_RATIO(1,880),
- MAKE_RATIO(1,940),
- MAKE_RATIO(2, 0)
-};
-
-static inline int
-search( unsigned short val,
- const unsigned short *arr,
- const int arrsize) {
- /*
- * This could be a binary search, but for small tables,
- * a linear search is likely to be faster
- */
-
- int i;
-
- for (i=0; i < arrsize; i++)
- if (arr[i] >= val)
- goto _1;
- return arrsize-1;
- _1:
- if (i == 0)
- return 0;
- return (arr[i]-val < val-arr[i-1]) ? i : i-1;
-}
-
-#define SEARCH(a, b) search(a, b, ARRAY_SIZE(b))
-
-static inline int
-time_index(unsigned short time)
-{
- return SEARCH(time, time_constants);
-}
-
-
-static inline int
-above_threshold_compression_index(unsigned short ratio)
-{
- return SEARCH(ratio, above_threshold_compression_ratio);
-}
-
-
-static inline int
-above_threshold_expansion_index(unsigned short ratio)
-{
- return SEARCH(ratio, above_threshold_expansion_ratio);
-}
-
-
-static inline int
-below_threshold_compression_index(unsigned short ratio)
-{
- return SEARCH(ratio, below_threshold_compression_ratio);
-}
-
-
-static inline int
-below_threshold_expansion_index(unsigned short ratio)
-{
- return SEARCH(ratio, below_threshold_expansion_ratio);
-}
-
-static inline unsigned char db_to_regval(short db) {
- int r=0;
-
- r=(db+0x59a0) / 0x60;
-
- if (r < 0x91) return 0x91;
- if (r > 0xef) return 0xef;
- return r;
-}
-
-static inline short quantize_db(short db)
-{
- return db_to_regval(db) * 0x60 - 0x59a0;
-}
-
-static inline int
-register_width(enum tas3004_reg_t r)
-{
- switch(r) {
- case TAS3004_REG_MCR:
- case TAS3004_REG_TREBLE:
- case TAS3004_REG_BASS:
- case TAS3004_REG_ANALOG_CTRL:
- case TAS3004_REG_TEST1:
- case TAS3004_REG_TEST2:
- case TAS3004_REG_MCR2:
- return 1;
-
- case TAS3004_REG_LEFT_LOUD_BIQUAD_GAIN:
- case TAS3004_REG_RIGHT_LOUD_BIQUAD_GAIN:
- return 3;
-
- case TAS3004_REG_DRC:
- case TAS3004_REG_VOLUME:
- return 6;
-
- case TAS3004_REG_LEFT_MIXER:
- case TAS3004_REG_RIGHT_MIXER:
- return 9;
-
- case TAS3004_REG_TEST:
- return 10;
-
- case TAS3004_REG_LEFT_BIQUAD0:
- case TAS3004_REG_LEFT_BIQUAD1:
- case TAS3004_REG_LEFT_BIQUAD2:
- case TAS3004_REG_LEFT_BIQUAD3:
- case TAS3004_REG_LEFT_BIQUAD4:
- case TAS3004_REG_LEFT_BIQUAD5:
- case TAS3004_REG_LEFT_BIQUAD6:
-
- case TAS3004_REG_RIGHT_BIQUAD0:
- case TAS3004_REG_RIGHT_BIQUAD1:
- case TAS3004_REG_RIGHT_BIQUAD2:
- case TAS3004_REG_RIGHT_BIQUAD3:
- case TAS3004_REG_RIGHT_BIQUAD4:
- case TAS3004_REG_RIGHT_BIQUAD5:
- case TAS3004_REG_RIGHT_BIQUAD6:
-
- case TAS3004_REG_LEFT_LOUD_BIQUAD:
- case TAS3004_REG_RIGHT_LOUD_BIQUAD:
- return 15;
-
- default:
- return 0;
- }
-}
-
-static int
-tas3004_write_register( struct tas3004_data_t *self,
- enum tas3004_reg_t reg_num,
- char *data,
- uint write_mode)
-{
- if (reg_num==TAS3004_REG_MCR ||
- reg_num==TAS3004_REG_BASS ||
- reg_num==TAS3004_REG_TREBLE ||
- reg_num==TAS3004_REG_ANALOG_CTRL) {
- return tas_write_byte_register(&self->super,
- (uint)reg_num,
- *data,
- write_mode);
- } else {
- return tas_write_register(&self->super,
- (uint)reg_num,
- register_width(reg_num),
- data,
- write_mode);
- }
-}
-
-static int
-tas3004_sync_register( struct tas3004_data_t *self,
- enum tas3004_reg_t reg_num)
-{
- if (reg_num==TAS3004_REG_MCR ||
- reg_num==TAS3004_REG_BASS ||
- reg_num==TAS3004_REG_TREBLE ||
- reg_num==TAS3004_REG_ANALOG_CTRL) {
- return tas_sync_byte_register(&self->super,
- (uint)reg_num,
- register_width(reg_num));
- } else {
- return tas_sync_register(&self->super,
- (uint)reg_num,
- register_width(reg_num));
- }
-}
-
-static int
-tas3004_read_register( struct tas3004_data_t *self,
- enum tas3004_reg_t reg_num,
- char *data,
- uint write_mode)
-{
- return tas_read_register(&self->super,
- (uint)reg_num,
- register_width(reg_num),
- data);
-}
-
-static inline int
-tas3004_fast_load(struct tas3004_data_t *self, int fast)
-{
- if (fast)
- self->super.shadow[TAS3004_REG_MCR][0] |= 0x80;
- else
- self->super.shadow[TAS3004_REG_MCR][0] &= 0x7f;
- return tas3004_sync_register(self,TAS3004_REG_MCR);
-}
-
-static uint
-tas3004_supported_mixers(struct tas3004_data_t *self)
-{
- return SOUND_MASK_VOLUME |
- SOUND_MASK_PCM |
- SOUND_MASK_ALTPCM |
- SOUND_MASK_IMIX |
- SOUND_MASK_TREBLE |
- SOUND_MASK_BASS |
- SOUND_MASK_MIC |
- SOUND_MASK_LINE;
-}
-
-static int
-tas3004_mixer_is_stereo(struct tas3004_data_t *self, int mixer)
-{
- switch(mixer) {
- case SOUND_MIXER_VOLUME:
- case SOUND_MIXER_PCM:
- case SOUND_MIXER_ALTPCM:
- case SOUND_MIXER_IMIX:
- return 1;
- default:
- return 0;
- }
-}
-
-static uint
-tas3004_stereo_mixers(struct tas3004_data_t *self)
-{
- uint r = tas3004_supported_mixers(self);
- uint i;
-
- for (i=1; i<SOUND_MIXER_NRDEVICES; i++)
- if (r&(1<<i) && !tas3004_mixer_is_stereo(self,i))
- r &= ~(1<<i);
- return r;
-}
-
-static int
-tas3004_get_mixer_level(struct tas3004_data_t *self, int mixer, uint *level)
-{
- if (!self)
- return -1;
-
- *level = self->super.mixer[mixer];
-
- return 0;
-}
-
-static int
-tas3004_set_mixer_level(struct tas3004_data_t *self, int mixer, uint level)
-{
- int rc;
- tas_shadow_t *shadow;
- uint temp;
- uint offset=0;
-
- if (!self)
- return -1;
-
- shadow = self->super.shadow;
-
- if (!tas3004_mixer_is_stereo(self,mixer))
- level = tas_mono_to_stereo(level);
- switch(mixer) {
- case SOUND_MIXER_VOLUME:
- temp = tas3004_gain.master[level&0xff];
- SET_4_20(shadow[TAS3004_REG_VOLUME], 0, temp);
- temp = tas3004_gain.master[(level>>8)&0xff];
- SET_4_20(shadow[TAS3004_REG_VOLUME], 3, temp);
- rc = tas3004_sync_register(self,TAS3004_REG_VOLUME);
- break;
- case SOUND_MIXER_IMIX:
- offset += 3;
- case SOUND_MIXER_ALTPCM:
- offset += 3;
- case SOUND_MIXER_PCM:
- /*
- * Don't load these in fast mode. The documentation
- * says it can be done in either mode, but testing it
- * shows that fast mode produces ugly clicking.
- */
- /* tas3004_fast_load(self,1); */
- temp = tas3004_gain.mixer[level&0xff];
- SET_4_20(shadow[TAS3004_REG_LEFT_MIXER], offset, temp);
- temp = tas3004_gain.mixer[(level>>8)&0xff];
- SET_4_20(shadow[TAS3004_REG_RIGHT_MIXER], offset, temp);
- rc = tas3004_sync_register(self,TAS3004_REG_LEFT_MIXER);
- if (rc == 0)
- rc=tas3004_sync_register(self,TAS3004_REG_RIGHT_MIXER);
- /* tas3004_fast_load(self,0); */
- break;
- case SOUND_MIXER_TREBLE:
- temp = tas3004_gain.treble[level&0xff];
- shadow[TAS3004_REG_TREBLE][0]=temp&0xff;
- rc = tas3004_sync_register(self,TAS3004_REG_TREBLE);
- break;
- case SOUND_MIXER_BASS:
- temp = tas3004_gain.bass[level&0xff];
- shadow[TAS3004_REG_BASS][0]=temp&0xff;
- rc = tas3004_sync_register(self,TAS3004_REG_BASS);
- break;
- case SOUND_MIXER_MIC:
- if ((level&0xff)>0) {
- software_input_volume = SW_INPUT_VOLUME_SCALE * (level&0xff);
- if (self->super.mixer[mixer] == 0) {
- self->super.mixer[SOUND_MIXER_LINE] = 0;
- shadow[TAS3004_REG_ANALOG_CTRL][0]=0xc2;
- rc = tas3004_sync_register(self,TAS3004_REG_ANALOG_CTRL);
- } else rc=0;
- } else {
- self->super.mixer[SOUND_MIXER_LINE] = SW_INPUT_VOLUME_DEFAULT;
- software_input_volume = SW_INPUT_VOLUME_SCALE *
- (self->super.mixer[SOUND_MIXER_LINE]&0xff);
- shadow[TAS3004_REG_ANALOG_CTRL][0]=0x00;
- rc = tas3004_sync_register(self,TAS3004_REG_ANALOG_CTRL);
- }
- break;
- case SOUND_MIXER_LINE:
- if (self->super.mixer[SOUND_MIXER_MIC] == 0) {
- software_input_volume = SW_INPUT_VOLUME_SCALE * (level&0xff);
- rc=0;
- }
- break;
- default:
- rc = -1;
- break;
- }
- if (rc < 0)
- return rc;
- self->super.mixer[mixer] = level;
-
- return 0;
-}
-
-static int
-tas3004_leave_sleep(struct tas3004_data_t *self)
-{
- unsigned char mcr = (1<<6)+(2<<4)+(2<<2);
-
- if (!self)
- return -1;
-
- /* Make sure something answers on the i2c bus */
- if (tas3004_write_register(self, TAS3004_REG_MCR, &mcr,
- WRITE_NORMAL | FORCE_WRITE) < 0)
- return -1;
-
- tas3004_fast_load(self, 1);
-
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD0);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD1);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD2);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD3);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD4);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD5);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD6);
-
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD0);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD1);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD2);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD3);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD4);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD5);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD6);
-
- tas3004_fast_load(self, 0);
-
- (void)tas3004_sync_register(self,TAS3004_REG_VOLUME);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_MIXER);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_MIXER);
- (void)tas3004_sync_register(self,TAS3004_REG_TREBLE);
- (void)tas3004_sync_register(self,TAS3004_REG_BASS);
- (void)tas3004_sync_register(self,TAS3004_REG_ANALOG_CTRL);
-
- return 0;
-}
-
-static int
-tas3004_enter_sleep(struct tas3004_data_t *self)
-{
- if (!self)
- return -1;
- return 0;
-}
-
-static int
-tas3004_sync_biquad( struct tas3004_data_t *self,
- u_int channel,
- u_int filter)
-{
- enum tas3004_reg_t reg;
-
- if (channel >= TAS3004_BIQUAD_CHANNEL_COUNT ||
- filter >= TAS3004_BIQUAD_FILTER_COUNT) return -EINVAL;
-
- reg=( channel ? TAS3004_REG_RIGHT_BIQUAD0 : TAS3004_REG_LEFT_BIQUAD0 ) + filter;
-
- return tas3004_sync_register(self,reg);
-}
-
-static int
-tas3004_write_biquad_shadow( struct tas3004_data_t *self,
- u_int channel,
- u_int filter,
- const union tas_biquad_t *biquad)
-{
- tas_shadow_t *shadow=self->super.shadow;
- enum tas3004_reg_t reg;
-
- if (channel >= TAS3004_BIQUAD_CHANNEL_COUNT ||
- filter >= TAS3004_BIQUAD_FILTER_COUNT) return -EINVAL;
-
- reg=( channel ? TAS3004_REG_RIGHT_BIQUAD0 : TAS3004_REG_LEFT_BIQUAD0 ) + filter;
-
- SET_4_20(shadow[reg], 0,biquad->coeff.b0);
- SET_4_20(shadow[reg], 3,biquad->coeff.b1);
- SET_4_20(shadow[reg], 6,biquad->coeff.b2);
- SET_4_20(shadow[reg], 9,biquad->coeff.a1);
- SET_4_20(shadow[reg],12,biquad->coeff.a2);
-
- return 0;
-}
-
-static int
-tas3004_write_biquad( struct tas3004_data_t *self,
- u_int channel,
- u_int filter,
- const union tas_biquad_t *biquad)
-{
- int rc;
-
- rc=tas3004_write_biquad_shadow(self, channel, filter, biquad);
- if (rc < 0) return rc;
-
- return tas3004_sync_biquad(self, channel, filter);
-}
-
-static int
-tas3004_write_biquad_list( struct tas3004_data_t *self,
- u_int filter_count,
- u_int flags,
- struct tas_biquad_ctrl_t *biquads)
-{
- int i;
- int rc;
-
- if (flags & TAS_BIQUAD_FAST_LOAD) tas3004_fast_load(self,1);
-
- for (i=0; i<filter_count; i++) {
- rc=tas3004_write_biquad(self,
- biquads[i].channel,
- biquads[i].filter,
- &biquads[i].data);
- if (rc < 0) break;
- }
-
- if (flags & TAS_BIQUAD_FAST_LOAD) tas3004_fast_load(self,0);
-
- return rc;
-}
-
-static int
-tas3004_read_biquad( struct tas3004_data_t *self,
- u_int channel,
- u_int filter,
- union tas_biquad_t *biquad)
-{
- tas_shadow_t *shadow=self->super.shadow;
- enum tas3004_reg_t reg;
-
- if (channel >= TAS3004_BIQUAD_CHANNEL_COUNT ||
- filter >= TAS3004_BIQUAD_FILTER_COUNT) return -EINVAL;
-
- reg=( channel ? TAS3004_REG_RIGHT_BIQUAD0 : TAS3004_REG_LEFT_BIQUAD0 ) + filter;
-
- biquad->coeff.b0=GET_4_20(shadow[reg], 0);
- biquad->coeff.b1=GET_4_20(shadow[reg], 3);
- biquad->coeff.b2=GET_4_20(shadow[reg], 6);
- biquad->coeff.a1=GET_4_20(shadow[reg], 9);
- biquad->coeff.a2=GET_4_20(shadow[reg],12);
-
- return 0;
-}
-
-static int
-tas3004_eq_rw( struct tas3004_data_t *self,
- u_int cmd,
- u_long arg)
-{
- void __user *argp = (void __user *)arg;
- int rc;
- struct tas_biquad_ctrl_t biquad;
-
- if (copy_from_user((void *)&biquad, argp, sizeof(struct tas_biquad_ctrl_t))) {
- return -EFAULT;
- }
-
- if (cmd & SIOC_IN) {
- rc=tas3004_write_biquad(self, biquad.channel, biquad.filter, &biquad.data);
- if (rc != 0) return rc;
- }
-
- if (cmd & SIOC_OUT) {
- rc=tas3004_read_biquad(self, biquad.channel, biquad.filter, &biquad.data);
- if (rc != 0) return rc;
-
- if (copy_to_user(argp, &biquad, sizeof(struct tas_biquad_ctrl_t))) {
- return -EFAULT;
- }
-
- }
- return 0;
-}
-
-static int
-tas3004_eq_list_rw( struct tas3004_data_t *self,
- u_int cmd,
- u_long arg)
-{
- int rc = 0;
- int filter_count;
- int flags;
- int i,j;
- char sync_required[TAS3004_BIQUAD_CHANNEL_COUNT][TAS3004_BIQUAD_FILTER_COUNT];
- struct tas_biquad_ctrl_t biquad;
- struct tas_biquad_ctrl_list_t __user *argp = (void __user *)arg;
-
- memset(sync_required,0,sizeof(sync_required));
-
- if (copy_from_user(&filter_count, &argp->filter_count, sizeof(int)))
- return -EFAULT;
-
- if (copy_from_user(&flags, &argp->flags, sizeof(int)))
- return -EFAULT;
-
- if (cmd & SIOC_IN) {
- }
-
- for (i=0; i < filter_count; i++) {
- if (copy_from_user(&biquad, &argp->biquads[i],
- sizeof(struct tas_biquad_ctrl_t))) {
- return -EFAULT;
- }
-
- if (cmd & SIOC_IN) {
- sync_required[biquad.channel][biquad.filter]=1;
- rc=tas3004_write_biquad_shadow(self, biquad.channel, biquad.filter, &biquad.data);
- if (rc != 0) return rc;
- }
-
- if (cmd & SIOC_OUT) {
- rc=tas3004_read_biquad(self, biquad.channel, biquad.filter, &biquad.data);
- if (rc != 0) return rc;
-
- if (copy_to_user(&argp->biquads[i], &biquad,
- sizeof(struct tas_biquad_ctrl_t))) {
- return -EFAULT;
- }
- }
- }
-
- if (cmd & SIOC_IN) {
- /*
- * This is OK for the tas3004. For the
- * tas3001c, going into fast load mode causes
- * the treble and bass to be reset to 0dB, and
- * volume controls to be muted.
- */
- if (flags & TAS_BIQUAD_FAST_LOAD) tas3004_fast_load(self,1);
- for (i=0; i<TAS3004_BIQUAD_CHANNEL_COUNT; i++) {
- for (j=0; j<TAS3004_BIQUAD_FILTER_COUNT; j++) {
- if (sync_required[i][j]) {
- rc=tas3004_sync_biquad(self, i, j);
- if (rc < 0) goto out;
- }
- }
- }
- out:
- if (flags & TAS_BIQUAD_FAST_LOAD)
- tas3004_fast_load(self,0);
- }
-
- return rc;
-}
-
-static int
-tas3004_update_drce( struct tas3004_data_t *self,
- int flags,
- struct tas_drce_t *drce)
-{
- tas_shadow_t *shadow;
- int i;
- shadow=self->super.shadow;
-
- if (flags & TAS_DRCE_ABOVE_RATIO) {
- self->drce_state.above.expand = drce->above.expand;
- if (drce->above.val == (1<<8)) {
- self->drce_state.above.val = 1<<8;
- shadow[TAS3004_REG_DRC][0] = 0x02;
-
- } else if (drce->above.expand) {
- i=above_threshold_expansion_index(drce->above.val);
- self->drce_state.above.val=above_threshold_expansion_ratio[i];
- shadow[TAS3004_REG_DRC][0] = 0x0a + (i<<3);
- } else {
- i=above_threshold_compression_index(drce->above.val);
- self->drce_state.above.val=above_threshold_compression_ratio[i];
- shadow[TAS3004_REG_DRC][0] = 0x08 + (i<<3);
- }
- }
-
- if (flags & TAS_DRCE_BELOW_RATIO) {
- self->drce_state.below.expand = drce->below.expand;
- if (drce->below.val == (1<<8)) {
- self->drce_state.below.val = 1<<8;
- shadow[TAS3004_REG_DRC][1] = 0x02;
-
- } else if (drce->below.expand) {
- i=below_threshold_expansion_index(drce->below.val);
- self->drce_state.below.val=below_threshold_expansion_ratio[i];
- shadow[TAS3004_REG_DRC][1] = 0x08 + (i<<3);
- } else {
- i=below_threshold_compression_index(drce->below.val);
- self->drce_state.below.val=below_threshold_compression_ratio[i];
- shadow[TAS3004_REG_DRC][1] = 0x0a + (i<<3);
- }
- }
-
- if (flags & TAS_DRCE_THRESHOLD) {
- self->drce_state.threshold=quantize_db(drce->threshold);
- shadow[TAS3004_REG_DRC][2] = db_to_regval(self->drce_state.threshold);
- }
-
- if (flags & TAS_DRCE_ENERGY) {
- i=time_index(drce->energy);
- self->drce_state.energy=time_constants[i];
- shadow[TAS3004_REG_DRC][3] = 0x40 + (i<<4);
- }
-
- if (flags & TAS_DRCE_ATTACK) {
- i=time_index(drce->attack);
- self->drce_state.attack=time_constants[i];
- shadow[TAS3004_REG_DRC][4] = 0x40 + (i<<4);
- }
-
- if (flags & TAS_DRCE_DECAY) {
- i=time_index(drce->decay);
- self->drce_state.decay=time_constants[i];
- shadow[TAS3004_REG_DRC][5] = 0x40 + (i<<4);
- }
-
- if (flags & TAS_DRCE_ENABLE) {
- self->drce_state.enable = drce->enable;
- }
-
- if (!self->drce_state.enable) {
- shadow[TAS3004_REG_DRC][0] |= 0x01;
- }
-
-#ifdef DEBUG_DRCE
- printk("DRCE: set [ ENABLE:%x ABOVE:%x/%x BELOW:%x/%x THRESH:%x ENERGY:%x ATTACK:%x DECAY:%x\n",
- self->drce_state.enable,
- self->drce_state.above.expand,self->drce_state.above.val,
- self->drce_state.below.expand,self->drce_state.below.val,
- self->drce_state.threshold,
- self->drce_state.energy,
- self->drce_state.attack,
- self->drce_state.decay);
-
- printk("DRCE: reg [ %02x %02x %02x %02x %02x %02x ]\n",
- (unsigned char)shadow[TAS3004_REG_DRC][0],
- (unsigned char)shadow[TAS3004_REG_DRC][1],
- (unsigned char)shadow[TAS3004_REG_DRC][2],
- (unsigned char)shadow[TAS3004_REG_DRC][3],
- (unsigned char)shadow[TAS3004_REG_DRC][4],
- (unsigned char)shadow[TAS3004_REG_DRC][5]);
-#endif
-
- return tas3004_sync_register(self, TAS3004_REG_DRC);
-}
-
-static int
-tas3004_drce_rw( struct tas3004_data_t *self,
- u_int cmd,
- u_long arg)
-{
- int rc;
- struct tas_drce_ctrl_t drce_ctrl;
- void __user *argp = (void __user *)arg;
-
- if (copy_from_user(&drce_ctrl, argp, sizeof(struct tas_drce_ctrl_t)))
- return -EFAULT;
-
-#ifdef DEBUG_DRCE
- printk("DRCE: input [ FLAGS:%x ENABLE:%x ABOVE:%x/%x BELOW:%x/%x THRESH:%x ENERGY:%x ATTACK:%x DECAY:%x\n",
- drce_ctrl.flags,
- drce_ctrl.data.enable,
- drce_ctrl.data.above.expand,drce_ctrl.data.above.val,
- drce_ctrl.data.below.expand,drce_ctrl.data.below.val,
- drce_ctrl.data.threshold,
- drce_ctrl.data.energy,
- drce_ctrl.data.attack,
- drce_ctrl.data.decay);
-#endif
-
- if (cmd & SIOC_IN) {
- rc = tas3004_update_drce(self, drce_ctrl.flags, &drce_ctrl.data);
- if (rc < 0) return rc;
- }
-
- if (cmd & SIOC_OUT) {
- if (drce_ctrl.flags & TAS_DRCE_ENABLE)
- drce_ctrl.data.enable = self->drce_state.enable;
- if (drce_ctrl.flags & TAS_DRCE_ABOVE_RATIO)
- drce_ctrl.data.above = self->drce_state.above;
- if (drce_ctrl.flags & TAS_DRCE_BELOW_RATIO)
- drce_ctrl.data.below = self->drce_state.below;
- if (drce_ctrl.flags & TAS_DRCE_THRESHOLD)
- drce_ctrl.data.threshold = self->drce_state.threshold;
- if (drce_ctrl.flags & TAS_DRCE_ENERGY)
- drce_ctrl.data.energy = self->drce_state.energy;
- if (drce_ctrl.flags & TAS_DRCE_ATTACK)
- drce_ctrl.data.attack = self->drce_state.attack;
- if (drce_ctrl.flags & TAS_DRCE_DECAY)
- drce_ctrl.data.decay = self->drce_state.decay;
-
- if (copy_to_user(argp, &drce_ctrl,
- sizeof(struct tas_drce_ctrl_t))) {
- return -EFAULT;
- }
- }
-
- return 0;
-}
-
-static void
-tas3004_update_device_parameters(struct tas3004_data_t *self)
-{
- char data;
- int i;
-
- if (!self) return;
-
- if (self->output_id == TAS_OUTPUT_HEADPHONES) {
- /* turn on allPass when headphones are plugged in */
- data = 0x02;
- } else {
- data = 0x00;
- }
-
- tas3004_write_register(self, TAS3004_REG_MCR2, &data, WRITE_NORMAL | FORCE_WRITE);
-
- for (i=0; tas3004_eq_prefs[i]; i++) {
- struct tas_eq_pref_t *eq = tas3004_eq_prefs[i];
-
- if (eq->device_id == self->device_id &&
- (eq->output_id == 0 || eq->output_id == self->output_id) &&
- (eq->speaker_id == 0 || eq->speaker_id == self->speaker_id)) {
-
- tas3004_update_drce(self, TAS_DRCE_ALL, eq->drce);
- tas3004_write_biquad_list(self, eq->filter_count, TAS_BIQUAD_FAST_LOAD, eq->biquads);
-
- break;
- }
- }
-}
-
-static void
-tas3004_device_change_handler(struct work_struct *work)
-{
- struct tas3004_data_t *self;
- self = container_of(work, struct tas3004_data_t, change);
- tas3004_update_device_parameters(self);
-}
-
-static int
-tas3004_output_device_change( struct tas3004_data_t *self,
- int device_id,
- int output_id,
- int speaker_id)
-{
- self->device_id=device_id;
- self->output_id=output_id;
- self->speaker_id=speaker_id;
-
- schedule_work(&self->change);
-
- return 0;
-}
-
-static int
-tas3004_device_ioctl( struct tas3004_data_t *self,
- u_int cmd,
- u_long arg)
-{
- uint __user *argp = (void __user *)arg;
- switch (cmd) {
- case TAS_READ_EQ:
- case TAS_WRITE_EQ:
- return tas3004_eq_rw(self, cmd, arg);
-
- case TAS_READ_EQ_LIST:
- case TAS_WRITE_EQ_LIST:
- return tas3004_eq_list_rw(self, cmd, arg);
-
- case TAS_READ_EQ_FILTER_COUNT:
- put_user(TAS3004_BIQUAD_FILTER_COUNT, argp);
- return 0;
-
- case TAS_READ_EQ_CHANNEL_COUNT:
- put_user(TAS3004_BIQUAD_CHANNEL_COUNT, argp);
- return 0;
-
- case TAS_READ_DRCE:
- case TAS_WRITE_DRCE:
- return tas3004_drce_rw(self, cmd, arg);
-
- case TAS_READ_DRCE_CAPS:
- put_user(TAS_DRCE_ENABLE |
- TAS_DRCE_ABOVE_RATIO |
- TAS_DRCE_BELOW_RATIO |
- TAS_DRCE_THRESHOLD |
- TAS_DRCE_ENERGY |
- TAS_DRCE_ATTACK |
- TAS_DRCE_DECAY,
- argp);
- return 0;
-
- case TAS_READ_DRCE_MIN:
- case TAS_READ_DRCE_MAX: {
- struct tas_drce_ctrl_t drce_ctrl;
- const struct tas_drce_t *drce_copy;
-
- if (copy_from_user(&drce_ctrl, argp,
- sizeof(struct tas_drce_ctrl_t))) {
- return -EFAULT;
- }
-
- if (cmd == TAS_READ_DRCE_MIN) {
- drce_copy=&tas3004_drce_min;
- } else {
- drce_copy=&tas3004_drce_max;
- }
-
- if (drce_ctrl.flags & TAS_DRCE_ABOVE_RATIO) {
- drce_ctrl.data.above=drce_copy->above;
- }
- if (drce_ctrl.flags & TAS_DRCE_BELOW_RATIO) {
- drce_ctrl.data.below=drce_copy->below;
- }
- if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) {
- drce_ctrl.data.threshold=drce_copy->threshold;
- }
- if (drce_ctrl.flags & TAS_DRCE_ENERGY) {
- drce_ctrl.data.energy=drce_copy->energy;
- }
- if (drce_ctrl.flags & TAS_DRCE_ATTACK) {
- drce_ctrl.data.attack=drce_copy->attack;
- }
- if (drce_ctrl.flags & TAS_DRCE_DECAY) {
- drce_ctrl.data.decay=drce_copy->decay;
- }
-
- if (copy_to_user(argp, &drce_ctrl,
- sizeof(struct tas_drce_ctrl_t))) {
- return -EFAULT;
- }
- }
- }
-
- return -EINVAL;
-}
-
-static int
-tas3004_init_mixer(struct tas3004_data_t *self)
-{
- unsigned char mcr = (1<<6)+(2<<4)+(2<<2);
-
- /* Make sure something answers on the i2c bus */
- if (tas3004_write_register(self, TAS3004_REG_MCR, &mcr,
- WRITE_NORMAL | FORCE_WRITE) < 0)
- return -1;
-
- tas3004_fast_load(self, 1);
-
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD0);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD1);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD2);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD3);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD4);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD5);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD6);
-
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD0);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD1);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD2);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD3);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD4);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD5);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD6);
-
- tas3004_sync_register(self, TAS3004_REG_DRC);
-
- tas3004_sync_register(self, TAS3004_REG_MCR2);
-
- tas3004_fast_load(self, 0);
-
- tas3004_set_mixer_level(self, SOUND_MIXER_VOLUME, VOL_DEFAULT<<8 | VOL_DEFAULT);
- tas3004_set_mixer_level(self, SOUND_MIXER_PCM, INPUT_DEFAULT<<8 | INPUT_DEFAULT);
- tas3004_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0);
- tas3004_set_mixer_level(self, SOUND_MIXER_IMIX, 0);
-
- tas3004_set_mixer_level(self, SOUND_MIXER_BASS, BASS_DEFAULT);
- tas3004_set_mixer_level(self, SOUND_MIXER_TREBLE, TREBLE_DEFAULT);
-
- tas3004_set_mixer_level(self, SOUND_MIXER_LINE,SW_INPUT_VOLUME_DEFAULT);
-
- return 0;
-}
-
-static int
-tas3004_uninit_mixer(struct tas3004_data_t *self)
-{
- tas3004_set_mixer_level(self, SOUND_MIXER_VOLUME, 0);
- tas3004_set_mixer_level(self, SOUND_MIXER_PCM, 0);
- tas3004_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0);
- tas3004_set_mixer_level(self, SOUND_MIXER_IMIX, 0);
-
- tas3004_set_mixer_level(self, SOUND_MIXER_BASS, 0);
- tas3004_set_mixer_level(self, SOUND_MIXER_TREBLE, 0);
-
- tas3004_set_mixer_level(self, SOUND_MIXER_LINE, 0);
-
- return 0;
-}
-
-static int
-tas3004_init(struct i2c_client *client)
-{
- struct tas3004_data_t *self;
- size_t sz = sizeof(*self) + (TAS3004_REG_MAX*sizeof(tas_shadow_t));
- char drce_init[] = { 0x69, 0x22, 0x9f, 0xb0, 0x60, 0xa0 };
- char mcr2 = 0;
- int i, j;
-
- self = kzalloc(sz, GFP_KERNEL);
- if (!self)
- return -ENOMEM;
-
- self->super.client = client;
- self->super.shadow = (tas_shadow_t *)(self+1);
- self->output_id = TAS_OUTPUT_HEADPHONES;
-
- dev_set_drvdata(&client->dev, self);
-
- for (i = 0; i < TAS3004_BIQUAD_CHANNEL_COUNT; i++)
- for (j = 0; j<TAS3004_BIQUAD_FILTER_COUNT; j++)
- tas3004_write_biquad_shadow(self, i, j,
- &tas3004_eq_unity);
-
- tas3004_write_register(self, TAS3004_REG_MCR2, &mcr2, WRITE_SHADOW);
- tas3004_write_register(self, TAS3004_REG_DRC, drce_init, WRITE_SHADOW);
-
- INIT_WORK(&self->change, tas3004_device_change_handler);
- return 0;
-}
-
-static void
-tas3004_uninit(struct tas3004_data_t *self)
-{
- tas3004_uninit_mixer(self);
- kfree(self);
-}
-
-
-struct tas_driver_hooks_t tas3004_hooks = {
- .init = (tas_hook_init_t)tas3004_init,
- .post_init = (tas_hook_post_init_t)tas3004_init_mixer,
- .uninit = (tas_hook_uninit_t)tas3004_uninit,
- .get_mixer_level = (tas_hook_get_mixer_level_t)tas3004_get_mixer_level,
- .set_mixer_level = (tas_hook_set_mixer_level_t)tas3004_set_mixer_level,
- .enter_sleep = (tas_hook_enter_sleep_t)tas3004_enter_sleep,
- .leave_sleep = (tas_hook_leave_sleep_t)tas3004_leave_sleep,
- .supported_mixers = (tas_hook_supported_mixers_t)tas3004_supported_mixers,
- .mixer_is_stereo = (tas_hook_mixer_is_stereo_t)tas3004_mixer_is_stereo,
- .stereo_mixers = (tas_hook_stereo_mixers_t)tas3004_stereo_mixers,
- .output_device_change = (tas_hook_output_device_change_t)tas3004_output_device_change,
- .device_ioctl = (tas_hook_device_ioctl_t)tas3004_device_ioctl
-};
diff --git a/sound/oss/dmasound/tas3004.h b/sound/oss/dmasound/tas3004.h
deleted file mode 100644
index c6d584bf2ca..00000000000
--- a/sound/oss/dmasound/tas3004.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Header file for the i2c/i2s based TA3004 sound chip used
- * on some Apple hardware. Also known as "tumbler".
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- *
- * Written by Christopher C. Chimelis <chris@debian.org>
- */
-
-#ifndef _TAS3004_H_
-#define _TAS3004_H_
-
-#include <linux/types.h>
-
-#include "tas_common.h"
-#include "tas_eq_prefs.h"
-
-/*
- * Macros that correspond to the registers that we write to
- * when setting the various values.
- */
-
-#define TAS3004_VERSION "0.3"
-#define TAS3004_DATE "20011214"
-
-#define I2C_DRIVERNAME_TAS3004 "TAS3004 driver V " TAS3004_VERSION
-#define I2C_DRIVERID_TAS3004 (I2C_DRIVERID_TAS_BASE+1)
-
-extern struct tas_driver_hooks_t tas3004_hooks;
-extern struct tas_gain_t tas3004_gain;
-extern struct tas_eq_pref_t *tas3004_eq_prefs[];
-
-enum tas3004_reg_t {
- TAS3004_REG_MCR = 0x01,
- TAS3004_REG_DRC = 0x02,
-
- TAS3004_REG_VOLUME = 0x04,
- TAS3004_REG_TREBLE = 0x05,
- TAS3004_REG_BASS = 0x06,
- TAS3004_REG_LEFT_MIXER = 0x07,
- TAS3004_REG_RIGHT_MIXER = 0x08,
-
- TAS3004_REG_LEFT_BIQUAD0 = 0x0a,
- TAS3004_REG_LEFT_BIQUAD1 = 0x0b,
- TAS3004_REG_LEFT_BIQUAD2 = 0x0c,
- TAS3004_REG_LEFT_BIQUAD3 = 0x0d,
- TAS3004_REG_LEFT_BIQUAD4 = 0x0e,
- TAS3004_REG_LEFT_BIQUAD5 = 0x0f,
- TAS3004_REG_LEFT_BIQUAD6 = 0x10,
-
- TAS3004_REG_RIGHT_BIQUAD0 = 0x13,
- TAS3004_REG_RIGHT_BIQUAD1 = 0x14,
- TAS3004_REG_RIGHT_BIQUAD2 = 0x15,
- TAS3004_REG_RIGHT_BIQUAD3 = 0x16,
- TAS3004_REG_RIGHT_BIQUAD4 = 0x17,
- TAS3004_REG_RIGHT_BIQUAD5 = 0x18,
- TAS3004_REG_RIGHT_BIQUAD6 = 0x19,
-
- TAS3004_REG_LEFT_LOUD_BIQUAD = 0x21,
- TAS3004_REG_RIGHT_LOUD_BIQUAD = 0x22,
-
- TAS3004_REG_LEFT_LOUD_BIQUAD_GAIN = 0x23,
- TAS3004_REG_RIGHT_LOUD_BIQUAD_GAIN = 0x24,
-
- TAS3004_REG_TEST = 0x29,
-
- TAS3004_REG_ANALOG_CTRL = 0x40,
- TAS3004_REG_TEST1 = 0x41,
- TAS3004_REG_TEST2 = 0x42,
- TAS3004_REG_MCR2 = 0x43,
-
- TAS3004_REG_MAX = 0x44
-};
-
-#endif /* _TAS3004_H_ */
diff --git a/sound/oss/dmasound/tas3004_tables.c b/sound/oss/dmasound/tas3004_tables.c
deleted file mode 100644
index b910e0a6677..00000000000
--- a/sound/oss/dmasound/tas3004_tables.c
+++ /dev/null
@@ -1,301 +0,0 @@
-#include "tas3004.h"
-#include "tas_eq_prefs.h"
-
-static struct tas_drce_t eqp_17_1_0_drce={
- .enable = 1,
- .above = { .val = 3.0 * (1<<8), .expand = 0 },
- .below = { .val = 1.0 * (1<<8), .expand = 0 },
- .threshold = -19.12 * (1<<8),
- .energy = 2.4 * (1<<12),
- .attack = 0.013 * (1<<12),
- .decay = 0.212 * (1<<12),
-};
-
-static struct tas_biquad_ctrl_t eqp_17_1_0_biquads[]={
- { .channel = 0, .filter = 0, .data = { .coeff = { 0x0fd0d4, 0xe05e56, 0x0fd0d4, 0xe05ee1, 0x0fa234 } } },
- { .channel = 0, .filter = 1, .data = { .coeff = { 0x0910d7, 0x088e1a, 0x030651, 0x01dcb1, 0x02c892 } } },
- { .channel = 0, .filter = 2, .data = { .coeff = { 0x0ff895, 0xe0970b, 0x0f7f00, 0xe0970b, 0x0f7795 } } },
- { .channel = 0, .filter = 3, .data = { .coeff = { 0x0fd1c4, 0xe1ac22, 0x0ec8cf, 0xe1ac22, 0x0e9a94 } } },
- { .channel = 0, .filter = 4, .data = { .coeff = { 0x0f7c1c, 0xe3cc03, 0x0df786, 0xe3cc03, 0x0d73a2 } } },
- { .channel = 0, .filter = 5, .data = { .coeff = { 0x11fb92, 0xf5a1a0, 0x073cd2, 0xf5a1a0, 0x093865 } } },
- { .channel = 0, .filter = 6, .data = { .coeff = { 0x0e17a9, 0x068b6c, 0x08a0e5, 0x068b6c, 0x06b88e } } },
-
- { .channel = 1, .filter = 0, .data = { .coeff = { 0x0fd0d4, 0xe05e56, 0x0fd0d4, 0xe05ee1, 0x0fa234 } } },
- { .channel = 1, .filter = 1, .data = { .coeff = { 0x0910d7, 0x088e1a, 0x030651, 0x01dcb1, 0x02c892 } } },
- { .channel = 1, .filter = 2, .data = { .coeff = { 0x0ff895, 0xe0970b, 0x0f7f00, 0xe0970b, 0x0f7795 } } },
- { .channel = 1, .filter = 3, .data = { .coeff = { 0x0fd1c4, 0xe1ac22, 0x0ec8cf, 0xe1ac22, 0x0e9a94 } } },
- { .channel = 1, .filter = 4, .data = { .coeff = { 0x0f7c1c, 0xe3cc03, 0x0df786, 0xe3cc03, 0x0d73a2 } } },
- { .channel = 1, .filter = 5, .data = { .coeff = { 0x11fb92, 0xf5a1a0, 0x073cd2, 0xf5a1a0, 0x093865 } } },
- { .channel = 1, .filter = 6, .data = { .coeff = { 0x0e17a9, 0x068b6c, 0x08a0e5, 0x068b6c, 0x06b88e } } }
-};
-
-static struct tas_eq_pref_t eqp_17_1_0 = {
- .sample_rate = 44100,
- .device_id = 0x17,
- .output_id = TAS_OUTPUT_INTERNAL_SPKR,
- .speaker_id = 0x00,
-
- .drce = &eqp_17_1_0_drce,
-
- .filter_count = 14,
- .biquads = eqp_17_1_0_biquads
-};
-
-/* ======================================================================== */
-
-static struct tas_drce_t eqp_18_1_0_drce={
- .enable = 1,
- .above = { .val = 3.0 * (1<<8), .expand = 0 },
- .below = { .val = 1.0 * (1<<8), .expand = 0 },
- .threshold = -13.14 * (1<<8),
- .energy = 2.4 * (1<<12),
- .attack = 0.013 * (1<<12),
- .decay = 0.212 * (1<<12),
-};
-
-static struct tas_biquad_ctrl_t eqp_18_1_0_biquads[]={
- { .channel = 0, .filter = 0, .data = { .coeff = { 0x0f5514, 0xe155d7, 0x0f5514, 0xe15cfa, 0x0eb14b } } },
- { .channel = 0, .filter = 1, .data = { .coeff = { 0x06ec33, 0x02abe3, 0x015eef, 0xf764d9, 0x03922d } } },
- { .channel = 0, .filter = 2, .data = { .coeff = { 0x0ef5f2, 0xe67d1f, 0x0bcf37, 0xe67d1f, 0x0ac529 } } },
- { .channel = 0, .filter = 3, .data = { .coeff = { 0x0db050, 0xe5be4d, 0x0d0c78, 0xe5be4d, 0x0abcc8 } } },
- { .channel = 0, .filter = 4, .data = { .coeff = { 0x0f1298, 0xe64ec6, 0x0cc03e, 0xe64ec6, 0x0bd2d7 } } },
- { .channel = 0, .filter = 5, .data = { .coeff = { 0x0c641a, 0x06537a, 0x08d155, 0x06537a, 0x053570 } } },
- { .channel = 0, .filter = 6, .data = { .coeff = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } },
-
- { .channel = 1, .filter = 0, .data = { .coeff = { 0x0f5514, 0xe155d7, 0x0f5514, 0xe15cfa, 0x0eb14b } } },
- { .channel = 1, .filter = 1, .data = { .coeff = { 0x06ec33, 0x02abe3, 0x015eef, 0xf764d9, 0x03922d } } },
- { .channel = 1, .filter = 2, .data = { .coeff = { 0x0ef5f2, 0xe67d1f, 0x0bcf37, 0xe67d1f, 0x0ac529 } } },
- { .channel = 1, .filter = 3, .data = { .coeff = { 0x0db050, 0xe5be4d, 0x0d0c78, 0xe5be4d, 0x0abcc8 } } },
- { .channel = 1, .filter = 4, .data = { .coeff = { 0x0f1298, 0xe64ec6, 0x0cc03e, 0xe64ec6, 0x0bd2d7 } } },
- { .channel = 1, .filter = 5, .data = { .coeff = { 0x0c641a, 0x06537a, 0x08d155, 0x06537a, 0x053570 } } },
- { .channel = 1, .filter = 6, .data = { .coeff = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } }
-};
-
-static struct tas_eq_pref_t eqp_18_1_0 = {
- .sample_rate = 44100,
- .device_id = 0x18,
- .output_id = TAS_OUTPUT_INTERNAL_SPKR,
- .speaker_id = 0x00,
-
- .drce = &eqp_18_1_0_drce,
-
- .filter_count = 14,
- .biquads = eqp_18_1_0_biquads
-};
-
-/* ======================================================================== */
-
-static struct tas_drce_t eqp_1a_1_0_drce={
- .enable = 1,
- .above = { .val = 3.0 * (1<<8), .expand = 0 },
- .below = { .val = 1.0 * (1<<8), .expand = 0 },
- .threshold = -10.75 * (1<<8),
- .energy = 2.4 * (1<<12),
- .attack = 0.013 * (1<<12),
- .decay = 0.212 * (1<<12),
-};
-
-static struct tas_biquad_ctrl_t eqp_1a_1_0_biquads[]={
- { .channel = 0, .filter = 0, .data = { .coeff = { 0x0fb8fd, 0xe08e04, 0x0fb8fd, 0xe08f40, 0x0f7336 } } },
- { .channel = 0, .filter = 1, .data = { .coeff = { 0x06371d, 0x0c6e3a, 0x06371d, 0x05bfd3, 0x031ca2 } } },
- { .channel = 0, .filter = 2, .data = { .coeff = { 0x0fa1c0, 0xe18692, 0x0f030e, 0xe18692, 0x0ea4ce } } },
- { .channel = 0, .filter = 3, .data = { .coeff = { 0x0fe495, 0xe17eff, 0x0f0452, 0xe17eff, 0x0ee8e7 } } },
- { .channel = 0, .filter = 4, .data = { .coeff = { 0x100857, 0xe7e71c, 0x0e9599, 0xe7e71c, 0x0e9df1 } } },
- { .channel = 0, .filter = 5, .data = { .coeff = { 0x0fb26e, 0x06a82c, 0x0db2b4, 0x06a82c, 0x0d6522 } } },
- { .channel = 0, .filter = 6, .data = { .coeff = { 0x11419d, 0xf06cbf, 0x0a4f6e, 0xf06cbf, 0x0b910c } } },
-
- { .channel = 1, .filter = 0, .data = { .coeff = { 0x0fb8fd, 0xe08e04, 0x0fb8fd, 0xe08f40, 0x0f7336 } } },
- { .channel = 1, .filter = 1, .data = { .coeff = { 0x06371d, 0x0c6e3a, 0x06371d, 0x05bfd3, 0x031ca2 } } },
- { .channel = 1, .filter = 2, .data = { .coeff = { 0x0fa1c0, 0xe18692, 0x0f030e, 0xe18692, 0x0ea4ce } } },
- { .channel = 1, .filter = 3, .data = { .coeff = { 0x0fe495, 0xe17eff, 0x0f0452, 0xe17eff, 0x0ee8e7 } } },
- { .channel = 1, .filter = 4, .data = { .coeff = { 0x100857, 0xe7e71c, 0x0e9599, 0xe7e71c, 0x0e9df1 } } },
- { .channel = 1, .filter = 5, .data = { .coeff = { 0x0fb26e, 0x06a82c, 0x0db2b4, 0x06a82c, 0x0d6522 } } },
- { .channel = 1, .filter = 6, .data = { .coeff = { 0x11419d, 0xf06cbf, 0x0a4f6e, 0xf06cbf, 0x0b910c } } }
-};
-
-static struct tas_eq_pref_t eqp_1a_1_0 = {
- .sample_rate = 44100,
- .device_id = 0x1a,
- .output_id = TAS_OUTPUT_INTERNAL_SPKR,
- .speaker_id = 0x00,
-
- .drce = &eqp_1a_1_0_drce,
-
- .filter_count = 14,
- .biquads = eqp_1a_1_0_biquads
-};
-
-/* ======================================================================== */
-
-static struct tas_drce_t eqp_1c_1_0_drce={
- .enable = 1,
- .above = { .val = 3.0 * (1<<8), .expand = 0 },
- .below = { .val = 1.0 * (1<<8), .expand = 0 },
- .threshold = -14.34 * (1<<8),
- .energy = 2.4 * (1<<12),
- .attack = 0.013 * (1<<12),
- .decay = 0.212 * (1<<12),
-};
-
-static struct tas_biquad_ctrl_t eqp_1c_1_0_biquads[]={
- { .channel = 0, .filter = 0, .data = { .coeff = { 0x0f4f95, 0xe160d4, 0x0f4f95, 0xe1686e, 0x0ea6c5 } } },
- { .channel = 0, .filter = 1, .data = { .coeff = { 0x066b92, 0x0290d4, 0x0148a0, 0xf6853f, 0x03bfc7 } } },
- { .channel = 0, .filter = 2, .data = { .coeff = { 0x0f57dc, 0xe51c91, 0x0dd1cb, 0xe51c91, 0x0d29a8 } } },
- { .channel = 0, .filter = 3, .data = { .coeff = { 0x0df1cb, 0xe4fa84, 0x0d7cdc, 0xe4fa84, 0x0b6ea7 } } },
- { .channel = 0, .filter = 4, .data = { .coeff = { 0x0eba36, 0xe6aa48, 0x0b9f52, 0xe6aa48, 0x0a5989 } } },
- { .channel = 0, .filter = 5, .data = { .coeff = { 0x0caf02, 0x05ef9d, 0x084beb, 0x05ef9d, 0x04faee } } },
- { .channel = 0, .filter = 6, .data = { .coeff = { 0x0fc686, 0xe22947, 0x0e4b5d, 0xe22947, 0x0e11e4 } } },
-
- { .channel = 1, .filter = 0, .data = { .coeff = { 0x0f4f95, 0xe160d4, 0x0f4f95, 0xe1686e, 0x0ea6c5 } } },
- { .channel = 1, .filter = 1, .data = { .coeff = { 0x066b92, 0x0290d4, 0x0148a0, 0xf6853f, 0x03bfc7 } } },
- { .channel = 1, .filter = 2, .data = { .coeff = { 0x0f57dc, 0xe51c91, 0x0dd1cb, 0xe51c91, 0x0d29a8 } } },
- { .channel = 1, .filter = 3, .data = { .coeff = { 0x0df1cb, 0xe4fa84, 0x0d7cdc, 0xe4fa84, 0x0b6ea7 } } },
- { .channel = 1, .filter = 4, .data = { .coeff = { 0x0eba36, 0xe6aa48, 0x0b9f52, 0xe6aa48, 0x0a5989 } } },
- { .channel = 1, .filter = 5, .data = { .coeff = { 0x0caf02, 0x05ef9d, 0x084beb, 0x05ef9d, 0x04faee } } },
- { .channel = 1, .filter = 6, .data = { .coeff = { 0x0fc686, 0xe22947, 0x0e4b5d, 0xe22947, 0x0e11e4 } } }
-};
-
-static struct tas_eq_pref_t eqp_1c_1_0 = {
- .sample_rate = 44100,
- .device_id = 0x1c,
- .output_id = TAS_OUTPUT_INTERNAL_SPKR,
- .speaker_id = 0x00,
-
- .drce = &eqp_1c_1_0_drce,
-
- .filter_count = 14,
- .biquads = eqp_1c_1_0_biquads
-};
-
-/* ======================================================================== */
-
-static uint tas3004_master_tab[]={
- 0x0, 0x75, 0x9c, 0xbb,
- 0xdb, 0xfb, 0x11e, 0x143,
- 0x16b, 0x196, 0x1c3, 0x1f5,
- 0x229, 0x263, 0x29f, 0x2e1,
- 0x328, 0x373, 0x3c5, 0x41b,
- 0x478, 0x4dc, 0x547, 0x5b8,
- 0x633, 0x6b5, 0x740, 0x7d5,
- 0x873, 0x91c, 0x9d2, 0xa92,
- 0xb5e, 0xc39, 0xd22, 0xe19,
- 0xf20, 0x1037, 0x1161, 0x129e,
- 0x13ed, 0x1551, 0x16ca, 0x185d,
- 0x1a08, 0x1bcc, 0x1dac, 0x1fa7,
- 0x21c1, 0x23fa, 0x2655, 0x28d6,
- 0x2b7c, 0x2e4a, 0x3141, 0x3464,
- 0x37b4, 0x3b35, 0x3ee9, 0x42d3,
- 0x46f6, 0x4b53, 0x4ff0, 0x54ce,
- 0x59f2, 0x5f5f, 0x6519, 0x6b24,
- 0x7183, 0x783c, 0x7f53, 0x86cc,
- 0x8ead, 0x96fa, 0x9fba, 0xa8f2,
- 0xb2a7, 0xbce1, 0xc7a5, 0xd2fa,
- 0xdee8, 0xeb75, 0xf8aa, 0x1068e,
- 0x1152a, 0x12487, 0x134ad, 0x145a5,
- 0x1577b, 0x16a37, 0x17df5, 0x192bd,
- 0x1a890, 0x1bf7b, 0x1d78d, 0x1f0d1,
- 0x20b55, 0x22727, 0x24456, 0x262f2,
- 0x2830b
-};
-
-static uint tas3004_mixer_tab[]={
- 0x0, 0x748, 0x9be, 0xbaf,
- 0xda4, 0xfb1, 0x11de, 0x1431,
- 0x16ad, 0x1959, 0x1c37, 0x1f4b,
- 0x2298, 0x2628, 0x29fb, 0x2e12,
- 0x327d, 0x3734, 0x3c47, 0x41b4,
- 0x4787, 0x4dbe, 0x546d, 0x5b86,
- 0x632e, 0x6b52, 0x7400, 0x7d54,
- 0x873b, 0x91c6, 0x9d1a, 0xa920,
- 0xb5e5, 0xc38c, 0xd21b, 0xe18f,
- 0xf1f5, 0x1036a, 0x1160f, 0x129d6,
- 0x13ed0, 0x1550c, 0x16ca0, 0x185c9,
- 0x1a07b, 0x1bcc3, 0x1dab9, 0x1fa75,
- 0x21c0f, 0x23fa3, 0x26552, 0x28d64,
- 0x2b7c9, 0x2e4a2, 0x31411, 0x3463b,
- 0x37b44, 0x3b353, 0x3ee94, 0x42d30,
- 0x46f55, 0x4b533, 0x4fefc, 0x54ce5,
- 0x59f25, 0x5f5f6, 0x65193, 0x6b23c,
- 0x71835, 0x783c3, 0x7f52c, 0x86cc0,
- 0x8eacc, 0x96fa5, 0x9fba0, 0xa8f1a,
- 0xb2a71, 0xbce0a, 0xc7a4a, 0xd2fa0,
- 0xdee7b, 0xeb752, 0xf8a9f, 0x1068e4,
- 0x1152a3, 0x12486a, 0x134ac8, 0x145a55,
- 0x1577ac, 0x16a370, 0x17df51, 0x192bc2,
- 0x1a88f8, 0x1bf7b7, 0x1d78c9, 0x1f0d04,
- 0x20b542, 0x227268, 0x244564, 0x262f26,
- 0x2830af
-};
-
-static uint tas3004_treble_tab[]={
- 0x96, 0x95, 0x95, 0x94,
- 0x93, 0x92, 0x92, 0x91,
- 0x90, 0x90, 0x8f, 0x8e,
- 0x8d, 0x8d, 0x8c, 0x8b,
- 0x8a, 0x8a, 0x89, 0x88,
- 0x88, 0x87, 0x86, 0x85,
- 0x85, 0x84, 0x83, 0x83,
- 0x82, 0x81, 0x80, 0x80,
- 0x7f, 0x7e, 0x7e, 0x7d,
- 0x7c, 0x7b, 0x7b, 0x7a,
- 0x79, 0x78, 0x78, 0x77,
- 0x76, 0x76, 0x75, 0x74,
- 0x73, 0x73, 0x72, 0x71,
- 0x71, 0x68, 0x45, 0x5b,
- 0x6d, 0x6c, 0x6b, 0x6a,
- 0x69, 0x68, 0x67, 0x66,
- 0x65, 0x63, 0x62, 0x62,
- 0x60, 0x5e, 0x5c, 0x5b,
- 0x59, 0x57, 0x55, 0x53,
- 0x52, 0x4f, 0x4d, 0x4a,
- 0x48, 0x46, 0x43, 0x40,
- 0x3d, 0x3a, 0x36, 0x33,
- 0x2f, 0x2c, 0x27, 0x23,
- 0x1f, 0x1a, 0x15, 0xf,
- 0x8, 0x5, 0x2, 0x1,
- 0x1
-};
-
-static uint tas3004_bass_tab[]={
- 0x96, 0x95, 0x95, 0x94,
- 0x93, 0x92, 0x92, 0x91,
- 0x90, 0x90, 0x8f, 0x8e,
- 0x8d, 0x8d, 0x8c, 0x8b,
- 0x8a, 0x8a, 0x89, 0x88,
- 0x88, 0x87, 0x86, 0x85,
- 0x85, 0x84, 0x83, 0x83,
- 0x82, 0x81, 0x80, 0x80,
- 0x7f, 0x7e, 0x7e, 0x7d,
- 0x7c, 0x7b, 0x7b, 0x7a,
- 0x79, 0x78, 0x78, 0x77,
- 0x76, 0x76, 0x75, 0x74,
- 0x73, 0x73, 0x72, 0x71,
- 0x70, 0x6f, 0x6e, 0x6d,
- 0x6c, 0x6b, 0x6a, 0x6a,
- 0x69, 0x67, 0x66, 0x66,
- 0x65, 0x63, 0x62, 0x62,
- 0x61, 0x60, 0x5e, 0x5d,
- 0x5b, 0x59, 0x57, 0x55,
- 0x53, 0x51, 0x4f, 0x4c,
- 0x4a, 0x48, 0x46, 0x44,
- 0x41, 0x3e, 0x3b, 0x38,
- 0x36, 0x33, 0x2f, 0x2b,
- 0x28, 0x24, 0x20, 0x1c,
- 0x17, 0x12, 0xd, 0x7,
- 0x1
-};
-
-struct tas_gain_t tas3004_gain={
- .master = tas3004_master_tab,
- .treble = tas3004_treble_tab,
- .bass = tas3004_bass_tab,
- .mixer = tas3004_mixer_tab
-};
-
-struct tas_eq_pref_t *tas3004_eq_prefs[]={
- &eqp_17_1_0,
- &eqp_18_1_0,
- &eqp_1a_1_0,
- &eqp_1c_1_0,
- NULL
-};
diff --git a/sound/oss/dmasound/tas_common.c b/sound/oss/dmasound/tas_common.c
deleted file mode 100644
index b295ef68219..00000000000
--- a/sound/oss/dmasound/tas_common.c
+++ /dev/null
@@ -1,214 +0,0 @@
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/proc_fs.h>
-#include <linux/ioport.h>
-#include <linux/sysctl.h>
-#include <linux/types.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/soundcard.h>
-#include <asm/uaccess.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-
-#include "tas_common.h"
-
-#define CALL0(proc) \
- do { \
- struct tas_data_t *self; \
- if (!tas_client || driver_hooks == NULL) \
- return -1; \
- self = dev_get_drvdata(&tas_client->dev); \
- if (driver_hooks->proc) \
- return driver_hooks->proc(self); \
- else \
- return -EINVAL; \
- } while (0)
-
-#define CALL(proc,arg...) \
- do { \
- struct tas_data_t *self; \
- if (!tas_client || driver_hooks == NULL) \
- return -1; \
- self = dev_get_drvdata(&tas_client->dev); \
- if (driver_hooks->proc) \
- return driver_hooks->proc(self, ## arg); \
- else \
- return -EINVAL; \
- } while (0)
-
-
-static u8 tas_i2c_address = 0x34;
-static struct i2c_client *tas_client;
-
-static int tas_attach_adapter(struct i2c_adapter *);
-static int tas_detach_client(struct i2c_client *);
-
-struct i2c_driver tas_driver = {
- .driver = {
- .name = "tas",
- },
- .attach_adapter = tas_attach_adapter,
- .detach_client = tas_detach_client,
-};
-
-struct tas_driver_hooks_t *driver_hooks;
-
-int
-tas_register_driver(struct tas_driver_hooks_t *hooks)
-{
- driver_hooks = hooks;
- return 0;
-}
-
-int
-tas_get_mixer_level(int mixer, uint *level)
-{
- CALL(get_mixer_level,mixer,level);
-}
-
-int
-tas_set_mixer_level(int mixer,uint level)
-{
- CALL(set_mixer_level,mixer,level);
-}
-
-int
-tas_enter_sleep(void)
-{
- CALL0(enter_sleep);
-}
-
-int
-tas_leave_sleep(void)
-{
- CALL0(leave_sleep);
-}
-
-int
-tas_supported_mixers(void)
-{
- CALL0(supported_mixers);
-}
-
-int
-tas_mixer_is_stereo(int mixer)
-{
- CALL(mixer_is_stereo,mixer);
-}
-
-int
-tas_stereo_mixers(void)
-{
- CALL0(stereo_mixers);
-}
-
-int
-tas_output_device_change(int device_id,int layout_id,int speaker_id)
-{
- CALL(output_device_change,device_id,layout_id,speaker_id);
-}
-
-int
-tas_device_ioctl(u_int cmd, u_long arg)
-{
- CALL(device_ioctl,cmd,arg);
-}
-
-int
-tas_post_init(void)
-{
- CALL0(post_init);
-}
-
-static int
-tas_detect_client(struct i2c_adapter *adapter, int address)
-{
- static const char *client_name = "tas Digital Equalizer";
- struct i2c_client *new_client;
- int rc = -ENODEV;
-
- if (!driver_hooks) {
- printk(KERN_ERR "tas_detect_client called with no hooks !\n");
- return -ENODEV;
- }
-
- new_client = kzalloc(sizeof(*new_client), GFP_KERNEL);
- if (!new_client)
- return -ENOMEM;
-
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &tas_driver;
- strlcpy(new_client->name, client_name, DEVICE_NAME_SIZE);
-
- if (driver_hooks->init(new_client))
- goto bail;
-
- /* Tell the i2c layer a new client has arrived */
- if (i2c_attach_client(new_client)) {
- driver_hooks->uninit(dev_get_drvdata(&new_client->dev));
- goto bail;
- }
-
- tas_client = new_client;
- return 0;
- bail:
- tas_client = NULL;
- kfree(new_client);
- return rc;
-}
-
-static int
-tas_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!strncmp(adapter->name, "mac-io", 6))
- return tas_detect_client(adapter, tas_i2c_address);
- return 0;
-}
-
-static int
-tas_detach_client(struct i2c_client *client)
-{
- if (client == tas_client) {
- driver_hooks->uninit(dev_get_drvdata(&client->dev));
-
- i2c_detach_client(client);
- kfree(client);
- }
- return 0;
-}
-
-void
-tas_cleanup(void)
-{
- i2c_del_driver(&tas_driver);
-}
-
-int __init
-tas_init(int driver_id, const char *driver_name)
-{
- const u32* paddr;
- struct device_node *tas_node;
-
- printk(KERN_INFO "tas driver [%s])\n", driver_name);
-
-#ifndef CONFIG_I2C_POWERMAC
- request_module("i2c-powermac");
-#endif
- tas_node = of_find_node_by_name("deq");
- if (tas_node == NULL)
- return -ENODEV;
- paddr = of_get_property(tas_node, "i2c-address", NULL);
- if (paddr) {
- tas_i2c_address = (*paddr) >> 1;
- printk(KERN_INFO "using i2c address: 0x%x from device-tree\n",
- tas_i2c_address);
- } else
- printk(KERN_INFO "using i2c address: 0x%x (default)\n",
- tas_i2c_address);
- of_node_put(tas_node);
-
- return i2c_add_driver(&tas_driver);
-}
diff --git a/sound/oss/dmasound/tas_common.h b/sound/oss/dmasound/tas_common.h
deleted file mode 100644
index 0741c28e56c..00000000000
--- a/sound/oss/dmasound/tas_common.h
+++ /dev/null
@@ -1,284 +0,0 @@
-#ifndef _TAS_COMMON_H_
-#define _TAS_COMMON_H_
-
-#include <linux/i2c.h>
-#include <linux/soundcard.h>
-#include <asm/string.h>
-
-#define I2C_DRIVERID_TAS_BASE (0xFEBA)
-
-#define SET_4_20(shadow, offset, val) \
- do { \
- (shadow)[(offset)+0] = ((val) >> 16) & 0xff; \
- (shadow)[(offset)+1] = ((val) >> 8) & 0xff; \
- (shadow)[(offset)+2] = ((val) >> 0) & 0xff; \
- } while (0)
-
-#define GET_4_20(shadow, offset) \
- (((u_int)((shadow)[(offset)+0]) << 16) | \
- ((u_int)((shadow)[(offset)+1]) << 8) | \
- ((u_int)((shadow)[(offset)+2]) << 0))
-
-
-#define TAS_BIQUAD_FAST_LOAD 0x01
-
-#define TAS_DRCE_ENABLE 0x01
-#define TAS_DRCE_ABOVE_RATIO 0x02
-#define TAS_DRCE_BELOW_RATIO 0x04
-#define TAS_DRCE_THRESHOLD 0x08
-#define TAS_DRCE_ENERGY 0x10
-#define TAS_DRCE_ATTACK 0x20
-#define TAS_DRCE_DECAY 0x40
-
-#define TAS_DRCE_ALL 0x7f
-
-
-#define TAS_OUTPUT_HEADPHONES 0x00
-#define TAS_OUTPUT_INTERNAL_SPKR 0x01
-#define TAS_OUTPUT_EXTERNAL_SPKR 0x02
-
-
-union tas_biquad_t {
- struct {
- int b0,b1,b2,a1,a2;
- } coeff;
- int buf[5];
-};
-
-struct tas_biquad_ctrl_t {
- u_int channel:4;
- u_int filter:4;
-
- union tas_biquad_t data;
-};
-
-struct tas_biquad_ctrl_list_t {
- int flags;
- int filter_count;
- struct tas_biquad_ctrl_t biquads[0];
-};
-
-struct tas_ratio_t {
- unsigned short val; /* 8.8 */
- unsigned short expand; /* 0 = compress, !0 = expand. */
-};
-
-struct tas_drce_t {
- unsigned short enable;
- struct tas_ratio_t above;
- struct tas_ratio_t below;
- short threshold; /* dB, 8.8 signed */
- unsigned short energy; /* seconds, 4.12 unsigned */
- unsigned short attack; /* seconds, 4.12 unsigned */
- unsigned short decay; /* seconds, 4.12 unsigned */
-};
-
-struct tas_drce_ctrl_t {
- uint flags;
-
- struct tas_drce_t data;
-};
-
-struct tas_gain_t
-{
- unsigned int *master;
- unsigned int *treble;
- unsigned int *bass;
- unsigned int *mixer;
-};
-
-typedef char tas_shadow_t[0x45];
-
-struct tas_data_t
-{
- struct i2c_client *client;
- tas_shadow_t *shadow;
- uint mixer[SOUND_MIXER_NRDEVICES];
-};
-
-typedef int (*tas_hook_init_t)(struct i2c_client *);
-typedef int (*tas_hook_post_init_t)(struct tas_data_t *);
-typedef void (*tas_hook_uninit_t)(struct tas_data_t *);
-
-typedef int (*tas_hook_get_mixer_level_t)(struct tas_data_t *,int,uint *);
-typedef int (*tas_hook_set_mixer_level_t)(struct tas_data_t *,int,uint);
-
-typedef int (*tas_hook_enter_sleep_t)(struct tas_data_t *);
-typedef int (*tas_hook_leave_sleep_t)(struct tas_data_t *);
-
-typedef int (*tas_hook_supported_mixers_t)(struct tas_data_t *);
-typedef int (*tas_hook_mixer_is_stereo_t)(struct tas_data_t *,int);
-typedef int (*tas_hook_stereo_mixers_t)(struct tas_data_t *);
-
-typedef int (*tas_hook_output_device_change_t)(struct tas_data_t *,int,int,int);
-typedef int (*tas_hook_device_ioctl_t)(struct tas_data_t *,u_int,u_long);
-
-struct tas_driver_hooks_t {
- /*
- * All hardware initialisation must be performed in
- * post_init(), as tas_dmasound_init() does a hardware reset.
- *
- * init() is called before tas_dmasound_init() so that
- * ouput_device_change() is always called after i2c driver
- * initialisation. The implication is that
- * output_device_change() must cope with the fact that it
- * may be called before post_init().
- */
-
- tas_hook_init_t init;
- tas_hook_post_init_t post_init;
- tas_hook_uninit_t uninit;
-
- tas_hook_get_mixer_level_t get_mixer_level;
- tas_hook_set_mixer_level_t set_mixer_level;
-
- tas_hook_enter_sleep_t enter_sleep;
- tas_hook_leave_sleep_t leave_sleep;
-
- tas_hook_supported_mixers_t supported_mixers;
- tas_hook_mixer_is_stereo_t mixer_is_stereo;
- tas_hook_stereo_mixers_t stereo_mixers;
-
- tas_hook_output_device_change_t output_device_change;
- tas_hook_device_ioctl_t device_ioctl;
-};
-
-enum tas_write_mode_t {
- WRITE_HW = 0x01,
- WRITE_SHADOW = 0x02,
- WRITE_NORMAL = 0x03,
- FORCE_WRITE = 0x04
-};
-
-static inline uint
-tas_mono_to_stereo(uint mono)
-{
- mono &=0xff;
- return mono | (mono<<8);
-}
-
-/*
- * Todo: make these functions a bit more efficient !
- */
-static inline int
-tas_write_register( struct tas_data_t *self,
- uint reg_num,
- uint reg_width,
- char *data,
- uint write_mode)
-{
- int rc;
-
- if (reg_width==0 || data==NULL || self==NULL)
- return -EINVAL;
- if (!(write_mode & FORCE_WRITE) &&
- !memcmp(data,self->shadow[reg_num],reg_width))
- return 0;
-
- if (write_mode & WRITE_SHADOW)
- memcpy(self->shadow[reg_num],data,reg_width);
- if (write_mode & WRITE_HW) {
- rc=i2c_smbus_write_i2c_block_data(self->client,
- reg_num,
- reg_width,
- data);
- if (rc < 0) {
- printk("tas: I2C block write failed \n");
- return rc;
- }
- }
- return 0;
-}
-
-static inline int
-tas_sync_register( struct tas_data_t *self,
- uint reg_num,
- uint reg_width)
-{
- int rc;
-
- if (reg_width==0 || self==NULL)
- return -EINVAL;
- rc=i2c_smbus_write_i2c_block_data(self->client,
- reg_num,
- reg_width,
- self->shadow[reg_num]);
- if (rc < 0) {
- printk("tas: I2C block write failed \n");
- return rc;
- }
- return 0;
-}
-
-static inline int
-tas_write_byte_register( struct tas_data_t *self,
- uint reg_num,
- char data,
- uint write_mode)
-{
- if (self==NULL)
- return -1;
- if (!(write_mode & FORCE_WRITE) && data != self->shadow[reg_num][0])
- return 0;
- if (write_mode & WRITE_SHADOW)
- self->shadow[reg_num][0]=data;
- if (write_mode & WRITE_HW) {
- if (i2c_smbus_write_byte_data(self->client, reg_num, data) < 0) {
- printk("tas: I2C byte write failed \n");
- return -1;
- }
- }
- return 0;
-}
-
-static inline int
-tas_sync_byte_register( struct tas_data_t *self,
- uint reg_num,
- uint reg_width)
-{
- if (reg_width==0 || self==NULL)
- return -1;
- if (i2c_smbus_write_byte_data(
- self->client, reg_num, self->shadow[reg_num][0]) < 0) {
- printk("tas: I2C byte write failed \n");
- return -1;
- }
- return 0;
-}
-
-static inline int
-tas_read_register( struct tas_data_t *self,
- uint reg_num,
- uint reg_width,
- char *data)
-{
- if (reg_width==0 || data==NULL || self==NULL)
- return -1;
- memcpy(data,self->shadow[reg_num],reg_width);
- return 0;
-}
-
-extern int tas_register_driver(struct tas_driver_hooks_t *hooks);
-
-extern int tas_get_mixer_level(int mixer,uint *level);
-extern int tas_set_mixer_level(int mixer,uint level);
-extern int tas_enter_sleep(void);
-extern int tas_leave_sleep(void);
-extern int tas_supported_mixers(void);
-extern int tas_mixer_is_stereo(int mixer);
-extern int tas_stereo_mixers(void);
-extern int tas_output_device_change(int,int,int);
-extern int tas_device_ioctl(u_int, u_long);
-
-extern void tas_cleanup(void);
-extern int tas_init(int driver_id,const char *driver_name);
-extern int tas_post_init(void);
-
-#endif /* _TAS_COMMON_H_ */
-/*
- * Local Variables:
- * tab-width: 8
- * indent-tabs-mode: t
- * c-basic-offset: 8
- * End:
- */
diff --git a/sound/oss/dmasound/tas_eq_prefs.h b/sound/oss/dmasound/tas_eq_prefs.h
deleted file mode 100644
index 3a994eda6ab..00000000000
--- a/sound/oss/dmasound/tas_eq_prefs.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef _TAS_EQ_PREFS_H_
-#define _TAS_EQ_PREFS_H_
-
-struct tas_eq_pref_t {
- u_int sample_rate;
- u_int device_id;
- u_int output_id;
- u_int speaker_id;
-
- struct tas_drce_t *drce;
-
- u_int filter_count;
- struct tas_biquad_ctrl_t *biquads;
-};
-
-#endif /* _TAS_EQ_PREFS_H_ */
-
-/*
- * Local Variables:
- * tab-width: 8
- * indent-tabs-mode: t
- * c-basic-offset: 8
- * End:
- */
diff --git a/sound/oss/dmasound/tas_ioctl.h b/sound/oss/dmasound/tas_ioctl.h
deleted file mode 100644
index 9d12b373b4a..00000000000
--- a/sound/oss/dmasound/tas_ioctl.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef _TAS_IOCTL_H_
-#define _TAS_IOCTL_H_
-
-#include <linux/soundcard.h>
-
-
-#define TAS_READ_EQ _SIOR('t',0,struct tas_biquad_ctrl_t)
-#define TAS_WRITE_EQ _SIOW('t',0,struct tas_biquad_ctrl_t)
-
-#define TAS_READ_EQ_LIST _SIOR('t',1,struct tas_biquad_ctrl_t)
-#define TAS_WRITE_EQ_LIST _SIOW('t',1,struct tas_biquad_ctrl_t)
-
-#define TAS_READ_EQ_FILTER_COUNT _SIOR('t',2,int)
-#define TAS_READ_EQ_CHANNEL_COUNT _SIOR('t',3,int)
-
-#define TAS_READ_DRCE _SIOR('t',4,struct tas_drce_ctrl_t)
-#define TAS_WRITE_DRCE _SIOW('t',4,struct tas_drce_ctrl_t)
-
-#define TAS_READ_DRCE_CAPS _SIOR('t',5,int)
-#define TAS_READ_DRCE_MIN _SIOR('t',6,int)
-#define TAS_READ_DRCE_MAX _SIOR('t',7,int)
-
-#endif
diff --git a/sound/oss/dmasound/trans_16.c b/sound/oss/dmasound/trans_16.c
deleted file mode 100644
index ca973ac2a30..00000000000
--- a/sound/oss/dmasound/trans_16.c
+++ /dev/null
@@ -1,898 +0,0 @@
-/*
- * linux/sound/oss/dmasound/trans_16.c
- *
- * 16 bit translation routines. Only used by Power mac at present.
- *
- * See linux/sound/oss/dmasound/dmasound_core.c for copyright and
- * history prior to 08/02/2001.
- *
- * 08/02/2001 Iain Sandoe
- * split from dmasound_awacs.c
- * 11/29/2003 Renzo Davoli (King Enzo)
- * - input resampling (for soft rate < hard rate)
- * - software line in gain control
- */
-
-#include <linux/soundcard.h>
-#include <asm/uaccess.h>
-#include "dmasound.h"
-
-extern int expand_bal; /* Balance factor for expanding (not volume!) */
-static short dmasound_alaw2dma16[] ;
-static short dmasound_ulaw2dma16[] ;
-
-static ssize_t pmac_ct_law(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ct_s8(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ct_u8(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ct_s16(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ct_u16(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-
-static ssize_t pmac_ctx_law(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ctx_s8(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ctx_u8(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ctx_s16(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ctx_u16(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-
-static ssize_t pmac_ct_s16_read(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ct_u16_read(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-
-/*** Translations ************************************************************/
-
-static int expand_data; /* Data for expanding */
-
-static ssize_t pmac_ct_law(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- short *table = dmasound.soft.format == AFMT_MU_LAW
- ? dmasound_ulaw2dma16 : dmasound_alaw2dma16;
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = dmasound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min_t(unsigned long, userCount, frameLeft);
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = table[data];
- *p++ = val;
- if (stereo) {
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = table[data];
- }
- *p++ = val;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_s8(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = dmasound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min_t(unsigned long, userCount, frameLeft);
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = data << 8;
- *p++ = val;
- if (stereo) {
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = data << 8;
- }
- *p++ = val;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_u8(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = dmasound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min_t(unsigned long, userCount, frameLeft);
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = (data ^ 0x80) << 8;
- *p++ = val;
- if (stereo) {
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = (data ^ 0x80) << 8;
- }
- *p++ = val;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_s16(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- int stereo = dmasound.soft.stereo;
- short *fp = (short *) &frame[*frameUsed];
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- used = count = min_t(unsigned long, userCount, frameLeft);
- if (!stereo) {
- short __user *up = (short __user *) userPtr;
- while (count > 0) {
- short data;
- if (get_user(data, up++))
- return -EFAULT;
- *fp++ = data;
- *fp++ = data;
- count--;
- }
- } else {
- if (copy_from_user(fp, userPtr, count * 4))
- return -EFAULT;
- }
- *frameUsed += used * 4;
- return stereo? used * 4: used * 2;
-}
-
-static ssize_t pmac_ct_u16(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
- int stereo = dmasound.soft.stereo;
- short *fp = (short *) &frame[*frameUsed];
- short __user *up = (short __user *) userPtr;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- used = count = min_t(unsigned long, userCount, frameLeft);
- while (count > 0) {
- short data;
- if (get_user(data, up++))
- return -EFAULT;
- data ^= mask;
- *fp++ = data;
- if (stereo) {
- if (get_user(data, up++))
- return -EFAULT;
- data ^= mask;
- }
- *fp++ = data;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 4: used * 2;
-}
-
-
-static ssize_t pmac_ctx_law(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- unsigned short *table = (unsigned short *)
- (dmasound.soft.format == AFMT_MU_LAW
- ? dmasound_ulaw2dma16 : dmasound_alaw2dma16);
- unsigned int data = expand_data;
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- int bal = expand_bal;
- int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
- int utotal, ftotal;
- int stereo = dmasound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- u_char c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = table[c];
- if (stereo) {
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = (data << 16) + table[c];
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- expand_bal = bal;
- expand_data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 2: utotal;
-}
-
-static ssize_t pmac_ctx_s8(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- unsigned int data = expand_data;
- int bal = expand_bal;
- int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
- int stereo = dmasound.soft.stereo;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- u_char c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = c << 8;
- if (stereo) {
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = (data << 16) + (c << 8);
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- expand_bal = bal;
- expand_data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t pmac_ctx_u8(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- unsigned int data = expand_data;
- int bal = expand_bal;
- int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
- int stereo = dmasound.soft.stereo;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- u_char c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = (c ^ 0x80) << 8;
- if (stereo) {
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = (data << 16) + ((c ^ 0x80) << 8);
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- expand_bal = bal;
- expand_data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t pmac_ctx_s16(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- unsigned int data = expand_data;
- unsigned short __user *up = (unsigned short __user *) userPtr;
- int bal = expand_bal;
- int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
- int stereo = dmasound.soft.stereo;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- unsigned short c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(data, up++))
- return -EFAULT;
- if (stereo) {
- if (get_user(c, up++))
- return -EFAULT;
- data = (data << 16) + c;
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- expand_bal = bal;
- expand_data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 4: utotal * 2;
-}
-
-
-static ssize_t pmac_ctx_u16(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- unsigned int data = expand_data;
- unsigned short __user *up = (unsigned short __user *) userPtr;
- int bal = expand_bal;
- int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
- int stereo = dmasound.soft.stereo;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- unsigned short c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(data, up++))
- return -EFAULT;
- data ^= mask;
- if (stereo) {
- if (get_user(c, up++))
- return -EFAULT;
- data = (data << 16) + (c ^ mask);
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- expand_bal = bal;
- expand_data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 4: utotal * 2;
-}
-
-/* data in routines... */
-
-static ssize_t pmac_ct_s8_read(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = dmasound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min_t(unsigned long, userCount, frameLeft);
- while (count > 0) {
- u_char data;
-
- val = *p++;
- val = (val * software_input_volume) >> 7;
- data = val >> 8;
- if (put_user(data, (u_char __user *)userPtr++))
- return -EFAULT;
- if (stereo) {
- val = *p;
- val = (val * software_input_volume) >> 7;
- data = val >> 8;
- if (put_user(data, (u_char __user *)userPtr++))
- return -EFAULT;
- }
- p++;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_u8_read(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = dmasound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min_t(unsigned long, userCount, frameLeft);
- while (count > 0) {
- u_char data;
-
- val = *p++;
- val = (val * software_input_volume) >> 7;
- data = (val >> 8) ^ 0x80;
- if (put_user(data, (u_char __user *)userPtr++))
- return -EFAULT;
- if (stereo) {
- val = *p;
- val = (val * software_input_volume) >> 7;
- data = (val >> 8) ^ 0x80;
- if (put_user(data, (u_char __user *)userPtr++))
- return -EFAULT;
- }
- p++;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-static ssize_t pmac_ct_s16_read(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- int stereo = dmasound.soft.stereo;
- short *fp = (short *) &frame[*frameUsed];
- short __user *up = (short __user *) userPtr;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- used = count = min_t(unsigned long, userCount, frameLeft);
- while (count > 0) {
- short data;
-
- data = *fp++;
- data = (data * software_input_volume) >> 7;
- if (put_user(data, up++))
- return -EFAULT;
- if (stereo) {
- data = *fp;
- data = (data * software_input_volume) >> 7;
- if (put_user(data, up++))
- return -EFAULT;
- }
- fp++;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 4: used * 2;
-}
-
-static ssize_t pmac_ct_u16_read(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
- int stereo = dmasound.soft.stereo;
- short *fp = (short *) &frame[*frameUsed];
- short __user *up = (short __user *) userPtr;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- used = count = min_t(unsigned long, userCount, frameLeft);
- while (count > 0) {
- int data;
-
- data = *fp++;
- data = (data * software_input_volume) >> 7;
- data ^= mask;
- if (put_user(data, up++))
- return -EFAULT;
- if (stereo) {
- data = *fp;
- data = (data * software_input_volume) >> 7;
- data ^= mask;
- if (put_user(data, up++))
- return -EFAULT;
- }
- fp++;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 4: used * 2;
-}
-
-/* data in routines (reducing speed)... */
-
-static ssize_t pmac_ctx_s8_read(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- short *p = (short *) &frame[*frameUsed];
- int bal = expand_read_bal;
- int vall,valr, stereo = dmasound.soft.stereo;
- int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- u_char data;
-
- if (bal<0 && userCount == 0)
- break;
- vall = *p++;
- vall = (vall * software_input_volume) >> 7;
- if (stereo) {
- valr = *p;
- valr = (valr * software_input_volume) >> 7;
- }
- p++;
- if (bal < 0) {
- data = vall >> 8;
- if (put_user(data, (u_char __user *)userPtr++))
- return -EFAULT;
- if (stereo) {
- data = valr >> 8;
- if (put_user(data, (u_char __user *)userPtr++))
- return -EFAULT;
- }
- userCount--;
- bal += hSpeed;
- }
- frameLeft--;
- bal -= sSpeed;
- }
- expand_read_bal=bal;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t pmac_ctx_u8_read(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- short *p = (short *) &frame[*frameUsed];
- int bal = expand_read_bal;
- int vall,valr, stereo = dmasound.soft.stereo;
- int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- u_char data;
-
- if (bal<0 && userCount == 0)
- break;
-
- vall = *p++;
- vall = (vall * software_input_volume) >> 7;
- if (stereo) {
- valr = *p;
- valr = (valr * software_input_volume) >> 7;
- }
- p++;
- if (bal < 0) {
- data = (vall >> 8) ^ 0x80;
- if (put_user(data, (u_char __user *)userPtr++))
- return -EFAULT;
- if (stereo) {
- data = (valr >> 8) ^ 0x80;
- if (put_user(data, (u_char __user *)userPtr++))
- return -EFAULT;
- }
- userCount--;
- bal += hSpeed;
- }
- frameLeft--;
- bal -= sSpeed;
- }
- expand_read_bal=bal;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 2: utotal;
-}
-
-static ssize_t pmac_ctx_s16_read(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- int bal = expand_read_bal;
- short *fp = (short *) &frame[*frameUsed];
- short __user *up = (short __user *) userPtr;
- int stereo = dmasound.soft.stereo;
- int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- int datal,datar;
-
- if (bal<0 && userCount == 0)
- break;
-
- datal = *fp++;
- datal = (datal * software_input_volume) >> 7;
- if (stereo) {
- datar = *fp;
- datar = (datar * software_input_volume) >> 7;
- }
- fp++;
- if (bal < 0) {
- if (put_user(datal, up++))
- return -EFAULT;
- if (stereo) {
- if (put_user(datar, up++))
- return -EFAULT;
- }
- userCount--;
- bal += hSpeed;
- }
- frameLeft--;
- bal -= sSpeed;
- }
- expand_read_bal=bal;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 4: utotal * 2;
-}
-
-static ssize_t pmac_ctx_u16_read(const u_char __user *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- int bal = expand_read_bal;
- int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
- short *fp = (short *) &frame[*frameUsed];
- short __user *up = (short __user *) userPtr;
- int stereo = dmasound.soft.stereo;
- int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- int datal,datar;
-
- if (bal<0 && userCount == 0)
- break;
-
- datal = *fp++;
- datal = (datal * software_input_volume) >> 7;
- datal ^= mask;
- if (stereo) {
- datar = *fp;
- datar = (datar * software_input_volume) >> 7;
- datar ^= mask;
- }
- fp++;
- if (bal < 0) {
- if (put_user(datal, up++))
- return -EFAULT;
- if (stereo) {
- if (put_user(datar, up++))
- return -EFAULT;
- }
- userCount--;
- bal += hSpeed;
- }
- frameLeft--;
- bal -= sSpeed;
- }
- expand_read_bal=bal;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 4: utotal * 2;
-}
-
-
-TRANS transAwacsNormal = {
- .ct_ulaw= pmac_ct_law,
- .ct_alaw= pmac_ct_law,
- .ct_s8= pmac_ct_s8,
- .ct_u8= pmac_ct_u8,
- .ct_s16be= pmac_ct_s16,
- .ct_u16be= pmac_ct_u16,
- .ct_s16le= pmac_ct_s16,
- .ct_u16le= pmac_ct_u16,
-};
-
-TRANS transAwacsExpand = {
- .ct_ulaw= pmac_ctx_law,
- .ct_alaw= pmac_ctx_law,
- .ct_s8= pmac_ctx_s8,
- .ct_u8= pmac_ctx_u8,
- .ct_s16be= pmac_ctx_s16,
- .ct_u16be= pmac_ctx_u16,
- .ct_s16le= pmac_ctx_s16,
- .ct_u16le= pmac_ctx_u16,
-};
-
-TRANS transAwacsNormalRead = {
- .ct_s8= pmac_ct_s8_read,
- .ct_u8= pmac_ct_u8_read,
- .ct_s16be= pmac_ct_s16_read,
- .ct_u16be= pmac_ct_u16_read,
- .ct_s16le= pmac_ct_s16_read,
- .ct_u16le= pmac_ct_u16_read,
-};
-
-TRANS transAwacsExpandRead = {
- .ct_s8= pmac_ctx_s8_read,
- .ct_u8= pmac_ctx_u8_read,
- .ct_s16be= pmac_ctx_s16_read,
- .ct_u16be= pmac_ctx_u16_read,
- .ct_s16le= pmac_ctx_s16_read,
- .ct_u16le= pmac_ctx_u16_read,
-};
-
-/* translation tables */
-/* 16 bit mu-law */
-
-static short dmasound_ulaw2dma16[] = {
- -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
- -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
- -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
- -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316,
- -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
- -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
- -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
- -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
- -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
- -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
- -876, -844, -812, -780, -748, -716, -684, -652,
- -620, -588, -556, -524, -492, -460, -428, -396,
- -372, -356, -340, -324, -308, -292, -276, -260,
- -244, -228, -212, -196, -180, -164, -148, -132,
- -120, -112, -104, -96, -88, -80, -72, -64,
- -56, -48, -40, -32, -24, -16, -8, 0,
- 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
- 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
- 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
- 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
- 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
- 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
- 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
- 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
- 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
- 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
- 876, 844, 812, 780, 748, 716, 684, 652,
- 620, 588, 556, 524, 492, 460, 428, 396,
- 372, 356, 340, 324, 308, 292, 276, 260,
- 244, 228, 212, 196, 180, 164, 148, 132,
- 120, 112, 104, 96, 88, 80, 72, 64,
- 56, 48, 40, 32, 24, 16, 8, 0,
-};
-
-/* 16 bit A-law */
-
-static short dmasound_alaw2dma16[] = {
- -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
- -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
- -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
- -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
- -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
- -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
- -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472,
- -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
- -344, -328, -376, -360, -280, -264, -312, -296,
- -472, -456, -504, -488, -408, -392, -440, -424,
- -88, -72, -120, -104, -24, -8, -56, -40,
- -216, -200, -248, -232, -152, -136, -184, -168,
- -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
- -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
- -688, -656, -752, -720, -560, -528, -624, -592,
- -944, -912, -1008, -976, -816, -784, -880, -848,
- 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
- 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
- 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
- 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
- 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
- 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
- 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
- 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
- 344, 328, 376, 360, 280, 264, 312, 296,
- 472, 456, 504, 488, 408, 392, 440, 424,
- 88, 72, 120, 104, 24, 8, 56, 40,
- 216, 200, 248, 232, 152, 136, 184, 168,
- 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
- 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
- 688, 656, 752, 720, 560, 528, 624, 592,
- 944, 912, 1008, 976, 816, 784, 880, 848,
-};
diff --git a/sound/oss/es1371.c b/sound/oss/es1371.c
deleted file mode 100644
index 52648573f60..00000000000
--- a/sound/oss/es1371.c
+++ /dev/null
@@ -1,3131 +0,0 @@
-/*****************************************************************************/
-
-/*
- * es1371.c -- Creative Ensoniq ES1371.
- *
- * Copyright (C) 1998-2001, 2003 Thomas Sailer (t.sailer@alumni.ethz.ch)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Special thanks to Ensoniq
- *
- * Supported devices:
- * /dev/dsp standard /dev/dsp device, (mostly) OSS compatible
- * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible
- * /dev/dsp1 additional DAC, like /dev/dsp, but outputs to mixer "SYNTH" setting
- * /dev/midi simple MIDI UART interface, no ioctl
- *
- * NOTE: the card does not have any FM/Wavetable synthesizer, it is supposed
- * to be done in software. That is what /dev/dac is for. By now (Q2 1998)
- * there are several MIDI to PCM (WAV) packages, one of them is timidity.
- *
- * Revision history
- * 04.06.1998 0.1 Initial release
- * Mixer stuff should be overhauled; especially optional AC97 mixer bits
- * should be detected. This results in strange behaviour of some mixer
- * settings, like master volume and mic.
- * 08.06.1998 0.2 First release using Alan Cox' soundcore instead of miscdevice
- * 03.08.1998 0.3 Do not include modversions.h
- * Now mixer behaviour can basically be selected between
- * "OSS documented" and "OSS actual" behaviour
- * 31.08.1998 0.4 Fix realplayer problems - dac.count issues
- * 27.10.1998 0.5 Fix joystick support
- * -- Oliver Neukum (c188@org.chemie.uni-muenchen.de)
- * 10.12.1998 0.6 Fix drain_dac trying to wait on not yet initialized DMA
- * 23.12.1998 0.7 Fix a few f_file & FMODE_ bugs
- * Don't wake up app until there are fragsize bytes to read/write
- * 06.01.1999 0.8 remove the silly SA_INTERRUPT flag.
- * hopefully killed the egcs section type conflict
- * 12.03.1999 0.9 cinfo.blocks should be reset after GETxPTR ioctl.
- * reported by Johan Maes <joma@telindus.be>
- * 22.03.1999 0.10 return EAGAIN instead of EBUSY when O_NONBLOCK
- * read/write cannot be executed
- * 07.04.1999 0.11 implemented the following ioctl's: SOUND_PCM_READ_RATE,
- * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS;
- * Alpha fixes reported by Peter Jones <pjones@redhat.com>
- * Another Alpha fix (wait_src_ready in init routine)
- * reported by "Ivan N. Kokshaysky" <ink@jurassic.park.msu.ru>
- * Note: joystick address handling might still be wrong on archs
- * other than i386
- * 15.06.1999 0.12 Fix bad allocation bug.
- * Thanks to Deti Fliegl <fliegl@in.tum.de>
- * 28.06.1999 0.13 Add pci_set_master
- * 03.08.1999 0.14 adapt to Linus' new __setup/__initcall
- * added kernel command line option "es1371=joystickaddr"
- * removed CONFIG_SOUND_ES1371_JOYPORT_BOOT kludge
- * 10.08.1999 0.15 (Re)added S/PDIF module option for cards revision >= 4.
- * Initial version by Dave Platt <dplatt@snulbug.mtview.ca.us>.
- * module_init/__setup fixes
- * 08.16.1999 0.16 Joe Cotellese <joec@ensoniq.com>
- * Added detection for ES1371 revision ID so that we can
- * detect the ES1373 and later parts.
- * added AC97 #defines for readability
- * added a /proc file system for dumping hardware state
- * updated SRC and CODEC w/r functions to accommodate bugs
- * in some versions of the ES137x chips.
- * 31.08.1999 0.17 add spin_lock_init
- * replaced current->state = x with set_current_state(x)
- * 03.09.1999 0.18 change read semantics for MIDI to match
- * OSS more closely; remove possible wakeup race
- * 21.10.1999 0.19 Round sampling rates, requested by
- * Kasamatsu Kenichi <t29w0267@ip.media.kyoto-u.ac.jp>
- * 27.10.1999 0.20 Added SigmaTel 3D enhancement string
- * Codec ID printing changes
- * 28.10.1999 0.21 More waitqueue races fixed
- * Joe Cotellese <joec@ensoniq.com>
- * Changed PCI detection routine so we can more easily
- * detect ES137x chip and derivatives.
- * 05.01.2000 0.22 Should now work with rev7 boards; patch by
- * Eric Lemar, elemar@cs.washington.edu
- * 08.01.2000 0.23 Prevent some ioctl's from returning bad count values on underrun/overrun;
- * Tim Janik's BSE (Bedevilled Sound Engine) found this
- * 07.02.2000 0.24 Use pci_alloc_consistent and pci_register_driver
- * 07.02.2000 0.25 Use ac97_codec
- * 01.03.2000 0.26 SPDIF patch by Mikael Bouillot <mikael.bouillot@bigfoot.com>
- * Use pci_module_init
- * 21.11.2000 0.27 Initialize dma buffers in poll, otherwise poll may return a bogus mask
- * 12.12.2000 0.28 More dma buffer initializations, patch from
- * Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com>
- * 05.01.2001 0.29 Hopefully updates will not be required anymore when Creative bumps
- * the CT5880 revision.
- * suggested by Stephan Müller <smueller@chronox.de>
- * 31.01.2001 0.30 Register/Unregister gameport
- * Fix SETTRIGGER non OSS API conformity
- * 14.07.2001 0.31 Add list of laptops needing amplifier control
- * 03.01.2003 0.32 open_mode fixes from Georg Acher <acher@in.tum.de>
- */
-
-/*****************************************************************************/
-
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/bitops.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/ac97_codec.h>
-#include <linux/gameport.h>
-#include <linux/wait.h>
-#include <linux/dma-mapping.h>
-#include <linux/mutex.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-#define SUPPORT_JOYSTICK
-#endif
-
-/* --------------------------------------------------------------------- */
-
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-#define ES1371_DEBUG
-#define DBG(x) {}
-/*#define DBG(x) {x}*/
-
-/* --------------------------------------------------------------------- */
-
-#ifndef PCI_VENDOR_ID_ENSONIQ
-#define PCI_VENDOR_ID_ENSONIQ 0x1274
-#endif
-
-#ifndef PCI_VENDOR_ID_ECTIVA
-#define PCI_VENDOR_ID_ECTIVA 0x1102
-#endif
-
-#ifndef PCI_DEVICE_ID_ENSONIQ_ES1371
-#define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371
-#endif
-
-#ifndef PCI_DEVICE_ID_ENSONIQ_CT5880
-#define PCI_DEVICE_ID_ENSONIQ_CT5880 0x5880
-#endif
-
-#ifndef PCI_DEVICE_ID_ECTIVA_EV1938
-#define PCI_DEVICE_ID_ECTIVA_EV1938 0x8938
-#endif
-
-/* ES1371 chip ID */
-/* This is a little confusing because all ES1371 compatible chips have the
- same DEVICE_ID, the only thing differentiating them is the REV_ID field.
- This is only significant if you want to enable features on the later parts.
- Yes, I know it's stupid and why didn't we use the sub IDs?
-*/
-#define ES1371REV_ES1373_A 0x04
-#define ES1371REV_ES1373_B 0x06
-#define ES1371REV_CT5880_A 0x07
-#define CT5880REV_CT5880_C 0x02
-#define CT5880REV_CT5880_D 0x03
-#define ES1371REV_ES1371_B 0x09
-#define EV1938REV_EV1938_A 0x00
-#define ES1371REV_ES1373_8 0x08
-
-#define ES1371_MAGIC ((PCI_VENDOR_ID_ENSONIQ<<16)|PCI_DEVICE_ID_ENSONIQ_ES1371)
-
-#define ES1371_EXTENT 0x40
-#define JOY_EXTENT 8
-
-#define ES1371_REG_CONTROL 0x00
-#define ES1371_REG_STATUS 0x04 /* on the 5880 it is control/status */
-#define ES1371_REG_UART_DATA 0x08
-#define ES1371_REG_UART_STATUS 0x09
-#define ES1371_REG_UART_CONTROL 0x09
-#define ES1371_REG_UART_TEST 0x0a
-#define ES1371_REG_MEMPAGE 0x0c
-#define ES1371_REG_SRCONV 0x10
-#define ES1371_REG_CODEC 0x14
-#define ES1371_REG_LEGACY 0x18
-#define ES1371_REG_SERIAL_CONTROL 0x20
-#define ES1371_REG_DAC1_SCOUNT 0x24
-#define ES1371_REG_DAC2_SCOUNT 0x28
-#define ES1371_REG_ADC_SCOUNT 0x2c
-
-#define ES1371_REG_DAC1_FRAMEADR 0xc30
-#define ES1371_REG_DAC1_FRAMECNT 0xc34
-#define ES1371_REG_DAC2_FRAMEADR 0xc38
-#define ES1371_REG_DAC2_FRAMECNT 0xc3c
-#define ES1371_REG_ADC_FRAMEADR 0xd30
-#define ES1371_REG_ADC_FRAMECNT 0xd34
-
-#define ES1371_FMT_U8_MONO 0
-#define ES1371_FMT_U8_STEREO 1
-#define ES1371_FMT_S16_MONO 2
-#define ES1371_FMT_S16_STEREO 3
-#define ES1371_FMT_STEREO 1
-#define ES1371_FMT_S16 2
-#define ES1371_FMT_MASK 3
-
-static const unsigned sample_size[] = { 1, 2, 2, 4 };
-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
-
-#define CTRL_RECEN_B 0x08000000 /* 1 = don't mix analog in to digital out */
-#define CTRL_SPDIFEN_B 0x04000000
-#define CTRL_JOY_SHIFT 24
-#define CTRL_JOY_MASK 3
-#define CTRL_JOY_200 0x00000000 /* joystick base address */
-#define CTRL_JOY_208 0x01000000
-#define CTRL_JOY_210 0x02000000
-#define CTRL_JOY_218 0x03000000
-#define CTRL_GPIO_IN0 0x00100000 /* general purpose inputs/outputs */
-#define CTRL_GPIO_IN1 0x00200000
-#define CTRL_GPIO_IN2 0x00400000
-#define CTRL_GPIO_IN3 0x00800000
-#define CTRL_GPIO_OUT0 0x00010000
-#define CTRL_GPIO_OUT1 0x00020000
-#define CTRL_GPIO_OUT2 0x00040000
-#define CTRL_GPIO_OUT3 0x00080000
-#define CTRL_MSFMTSEL 0x00008000 /* MPEG serial data fmt: 0 = Sony, 1 = I2S */
-#define CTRL_SYNCRES 0x00004000 /* AC97 warm reset */
-#define CTRL_ADCSTOP 0x00002000 /* stop ADC transfers */
-#define CTRL_PWR_INTRM 0x00001000 /* 1 = power level ints enabled */
-#define CTRL_M_CB 0x00000800 /* recording source: 0 = ADC, 1 = MPEG */
-#define CTRL_CCB_INTRM 0x00000400 /* 1 = CCB "voice" ints enabled */
-#define CTRL_PDLEV0 0x00000000 /* power down level */
-#define CTRL_PDLEV1 0x00000100
-#define CTRL_PDLEV2 0x00000200
-#define CTRL_PDLEV3 0x00000300
-#define CTRL_BREQ 0x00000080 /* 1 = test mode (internal mem test) */
-#define CTRL_DAC1_EN 0x00000040 /* enable DAC1 */
-#define CTRL_DAC2_EN 0x00000020 /* enable DAC2 */
-#define CTRL_ADC_EN 0x00000010 /* enable ADC */
-#define CTRL_UART_EN 0x00000008 /* enable MIDI uart */
-#define CTRL_JYSTK_EN 0x00000004 /* enable Joystick port */
-#define CTRL_XTALCLKDIS 0x00000002 /* 1 = disable crystal clock input */
-#define CTRL_PCICLKDIS 0x00000001 /* 1 = disable PCI clock distribution */
-
-
-#define STAT_INTR 0x80000000 /* wired or of all interrupt bits */
-#define CSTAT_5880_AC97_RST 0x20000000 /* CT5880 Reset bit */
-#define STAT_EN_SPDIF 0x00040000 /* enable S/PDIF circuitry */
-#define STAT_TS_SPDIF 0x00020000 /* test S/PDIF circuitry */
-#define STAT_TESTMODE 0x00010000 /* test ASIC */
-#define STAT_SYNC_ERR 0x00000100 /* 1 = codec sync error */
-#define STAT_VC 0x000000c0 /* CCB int source, 0=DAC1, 1=DAC2, 2=ADC, 3=undef */
-#define STAT_SH_VC 6
-#define STAT_MPWR 0x00000020 /* power level interrupt */
-#define STAT_MCCB 0x00000010 /* CCB int pending */
-#define STAT_UART 0x00000008 /* UART int pending */
-#define STAT_DAC1 0x00000004 /* DAC1 int pending */
-#define STAT_DAC2 0x00000002 /* DAC2 int pending */
-#define STAT_ADC 0x00000001 /* ADC int pending */
-
-#define USTAT_RXINT 0x80 /* UART rx int pending */
-#define USTAT_TXINT 0x04 /* UART tx int pending */
-#define USTAT_TXRDY 0x02 /* UART tx ready */
-#define USTAT_RXRDY 0x01 /* UART rx ready */
-
-#define UCTRL_RXINTEN 0x80 /* 1 = enable RX ints */
-#define UCTRL_TXINTEN 0x60 /* TX int enable field mask */
-#define UCTRL_ENA_TXINT 0x20 /* enable TX int */
-#define UCTRL_CNTRL 0x03 /* control field */
-#define UCTRL_CNTRL_SWR 0x03 /* software reset command */
-
-/* sample rate converter */
-#define SRC_OKSTATE 1
-
-#define SRC_RAMADDR_MASK 0xfe000000
-#define SRC_RAMADDR_SHIFT 25
-#define SRC_DAC1FREEZE (1UL << 21)
-#define SRC_DAC2FREEZE (1UL << 20)
-#define SRC_ADCFREEZE (1UL << 19)
-
-
-#define SRC_WE 0x01000000 /* read/write control for SRC RAM */
-#define SRC_BUSY 0x00800000 /* SRC busy */
-#define SRC_DIS 0x00400000 /* 1 = disable SRC */
-#define SRC_DDAC1 0x00200000 /* 1 = disable accum update for DAC1 */
-#define SRC_DDAC2 0x00100000 /* 1 = disable accum update for DAC2 */
-#define SRC_DADC 0x00080000 /* 1 = disable accum update for ADC2 */
-#define SRC_CTLMASK 0x00780000
-#define SRC_RAMDATA_MASK 0x0000ffff
-#define SRC_RAMDATA_SHIFT 0
-
-#define SRCREG_ADC 0x78
-#define SRCREG_DAC1 0x70
-#define SRCREG_DAC2 0x74
-#define SRCREG_VOL_ADC 0x6c
-#define SRCREG_VOL_DAC1 0x7c
-#define SRCREG_VOL_DAC2 0x7e
-
-#define SRCREG_TRUNC_N 0x00
-#define SRCREG_INT_REGS 0x01
-#define SRCREG_ACCUM_FRAC 0x02
-#define SRCREG_VFREQ_FRAC 0x03
-
-#define CODEC_PIRD 0x00800000 /* 0 = write AC97 register */
-#define CODEC_PIADD_MASK 0x007f0000
-#define CODEC_PIADD_SHIFT 16
-#define CODEC_PIDAT_MASK 0x0000ffff
-#define CODEC_PIDAT_SHIFT 0
-
-#define CODEC_RDY 0x80000000 /* AC97 read data valid */
-#define CODEC_WIP 0x40000000 /* AC97 write in progress */
-#define CODEC_PORD 0x00800000 /* 0 = write AC97 register */
-#define CODEC_POADD_MASK 0x007f0000
-#define CODEC_POADD_SHIFT 16
-#define CODEC_PODAT_MASK 0x0000ffff
-#define CODEC_PODAT_SHIFT 0
-
-
-#define LEGACY_JFAST 0x80000000 /* fast joystick timing */
-#define LEGACY_FIRQ 0x01000000 /* force IRQ */
-
-#define SCTRL_DACTEST 0x00400000 /* 1 = DAC test, test vector generation purposes */
-#define SCTRL_P2ENDINC 0x00380000 /* */
-#define SCTRL_SH_P2ENDINC 19
-#define SCTRL_P2STINC 0x00070000 /* */
-#define SCTRL_SH_P2STINC 16
-#define SCTRL_R1LOOPSEL 0x00008000 /* 0 = loop mode */
-#define SCTRL_P2LOOPSEL 0x00004000 /* 0 = loop mode */
-#define SCTRL_P1LOOPSEL 0x00002000 /* 0 = loop mode */
-#define SCTRL_P2PAUSE 0x00001000 /* 1 = pause mode */
-#define SCTRL_P1PAUSE 0x00000800 /* 1 = pause mode */
-#define SCTRL_R1INTEN 0x00000400 /* enable interrupt */
-#define SCTRL_P2INTEN 0x00000200 /* enable interrupt */
-#define SCTRL_P1INTEN 0x00000100 /* enable interrupt */
-#define SCTRL_P1SCTRLD 0x00000080 /* reload sample count register for DAC1 */
-#define SCTRL_P2DACSEN 0x00000040 /* 1 = DAC2 play back last sample when disabled */
-#define SCTRL_R1SEB 0x00000020 /* 1 = 16bit */
-#define SCTRL_R1SMB 0x00000010 /* 1 = stereo */
-#define SCTRL_R1FMT 0x00000030 /* format mask */
-#define SCTRL_SH_R1FMT 4
-#define SCTRL_P2SEB 0x00000008 /* 1 = 16bit */
-#define SCTRL_P2SMB 0x00000004 /* 1 = stereo */
-#define SCTRL_P2FMT 0x0000000c /* format mask */
-#define SCTRL_SH_P2FMT 2
-#define SCTRL_P1SEB 0x00000002 /* 1 = 16bit */
-#define SCTRL_P1SMB 0x00000001 /* 1 = stereo */
-#define SCTRL_P1FMT 0x00000003 /* format mask */
-#define SCTRL_SH_P1FMT 0
-
-
-/* misc stuff */
-#define POLL_COUNT 0x1000
-#define FMODE_DAC 4 /* slight misuse of mode_t */
-
-/* MIDI buffer sizes */
-
-#define MIDIINBUF 256
-#define MIDIOUTBUF 256
-
-#define FMODE_MIDI_SHIFT 3
-#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT)
-#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)
-
-#define ES1371_MODULE_NAME "es1371"
-#define PFX ES1371_MODULE_NAME ": "
-
-/* --------------------------------------------------------------------- */
-
-struct es1371_state {
- /* magic */
- unsigned int magic;
-
- /* list of es1371 devices */
- struct list_head devs;
-
- /* the corresponding pci_dev structure */
- struct pci_dev *dev;
-
- /* soundcore stuff */
- int dev_audio;
- int dev_dac;
- int dev_midi;
-
- /* hardware resources */
- unsigned long io; /* long for SPARC */
- unsigned int irq;
-
- /* PCI ID's */
- u16 vendor;
- u16 device;
- u8 rev; /* the chip revision */
-
- /* options */
- int spdif_volume; /* S/PDIF output is enabled if != -1 */
-
-#ifdef ES1371_DEBUG
- /* debug /proc entry */
- struct proc_dir_entry *ps;
-#endif /* ES1371_DEBUG */
-
- struct ac97_codec *codec;
-
- /* wave stuff */
- unsigned ctrl;
- unsigned sctrl;
- unsigned dac1rate, dac2rate, adcrate;
-
- spinlock_t lock;
- struct mutex open_mutex;
- mode_t open_mode;
- wait_queue_head_t open_wait;
-
- struct dmabuf {
- void *rawbuf;
- dma_addr_t dmaaddr;
- unsigned buforder;
- unsigned numfrag;
- unsigned fragshift;
- unsigned hwptr, swptr;
- unsigned total_bytes;
- int count;
- unsigned error; /* over/underrun */
- wait_queue_head_t wait;
- /* redundant, but makes calculations easier */
- unsigned fragsize;
- unsigned dmasize;
- unsigned fragsamples;
- /* OSS stuff */
- unsigned mapped:1;
- unsigned ready:1;
- unsigned endcleared:1;
- unsigned enabled:1;
- unsigned ossfragshift;
- int ossmaxfrags;
- unsigned subdivision;
- } dma_dac1, dma_dac2, dma_adc;
-
- /* midi stuff */
- struct {
- unsigned ird, iwr, icnt;
- unsigned ord, owr, ocnt;
- wait_queue_head_t iwait;
- wait_queue_head_t owait;
- unsigned char ibuf[MIDIINBUF];
- unsigned char obuf[MIDIOUTBUF];
- } midi;
-
-#ifdef SUPPORT_JOYSTICK
- struct gameport *gameport;
-#endif
-
- struct mutex sem;
-};
-
-/* --------------------------------------------------------------------- */
-
-static LIST_HEAD(devs);
-
-/* --------------------------------------------------------------------- */
-
-static inline unsigned ld2(unsigned int x)
-{
- unsigned r = 0;
-
- if (x >= 0x10000) {
- x >>= 16;
- r += 16;
- }
- if (x >= 0x100) {
- x >>= 8;
- r += 8;
- }
- if (x >= 0x10) {
- x >>= 4;
- r += 4;
- }
- if (x >= 4) {
- x >>= 2;
- r += 2;
- }
- if (x >= 2)
- r++;
- return r;
-}
-
-/* --------------------------------------------------------------------- */
-
-static unsigned wait_src_ready(struct es1371_state *s)
-{
- unsigned int t, r;
-
- for (t = 0; t < POLL_COUNT; t++) {
- if (!((r = inl(s->io + ES1371_REG_SRCONV)) & SRC_BUSY))
- return r;
- udelay(1);
- }
- printk(KERN_DEBUG PFX "sample rate converter timeout r = 0x%08x\n", r);
- return r;
-}
-
-static unsigned src_read(struct es1371_state *s, unsigned reg)
-{
- unsigned int temp,i,orig;
-
- /* wait for ready */
- temp = wait_src_ready (s);
-
- /* we can only access the SRC at certain times, make sure
- we're allowed to before we read */
-
- orig = temp;
- /* expose the SRC state bits */
- outl ( (temp & SRC_CTLMASK) | (reg << SRC_RAMADDR_SHIFT) | 0x10000UL,
- s->io + ES1371_REG_SRCONV);
-
- /* now, wait for busy and the correct time to read */
- temp = wait_src_ready (s);
-
- if ( (temp & 0x00870000UL ) != ( SRC_OKSTATE << 16 )){
- /* wait for the right state */
- for (i=0; i<POLL_COUNT; i++){
- temp = inl (s->io + ES1371_REG_SRCONV);
- if ( (temp & 0x00870000UL ) == ( SRC_OKSTATE << 16 ))
- break;
- }
- }
-
- /* hide the state bits */
- outl ((orig & SRC_CTLMASK) | (reg << SRC_RAMADDR_SHIFT), s->io + ES1371_REG_SRCONV);
- return temp;
-
-
-}
-
-static void src_write(struct es1371_state *s, unsigned reg, unsigned data)
-{
-
- unsigned int r;
-
- r = wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC);
- r |= (reg << SRC_RAMADDR_SHIFT) & SRC_RAMADDR_MASK;
- r |= (data << SRC_RAMDATA_SHIFT) & SRC_RAMDATA_MASK;
- outl(r | SRC_WE, s->io + ES1371_REG_SRCONV);
-
-}
-
-/* --------------------------------------------------------------------- */
-
-/* most of the following here is black magic */
-static void set_adc_rate(struct es1371_state *s, unsigned rate)
-{
- unsigned long flags;
- unsigned int n, truncm, freq;
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 4000)
- rate = 4000;
- n = rate / 3000;
- if ((1 << n) & ((1 << 15) | (1 << 13) | (1 << 11) | (1 << 9)))
- n--;
- truncm = (21 * n - 1) | 1;
- freq = ((48000UL << 15) / rate) * n;
- s->adcrate = (48000UL << 15) / (freq / n);
- spin_lock_irqsave(&s->lock, flags);
- if (rate >= 24000) {
- if (truncm > 239)
- truncm = 239;
- src_write(s, SRCREG_ADC+SRCREG_TRUNC_N,
- (((239 - truncm) >> 1) << 9) | (n << 4));
- } else {
- if (truncm > 119)
- truncm = 119;
- src_write(s, SRCREG_ADC+SRCREG_TRUNC_N,
- 0x8000 | (((119 - truncm) >> 1) << 9) | (n << 4));
- }
- src_write(s, SRCREG_ADC+SRCREG_INT_REGS,
- (src_read(s, SRCREG_ADC+SRCREG_INT_REGS) & 0x00ff) |
- ((freq >> 5) & 0xfc00));
- src_write(s, SRCREG_ADC+SRCREG_VFREQ_FRAC, freq & 0x7fff);
- src_write(s, SRCREG_VOL_ADC, n << 8);
- src_write(s, SRCREG_VOL_ADC+1, n << 8);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-
-static void set_dac1_rate(struct es1371_state *s, unsigned rate)
-{
- unsigned long flags;
- unsigned int freq, r;
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 4000)
- rate = 4000;
- freq = ((rate << 15) + 1500) / 3000;
- s->dac1rate = (freq * 3000 + 16384) >> 15;
- spin_lock_irqsave(&s->lock, flags);
- r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC2 | SRC_DADC)) | SRC_DDAC1;
- outl(r, s->io + ES1371_REG_SRCONV);
- src_write(s, SRCREG_DAC1+SRCREG_INT_REGS,
- (src_read(s, SRCREG_DAC1+SRCREG_INT_REGS) & 0x00ff) |
- ((freq >> 5) & 0xfc00));
- src_write(s, SRCREG_DAC1+SRCREG_VFREQ_FRAC, freq & 0x7fff);
- r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC2 | SRC_DADC));
- outl(r, s->io + ES1371_REG_SRCONV);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void set_dac2_rate(struct es1371_state *s, unsigned rate)
-{
- unsigned long flags;
- unsigned int freq, r;
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 4000)
- rate = 4000;
- freq = ((rate << 15) + 1500) / 3000;
- s->dac2rate = (freq * 3000 + 16384) >> 15;
- spin_lock_irqsave(&s->lock, flags);
- r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DADC)) | SRC_DDAC2;
- outl(r, s->io + ES1371_REG_SRCONV);
- src_write(s, SRCREG_DAC2+SRCREG_INT_REGS,
- (src_read(s, SRCREG_DAC2+SRCREG_INT_REGS) & 0x00ff) |
- ((freq >> 5) & 0xfc00));
- src_write(s, SRCREG_DAC2+SRCREG_VFREQ_FRAC, freq & 0x7fff);
- r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DADC));
- outl(r, s->io + ES1371_REG_SRCONV);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void __devinit src_init(struct es1371_state *s)
-{
- unsigned int i;
-
- /* before we enable or disable the SRC we need
- to wait for it to become ready */
- wait_src_ready(s);
-
- outl(SRC_DIS, s->io + ES1371_REG_SRCONV);
-
- for (i = 0; i < 0x80; i++)
- src_write(s, i, 0);
-
- src_write(s, SRCREG_DAC1+SRCREG_TRUNC_N, 16 << 4);
- src_write(s, SRCREG_DAC1+SRCREG_INT_REGS, 16 << 10);
- src_write(s, SRCREG_DAC2+SRCREG_TRUNC_N, 16 << 4);
- src_write(s, SRCREG_DAC2+SRCREG_INT_REGS, 16 << 10);
- src_write(s, SRCREG_VOL_ADC, 1 << 12);
- src_write(s, SRCREG_VOL_ADC+1, 1 << 12);
- src_write(s, SRCREG_VOL_DAC1, 1 << 12);
- src_write(s, SRCREG_VOL_DAC1+1, 1 << 12);
- src_write(s, SRCREG_VOL_DAC2, 1 << 12);
- src_write(s, SRCREG_VOL_DAC2+1, 1 << 12);
- set_adc_rate(s, 22050);
- set_dac1_rate(s, 22050);
- set_dac2_rate(s, 22050);
-
- /* WARNING:
- * enabling the sample rate converter without properly programming
- * its parameters causes the chip to lock up (the SRC busy bit will
- * be stuck high, and I've found no way to rectify this other than
- * power cycle)
- */
- wait_src_ready(s);
- outl(0, s->io+ES1371_REG_SRCONV);
-}
-
-/* --------------------------------------------------------------------- */
-
-static void wrcodec(struct ac97_codec *codec, u8 addr, u16 data)
-{
- struct es1371_state *s = (struct es1371_state *)codec->private_data;
- unsigned long flags;
- unsigned t, x;
-
- spin_lock_irqsave(&s->lock, flags);
- for (t = 0; t < POLL_COUNT; t++)
- if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP))
- break;
-
- /* save the current state for later */
- x = wait_src_ready(s);
-
- /* enable SRC state data in SRC mux */
- outl((x & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000,
- s->io+ES1371_REG_SRCONV);
-
- /* wait for not busy (state 0) first to avoid
- transition states */
- for (t=0; t<POLL_COUNT; t++){
- if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0 )
- break;
- udelay(1);
- }
-
- /* wait for a SAFE time to write addr/data and then do it, dammit */
- for (t=0; t<POLL_COUNT; t++){
- if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0x00010000)
- break;
- udelay(1);
- }
-
- outl(((addr << CODEC_POADD_SHIFT) & CODEC_POADD_MASK) |
- ((data << CODEC_PODAT_SHIFT) & CODEC_PODAT_MASK), s->io+ES1371_REG_CODEC);
-
- /* restore SRC reg */
- wait_src_ready(s);
- outl(x, s->io+ES1371_REG_SRCONV);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static u16 rdcodec(struct ac97_codec *codec, u8 addr)
-{
- struct es1371_state *s = (struct es1371_state *)codec->private_data;
- unsigned long flags;
- unsigned t, x;
-
- spin_lock_irqsave(&s->lock, flags);
-
- /* wait for WIP to go away */
- for (t = 0; t < 0x1000; t++)
- if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP))
- break;
-
- /* save the current state for later */
- x = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC));
-
- /* enable SRC state data in SRC mux */
- outl( x | 0x00010000,
- s->io+ES1371_REG_SRCONV);
-
- /* wait for not busy (state 0) first to avoid
- transition states */
- for (t=0; t<POLL_COUNT; t++){
- if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0 )
- break;
- udelay(1);
- }
-
- /* wait for a SAFE time to write addr/data and then do it, dammit */
- for (t=0; t<POLL_COUNT; t++){
- if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0x00010000)
- break;
- udelay(1);
- }
-
- outl(((addr << CODEC_POADD_SHIFT) & CODEC_POADD_MASK) | CODEC_PORD, s->io+ES1371_REG_CODEC);
- /* restore SRC reg */
- wait_src_ready(s);
- outl(x, s->io+ES1371_REG_SRCONV);
-
- /* wait for WIP again */
- for (t = 0; t < 0x1000; t++)
- if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP))
- break;
-
- /* now wait for the stinkin' data (RDY) */
- for (t = 0; t < POLL_COUNT; t++)
- if ((x = inl(s->io+ES1371_REG_CODEC)) & CODEC_RDY)
- break;
-
- spin_unlock_irqrestore(&s->lock, flags);
- return ((x & CODEC_PIDAT_MASK) >> CODEC_PIDAT_SHIFT);
-}
-
-/* --------------------------------------------------------------------- */
-
-static inline void stop_adc(struct es1371_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- s->ctrl &= ~CTRL_ADC_EN;
- outl(s->ctrl, s->io+ES1371_REG_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static inline void stop_dac1(struct es1371_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- s->ctrl &= ~CTRL_DAC1_EN;
- outl(s->ctrl, s->io+ES1371_REG_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static inline void stop_dac2(struct es1371_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- s->ctrl &= ~CTRL_DAC2_EN;
- outl(s->ctrl, s->io+ES1371_REG_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_dac1(struct es1371_state *s)
-{
- unsigned long flags;
- unsigned fragremain, fshift;
-
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->ctrl & CTRL_DAC1_EN) && (s->dma_dac1.mapped || s->dma_dac1.count > 0)
- && s->dma_dac1.ready) {
- s->ctrl |= CTRL_DAC1_EN;
- s->sctrl = (s->sctrl & ~(SCTRL_P1LOOPSEL | SCTRL_P1PAUSE | SCTRL_P1SCTRLD)) | SCTRL_P1INTEN;
- outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
- fragremain = ((- s->dma_dac1.hwptr) & (s->dma_dac1.fragsize-1));
- fshift = sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT];
- if (fragremain < 2*fshift)
- fragremain = s->dma_dac1.fragsize;
- outl((fragremain >> fshift) - 1, s->io+ES1371_REG_DAC1_SCOUNT);
- outl(s->ctrl, s->io+ES1371_REG_CONTROL);
- outl((s->dma_dac1.fragsize >> fshift) - 1, s->io+ES1371_REG_DAC1_SCOUNT);
- }
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_dac2(struct es1371_state *s)
-{
- unsigned long flags;
- unsigned fragremain, fshift;
-
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->ctrl & CTRL_DAC2_EN) && (s->dma_dac2.mapped || s->dma_dac2.count > 0)
- && s->dma_dac2.ready) {
- s->ctrl |= CTRL_DAC2_EN;
- s->sctrl = (s->sctrl & ~(SCTRL_P2LOOPSEL | SCTRL_P2PAUSE | SCTRL_P2DACSEN |
- SCTRL_P2ENDINC | SCTRL_P2STINC)) | SCTRL_P2INTEN |
- (((s->sctrl & SCTRL_P2FMT) ? 2 : 1) << SCTRL_SH_P2ENDINC) |
- (0 << SCTRL_SH_P2STINC);
- outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
- fragremain = ((- s->dma_dac2.hwptr) & (s->dma_dac2.fragsize-1));
- fshift = sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT];
- if (fragremain < 2*fshift)
- fragremain = s->dma_dac2.fragsize;
- outl((fragremain >> fshift) - 1, s->io+ES1371_REG_DAC2_SCOUNT);
- outl(s->ctrl, s->io+ES1371_REG_CONTROL);
- outl((s->dma_dac2.fragsize >> fshift) - 1, s->io+ES1371_REG_DAC2_SCOUNT);
- }
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_adc(struct es1371_state *s)
-{
- unsigned long flags;
- unsigned fragremain, fshift;
-
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->ctrl & CTRL_ADC_EN) && (s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
- && s->dma_adc.ready) {
- s->ctrl |= CTRL_ADC_EN;
- s->sctrl = (s->sctrl & ~SCTRL_R1LOOPSEL) | SCTRL_R1INTEN;
- outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
- fragremain = ((- s->dma_adc.hwptr) & (s->dma_adc.fragsize-1));
- fshift = sample_shift[(s->sctrl & SCTRL_R1FMT) >> SCTRL_SH_R1FMT];
- if (fragremain < 2*fshift)
- fragremain = s->dma_adc.fragsize;
- outl((fragremain >> fshift) - 1, s->io+ES1371_REG_ADC_SCOUNT);
- outl(s->ctrl, s->io+ES1371_REG_CONTROL);
- outl((s->dma_adc.fragsize >> fshift) - 1, s->io+ES1371_REG_ADC_SCOUNT);
- }
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-
-static inline void dealloc_dmabuf(struct es1371_state *s, struct dmabuf *db)
-{
- struct page *page, *pend;
-
- if (db->rawbuf) {
- /* undo marking the pages as reserved */
- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
- ClearPageReserved(page);
- pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr);
- }
- db->rawbuf = NULL;
- db->mapped = db->ready = 0;
-}
-
-static int prog_dmabuf(struct es1371_state *s, struct dmabuf *db, unsigned rate, unsigned fmt, unsigned reg)
-{
- int order;
- unsigned bytepersec;
- unsigned bufs;
- struct page *page, *pend;
-
- db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
- if (!db->rawbuf) {
- db->ready = db->mapped = 0;
- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
- if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr)))
- break;
- if (!db->rawbuf)
- return -ENOMEM;
- db->buforder = order;
- /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
- SetPageReserved(page);
- }
- fmt &= ES1371_FMT_MASK;
- bytepersec = rate << sample_shift[fmt];
- bufs = PAGE_SIZE << db->buforder;
- if (db->ossfragshift) {
- if ((1000 << db->ossfragshift) < bytepersec)
- db->fragshift = ld2(bytepersec/1000);
- else
- db->fragshift = db->ossfragshift;
- } else {
- db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
- if (db->fragshift < 3)
- db->fragshift = 3;
- }
- db->numfrag = bufs >> db->fragshift;
- while (db->numfrag < 4 && db->fragshift > 3) {
- db->fragshift--;
- db->numfrag = bufs >> db->fragshift;
- }
- db->fragsize = 1 << db->fragshift;
- if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
- db->numfrag = db->ossmaxfrags;
- db->fragsamples = db->fragsize >> sample_shift[fmt];
- db->dmasize = db->numfrag << db->fragshift;
- memset(db->rawbuf, (fmt & ES1371_FMT_S16) ? 0 : 0x80, db->dmasize);
- outl((reg >> 8) & 15, s->io+ES1371_REG_MEMPAGE);
- outl(db->dmaaddr, s->io+(reg & 0xff));
- outl((db->dmasize >> 2)-1, s->io+((reg + 4) & 0xff));
- db->enabled = 1;
- db->ready = 1;
- return 0;
-}
-
-static inline int prog_dmabuf_adc(struct es1371_state *s)
-{
- stop_adc(s);
- return prog_dmabuf(s, &s->dma_adc, s->adcrate, (s->sctrl >> SCTRL_SH_R1FMT) & ES1371_FMT_MASK,
- ES1371_REG_ADC_FRAMEADR);
-}
-
-static inline int prog_dmabuf_dac2(struct es1371_state *s)
-{
- stop_dac2(s);
- return prog_dmabuf(s, &s->dma_dac2, s->dac2rate, (s->sctrl >> SCTRL_SH_P2FMT) & ES1371_FMT_MASK,
- ES1371_REG_DAC2_FRAMEADR);
-}
-
-static inline int prog_dmabuf_dac1(struct es1371_state *s)
-{
- stop_dac1(s);
- return prog_dmabuf(s, &s->dma_dac1, s->dac1rate, (s->sctrl >> SCTRL_SH_P1FMT) & ES1371_FMT_MASK,
- ES1371_REG_DAC1_FRAMEADR);
-}
-
-static inline unsigned get_hwptr(struct es1371_state *s, struct dmabuf *db, unsigned reg)
-{
- unsigned hwptr, diff;
-
- outl((reg >> 8) & 15, s->io+ES1371_REG_MEMPAGE);
- hwptr = (inl(s->io+(reg & 0xff)) >> 14) & 0x3fffc;
- diff = (db->dmasize + hwptr - db->hwptr) % db->dmasize;
- db->hwptr = hwptr;
- return diff;
-}
-
-static inline void clear_advance(void *buf, unsigned bsize, unsigned bptr, unsigned len, unsigned char c)
-{
- if (bptr + len > bsize) {
- unsigned x = bsize - bptr;
- memset(((char *)buf) + bptr, c, x);
- bptr = 0;
- len -= x;
- }
- memset(((char *)buf) + bptr, c, len);
-}
-
-/* call with spinlock held! */
-static void es1371_update_ptr(struct es1371_state *s)
-{
- int diff;
-
- /* update ADC pointer */
- if (s->ctrl & CTRL_ADC_EN) {
- diff = get_hwptr(s, &s->dma_adc, ES1371_REG_ADC_FRAMECNT);
- s->dma_adc.total_bytes += diff;
- s->dma_adc.count += diff;
- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
- wake_up(&s->dma_adc.wait);
- if (!s->dma_adc.mapped) {
- if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
- s->ctrl &= ~CTRL_ADC_EN;
- outl(s->ctrl, s->io+ES1371_REG_CONTROL);
- s->dma_adc.error++;
- }
- }
- }
- /* update DAC1 pointer */
- if (s->ctrl & CTRL_DAC1_EN) {
- diff = get_hwptr(s, &s->dma_dac1, ES1371_REG_DAC1_FRAMECNT);
- s->dma_dac1.total_bytes += diff;
- if (s->dma_dac1.mapped) {
- s->dma_dac1.count += diff;
- if (s->dma_dac1.count >= (signed)s->dma_dac1.fragsize)
- wake_up(&s->dma_dac1.wait);
- } else {
- s->dma_dac1.count -= diff;
- if (s->dma_dac1.count <= 0) {
- s->ctrl &= ~CTRL_DAC1_EN;
- outl(s->ctrl, s->io+ES1371_REG_CONTROL);
- s->dma_dac1.error++;
- } else if (s->dma_dac1.count <= (signed)s->dma_dac1.fragsize && !s->dma_dac1.endcleared) {
- clear_advance(s->dma_dac1.rawbuf, s->dma_dac1.dmasize, s->dma_dac1.swptr,
- s->dma_dac1.fragsize, (s->sctrl & SCTRL_P1SEB) ? 0 : 0x80);
- s->dma_dac1.endcleared = 1;
- }
- if (s->dma_dac1.count + (signed)s->dma_dac1.fragsize <= (signed)s->dma_dac1.dmasize)
- wake_up(&s->dma_dac1.wait);
- }
- }
- /* update DAC2 pointer */
- if (s->ctrl & CTRL_DAC2_EN) {
- diff = get_hwptr(s, &s->dma_dac2, ES1371_REG_DAC2_FRAMECNT);
- s->dma_dac2.total_bytes += diff;
- if (s->dma_dac2.mapped) {
- s->dma_dac2.count += diff;
- if (s->dma_dac2.count >= (signed)s->dma_dac2.fragsize)
- wake_up(&s->dma_dac2.wait);
- } else {
- s->dma_dac2.count -= diff;
- if (s->dma_dac2.count <= 0) {
- s->ctrl &= ~CTRL_DAC2_EN;
- outl(s->ctrl, s->io+ES1371_REG_CONTROL);
- s->dma_dac2.error++;
- } else if (s->dma_dac2.count <= (signed)s->dma_dac2.fragsize && !s->dma_dac2.endcleared) {
- clear_advance(s->dma_dac2.rawbuf, s->dma_dac2.dmasize, s->dma_dac2.swptr,
- s->dma_dac2.fragsize, (s->sctrl & SCTRL_P2SEB) ? 0 : 0x80);
- s->dma_dac2.endcleared = 1;
- }
- if (s->dma_dac2.count + (signed)s->dma_dac2.fragsize <= (signed)s->dma_dac2.dmasize)
- wake_up(&s->dma_dac2.wait);
- }
- }
-}
-
-/* hold spinlock for the following! */
-static void es1371_handle_midi(struct es1371_state *s)
-{
- unsigned char ch;
- int wake;
-
- if (!(s->ctrl & CTRL_UART_EN))
- return;
- wake = 0;
- while (inb(s->io+ES1371_REG_UART_STATUS) & USTAT_RXRDY) {
- ch = inb(s->io+ES1371_REG_UART_DATA);
- if (s->midi.icnt < MIDIINBUF) {
- s->midi.ibuf[s->midi.iwr] = ch;
- s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF;
- s->midi.icnt++;
- }
- wake = 1;
- }
- if (wake)
- wake_up(&s->midi.iwait);
- wake = 0;
- while ((inb(s->io+ES1371_REG_UART_STATUS) & USTAT_TXRDY) && s->midi.ocnt > 0) {
- outb(s->midi.obuf[s->midi.ord], s->io+ES1371_REG_UART_DATA);
- s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF;
- s->midi.ocnt--;
- if (s->midi.ocnt < MIDIOUTBUF-16)
- wake = 1;
- }
- if (wake)
- wake_up(&s->midi.owait);
- outb((s->midi.ocnt > 0) ? UCTRL_RXINTEN | UCTRL_ENA_TXINT : UCTRL_RXINTEN, s->io+ES1371_REG_UART_CONTROL);
-}
-
-static irqreturn_t es1371_interrupt(int irq, void *dev_id)
-{
- struct es1371_state *s = dev_id;
- unsigned int intsrc, sctl;
-
- /* fastpath out, to ease interrupt sharing */
- intsrc = inl(s->io+ES1371_REG_STATUS);
- if (!(intsrc & 0x80000000))
- return IRQ_NONE;
- spin_lock(&s->lock);
- /* clear audio interrupts first */
- sctl = s->sctrl;
- if (intsrc & STAT_ADC)
- sctl &= ~SCTRL_R1INTEN;
- if (intsrc & STAT_DAC1)
- sctl &= ~SCTRL_P1INTEN;
- if (intsrc & STAT_DAC2)
- sctl &= ~SCTRL_P2INTEN;
- outl(sctl, s->io+ES1371_REG_SERIAL_CONTROL);
- outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
- es1371_update_ptr(s);
- es1371_handle_midi(s);
- spin_unlock(&s->lock);
- return IRQ_HANDLED;
-}
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT PFX "invalid magic value\n";
-
-#define VALIDATE_STATE(s) \
-({ \
- if (!(s) || (s)->magic != ES1371_MAGIC) { \
- printk(invalid_magic); \
- return -ENXIO; \
- } \
-})
-
-/* --------------------------------------------------------------------- */
-
-/* Conversion table for S/PDIF PCM volume emulation through the SRC */
-/* dB-linear table of DAC vol values; -0dB to -46.5dB with mute */
-static const unsigned short DACVolTable[101] =
-{
- 0x1000, 0x0f2a, 0x0e60, 0x0da0, 0x0cea, 0x0c3e, 0x0b9a, 0x0aff,
- 0x0a6d, 0x09e1, 0x095e, 0x08e1, 0x086a, 0x07fa, 0x078f, 0x072a,
- 0x06cb, 0x0670, 0x061a, 0x05c9, 0x057b, 0x0532, 0x04ed, 0x04ab,
- 0x046d, 0x0432, 0x03fa, 0x03c5, 0x0392, 0x0363, 0x0335, 0x030b,
- 0x02e2, 0x02bc, 0x0297, 0x0275, 0x0254, 0x0235, 0x0217, 0x01fb,
- 0x01e1, 0x01c8, 0x01b0, 0x0199, 0x0184, 0x0170, 0x015d, 0x014b,
- 0x0139, 0x0129, 0x0119, 0x010b, 0x00fd, 0x00f0, 0x00e3, 0x00d7,
- 0x00cc, 0x00c1, 0x00b7, 0x00ae, 0x00a5, 0x009c, 0x0094, 0x008c,
- 0x0085, 0x007e, 0x0077, 0x0071, 0x006b, 0x0066, 0x0060, 0x005b,
- 0x0057, 0x0052, 0x004e, 0x004a, 0x0046, 0x0042, 0x003f, 0x003c,
- 0x0038, 0x0036, 0x0033, 0x0030, 0x002e, 0x002b, 0x0029, 0x0027,
- 0x0025, 0x0023, 0x0021, 0x001f, 0x001e, 0x001c, 0x001b, 0x0019,
- 0x0018, 0x0017, 0x0016, 0x0014, 0x0000
-};
-
-/*
- * when we are in S/PDIF mode, we want to disable any analog output so
- * we filter the mixer ioctls
- */
-static int mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg)
-{
- struct es1371_state *s = (struct es1371_state *)codec->private_data;
- int val;
- unsigned long flags;
- unsigned int left, right;
-
- VALIDATE_STATE(s);
- /* filter mixer ioctls to catch PCM and MASTER volume when in S/PDIF mode */
- if (s->spdif_volume == -1)
- return codec->mixer_ioctl(codec, cmd, arg);
- switch (cmd) {
- case SOUND_MIXER_WRITE_VOLUME:
- return 0;
-
- case SOUND_MIXER_WRITE_PCM: /* use SRC for PCM volume */
- if (get_user(val, (int __user *)arg))
- return -EFAULT;
- right = ((val >> 8) & 0xff);
- left = (val & 0xff);
- if (right > 100)
- right = 100;
- if (left > 100)
- left = 100;
- s->spdif_volume = (right << 8) | left;
- spin_lock_irqsave(&s->lock, flags);
- src_write(s, SRCREG_VOL_DAC2, DACVolTable[100 - left]);
- src_write(s, SRCREG_VOL_DAC2+1, DACVolTable[100 - right]);
- spin_unlock_irqrestore(&s->lock, flags);
- return 0;
-
- case SOUND_MIXER_READ_PCM:
- return put_user(s->spdif_volume, (int __user *)arg);
- }
- return codec->mixer_ioctl(codec, cmd, arg);
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * AC97 Mixer Register to Connections mapping of the Concert 97 board
- *
- * AC97_MASTER_VOL_STEREO Line Out
- * AC97_MASTER_VOL_MONO TAD Output
- * AC97_PCBEEP_VOL none
- * AC97_PHONE_VOL TAD Input (mono)
- * AC97_MIC_VOL MIC Input (mono)
- * AC97_LINEIN_VOL Line Input (stereo)
- * AC97_CD_VOL CD Input (stereo)
- * AC97_VIDEO_VOL none
- * AC97_AUX_VOL Aux Input (stereo)
- * AC97_PCMOUT_VOL Wave Output (stereo)
- */
-
-static int es1371_open_mixdev(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct list_head *list;
- struct es1371_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct es1371_state, devs);
- if (s->codec->dev_mixer == minor)
- break;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
- return nonseekable_open(inode, file);
-}
-
-static int es1371_release_mixdev(struct inode *inode, struct file *file)
-{
- struct es1371_state *s = (struct es1371_state *)file->private_data;
-
- VALIDATE_STATE(s);
- return 0;
-}
-
-static int es1371_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct es1371_state *s = (struct es1371_state *)file->private_data;
- struct ac97_codec *codec = s->codec;
-
- return mixdev_ioctl(codec, cmd, arg);
-}
-
-static /*const*/ struct file_operations es1371_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = es1371_ioctl_mixdev,
- .open = es1371_open_mixdev,
- .release = es1371_release_mixdev,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac1(struct es1371_state *s, int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- int count, tmo;
-
- if (s->dma_dac1.mapped || !s->dma_dac1.ready)
- return 0;
- add_wait_queue(&s->dma_dac1.wait, &wait);
- for (;;) {
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac1.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (nonblock) {
- remove_wait_queue(&s->dma_dac1.wait, &wait);
- set_current_state(TASK_RUNNING);
- return -EBUSY;
- }
- tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2 / s->dac1rate;
- tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT];
- if (!schedule_timeout(tmo + 1))
- DBG(printk(KERN_DEBUG PFX "dac1 dma timed out??\n");)
- }
- remove_wait_queue(&s->dma_dac1.wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-static int drain_dac2(struct es1371_state *s, int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- int count, tmo;
-
- if (s->dma_dac2.mapped || !s->dma_dac2.ready)
- return 0;
- add_wait_queue(&s->dma_dac2.wait, &wait);
- for (;;) {
- __set_current_state(TASK_UNINTERRUPTIBLE);
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac2.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (nonblock) {
- remove_wait_queue(&s->dma_dac2.wait, &wait);
- set_current_state(TASK_RUNNING);
- return -EBUSY;
- }
- tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2 / s->dac2rate;
- tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT];
- if (!schedule_timeout(tmo + 1))
- DBG(printk(KERN_DEBUG PFX "dac2 dma timed out??\n");)
- }
- remove_wait_queue(&s->dma_dac2.wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t es1371_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct es1371_state *s = (struct es1371_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret = 0;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_adc.mapped)
- return -ENXIO;
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- mutex_lock(&s->sem);
- if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
- goto out2;
-
- add_wait_queue(&s->dma_adc.wait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- swptr = s->dma_adc.swptr;
- cnt = s->dma_adc.dmasize-swptr;
- if (s->dma_adc.count < cnt)
- cnt = s->dma_adc.count;
- if (cnt <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (s->dma_adc.enabled)
- start_adc(s);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- goto out;
- }
- mutex_unlock(&s->sem);
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- goto out2;
- }
- mutex_lock(&s->sem);
- if (s->dma_adc.mapped)
- {
- ret = -ENXIO;
- goto out;
- }
- continue;
- }
- if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
- if (!ret)
- ret = -EFAULT;
- goto out;
- }
- swptr = (swptr + cnt) % s->dma_adc.dmasize;
- spin_lock_irqsave(&s->lock, flags);
- s->dma_adc.swptr = swptr;
- s->dma_adc.count -= cnt;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- if (s->dma_adc.enabled)
- start_adc(s);
- }
-out:
- mutex_unlock(&s->sem);
-out2:
- remove_wait_queue(&s->dma_adc.wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-static ssize_t es1371_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct es1371_state *s = (struct es1371_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_dac2.mapped)
- return -ENXIO;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- mutex_lock(&s->sem);
- if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
- goto out3;
- ret = 0;
- add_wait_queue(&s->dma_dac2.wait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- if (s->dma_dac2.count < 0) {
- s->dma_dac2.count = 0;
- s->dma_dac2.swptr = s->dma_dac2.hwptr;
- }
- swptr = s->dma_dac2.swptr;
- cnt = s->dma_dac2.dmasize-swptr;
- if (s->dma_dac2.count + cnt > s->dma_dac2.dmasize)
- cnt = s->dma_dac2.dmasize - s->dma_dac2.count;
- if (cnt <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (s->dma_dac2.enabled)
- start_dac2(s);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- goto out;
- }
- mutex_unlock(&s->sem);
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- goto out2;
- }
- mutex_lock(&s->sem);
- if (s->dma_dac2.mapped)
- {
- ret = -ENXIO;
- goto out;
- }
- continue;
- }
- if (copy_from_user(s->dma_dac2.rawbuf + swptr, buffer, cnt)) {
- if (!ret)
- ret = -EFAULT;
- goto out;
- }
- swptr = (swptr + cnt) % s->dma_dac2.dmasize;
- spin_lock_irqsave(&s->lock, flags);
- s->dma_dac2.swptr = swptr;
- s->dma_dac2.count += cnt;
- s->dma_dac2.endcleared = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- if (s->dma_dac2.enabled)
- start_dac2(s);
- }
-out:
- mutex_unlock(&s->sem);
-out2:
- remove_wait_queue(&s->dma_dac2.wait, &wait);
-out3:
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int es1371_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct es1371_state *s = (struct es1371_state *)file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- VALIDATE_STATE(s);
- if (file->f_mode & FMODE_WRITE) {
- if (!s->dma_dac2.ready && prog_dmabuf_dac2(s))
- return 0;
- poll_wait(file, &s->dma_dac2.wait, wait);
- }
- if (file->f_mode & FMODE_READ) {
- if (!s->dma_adc.ready && prog_dmabuf_adc(s))
- return 0;
- poll_wait(file, &s->dma_adc.wait, wait);
- }
- spin_lock_irqsave(&s->lock, flags);
- es1371_update_ptr(s);
- if (file->f_mode & FMODE_READ) {
- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
- mask |= POLLIN | POLLRDNORM;
- }
- if (file->f_mode & FMODE_WRITE) {
- if (s->dma_dac2.mapped) {
- if (s->dma_dac2.count >= (signed)s->dma_dac2.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- if ((signed)s->dma_dac2.dmasize >= s->dma_dac2.count + (signed)s->dma_dac2.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return mask;
-}
-
-static int es1371_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct es1371_state *s = (struct es1371_state *)file->private_data;
- struct dmabuf *db;
- int ret = 0;
- unsigned long size;
-
- VALIDATE_STATE(s);
- lock_kernel();
- mutex_lock(&s->sem);
-
- if (vma->vm_flags & VM_WRITE) {
- if ((ret = prog_dmabuf_dac2(s)) != 0) {
- goto out;
- }
- db = &s->dma_dac2;
- } else if (vma->vm_flags & VM_READ) {
- if ((ret = prog_dmabuf_adc(s)) != 0) {
- goto out;
- }
- db = &s->dma_adc;
- } else {
- ret = -EINVAL;
- goto out;
- }
- if (vma->vm_pgoff != 0) {
- ret = -EINVAL;
- goto out;
- }
- size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << db->buforder)) {
- ret = -EINVAL;
- goto out;
- }
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot)) {
- ret = -EAGAIN;
- goto out;
- }
- db->mapped = 1;
-out:
- mutex_unlock(&s->sem);
- unlock_kernel();
- return ret;
-}
-
-static int es1371_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct es1371_state *s = (struct es1371_state *)file->private_data;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int count;
- int val, mapped, ret;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- VALIDATE_STATE(s);
- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac2.mapped) ||
- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, p);
-
- case SNDCTL_DSP_SYNC:
- if (file->f_mode & FMODE_WRITE)
- return drain_dac2(s, 0/*file->f_flags & O_NONBLOCK*/);
- return 0;
-
- case SNDCTL_DSP_SETDUPLEX:
- return 0;
-
- case SNDCTL_DSP_GETCAPS:
- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
-
- case SNDCTL_DSP_RESET:
- if (file->f_mode & FMODE_WRITE) {
- stop_dac2(s);
- synchronize_irq(s->irq);
- s->dma_dac2.swptr = s->dma_dac2.hwptr = s->dma_dac2.count = s->dma_dac2.total_bytes = 0;
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- synchronize_irq(s->irq);
- s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
- }
- return 0;
-
- case SNDCTL_DSP_SPEED:
- if (get_user(val, p))
- return -EFAULT;
- if (val >= 0) {
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- set_adc_rate(s, val);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac2(s);
- s->dma_dac2.ready = 0;
- set_dac2_rate(s, val);
- }
- }
- return put_user((file->f_mode & FMODE_READ) ? s->adcrate : s->dac2rate, p);
-
- case SNDCTL_DSP_STEREO:
- if (get_user(val, p))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- spin_lock_irqsave(&s->lock, flags);
- if (val)
- s->sctrl |= SCTRL_R1SMB;
- else
- s->sctrl &= ~SCTRL_R1SMB;
- outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac2(s);
- s->dma_dac2.ready = 0;
- spin_lock_irqsave(&s->lock, flags);
- if (val)
- s->sctrl |= SCTRL_P2SMB;
- else
- s->sctrl &= ~SCTRL_P2SMB;
- outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, p))
- return -EFAULT;
- if (val != 0) {
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- spin_lock_irqsave(&s->lock, flags);
- if (val >= 2)
- s->sctrl |= SCTRL_R1SMB;
- else
- s->sctrl &= ~SCTRL_R1SMB;
- outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac2(s);
- s->dma_dac2.ready = 0;
- spin_lock_irqsave(&s->lock, flags);
- if (val >= 2)
- s->sctrl |= SCTRL_P2SMB;
- else
- s->sctrl &= ~SCTRL_P2SMB;
- outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- }
- return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SMB : SCTRL_P2SMB)) ? 2 : 1, p);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(AFMT_S16_LE|AFMT_U8, p);
-
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- if (get_user(val, p))
- return -EFAULT;
- if (val != AFMT_QUERY) {
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- spin_lock_irqsave(&s->lock, flags);
- if (val == AFMT_S16_LE)
- s->sctrl |= SCTRL_R1SEB;
- else
- s->sctrl &= ~SCTRL_R1SEB;
- outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac2(s);
- s->dma_dac2.ready = 0;
- spin_lock_irqsave(&s->lock, flags);
- if (val == AFMT_S16_LE)
- s->sctrl |= SCTRL_P2SEB;
- else
- s->sctrl &= ~SCTRL_P2SEB;
- outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- }
- return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SEB : SCTRL_P2SEB)) ?
- AFMT_S16_LE : AFMT_U8, p);
-
- case SNDCTL_DSP_POST:
- return 0;
-
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
- if (file->f_mode & FMODE_READ && s->ctrl & CTRL_ADC_EN)
- val |= PCM_ENABLE_INPUT;
- if (file->f_mode & FMODE_WRITE && s->ctrl & CTRL_DAC2_EN)
- val |= PCM_ENABLE_OUTPUT;
- return put_user(val, p);
-
- case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, p))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- if (val & PCM_ENABLE_INPUT) {
- if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
- return ret;
- s->dma_adc.enabled = 1;
- start_adc(s);
- } else {
- s->dma_adc.enabled = 0;
- stop_adc(s);
- }
- }
- if (file->f_mode & FMODE_WRITE) {
- if (val & PCM_ENABLE_OUTPUT) {
- if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
- return ret;
- s->dma_dac2.enabled = 1;
- start_dac2(s);
- } else {
- s->dma_dac2.enabled = 0;
- stop_dac2(s);
- }
- }
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- es1371_update_ptr(s);
- abinfo.fragsize = s->dma_dac2.fragsize;
- count = s->dma_dac2.count;
- if (count < 0)
- count = 0;
- abinfo.bytes = s->dma_dac2.dmasize - count;
- abinfo.fragstotal = s->dma_dac2.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac2.fragshift;
- spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- es1371_update_ptr(s);
- abinfo.fragsize = s->dma_adc.fragsize;
- count = s->dma_adc.count;
- if (count < 0)
- count = 0;
- abinfo.bytes = count;
- abinfo.fragstotal = s->dma_adc.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
- spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_GETODELAY:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- es1371_update_ptr(s);
- count = s->dma_dac2.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count < 0)
- count = 0;
- return put_user(count, p);
-
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- es1371_update_ptr(s);
- cinfo.bytes = s->dma_adc.total_bytes;
- count = s->dma_adc.count;
- if (count < 0)
- count = 0;
- cinfo.blocks = count >> s->dma_adc.fragshift;
- cinfo.ptr = s->dma_adc.hwptr;
- if (s->dma_adc.mapped)
- s->dma_adc.count &= s->dma_adc.fragsize-1;
- spin_unlock_irqrestore(&s->lock, flags);
- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- es1371_update_ptr(s);
- cinfo.bytes = s->dma_dac2.total_bytes;
- count = s->dma_dac2.count;
- if (count < 0)
- count = 0;
- cinfo.blocks = count >> s->dma_dac2.fragshift;
- cinfo.ptr = s->dma_dac2.hwptr;
- if (s->dma_dac2.mapped)
- s->dma_dac2.count &= s->dma_dac2.fragsize-1;
- spin_unlock_irqrestore(&s->lock, flags);
- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETBLKSIZE:
- if (file->f_mode & FMODE_WRITE) {
- if ((val = prog_dmabuf_dac2(s)))
- return val;
- return put_user(s->dma_dac2.fragsize, p);
- }
- if ((val = prog_dmabuf_adc(s)))
- return val;
- return put_user(s->dma_adc.fragsize, p);
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, p))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- s->dma_adc.ossfragshift = val & 0xffff;
- s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_adc.ossfragshift < 4)
- s->dma_adc.ossfragshift = 4;
- if (s->dma_adc.ossfragshift > 15)
- s->dma_adc.ossfragshift = 15;
- if (s->dma_adc.ossmaxfrags < 4)
- s->dma_adc.ossmaxfrags = 4;
- }
- if (file->f_mode & FMODE_WRITE) {
- s->dma_dac2.ossfragshift = val & 0xffff;
- s->dma_dac2.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_dac2.ossfragshift < 4)
- s->dma_dac2.ossfragshift = 4;
- if (s->dma_dac2.ossfragshift > 15)
- s->dma_dac2.ossfragshift = 15;
- if (s->dma_dac2.ossmaxfrags < 4)
- s->dma_dac2.ossmaxfrags = 4;
- }
- return 0;
-
- case SNDCTL_DSP_SUBDIVIDE:
- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
- (file->f_mode & FMODE_WRITE && s->dma_dac2.subdivision))
- return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- if (val != 1 && val != 2 && val != 4)
- return -EINVAL;
- if (file->f_mode & FMODE_READ)
- s->dma_adc.subdivision = val;
- if (file->f_mode & FMODE_WRITE)
- s->dma_dac2.subdivision = val;
- return 0;
-
- case SOUND_PCM_READ_RATE:
- return put_user((file->f_mode & FMODE_READ) ? s->adcrate : s->dac2rate, p);
-
- case SOUND_PCM_READ_CHANNELS:
- return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SMB : SCTRL_P2SMB)) ? 2 : 1, p);
-
- case SOUND_PCM_READ_BITS:
- return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SEB : SCTRL_P2SEB)) ? 16 : 8, p);
-
- case SOUND_PCM_WRITE_FILTER:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_READ_FILTER:
- return -EINVAL;
-
- }
- return mixdev_ioctl(s->codec, cmd, arg);
-}
-
-static int es1371_open(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- struct list_head *list;
- struct es1371_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct es1371_state, devs);
- if (!((s->dev_audio ^ minor) & ~0xf))
- break;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
- /* wait for device to become free */
- mutex_lock(&s->open_mutex);
- while (s->open_mode & file->f_mode) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_mutex);
- return -EBUSY;
- }
- add_wait_queue(&s->open_wait, &wait);
- __set_current_state(TASK_INTERRUPTIBLE);
- mutex_unlock(&s->open_mutex);
- schedule();
- remove_wait_queue(&s->open_wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_mutex);
- }
- if (file->f_mode & FMODE_READ) {
- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
- s->dma_adc.enabled = 1;
- set_adc_rate(s, 8000);
- }
- if (file->f_mode & FMODE_WRITE) {
- s->dma_dac2.ossfragshift = s->dma_dac2.ossmaxfrags = s->dma_dac2.subdivision = 0;
- s->dma_dac2.enabled = 1;
- set_dac2_rate(s, 8000);
- }
- spin_lock_irqsave(&s->lock, flags);
- if (file->f_mode & FMODE_READ) {
- s->sctrl &= ~SCTRL_R1FMT;
- if ((minor & 0xf) == SND_DEV_DSP16)
- s->sctrl |= ES1371_FMT_S16_MONO << SCTRL_SH_R1FMT;
- else
- s->sctrl |= ES1371_FMT_U8_MONO << SCTRL_SH_R1FMT;
- }
- if (file->f_mode & FMODE_WRITE) {
- s->sctrl &= ~SCTRL_P2FMT;
- if ((minor & 0xf) == SND_DEV_DSP16)
- s->sctrl |= ES1371_FMT_S16_MONO << SCTRL_SH_P2FMT;
- else
- s->sctrl |= ES1371_FMT_U8_MONO << SCTRL_SH_P2FMT;
- }
- outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
- mutex_unlock(&s->open_mutex);
- mutex_init(&s->sem);
- return nonseekable_open(inode, file);
-}
-
-static int es1371_release(struct inode *inode, struct file *file)
-{
- struct es1371_state *s = (struct es1371_state *)file->private_data;
-
- VALIDATE_STATE(s);
- lock_kernel();
- if (file->f_mode & FMODE_WRITE)
- drain_dac2(s, file->f_flags & O_NONBLOCK);
- mutex_lock(&s->open_mutex);
- if (file->f_mode & FMODE_WRITE) {
- stop_dac2(s);
- dealloc_dmabuf(s, &s->dma_dac2);
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- dealloc_dmabuf(s, &s->dma_adc);
- }
- s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE));
- mutex_unlock(&s->open_mutex);
- wake_up(&s->open_wait);
- unlock_kernel();
- return 0;
-}
-
-static /*const*/ struct file_operations es1371_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = es1371_read,
- .write = es1371_write,
- .poll = es1371_poll,
- .ioctl = es1371_ioctl,
- .mmap = es1371_mmap,
- .open = es1371_open,
- .release = es1371_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t es1371_write_dac(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct es1371_state *s = (struct es1371_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret = 0;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_dac1.mapped)
- return -ENXIO;
- if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s)))
- return ret;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- add_wait_queue(&s->dma_dac1.wait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- if (s->dma_dac1.count < 0) {
- s->dma_dac1.count = 0;
- s->dma_dac1.swptr = s->dma_dac1.hwptr;
- }
- swptr = s->dma_dac1.swptr;
- cnt = s->dma_dac1.dmasize-swptr;
- if (s->dma_dac1.count + cnt > s->dma_dac1.dmasize)
- cnt = s->dma_dac1.dmasize - s->dma_dac1.count;
- if (cnt <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (s->dma_dac1.enabled)
- start_dac1(s);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
- continue;
- }
- if (copy_from_user(s->dma_dac1.rawbuf + swptr, buffer, cnt)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
- swptr = (swptr + cnt) % s->dma_dac1.dmasize;
- spin_lock_irqsave(&s->lock, flags);
- s->dma_dac1.swptr = swptr;
- s->dma_dac1.count += cnt;
- s->dma_dac1.endcleared = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- if (s->dma_dac1.enabled)
- start_dac1(s);
- }
- remove_wait_queue(&s->dma_dac1.wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int es1371_poll_dac(struct file *file, struct poll_table_struct *wait)
-{
- struct es1371_state *s = (struct es1371_state *)file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- VALIDATE_STATE(s);
- if (!s->dma_dac1.ready && prog_dmabuf_dac1(s))
- return 0;
- poll_wait(file, &s->dma_dac1.wait, wait);
- spin_lock_irqsave(&s->lock, flags);
- es1371_update_ptr(s);
- if (s->dma_dac1.mapped) {
- if (s->dma_dac1.count >= (signed)s->dma_dac1.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- if ((signed)s->dma_dac1.dmasize >= s->dma_dac1.count + (signed)s->dma_dac1.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return mask;
-}
-
-static int es1371_mmap_dac(struct file *file, struct vm_area_struct *vma)
-{
- struct es1371_state *s = (struct es1371_state *)file->private_data;
- int ret;
- unsigned long size;
-
- VALIDATE_STATE(s);
- if (!(vma->vm_flags & VM_WRITE))
- return -EINVAL;
- lock_kernel();
- if ((ret = prog_dmabuf_dac1(s)) != 0)
- goto out;
- ret = -EINVAL;
- if (vma->vm_pgoff != 0)
- goto out;
- size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << s->dma_dac1.buforder))
- goto out;
- ret = -EAGAIN;
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(s->dma_dac1.rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- goto out;
- s->dma_dac1.mapped = 1;
- ret = 0;
-out:
- unlock_kernel();
- return ret;
-}
-
-static int es1371_ioctl_dac(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct es1371_state *s = (struct es1371_state *)file->private_data;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int count;
- int val, ret;
- int __user *p = (int __user *)arg;
-
- VALIDATE_STATE(s);
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, p);
-
- case SNDCTL_DSP_SYNC:
- return drain_dac1(s, 0/*file->f_flags & O_NONBLOCK*/);
-
- case SNDCTL_DSP_SETDUPLEX:
- return -EINVAL;
-
- case SNDCTL_DSP_GETCAPS:
- return put_user(DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
-
- case SNDCTL_DSP_RESET:
- stop_dac1(s);
- synchronize_irq(s->irq);
- s->dma_dac1.swptr = s->dma_dac1.hwptr = s->dma_dac1.count = s->dma_dac1.total_bytes = 0;
- return 0;
-
- case SNDCTL_DSP_SPEED:
- if (get_user(val, p))
- return -EFAULT;
- if (val >= 0) {
- stop_dac1(s);
- s->dma_dac1.ready = 0;
- set_dac1_rate(s, val);
- }
- return put_user(s->dac1rate, p);
-
- case SNDCTL_DSP_STEREO:
- if (get_user(val, p))
- return -EFAULT;
- stop_dac1(s);
- s->dma_dac1.ready = 0;
- spin_lock_irqsave(&s->lock, flags);
- if (val)
- s->sctrl |= SCTRL_P1SMB;
- else
- s->sctrl &= ~SCTRL_P1SMB;
- outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, p))
- return -EFAULT;
- if (val != 0) {
- stop_dac1(s);
- s->dma_dac1.ready = 0;
- spin_lock_irqsave(&s->lock, flags);
- if (val >= 2)
- s->sctrl |= SCTRL_P1SMB;
- else
- s->sctrl &= ~SCTRL_P1SMB;
- outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- return put_user((s->sctrl & SCTRL_P1SMB) ? 2 : 1, p);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(AFMT_S16_LE|AFMT_U8, p);
-
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- if (get_user(val, p))
- return -EFAULT;
- if (val != AFMT_QUERY) {
- stop_dac1(s);
- s->dma_dac1.ready = 0;
- spin_lock_irqsave(&s->lock, flags);
- if (val == AFMT_S16_LE)
- s->sctrl |= SCTRL_P1SEB;
- else
- s->sctrl &= ~SCTRL_P1SEB;
- outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- return put_user((s->sctrl & SCTRL_P1SEB) ? AFMT_S16_LE : AFMT_U8, p);
-
- case SNDCTL_DSP_POST:
- return 0;
-
- case SNDCTL_DSP_GETTRIGGER:
- return put_user((s->ctrl & CTRL_DAC1_EN) ? PCM_ENABLE_OUTPUT : 0, p);
-
- case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, p))
- return -EFAULT;
- if (val & PCM_ENABLE_OUTPUT) {
- if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s)))
- return ret;
- s->dma_dac1.enabled = 1;
- start_dac1(s);
- } else {
- s->dma_dac1.enabled = 0;
- stop_dac1(s);
- }
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- es1371_update_ptr(s);
- abinfo.fragsize = s->dma_dac1.fragsize;
- count = s->dma_dac1.count;
- if (count < 0)
- count = 0;
- abinfo.bytes = s->dma_dac1.dmasize - count;
- abinfo.fragstotal = s->dma_dac1.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac1.fragshift;
- spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_GETODELAY:
- if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- es1371_update_ptr(s);
- count = s->dma_dac1.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count < 0)
- count = 0;
- return put_user(count, p);
-
- case SNDCTL_DSP_GETOPTR:
- if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- es1371_update_ptr(s);
- cinfo.bytes = s->dma_dac1.total_bytes;
- count = s->dma_dac1.count;
- if (count < 0)
- count = 0;
- cinfo.blocks = count >> s->dma_dac1.fragshift;
- cinfo.ptr = s->dma_dac1.hwptr;
- if (s->dma_dac1.mapped)
- s->dma_dac1.count &= s->dma_dac1.fragsize-1;
- spin_unlock_irqrestore(&s->lock, flags);
- if (copy_to_user((void __user *)arg, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETBLKSIZE:
- if ((val = prog_dmabuf_dac1(s)))
- return val;
- return put_user(s->dma_dac1.fragsize, p);
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, p))
- return -EFAULT;
- s->dma_dac1.ossfragshift = val & 0xffff;
- s->dma_dac1.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_dac1.ossfragshift < 4)
- s->dma_dac1.ossfragshift = 4;
- if (s->dma_dac1.ossfragshift > 15)
- s->dma_dac1.ossfragshift = 15;
- if (s->dma_dac1.ossmaxfrags < 4)
- s->dma_dac1.ossmaxfrags = 4;
- return 0;
-
- case SNDCTL_DSP_SUBDIVIDE:
- if (s->dma_dac1.subdivision)
- return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- if (val != 1 && val != 2 && val != 4)
- return -EINVAL;
- s->dma_dac1.subdivision = val;
- return 0;
-
- case SOUND_PCM_READ_RATE:
- return put_user(s->dac1rate, p);
-
- case SOUND_PCM_READ_CHANNELS:
- return put_user((s->sctrl & SCTRL_P1SMB) ? 2 : 1, p);
-
- case SOUND_PCM_READ_BITS:
- return put_user((s->sctrl & SCTRL_P1SEB) ? 16 : 8, p);
-
- case SOUND_PCM_WRITE_FILTER:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_READ_FILTER:
- return -EINVAL;
-
- }
- return mixdev_ioctl(s->codec, cmd, arg);
-}
-
-static int es1371_open_dac(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- struct list_head *list;
- struct es1371_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct es1371_state, devs);
- if (!((s->dev_dac ^ minor) & ~0xf))
- break;
- }
- VALIDATE_STATE(s);
- /* we allow opening with O_RDWR, most programs do it although they will only write */
-#if 0
- if (file->f_mode & FMODE_READ)
- return -EPERM;
-#endif
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- file->private_data = s;
- /* wait for device to become free */
- mutex_lock(&s->open_mutex);
- while (s->open_mode & FMODE_DAC) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_mutex);
- return -EBUSY;
- }
- add_wait_queue(&s->open_wait, &wait);
- __set_current_state(TASK_INTERRUPTIBLE);
- mutex_unlock(&s->open_mutex);
- schedule();
- remove_wait_queue(&s->open_wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_mutex);
- }
- s->dma_dac1.ossfragshift = s->dma_dac1.ossmaxfrags = s->dma_dac1.subdivision = 0;
- s->dma_dac1.enabled = 1;
- set_dac1_rate(s, 8000);
- spin_lock_irqsave(&s->lock, flags);
- s->sctrl &= ~SCTRL_P1FMT;
- if ((minor & 0xf) == SND_DEV_DSP16)
- s->sctrl |= ES1371_FMT_S16_MONO << SCTRL_SH_P1FMT;
- else
- s->sctrl |= ES1371_FMT_U8_MONO << SCTRL_SH_P1FMT;
- outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- s->open_mode |= FMODE_DAC;
- mutex_unlock(&s->open_mutex);
- return nonseekable_open(inode, file);
-}
-
-static int es1371_release_dac(struct inode *inode, struct file *file)
-{
- struct es1371_state *s = (struct es1371_state *)file->private_data;
-
- VALIDATE_STATE(s);
- lock_kernel();
- drain_dac1(s, file->f_flags & O_NONBLOCK);
- mutex_lock(&s->open_mutex);
- stop_dac1(s);
- dealloc_dmabuf(s, &s->dma_dac1);
- s->open_mode &= ~FMODE_DAC;
- mutex_unlock(&s->open_mutex);
- wake_up(&s->open_wait);
- unlock_kernel();
- return 0;
-}
-
-static /*const*/ struct file_operations es1371_dac_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = es1371_write_dac,
- .poll = es1371_poll_dac,
- .ioctl = es1371_ioctl_dac,
- .mmap = es1371_mmap_dac,
- .open = es1371_open_dac,
- .release = es1371_release_dac,
-};
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t es1371_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct es1371_state *s = (struct es1371_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- unsigned ptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- if (count == 0)
- return 0;
- ret = 0;
- add_wait_queue(&s->midi.iwait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- ptr = s->midi.ird;
- cnt = MIDIINBUF - ptr;
- if (s->midi.icnt < cnt)
- cnt = s->midi.icnt;
- if (cnt <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
- continue;
- }
- if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
- ptr = (ptr + cnt) % MIDIINBUF;
- spin_lock_irqsave(&s->lock, flags);
- s->midi.ird = ptr;
- s->midi.icnt -= cnt;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- break;
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&s->midi.iwait, &wait);
- return ret;
-}
-
-static ssize_t es1371_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct es1371_state *s = (struct es1371_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- unsigned ptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- if (count == 0)
- return 0;
- ret = 0;
- add_wait_queue(&s->midi.owait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- ptr = s->midi.owr;
- cnt = MIDIOUTBUF - ptr;
- if (s->midi.ocnt + cnt > MIDIOUTBUF)
- cnt = MIDIOUTBUF - s->midi.ocnt;
- if (cnt <= 0) {
- __set_current_state(TASK_INTERRUPTIBLE);
- es1371_handle_midi(s);
- }
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
- continue;
- }
- if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
- ptr = (ptr + cnt) % MIDIOUTBUF;
- spin_lock_irqsave(&s->lock, flags);
- s->midi.owr = ptr;
- s->midi.ocnt += cnt;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- spin_lock_irqsave(&s->lock, flags);
- es1371_handle_midi(s);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&s->midi.owait, &wait);
- return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int es1371_midi_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct es1371_state *s = (struct es1371_state *)file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- VALIDATE_STATE(s);
- if (file->f_mode & FMODE_WRITE)
- poll_wait(file, &s->midi.owait, wait);
- if (file->f_mode & FMODE_READ)
- poll_wait(file, &s->midi.iwait, wait);
- spin_lock_irqsave(&s->lock, flags);
- if (file->f_mode & FMODE_READ) {
- if (s->midi.icnt > 0)
- mask |= POLLIN | POLLRDNORM;
- }
- if (file->f_mode & FMODE_WRITE) {
- if (s->midi.ocnt < MIDIOUTBUF)
- mask |= POLLOUT | POLLWRNORM;
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return mask;
-}
-
-static int es1371_midi_open(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- struct list_head *list;
- struct es1371_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct es1371_state, devs);
- if (s->dev_midi == minor)
- break;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
- /* wait for device to become free */
- mutex_lock(&s->open_mutex);
- while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_mutex);
- return -EBUSY;
- }
- add_wait_queue(&s->open_wait, &wait);
- __set_current_state(TASK_INTERRUPTIBLE);
- mutex_unlock(&s->open_mutex);
- schedule();
- remove_wait_queue(&s->open_wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_mutex);
- }
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
- s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
- outb(UCTRL_CNTRL_SWR, s->io+ES1371_REG_UART_CONTROL);
- outb(0, s->io+ES1371_REG_UART_CONTROL);
- outb(0, s->io+ES1371_REG_UART_TEST);
- }
- if (file->f_mode & FMODE_READ) {
- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
- }
- if (file->f_mode & FMODE_WRITE) {
- s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
- }
- s->ctrl |= CTRL_UART_EN;
- outl(s->ctrl, s->io+ES1371_REG_CONTROL);
- es1371_handle_midi(s);
- spin_unlock_irqrestore(&s->lock, flags);
- s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
- mutex_unlock(&s->open_mutex);
- return nonseekable_open(inode, file);
-}
-
-static int es1371_midi_release(struct inode *inode, struct file *file)
-{
- struct es1371_state *s = (struct es1371_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- unsigned count, tmo;
-
- VALIDATE_STATE(s);
- lock_kernel();
- if (file->f_mode & FMODE_WRITE) {
- add_wait_queue(&s->midi.owait, &wait);
- for (;;) {
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&s->lock, flags);
- count = s->midi.ocnt;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (file->f_flags & O_NONBLOCK)
- break;
- tmo = (count * HZ) / 3100;
- if (!schedule_timeout(tmo ? : 1) && tmo)
- printk(KERN_DEBUG PFX "midi timed out??\n");
- }
- remove_wait_queue(&s->midi.owait, &wait);
- set_current_state(TASK_RUNNING);
- }
- mutex_lock(&s->open_mutex);
- s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE));
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
- s->ctrl &= ~CTRL_UART_EN;
- outl(s->ctrl, s->io+ES1371_REG_CONTROL);
- }
- spin_unlock_irqrestore(&s->lock, flags);
- mutex_unlock(&s->open_mutex);
- wake_up(&s->open_wait);
- unlock_kernel();
- return 0;
-}
-
-static /*const*/ struct file_operations es1371_midi_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = es1371_midi_read,
- .write = es1371_midi_write,
- .poll = es1371_midi_poll,
- .open = es1371_midi_open,
- .release = es1371_midi_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-/*
- * for debugging purposes, we'll create a proc device that dumps the
- * CODEC chipstate
- */
-
-#ifdef ES1371_DEBUG
-static int proc_es1371_dump (char *buf, char **start, off_t fpos, int length, int *eof, void *data)
-{
- struct es1371_state *s;
- int cnt, len = 0;
-
- if (list_empty(&devs))
- return 0;
- s = list_entry(devs.next, struct es1371_state, devs);
- /* print out header */
- len += sprintf(buf + len, "\t\tCreative ES137x Debug Dump-o-matic\n");
-
- /* print out CODEC state */
- len += sprintf (buf + len, "AC97 CODEC state\n");
- for (cnt=0; cnt <= 0x7e; cnt = cnt +2)
- len+= sprintf (buf + len, "reg:0x%02x val:0x%04x\n", cnt, rdcodec(s->codec, cnt));
-
- if (fpos >=len){
- *start = buf;
- *eof =1;
- return 0;
- }
- *start = buf + fpos;
- if ((len -= fpos) > length)
- return length;
- *eof =1;
- return len;
-
-}
-#endif /* ES1371_DEBUG */
-
-/* --------------------------------------------------------------------- */
-
-/* maximum number of devices; only used for command line params */
-#define NR_DEVICE 5
-
-static int spdif[NR_DEVICE];
-static int nomix[NR_DEVICE];
-static int amplifier[NR_DEVICE];
-
-static unsigned int devindex;
-
-module_param_array(spdif, bool, NULL, 0);
-MODULE_PARM_DESC(spdif, "if 1 the output is in S/PDIF digital mode");
-module_param_array(nomix, bool, NULL, 0);
-MODULE_PARM_DESC(nomix, "if 1 no analog audio is mixed to the digital output");
-module_param_array(amplifier, bool, NULL, 0);
-MODULE_PARM_DESC(amplifier, "Set to 1 if the machine needs the amp control enabling (many laptops)");
-
-MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
-MODULE_DESCRIPTION("ES1371 AudioPCI97 Driver");
-MODULE_LICENSE("GPL");
-
-
-/* --------------------------------------------------------------------- */
-
-static struct initvol {
- int mixch;
- int vol;
-} initvol[] __devinitdata = {
- { SOUND_MIXER_WRITE_LINE, 0x4040 },
- { SOUND_MIXER_WRITE_CD, 0x4040 },
- { MIXER_WRITE(SOUND_MIXER_VIDEO), 0x4040 },
- { SOUND_MIXER_WRITE_LINE1, 0x4040 },
- { SOUND_MIXER_WRITE_PCM, 0x4040 },
- { SOUND_MIXER_WRITE_VOLUME, 0x4040 },
- { MIXER_WRITE(SOUND_MIXER_PHONEOUT), 0x4040 },
- { SOUND_MIXER_WRITE_OGAIN, 0x4040 },
- { MIXER_WRITE(SOUND_MIXER_PHONEIN), 0x4040 },
- { SOUND_MIXER_WRITE_SPEAKER, 0x4040 },
- { SOUND_MIXER_WRITE_MIC, 0x4040 },
- { SOUND_MIXER_WRITE_RECLEV, 0x4040 },
- { SOUND_MIXER_WRITE_IGAIN, 0x4040 }
-};
-
-static struct
-{
- short svid, sdid;
-} amplifier_needed[] =
-{
- { 0x107B, 0x2150 }, /* Gateway Solo 2150 */
- { 0x13BD, 0x100C }, /* Mebius PC-MJ100V */
- { 0x1102, 0x5938 }, /* Targa Xtender 300 */
- { 0x1102, 0x8938 }, /* IPC notebook */
- { PCI_ANY_ID, PCI_ANY_ID }
-};
-
-#ifdef SUPPORT_JOYSTICK
-
-static int __devinit es1371_register_gameport(struct es1371_state *s)
-{
- struct gameport *gp;
- int gpio;
-
- for (gpio = 0x218; gpio >= 0x200; gpio -= 0x08)
- if (request_region(gpio, JOY_EXTENT, "es1371"))
- break;
-
- if (gpio < 0x200) {
- printk(KERN_ERR PFX "no free joystick address found\n");
- return -EBUSY;
- }
-
- s->gameport = gp = gameport_allocate_port();
- if (!gp) {
- printk(KERN_ERR PFX "can not allocate memory for gameport\n");
- release_region(gpio, JOY_EXTENT);
- return -ENOMEM;
- }
-
- gameport_set_name(gp, "ESS1371 Gameport");
- gameport_set_phys(gp, "isa%04x/gameport0", gpio);
- gp->dev.parent = &s->dev->dev;
- gp->io = gpio;
-
- s->ctrl |= CTRL_JYSTK_EN | (((gpio >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
- outl(s->ctrl, s->io + ES1371_REG_CONTROL);
-
- gameport_register_port(gp);
-
- return 0;
-}
-
-static inline void es1371_unregister_gameport(struct es1371_state *s)
-{
- if (s->gameport) {
- int gpio = s->gameport->io;
- gameport_unregister_port(s->gameport);
- release_region(gpio, JOY_EXTENT);
-
- }
-}
-
-#else
-static inline int es1371_register_gameport(struct es1371_state *s) { return -ENOSYS; }
-static inline void es1371_unregister_gameport(struct es1371_state *s) { }
-#endif /* SUPPORT_JOYSTICK */
-
-
-static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
-{
- struct es1371_state *s;
- mm_segment_t fs;
- int i, val, res = -1;
- int idx;
- unsigned long tmo;
- signed long tmo2;
- unsigned int cssr;
-
- if ((res=pci_enable_device(pcidev)))
- return res;
-
- if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_IO))
- return -ENODEV;
- if (pcidev->irq == 0)
- return -ENODEV;
- i = pci_set_dma_mask(pcidev, DMA_32BIT_MASK);
- if (i) {
- printk(KERN_WARNING "es1371: architecture does not support 32bit PCI busmaster DMA\n");
- return i;
- }
- if (!(s = kzalloc(sizeof(struct es1371_state), GFP_KERNEL))) {
- printk(KERN_WARNING PFX "out of memory\n");
- return -ENOMEM;
- }
-
- s->codec = ac97_alloc_codec();
- if(s->codec == NULL)
- goto err_codec;
-
- init_waitqueue_head(&s->dma_adc.wait);
- init_waitqueue_head(&s->dma_dac1.wait);
- init_waitqueue_head(&s->dma_dac2.wait);
- init_waitqueue_head(&s->open_wait);
- init_waitqueue_head(&s->midi.iwait);
- init_waitqueue_head(&s->midi.owait);
- mutex_init(&s->open_mutex);
- spin_lock_init(&s->lock);
- s->magic = ES1371_MAGIC;
- s->dev = pcidev;
- s->io = pci_resource_start(pcidev, 0);
- s->irq = pcidev->irq;
- s->vendor = pcidev->vendor;
- s->device = pcidev->device;
- s->rev = pcidev->revision;
- s->codec->private_data = s;
- s->codec->id = 0;
- s->codec->codec_read = rdcodec;
- s->codec->codec_write = wrcodec;
- printk(KERN_INFO PFX "found chip, vendor id 0x%04x device id 0x%04x revision 0x%02x\n",
- s->vendor, s->device, s->rev);
- if (!request_region(s->io, ES1371_EXTENT, "es1371")) {
- printk(KERN_ERR PFX "io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1);
- res = -EBUSY;
- goto err_region;
- }
- if ((res=request_irq(s->irq, es1371_interrupt, IRQF_SHARED, "es1371",s))) {
- printk(KERN_ERR PFX "irq %u in use\n", s->irq);
- goto err_irq;
- }
- printk(KERN_INFO PFX "found es1371 rev %d at io %#lx irq %u\n",
- s->rev, s->io, s->irq);
- /* register devices */
- if ((res=(s->dev_audio = register_sound_dsp(&es1371_audio_fops,-1)))<0)
- goto err_dev1;
- if ((res=(s->codec->dev_mixer = register_sound_mixer(&es1371_mixer_fops, -1))) < 0)
- goto err_dev2;
- if ((res=(s->dev_dac = register_sound_dsp(&es1371_dac_fops, -1))) < 0)
- goto err_dev3;
- if ((res=(s->dev_midi = register_sound_midi(&es1371_midi_fops, -1)))<0 )
- goto err_dev4;
-#ifdef ES1371_DEBUG
- /* initialize the debug proc device */
- s->ps = create_proc_read_entry("es1371",0,NULL,proc_es1371_dump,NULL);
-#endif /* ES1371_DEBUG */
-
- /* initialize codec registers */
- s->ctrl = 0;
-
- /* Check amplifier requirements */
-
- if (amplifier[devindex])
- s->ctrl |= CTRL_GPIO_OUT0;
- else for(idx = 0; amplifier_needed[idx].svid != PCI_ANY_ID; idx++)
- {
- if(pcidev->subsystem_vendor == amplifier_needed[idx].svid &&
- pcidev->subsystem_device == amplifier_needed[idx].sdid)
- {
- s->ctrl |= CTRL_GPIO_OUT0; /* turn internal amplifier on */
- printk(KERN_INFO PFX "Enabling internal amplifier.\n");
- }
- }
-
- s->sctrl = 0;
- cssr = 0;
- s->spdif_volume = -1;
- /* check to see if s/pdif mode is being requested */
- if (spdif[devindex]) {
- if (s->rev >= 4) {
- printk(KERN_INFO PFX "enabling S/PDIF output\n");
- s->spdif_volume = 0;
- cssr |= STAT_EN_SPDIF;
- s->ctrl |= CTRL_SPDIFEN_B;
- if (nomix[devindex]) /* don't mix analog inputs to s/pdif output */
- s->ctrl |= CTRL_RECEN_B;
- } else {
- printk(KERN_ERR PFX "revision %d does not support S/PDIF\n", s->rev);
- }
- }
- /* initialize the chips */
- outl(s->ctrl, s->io+ES1371_REG_CONTROL);
- outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
- outl(LEGACY_JFAST, s->io+ES1371_REG_LEGACY);
- pci_set_master(pcidev); /* enable bus mastering */
- /* if we are a 5880 turn on the AC97 */
- if (s->vendor == PCI_VENDOR_ID_ENSONIQ &&
- ((s->device == PCI_DEVICE_ID_ENSONIQ_CT5880 && s->rev >= CT5880REV_CT5880_C) ||
- (s->device == PCI_DEVICE_ID_ENSONIQ_ES1371 && s->rev == ES1371REV_CT5880_A) ||
- (s->device == PCI_DEVICE_ID_ENSONIQ_ES1371 && s->rev == ES1371REV_ES1373_8))) {
- cssr |= CSTAT_5880_AC97_RST;
- outl(cssr, s->io+ES1371_REG_STATUS);
- /* need to delay around 20ms(bleech) to give
- some CODECs enough time to wakeup */
- tmo = jiffies + (HZ / 50) + 1;
- for (;;) {
- tmo2 = tmo - jiffies;
- if (tmo2 <= 0)
- break;
- schedule_timeout(tmo2);
- }
- }
- /* AC97 warm reset to start the bitclk */
- outl(s->ctrl | CTRL_SYNCRES, s->io+ES1371_REG_CONTROL);
- udelay(2);
- outl(s->ctrl, s->io+ES1371_REG_CONTROL);
- /* init the sample rate converter */
- src_init(s);
- /* codec init */
- if (!ac97_probe_codec(s->codec)) {
- res = -ENODEV;
- goto err_gp;
- }
- /* set default values */
-
- fs = get_fs();
- set_fs(KERNEL_DS);
- val = SOUND_MASK_LINE;
- mixdev_ioctl(s->codec, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
- for (i = 0; i < ARRAY_SIZE(initvol); i++) {
- val = initvol[i].vol;
- mixdev_ioctl(s->codec, initvol[i].mixch, (unsigned long)&val);
- }
- /* mute master and PCM when in S/PDIF mode */
- if (s->spdif_volume != -1) {
- val = 0x0000;
- s->codec->mixer_ioctl(s->codec, SOUND_MIXER_WRITE_VOLUME, (unsigned long)&val);
- s->codec->mixer_ioctl(s->codec, SOUND_MIXER_WRITE_PCM, (unsigned long)&val);
- }
- set_fs(fs);
- /* turn on S/PDIF output driver if requested */
- outl(cssr, s->io+ES1371_REG_STATUS);
-
- es1371_register_gameport(s);
-
- /* store it in the driver field */
- pci_set_drvdata(pcidev, s);
- /* put it into driver list */
- list_add_tail(&s->devs, &devs);
- /* increment devindex */
- if (devindex < NR_DEVICE-1)
- devindex++;
- return 0;
-
- err_gp:
-#ifdef ES1371_DEBUG
- if (s->ps)
- remove_proc_entry("es1371", NULL);
-#endif
- unregister_sound_midi(s->dev_midi);
- err_dev4:
- unregister_sound_dsp(s->dev_dac);
- err_dev3:
- unregister_sound_mixer(s->codec->dev_mixer);
- err_dev2:
- unregister_sound_dsp(s->dev_audio);
- err_dev1:
- printk(KERN_ERR PFX "cannot register misc device\n");
- free_irq(s->irq, s);
- err_irq:
- release_region(s->io, ES1371_EXTENT);
- err_region:
- err_codec:
- ac97_release_codec(s->codec);
- kfree(s);
- return res;
-}
-
-static void __devexit es1371_remove(struct pci_dev *dev)
-{
- struct es1371_state *s = pci_get_drvdata(dev);
-
- if (!s)
- return;
- list_del(&s->devs);
-#ifdef ES1371_DEBUG
- if (s->ps)
- remove_proc_entry("es1371", NULL);
-#endif /* ES1371_DEBUG */
- outl(0, s->io+ES1371_REG_CONTROL); /* switch everything off */
- outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */
- synchronize_irq(s->irq);
- free_irq(s->irq, s);
- es1371_unregister_gameport(s);
- release_region(s->io, ES1371_EXTENT);
- unregister_sound_dsp(s->dev_audio);
- unregister_sound_mixer(s->codec->dev_mixer);
- unregister_sound_dsp(s->dev_dac);
- unregister_sound_midi(s->dev_midi);
- ac97_release_codec(s->codec);
- kfree(s);
- pci_set_drvdata(dev, NULL);
-}
-
-static struct pci_device_id id_table[] = {
- { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
- { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_CT5880, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
- { PCI_VENDOR_ID_ECTIVA, PCI_DEVICE_ID_ECTIVA_EV1938, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
- { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, id_table);
-
-static struct pci_driver es1371_driver = {
- .name = "es1371",
- .id_table = id_table,
- .probe = es1371_probe,
- .remove = __devexit_p(es1371_remove),
-};
-
-static int __init init_es1371(void)
-{
- printk(KERN_INFO PFX "version v0.32 time " __TIME__ " " __DATE__ "\n");
- return pci_register_driver(&es1371_driver);
-}
-
-static void __exit cleanup_es1371(void)
-{
- printk(KERN_INFO PFX "unloading\n");
- pci_unregister_driver(&es1371_driver);
-}
-
-module_init(init_es1371);
-module_exit(cleanup_es1371);
-
-/* --------------------------------------------------------------------- */
-
-#ifndef MODULE
-
-/* format is: es1371=[spdif,[nomix,[amplifier]]] */
-
-static int __init es1371_setup(char *str)
-{
- static unsigned __initdata nr_dev = 0;
-
- if (nr_dev >= NR_DEVICE)
- return 0;
-
- (void)
- ((get_option(&str, &spdif[nr_dev]) == 2)
- && (get_option(&str, &nomix[nr_dev]) == 2)
- && (get_option(&str, &amplifier[nr_dev])));
-
- nr_dev++;
- return 1;
-}
-
-__setup("es1371=", es1371_setup);
-
-#endif /* MODULE */
diff --git a/sound/oss/hal2.c b/sound/oss/hal2.c
deleted file mode 100644
index a94b9df489d..00000000000
--- a/sound/oss/hal2.c
+++ /dev/null
@@ -1,1558 +0,0 @@
-/*
- * Driver for A2 audio system used in SGI machines
- * Copyright (c) 2001, 2002, 2003 Ladislav Michl <ladis@linux-mips.org>
- *
- * Based on Ulf Carlsson's code.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- *
- * Supported devices:
- * /dev/dsp standard dsp device, (mostly) OSS compatible
- * /dev/mixer standard mixer device, (mostly) OSS compatible
- *
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-#include <linux/mutex.h>
-
-
-#include <asm/io.h>
-#include <asm/sgi/hpc3.h>
-#include <asm/sgi/ip22.h>
-
-#include "hal2.h"
-
-#if 0
-#define DEBUG(args...) printk(args)
-#else
-#define DEBUG(args...)
-#endif
-
-#if 0
-#define DEBUG_MIX(args...) printk(args)
-#else
-#define DEBUG_MIX(args...)
-#endif
-
-/*
- * Before touching these look how it works. It is a bit unusual I know,
- * but it helps to keep things simple. This driver is considered complete
- * and I won't add any new features although hardware has many cool
- * capabilities.
- * (Historical note: HAL2 driver was first written by Ulf Carlsson - ALSA
- * 0.3 running with 2.2.x kernel. Then ALSA changed completely and it
- * seemed easier to me to write OSS driver from scratch - this one. Now
- * when ALSA is official part of 2.6 kernel it's time to write ALSA driver
- * using (hopefully) final version of ALSA interface)
- */
-#define H2_BLOCK_SIZE 1024
-#define H2_ADC_BUFSIZE 8192
-#define H2_DAC_BUFSIZE 16834
-
-struct hal2_pbus {
- struct hpc3_pbus_dmacregs *pbus;
- int pbusnr;
- unsigned int ctrl; /* Current state of pbus->pbdma_ctrl */
-};
-
-struct hal2_desc {
- struct hpc_dma_desc desc;
- u32 cnt; /* don't touch, it is also padding */
-};
-
-struct hal2_codec {
- unsigned char *buffer;
- struct hal2_desc *desc;
- int desc_count;
- int tail, head; /* tail index, head index */
- struct hal2_pbus pbus;
- unsigned int format; /* Audio data format */
- int voices; /* mono/stereo */
- unsigned int sample_rate;
- unsigned int master; /* Master frequency */
- unsigned short mod; /* MOD value */
- unsigned short inc; /* INC value */
-
- wait_queue_head_t dma_wait;
- spinlock_t lock;
- struct mutex sem;
-
- int usecount; /* recording and playback are
- * independent */
-};
-
-#define H2_MIX_OUTPUT_ATT 0
-#define H2_MIX_INPUT_GAIN 1
-#define H2_MIXERS 2
-struct hal2_mixer {
- int modcnt;
- unsigned int master;
- unsigned int volume[H2_MIXERS];
-};
-
-struct hal2_card {
- int dev_dsp; /* audio device */
- int dev_mixer; /* mixer device */
- int dev_midi; /* midi device */
-
- struct hal2_ctl_regs *ctl_regs; /* HAL2 ctl registers */
- struct hal2_aes_regs *aes_regs; /* HAL2 aes registers */
- struct hal2_vol_regs *vol_regs; /* HAL2 vol registers */
- struct hal2_syn_regs *syn_regs; /* HAL2 syn registers */
-
- struct hal2_codec dac;
- struct hal2_codec adc;
- struct hal2_mixer mixer;
-};
-
-#define H2_INDIRECT_WAIT(regs) while (regs->isr & H2_ISR_TSTATUS);
-
-#define H2_READ_ADDR(addr) (addr | (1<<7))
-#define H2_WRITE_ADDR(addr) (addr)
-
-static char *hal2str = "HAL2";
-
-/*
- * I doubt anyone has a machine with two HAL2 cards. It's possible to
- * have two HPC's, so it is probably possible to have two HAL2 cards.
- * Try to deal with it, but note that it is not tested.
- */
-#define MAXCARDS 2
-static struct hal2_card* hal2_card[MAXCARDS];
-
-static const struct {
- unsigned char idx:4, avail:1;
-} mixtable[SOUND_MIXER_NRDEVICES] = {
- [SOUND_MIXER_PCM] = { H2_MIX_OUTPUT_ATT, 1 }, /* voice */
- [SOUND_MIXER_MIC] = { H2_MIX_INPUT_GAIN, 1 }, /* mic */
-};
-
-#define H2_SUPPORTED_FORMATS (AFMT_S16_LE | AFMT_S16_BE)
-
-static inline void hal2_isr_write(struct hal2_card *hal2, u16 val)
-{
- hal2->ctl_regs->isr = val;
-}
-
-static inline u16 hal2_isr_look(struct hal2_card *hal2)
-{
- return hal2->ctl_regs->isr;
-}
-
-static inline u16 hal2_rev_look(struct hal2_card *hal2)
-{
- return hal2->ctl_regs->rev;
-}
-
-#ifdef HAL2_DUMP_REGS
-static u16 hal2_i_look16(struct hal2_card *hal2, u16 addr)
-{
- struct hal2_ctl_regs *regs = hal2->ctl_regs;
-
- regs->iar = H2_READ_ADDR(addr);
- H2_INDIRECT_WAIT(regs);
- return regs->idr0;
-}
-#endif
-
-static u32 hal2_i_look32(struct hal2_card *hal2, u16 addr)
-{
- u32 ret;
- struct hal2_ctl_regs *regs = hal2->ctl_regs;
-
- regs->iar = H2_READ_ADDR(addr);
- H2_INDIRECT_WAIT(regs);
- ret = regs->idr0 & 0xffff;
- regs->iar = H2_READ_ADDR(addr | 0x1);
- H2_INDIRECT_WAIT(regs);
- ret |= (regs->idr0 & 0xffff) << 16;
- return ret;
-}
-
-static void hal2_i_write16(struct hal2_card *hal2, u16 addr, u16 val)
-{
- struct hal2_ctl_regs *regs = hal2->ctl_regs;
-
- regs->idr0 = val;
- regs->idr1 = 0;
- regs->idr2 = 0;
- regs->idr3 = 0;
- regs->iar = H2_WRITE_ADDR(addr);
- H2_INDIRECT_WAIT(regs);
-}
-
-static void hal2_i_write32(struct hal2_card *hal2, u16 addr, u32 val)
-{
- struct hal2_ctl_regs *regs = hal2->ctl_regs;
-
- regs->idr0 = val & 0xffff;
- regs->idr1 = val >> 16;
- regs->idr2 = 0;
- regs->idr3 = 0;
- regs->iar = H2_WRITE_ADDR(addr);
- H2_INDIRECT_WAIT(regs);
-}
-
-static void hal2_i_setbit16(struct hal2_card *hal2, u16 addr, u16 bit)
-{
- struct hal2_ctl_regs *regs = hal2->ctl_regs;
-
- regs->iar = H2_READ_ADDR(addr);
- H2_INDIRECT_WAIT(regs);
- regs->idr0 = (regs->idr0 & 0xffff) | bit;
- regs->idr1 = 0;
- regs->idr2 = 0;
- regs->idr3 = 0;
- regs->iar = H2_WRITE_ADDR(addr);
- H2_INDIRECT_WAIT(regs);
-}
-
-static void hal2_i_setbit32(struct hal2_card *hal2, u16 addr, u32 bit)
-{
- u32 tmp;
- struct hal2_ctl_regs *regs = hal2->ctl_regs;
-
- regs->iar = H2_READ_ADDR(addr);
- H2_INDIRECT_WAIT(regs);
- tmp = (regs->idr0 & 0xffff) | (regs->idr1 << 16) | bit;
- regs->idr0 = tmp & 0xffff;
- regs->idr1 = tmp >> 16;
- regs->idr2 = 0;
- regs->idr3 = 0;
- regs->iar = H2_WRITE_ADDR(addr);
- H2_INDIRECT_WAIT(regs);
-}
-
-static void hal2_i_clearbit16(struct hal2_card *hal2, u16 addr, u16 bit)
-{
- struct hal2_ctl_regs *regs = hal2->ctl_regs;
-
- regs->iar = H2_READ_ADDR(addr);
- H2_INDIRECT_WAIT(regs);
- regs->idr0 = (regs->idr0 & 0xffff) & ~bit;
- regs->idr1 = 0;
- regs->idr2 = 0;
- regs->idr3 = 0;
- regs->iar = H2_WRITE_ADDR(addr);
- H2_INDIRECT_WAIT(regs);
-}
-
-#if 0
-static void hal2_i_clearbit32(struct hal2_card *hal2, u16 addr, u32 bit)
-{
- u32 tmp;
- hal2_ctl_regs_t *regs = hal2->ctl_regs;
-
- regs->iar = H2_READ_ADDR(addr);
- H2_INDIRECT_WAIT(regs);
- tmp = ((regs->idr0 & 0xffff) | (regs->idr1 << 16)) & ~bit;
- regs->idr0 = tmp & 0xffff;
- regs->idr1 = tmp >> 16;
- regs->idr2 = 0;
- regs->idr3 = 0;
- regs->iar = H2_WRITE_ADDR(addr);
- H2_INDIRECT_WAIT(regs);
-}
-#endif
-
-#ifdef HAL2_DUMP_REGS
-static void hal2_dump_regs(struct hal2_card *hal2)
-{
- DEBUG("isr: %08hx ", hal2_isr_look(hal2));
- DEBUG("rev: %08hx\n", hal2_rev_look(hal2));
- DEBUG("relay: %04hx\n", hal2_i_look16(hal2, H2I_RELAY_C));
- DEBUG("port en: %04hx ", hal2_i_look16(hal2, H2I_DMA_PORT_EN));
- DEBUG("dma end: %04hx ", hal2_i_look16(hal2, H2I_DMA_END));
- DEBUG("dma drv: %04hx\n", hal2_i_look16(hal2, H2I_DMA_DRV));
- DEBUG("syn ctl: %04hx ", hal2_i_look16(hal2, H2I_SYNTH_C));
- DEBUG("aesrx ctl: %04hx ", hal2_i_look16(hal2, H2I_AESRX_C));
- DEBUG("aestx ctl: %04hx ", hal2_i_look16(hal2, H2I_AESTX_C));
- DEBUG("dac ctl1: %04hx ", hal2_i_look16(hal2, H2I_ADC_C1));
- DEBUG("dac ctl2: %08x ", hal2_i_look32(hal2, H2I_ADC_C2));
- DEBUG("adc ctl1: %04hx ", hal2_i_look16(hal2, H2I_DAC_C1));
- DEBUG("adc ctl2: %08x ", hal2_i_look32(hal2, H2I_DAC_C2));
- DEBUG("syn map: %04hx\n", hal2_i_look16(hal2, H2I_SYNTH_MAP_C));
- DEBUG("bres1 ctl1: %04hx ", hal2_i_look16(hal2, H2I_BRES1_C1));
- DEBUG("bres1 ctl2: %04x ", hal2_i_look32(hal2, H2I_BRES1_C2));
- DEBUG("bres2 ctl1: %04hx ", hal2_i_look16(hal2, H2I_BRES2_C1));
- DEBUG("bres2 ctl2: %04x ", hal2_i_look32(hal2, H2I_BRES2_C2));
- DEBUG("bres3 ctl1: %04hx ", hal2_i_look16(hal2, H2I_BRES3_C1));
- DEBUG("bres3 ctl2: %04x\n", hal2_i_look32(hal2, H2I_BRES3_C2));
-}
-#endif
-
-static struct hal2_card* hal2_dsp_find_card(int minor)
-{
- int i;
-
- for (i = 0; i < MAXCARDS; i++)
- if (hal2_card[i] != NULL && hal2_card[i]->dev_dsp == minor)
- return hal2_card[i];
- return NULL;
-}
-
-static struct hal2_card* hal2_mixer_find_card(int minor)
-{
- int i;
-
- for (i = 0; i < MAXCARDS; i++)
- if (hal2_card[i] != NULL && hal2_card[i]->dev_mixer == minor)
- return hal2_card[i];
- return NULL;
-}
-
-static void hal2_inc_head(struct hal2_codec *codec)
-{
- codec->head++;
- if (codec->head == codec->desc_count)
- codec->head = 0;
-}
-
-static void hal2_inc_tail(struct hal2_codec *codec)
-{
- codec->tail++;
- if (codec->tail == codec->desc_count)
- codec->tail = 0;
-}
-
-static void hal2_dac_interrupt(struct hal2_codec *dac)
-{
- int running;
-
- spin_lock(&dac->lock);
- /* if tail buffer contains zero samples DMA stream was already
- * stopped */
- running = dac->desc[dac->tail].cnt;
- dac->desc[dac->tail].cnt = 0;
- dac->desc[dac->tail].desc.cntinfo = HPCDMA_XIE | HPCDMA_EOX;
- /* we just proccessed empty buffer, don't update tail pointer */
- if (running)
- hal2_inc_tail(dac);
- spin_unlock(&dac->lock);
-
- wake_up(&dac->dma_wait);
-}
-
-static void hal2_adc_interrupt(struct hal2_codec *adc)
-{
- int running;
-
- spin_lock(&adc->lock);
- /* if head buffer contains nonzero samples DMA stream was already
- * stopped */
- running = !adc->desc[adc->head].cnt;
- adc->desc[adc->head].cnt = H2_BLOCK_SIZE;
- adc->desc[adc->head].desc.cntinfo = HPCDMA_XIE | HPCDMA_EOR;
- /* we just proccessed empty buffer, don't update head pointer */
- if (running)
- hal2_inc_head(adc);
- spin_unlock(&adc->lock);
-
- wake_up(&adc->dma_wait);
-}
-
-static irqreturn_t hal2_interrupt(int irq, void *dev_id)
-{
- struct hal2_card *hal2 = dev_id;
- irqreturn_t ret = IRQ_NONE;
-
- /* decide what caused this interrupt */
- if (hal2->dac.pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_INT) {
- hal2_dac_interrupt(&hal2->dac);
- ret = IRQ_HANDLED;
- }
- if (hal2->adc.pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_INT) {
- hal2_adc_interrupt(&hal2->adc);
- ret = IRQ_HANDLED;
- }
- return ret;
-}
-
-static int hal2_compute_rate(struct hal2_codec *codec, unsigned int rate)
-{
- unsigned short mod;
-
- DEBUG("rate: %d\n", rate);
-
- if (rate < 4000) rate = 4000;
- else if (rate > 48000) rate = 48000;
-
- if (44100 % rate < 48000 % rate) {
- mod = 4 * 44100 / rate;
- codec->master = 44100;
- } else {
- mod = 4 * 48000 / rate;
- codec->master = 48000;
- }
-
- codec->inc = 4;
- codec->mod = mod;
- rate = 4 * codec->master / mod;
-
- DEBUG("real_rate: %d\n", rate);
-
- return rate;
-}
-
-static void hal2_set_dac_rate(struct hal2_card *hal2)
-{
- unsigned int master = hal2->dac.master;
- int inc = hal2->dac.inc;
- int mod = hal2->dac.mod;
-
- DEBUG("master: %d inc: %d mod: %d\n", master, inc, mod);
-
- hal2_i_write16(hal2, H2I_BRES1_C1, (master == 44100) ? 1 : 0);
- hal2_i_write32(hal2, H2I_BRES1_C2, ((0xffff & (inc - mod - 1)) << 16) | inc);
-}
-
-static void hal2_set_adc_rate(struct hal2_card *hal2)
-{
- unsigned int master = hal2->adc.master;
- int inc = hal2->adc.inc;
- int mod = hal2->adc.mod;
-
- DEBUG("master: %d inc: %d mod: %d\n", master, inc, mod);
-
- hal2_i_write16(hal2, H2I_BRES2_C1, (master == 44100) ? 1 : 0);
- hal2_i_write32(hal2, H2I_BRES2_C2, ((0xffff & (inc - mod - 1)) << 16) | inc);
-}
-
-static void hal2_setup_dac(struct hal2_card *hal2)
-{
- unsigned int fifobeg, fifoend, highwater, sample_size;
- struct hal2_pbus *pbus = &hal2->dac.pbus;
-
- DEBUG("hal2_setup_dac\n");
-
- /* Now we set up some PBUS information. The PBUS needs information about
- * what portion of the fifo it will use. If it's receiving or
- * transmitting, and finally whether the stream is little endian or big
- * endian. The information is written later, on the start call.
- */
- sample_size = 2 * hal2->dac.voices;
- /* Fifo should be set to hold exactly four samples. Highwater mark
- * should be set to two samples. */
- highwater = (sample_size * 2) >> 1; /* halfwords */
- fifobeg = 0; /* playback is first */
- fifoend = (sample_size * 4) >> 3; /* doublewords */
- pbus->ctrl = HPC3_PDMACTRL_RT | HPC3_PDMACTRL_LD |
- (highwater << 8) | (fifobeg << 16) | (fifoend << 24) |
- (hal2->dac.format & AFMT_S16_LE ? HPC3_PDMACTRL_SEL : 0);
- /* We disable everything before we do anything at all */
- pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
- hal2_i_clearbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECTX);
- /* Setup the HAL2 for playback */
- hal2_set_dac_rate(hal2);
- /* Set endianess */
- if (hal2->dac.format & AFMT_S16_LE)
- hal2_i_setbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECTX);
- else
- hal2_i_clearbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECTX);
- /* Set DMA bus */
- hal2_i_setbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr));
- /* We are using 1st Bresenham clock generator for playback */
- hal2_i_write16(hal2, H2I_DAC_C1, (pbus->pbusnr << H2I_C1_DMA_SHIFT)
- | (1 << H2I_C1_CLKID_SHIFT)
- | (hal2->dac.voices << H2I_C1_DATAT_SHIFT));
-}
-
-static void hal2_setup_adc(struct hal2_card *hal2)
-{
- unsigned int fifobeg, fifoend, highwater, sample_size;
- struct hal2_pbus *pbus = &hal2->adc.pbus;
-
- DEBUG("hal2_setup_adc\n");
-
- sample_size = 2 * hal2->adc.voices;
- highwater = (sample_size * 2) >> 1; /* halfwords */
- fifobeg = (4 * 4) >> 3; /* record is second */
- fifoend = (4 * 4 + sample_size * 4) >> 3; /* doublewords */
- pbus->ctrl = HPC3_PDMACTRL_RT | HPC3_PDMACTRL_RCV | HPC3_PDMACTRL_LD |
- (highwater << 8) | (fifobeg << 16) | (fifoend << 24) |
- (hal2->adc.format & AFMT_S16_LE ? HPC3_PDMACTRL_SEL : 0);
- pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
- hal2_i_clearbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR);
- /* Setup the HAL2 for record */
- hal2_set_adc_rate(hal2);
- /* Set endianess */
- if (hal2->adc.format & AFMT_S16_LE)
- hal2_i_setbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECR);
- else
- hal2_i_clearbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECR);
- /* Set DMA bus */
- hal2_i_setbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr));
- /* We are using 2nd Bresenham clock generator for record */
- hal2_i_write16(hal2, H2I_ADC_C1, (pbus->pbusnr << H2I_C1_DMA_SHIFT)
- | (2 << H2I_C1_CLKID_SHIFT)
- | (hal2->adc.voices << H2I_C1_DATAT_SHIFT));
-}
-
-static dma_addr_t hal2_desc_addr(struct hal2_codec *codec, int i)
-{
- if (--i < 0)
- i = codec->desc_count - 1;
- return codec->desc[i].desc.pnext;
-}
-
-static void hal2_start_dac(struct hal2_card *hal2)
-{
- struct hal2_codec *dac = &hal2->dac;
- struct hal2_pbus *pbus = &dac->pbus;
-
- pbus->pbus->pbdma_dptr = hal2_desc_addr(dac, dac->tail);
- pbus->pbus->pbdma_ctrl = pbus->ctrl | HPC3_PDMACTRL_ACT;
- /* enable DAC */
- hal2_i_setbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECTX);
-}
-
-static void hal2_start_adc(struct hal2_card *hal2)
-{
- struct hal2_codec *adc = &hal2->adc;
- struct hal2_pbus *pbus = &adc->pbus;
-
- pbus->pbus->pbdma_dptr = hal2_desc_addr(adc, adc->head);
- pbus->pbus->pbdma_ctrl = pbus->ctrl | HPC3_PDMACTRL_ACT;
- /* enable ADC */
- hal2_i_setbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR);
-}
-
-static inline void hal2_stop_dac(struct hal2_card *hal2)
-{
- hal2->dac.pbus.pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
- /* The HAL2 itself may remain enabled safely */
-}
-
-static inline void hal2_stop_adc(struct hal2_card *hal2)
-{
- hal2->adc.pbus.pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
-}
-
-static int hal2_alloc_dmabuf(struct hal2_codec *codec, int size,
- int count, int cntinfo, int dir)
-{
- struct hal2_desc *desc, *dma_addr;
- int i;
-
- DEBUG("allocating %dk DMA buffer.\n", size / 1024);
-
- codec->buffer = (unsigned char *)__get_free_pages(GFP_KERNEL | GFP_DMA,
- get_order(size));
- if (!codec->buffer)
- return -ENOMEM;
- desc = dma_alloc_coherent(NULL, count * sizeof(struct hal2_desc),
- (dma_addr_t *)&dma_addr, GFP_KERNEL);
- if (!desc) {
- free_pages((unsigned long)codec->buffer, get_order(size));
- return -ENOMEM;
- }
- codec->desc = desc;
- for (i = 0; i < count; i++) {
- desc->desc.pbuf = dma_map_single(NULL,
- (void *)(codec->buffer + i * H2_BLOCK_SIZE),
- H2_BLOCK_SIZE, dir);
- desc->desc.cntinfo = cntinfo;
- desc->desc.pnext = (i == count - 1) ?
- (u32)dma_addr : (u32)(dma_addr + i + 1);
- desc->cnt = 0;
- desc++;
- }
- codec->desc_count = count;
- codec->head = codec->tail = 0;
- return 0;
-}
-
-static int hal2_alloc_dac_dmabuf(struct hal2_codec *codec)
-{
- return hal2_alloc_dmabuf(codec, H2_DAC_BUFSIZE,
- H2_DAC_BUFSIZE / H2_BLOCK_SIZE,
- HPCDMA_XIE | HPCDMA_EOX,
- DMA_TO_DEVICE);
-}
-
-static int hal2_alloc_adc_dmabuf(struct hal2_codec *codec)
-{
- return hal2_alloc_dmabuf(codec, H2_ADC_BUFSIZE,
- H2_ADC_BUFSIZE / H2_BLOCK_SIZE,
- HPCDMA_XIE | H2_BLOCK_SIZE,
- DMA_TO_DEVICE);
-}
-
-static void hal2_free_dmabuf(struct hal2_codec *codec, int size, int dir)
-{
- dma_addr_t dma_addr;
- int i;
-
- dma_addr = codec->desc[codec->desc_count - 1].desc.pnext;
- for (i = 0; i < codec->desc_count; i++)
- dma_unmap_single(NULL, codec->desc[i].desc.pbuf,
- H2_BLOCK_SIZE, dir);
- dma_free_coherent(NULL, codec->desc_count * sizeof(struct hal2_desc),
- (void *)codec->desc, dma_addr);
- free_pages((unsigned long)codec->buffer, get_order(size));
-}
-
-static void hal2_free_dac_dmabuf(struct hal2_codec *codec)
-{
- return hal2_free_dmabuf(codec, H2_DAC_BUFSIZE, DMA_TO_DEVICE);
-}
-
-static void hal2_free_adc_dmabuf(struct hal2_codec *codec)
-{
- return hal2_free_dmabuf(codec, H2_ADC_BUFSIZE, DMA_FROM_DEVICE);
-}
-
-/*
- * Add 'count' bytes to 'buffer' from DMA ring buffers. Return number of
- * bytes added or -EFAULT if copy_from_user failed.
- */
-static int hal2_get_buffer(struct hal2_card *hal2, char *buffer, int count)
-{
- unsigned long flags;
- int size, ret = 0;
- unsigned char *buf;
- struct hal2_desc *tail;
- struct hal2_codec *adc = &hal2->adc;
-
- DEBUG("getting %d bytes ", count);
-
- spin_lock_irqsave(&adc->lock, flags);
- tail = &adc->desc[adc->tail];
- /* enable DMA stream if there are no data */
- if (!tail->cnt && !(adc->pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_ISACT))
- hal2_start_adc(hal2);
- while (tail->cnt > 0 && count > 0) {
- size = min((int)tail->cnt, count);
- buf = &adc->buffer[(adc->tail + 1) * H2_BLOCK_SIZE - tail->cnt];
- spin_unlock_irqrestore(&adc->lock, flags);
- dma_sync_single(NULL, tail->desc.pbuf, size, DMA_FROM_DEVICE);
- if (copy_to_user(buffer, buf, size)) {
- ret = -EFAULT;
- goto out;
- }
- spin_lock_irqsave(&adc->lock, flags);
- tail->cnt -= size;
- /* buffer is empty, update tail pointer */
- if (tail->cnt == 0) {
- tail->desc.cntinfo = HPCDMA_XIE | H2_BLOCK_SIZE;
- hal2_inc_tail(adc);
- tail = &adc->desc[adc->tail];
- /* enable DMA stream again if needed */
- if (!(adc->pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_ISACT))
- hal2_start_adc(hal2);
- }
- buffer += size;
- ret += size;
- count -= size;
-
- DEBUG("(%d) ", size);
- }
- spin_unlock_irqrestore(&adc->lock, flags);
-out:
- DEBUG("\n");
-
- return ret;
-}
-
-/*
- * Add 'count' bytes from 'buffer' to DMA ring buffers. Return number of
- * bytes added or -EFAULT if copy_from_user failed.
- */
-static int hal2_add_buffer(struct hal2_card *hal2, char *buffer, int count)
-{
- unsigned long flags;
- unsigned char *buf;
- int size, ret = 0;
- struct hal2_desc *head;
- struct hal2_codec *dac = &hal2->dac;
-
- DEBUG("adding %d bytes ", count);
-
- spin_lock_irqsave(&dac->lock, flags);
- head = &dac->desc[dac->head];
- while (head->cnt == 0 && count > 0) {
- size = min((int)H2_BLOCK_SIZE, count);
- buf = &dac->buffer[dac->head * H2_BLOCK_SIZE];
- spin_unlock_irqrestore(&dac->lock, flags);
- if (copy_from_user(buf, buffer, size)) {
- ret = -EFAULT;
- goto out;
- }
- dma_sync_single(NULL, head->desc.pbuf, size, DMA_TO_DEVICE);
- spin_lock_irqsave(&dac->lock, flags);
- head->desc.cntinfo = size | HPCDMA_XIE;
- head->cnt = size;
- buffer += size;
- ret += size;
- count -= size;
- hal2_inc_head(dac);
- head = &dac->desc[dac->head];
-
- DEBUG("(%d) ", size);
- }
- if (!(dac->pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_ISACT) && ret > 0)
- hal2_start_dac(hal2);
- spin_unlock_irqrestore(&dac->lock, flags);
-out:
- DEBUG("\n");
-
- return ret;
-}
-
-#define hal2_reset_dac_pointer(hal2) hal2_reset_pointer(hal2, 1)
-#define hal2_reset_adc_pointer(hal2) hal2_reset_pointer(hal2, 0)
-static void hal2_reset_pointer(struct hal2_card *hal2, int is_dac)
-{
- int i;
- struct hal2_codec *codec = (is_dac) ? &hal2->dac : &hal2->adc;
-
- DEBUG("hal2_reset_pointer\n");
-
- for (i = 0; i < codec->desc_count; i++) {
- codec->desc[i].cnt = 0;
- codec->desc[i].desc.cntinfo = HPCDMA_XIE | (is_dac) ?
- HPCDMA_EOX : H2_BLOCK_SIZE;
- }
- codec->head = codec->tail = 0;
-}
-
-static int hal2_sync_dac(struct hal2_card *hal2)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct hal2_codec *dac = &hal2->dac;
- int ret = 0;
- unsigned long flags;
- signed long timeout = 1000 * H2_BLOCK_SIZE * 2 * dac->voices *
- HZ / dac->sample_rate / 900;
-
- while (dac->pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_ISACT) {
- add_wait_queue(&dac->dma_wait, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(timeout);
- spin_lock_irqsave(&dac->lock, flags);
- if (dac->desc[dac->tail].cnt)
- ret = -ETIME;
- spin_unlock_irqrestore(&dac->lock, flags);
- if (signal_pending(current))
- ret = -ERESTARTSYS;
- if (ret) {
- hal2_stop_dac(hal2);
- hal2_reset_dac_pointer(hal2);
- }
- remove_wait_queue(&dac->dma_wait, &wait);
- }
-
- return ret;
-}
-
-static int hal2_write_mixer(struct hal2_card *hal2, int index, int vol)
-{
- unsigned int l, r, tmp;
-
- DEBUG_MIX("mixer %d write\n", index);
-
- if (index >= SOUND_MIXER_NRDEVICES || !mixtable[index].avail)
- return -EINVAL;
-
- r = (vol >> 8) & 0xff;
- if (r > 100)
- r = 100;
- l = vol & 0xff;
- if (l > 100)
- l = 100;
-
- hal2->mixer.volume[mixtable[index].idx] = l | (r << 8);
-
- switch (mixtable[index].idx) {
- case H2_MIX_OUTPUT_ATT:
-
- DEBUG_MIX("output attenuator %d,%d\n", l, r);
-
- if (r | l) {
- tmp = hal2_i_look32(hal2, H2I_DAC_C2);
- tmp &= ~(H2I_C2_L_ATT_M | H2I_C2_R_ATT_M | H2I_C2_MUTE);
-
- /* Attenuator has five bits */
- l = 31 * (100 - l) / 99;
- r = 31 * (100 - r) / 99;
-
- DEBUG_MIX("left: %d, right %d\n", l, r);
-
- tmp |= (l << H2I_C2_L_ATT_SHIFT) & H2I_C2_L_ATT_M;
- tmp |= (r << H2I_C2_R_ATT_SHIFT) & H2I_C2_R_ATT_M;
- hal2_i_write32(hal2, H2I_DAC_C2, tmp);
- } else
- hal2_i_setbit32(hal2, H2I_DAC_C2, H2I_C2_MUTE);
- break;
- case H2_MIX_INPUT_GAIN:
-
- DEBUG_MIX("input gain %d,%d\n", l, r);
-
- tmp = hal2_i_look32(hal2, H2I_ADC_C2);
- tmp &= ~(H2I_C2_L_GAIN_M | H2I_C2_R_GAIN_M);
-
- /* Gain control has four bits */
- l = 16 * l / 100;
- r = 16 * r / 100;
-
- DEBUG_MIX("left: %d, right %d\n", l, r);
-
- tmp |= (l << H2I_C2_L_GAIN_SHIFT) & H2I_C2_L_GAIN_M;
- tmp |= (r << H2I_C2_R_GAIN_SHIFT) & H2I_C2_R_GAIN_M;
- hal2_i_write32(hal2, H2I_ADC_C2, tmp);
-
- break;
- }
-
- return 0;
-}
-
-static void hal2_init_mixer(struct hal2_card *hal2)
-{
- int i;
-
- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (mixtable[i].avail)
- hal2->mixer.volume[mixtable[i].idx] = 100 | (100 << 8);
-
- /* disable attenuator */
- hal2_i_write32(hal2, H2I_DAC_C2, 0);
- /* set max input gain */
- hal2_i_write32(hal2, H2I_ADC_C2, H2I_C2_MUTE |
- (H2I_C2_L_GAIN_M << H2I_C2_L_GAIN_SHIFT) |
- (H2I_C2_R_GAIN_M << H2I_C2_R_GAIN_SHIFT));
- /* set max volume */
- hal2->mixer.master = 0xff;
- hal2->vol_regs->left = 0xff;
- hal2->vol_regs->right = 0xff;
-}
-
-/*
- * XXX: later i'll implement mixer for main volume which will be disabled
- * by default. enabling it users will be allowed to have master volume level
- * control on panel in their favourite X desktop
- */
-static void hal2_volume_control(int direction)
-{
- unsigned int master = hal2_card[0]->mixer.master;
- struct hal2_vol_regs *vol = hal2_card[0]->vol_regs;
-
- /* volume up */
- if (direction > 0 && master < 0xff)
- master++;
- /* volume down */
- else if (direction < 0 && master > 0)
- master--;
- /* TODO: mute/unmute */
- vol->left = master;
- vol->right = master;
- hal2_card[0]->mixer.master = master;
-}
-
-static int hal2_mixer_ioctl(struct hal2_card *hal2, unsigned int cmd,
- unsigned long arg)
-{
- int val;
-
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
-
- memset(&info, 0, sizeof(info));
- strlcpy(info.id, hal2str, sizeof(info.id));
- strlcpy(info.name, hal2str, sizeof(info.name));
- info.modify_counter = hal2->mixer.modcnt;
- if (copy_to_user((void *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == SOUND_OLD_MIXER_INFO) {
- _old_mixer_info info;
-
- memset(&info, 0, sizeof(info));
- strlcpy(info.id, hal2str, sizeof(info.id));
- strlcpy(info.name, hal2str, sizeof(info.name));
- if (copy_to_user((void *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, (int *)arg);
-
- if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
- return -EINVAL;
-
- if (_IOC_DIR(cmd) == _IOC_READ) {
- switch (_IOC_NR(cmd)) {
- /* Give the current record source */
- case SOUND_MIXER_RECSRC:
- val = 0; /* FIXME */
- break;
- /* Give the supported mixers, all of them support stereo */
- case SOUND_MIXER_DEVMASK:
- case SOUND_MIXER_STEREODEVS: {
- int i;
-
- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (mixtable[i].avail)
- val |= 1 << i;
- break;
- }
- /* Arg contains a bit for each supported recording source */
- case SOUND_MIXER_RECMASK:
- val = 0;
- break;
- case SOUND_MIXER_CAPS:
- val = 0;
- break;
- /* Read a specific mixer */
- default: {
- int i = _IOC_NR(cmd);
-
- if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].avail)
- return -EINVAL;
- val = hal2->mixer.volume[mixtable[i].idx];
- break;
- }
- }
- return put_user(val, (int *)arg);
- }
-
- if (_IOC_DIR(cmd) != (_IOC_WRITE|_IOC_READ))
- return -EINVAL;
-
- hal2->mixer.modcnt++;
-
- if (get_user(val, (int *)arg))
- return -EFAULT;
-
- switch (_IOC_NR(cmd)) {
- /* Arg contains a bit for each recording source */
- case SOUND_MIXER_RECSRC:
- return 0; /* FIXME */
- default:
- return hal2_write_mixer(hal2, _IOC_NR(cmd), val);
- }
-
- return 0;
-}
-
-static int hal2_open_mixdev(struct inode *inode, struct file *file)
-{
- struct hal2_card *hal2 = hal2_mixer_find_card(iminor(inode));
-
- if (hal2) {
- file->private_data = hal2;
- return nonseekable_open(inode, file);
- }
- return -ENODEV;
-}
-
-static int hal2_release_mixdev(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static int hal2_ioctl_mixdev(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- return hal2_mixer_ioctl((struct hal2_card *)file->private_data, cmd, arg);
-}
-
-static int hal2_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int val;
- struct hal2_card *hal2 = (struct hal2_card *) file->private_data;
-
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, (int *)arg);
-
- case SNDCTL_DSP_SYNC:
- if (file->f_mode & FMODE_WRITE)
- return hal2_sync_dac(hal2);
- return 0;
-
- case SNDCTL_DSP_SETDUPLEX:
- return 0;
-
- case SNDCTL_DSP_GETCAPS:
- return put_user(DSP_CAP_DUPLEX | DSP_CAP_MULTI, (int *)arg);
-
- case SNDCTL_DSP_RESET:
- if (file->f_mode & FMODE_READ) {
- hal2_stop_adc(hal2);
- hal2_reset_adc_pointer(hal2);
- }
- if (file->f_mode & FMODE_WRITE) {
- hal2_stop_dac(hal2);
- hal2_reset_dac_pointer(hal2);
- }
- return 0;
-
- case SNDCTL_DSP_SPEED:
- if (get_user(val, (int *)arg))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- hal2_stop_adc(hal2);
- val = hal2_compute_rate(&hal2->adc, val);
- hal2->adc.sample_rate = val;
- hal2_set_adc_rate(hal2);
- }
- if (file->f_mode & FMODE_WRITE) {
- hal2_stop_dac(hal2);
- val = hal2_compute_rate(&hal2->dac, val);
- hal2->dac.sample_rate = val;
- hal2_set_dac_rate(hal2);
- }
- return put_user(val, (int *)arg);
-
- case SNDCTL_DSP_STEREO:
- if (get_user(val, (int *)arg))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- hal2_stop_adc(hal2);
- hal2->adc.voices = (val) ? 2 : 1;
- hal2_setup_adc(hal2);
- }
- if (file->f_mode & FMODE_WRITE) {
- hal2_stop_dac(hal2);
- hal2->dac.voices = (val) ? 2 : 1;
- hal2_setup_dac(hal2);
- }
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, (int *)arg))
- return -EFAULT;
- if (val != 0) {
- if (file->f_mode & FMODE_READ) {
- hal2_stop_adc(hal2);
- hal2->adc.voices = (val == 1) ? 1 : 2;
- hal2_setup_adc(hal2);
- }
- if (file->f_mode & FMODE_WRITE) {
- hal2_stop_dac(hal2);
- hal2->dac.voices = (val == 1) ? 1 : 2;
- hal2_setup_dac(hal2);
- }
- }
- val = -EINVAL;
- if (file->f_mode & FMODE_READ)
- val = hal2->adc.voices;
- if (file->f_mode & FMODE_WRITE)
- val = hal2->dac.voices;
- return put_user(val, (int *)arg);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(H2_SUPPORTED_FORMATS, (int *)arg);
-
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- if (get_user(val, (int *)arg))
- return -EFAULT;
- if (val != AFMT_QUERY) {
- if (!(val & H2_SUPPORTED_FORMATS))
- return -EINVAL;
- if (file->f_mode & FMODE_READ) {
- hal2_stop_adc(hal2);
- hal2->adc.format = val;
- hal2_setup_adc(hal2);
- }
- if (file->f_mode & FMODE_WRITE) {
- hal2_stop_dac(hal2);
- hal2->dac.format = val;
- hal2_setup_dac(hal2);
- }
- } else {
- val = -EINVAL;
- if (file->f_mode & FMODE_READ)
- val = hal2->adc.format;
- if (file->f_mode & FMODE_WRITE)
- val = hal2->dac.format;
- }
- return put_user(val, (int *)arg);
-
- case SNDCTL_DSP_POST:
- return 0;
-
- case SNDCTL_DSP_GETOSPACE: {
- audio_buf_info info;
- int i;
- unsigned long flags;
- struct hal2_codec *dac = &hal2->dac;
-
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- info.fragments = 0;
- spin_lock_irqsave(&dac->lock, flags);
- for (i = 0; i < dac->desc_count; i++)
- if (dac->desc[i].cnt == 0)
- info.fragments++;
- spin_unlock_irqrestore(&dac->lock, flags);
- info.fragstotal = dac->desc_count;
- info.fragsize = H2_BLOCK_SIZE;
- info.bytes = info.fragsize * info.fragments;
-
- return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0;
- }
-
- case SNDCTL_DSP_GETISPACE: {
- audio_buf_info info;
- int i;
- unsigned long flags;
- struct hal2_codec *adc = &hal2->adc;
-
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- info.fragments = 0;
- info.bytes = 0;
- spin_lock_irqsave(&adc->lock, flags);
- for (i = 0; i < adc->desc_count; i++)
- if (adc->desc[i].cnt > 0) {
- info.fragments++;
- info.bytes += adc->desc[i].cnt;
- }
- spin_unlock_irqrestore(&adc->lock, flags);
- info.fragstotal = adc->desc_count;
- info.fragsize = H2_BLOCK_SIZE;
-
- return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0;
- }
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_GETBLKSIZE:
- return put_user(H2_BLOCK_SIZE, (int *)arg);
-
- case SNDCTL_DSP_SETFRAGMENT:
- return 0;
-
- case SOUND_PCM_READ_RATE:
- val = -EINVAL;
- if (file->f_mode & FMODE_READ)
- val = hal2->adc.sample_rate;
- if (file->f_mode & FMODE_WRITE)
- val = hal2->dac.sample_rate;
- return put_user(val, (int *)arg);
-
- case SOUND_PCM_READ_CHANNELS:
- val = -EINVAL;
- if (file->f_mode & FMODE_READ)
- val = hal2->adc.voices;
- if (file->f_mode & FMODE_WRITE)
- val = hal2->dac.voices;
- return put_user(val, (int *)arg);
-
- case SOUND_PCM_READ_BITS:
- return put_user(16, (int *)arg);
- }
-
- return hal2_mixer_ioctl(hal2, cmd, arg);
-}
-
-static ssize_t hal2_read(struct file *file, char *buffer,
- size_t count, loff_t *ppos)
-{
- ssize_t err;
- struct hal2_card *hal2 = (struct hal2_card *) file->private_data;
- struct hal2_codec *adc = &hal2->adc;
-
- if (!count)
- return 0;
- if (mutex_lock_interruptible(&adc->sem))
- return -EINTR;
- if (file->f_flags & O_NONBLOCK) {
- err = hal2_get_buffer(hal2, buffer, count);
- err = err == 0 ? -EAGAIN : err;
- } else {
- do {
- /* ~10% longer */
- signed long timeout = 1000 * H2_BLOCK_SIZE *
- 2 * adc->voices * HZ / adc->sample_rate / 900;
- unsigned long flags;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t cnt = 0;
-
- err = hal2_get_buffer(hal2, buffer, count);
- if (err > 0) {
- count -= err;
- cnt += err;
- buffer += err;
- err = cnt;
- }
- if (count > 0 && err >= 0) {
- add_wait_queue(&adc->dma_wait, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(timeout);
- spin_lock_irqsave(&adc->lock, flags);
- if (!adc->desc[adc->tail].cnt)
- err = -EAGAIN;
- spin_unlock_irqrestore(&adc->lock, flags);
- if (signal_pending(current))
- err = -ERESTARTSYS;
- remove_wait_queue(&adc->dma_wait, &wait);
- if (err < 0) {
- hal2_stop_adc(hal2);
- hal2_reset_adc_pointer(hal2);
- }
- }
- } while (count > 0 && err >= 0);
- }
- mutex_unlock(&adc->sem);
-
- return err;
-}
-
-static ssize_t hal2_write(struct file *file, const char *buffer,
- size_t count, loff_t *ppos)
-{
- ssize_t err;
- char *buf = (char*) buffer;
- struct hal2_card *hal2 = (struct hal2_card *) file->private_data;
- struct hal2_codec *dac = &hal2->dac;
-
- if (!count)
- return 0;
- if (mutex_lock_interruptible(&dac->sem))
- return -EINTR;
- if (file->f_flags & O_NONBLOCK) {
- err = hal2_add_buffer(hal2, buf, count);
- err = err == 0 ? -EAGAIN : err;
- } else {
- do {
- /* ~10% longer */
- signed long timeout = 1000 * H2_BLOCK_SIZE *
- 2 * dac->voices * HZ / dac->sample_rate / 900;
- unsigned long flags;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t cnt = 0;
-
- err = hal2_add_buffer(hal2, buf, count);
- if (err > 0) {
- count -= err;
- cnt += err;
- buf += err;
- err = cnt;
- }
- if (count > 0 && err >= 0) {
- add_wait_queue(&dac->dma_wait, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(timeout);
- spin_lock_irqsave(&dac->lock, flags);
- if (dac->desc[dac->head].cnt)
- err = -EAGAIN;
- spin_unlock_irqrestore(&dac->lock, flags);
- if (signal_pending(current))
- err = -ERESTARTSYS;
- remove_wait_queue(&dac->dma_wait, &wait);
- if (err < 0) {
- hal2_stop_dac(hal2);
- hal2_reset_dac_pointer(hal2);
- }
- }
- } while (count > 0 && err >= 0);
- }
- mutex_unlock(&dac->sem);
-
- return err;
-}
-
-static unsigned int hal2_poll(struct file *file, struct poll_table_struct *wait)
-{
- unsigned long flags;
- unsigned int mask = 0;
- struct hal2_card *hal2 = (struct hal2_card *) file->private_data;
-
- if (file->f_mode & FMODE_READ) {
- struct hal2_codec *adc = &hal2->adc;
-
- poll_wait(file, &adc->dma_wait, wait);
- spin_lock_irqsave(&adc->lock, flags);
- if (adc->desc[adc->tail].cnt > 0)
- mask |= POLLIN;
- spin_unlock_irqrestore(&adc->lock, flags);
- }
-
- if (file->f_mode & FMODE_WRITE) {
- struct hal2_codec *dac = &hal2->dac;
-
- poll_wait(file, &dac->dma_wait, wait);
- spin_lock_irqsave(&dac->lock, flags);
- if (dac->desc[dac->head].cnt == 0)
- mask |= POLLOUT;
- spin_unlock_irqrestore(&dac->lock, flags);
- }
-
- return mask;
-}
-
-static int hal2_open(struct inode *inode, struct file *file)
-{
- int err;
- struct hal2_card *hal2 = hal2_dsp_find_card(iminor(inode));
-
- if (!hal2)
- return -ENODEV;
- file->private_data = hal2;
- if (file->f_mode & FMODE_READ) {
- struct hal2_codec *adc = &hal2->adc;
-
- if (adc->usecount)
- return -EBUSY;
- /* OSS spec wanted us to use 8 bit, 8 kHz mono by default,
- * but HAL2 can't do 8bit audio */
- adc->format = AFMT_S16_BE;
- adc->voices = 1;
- adc->sample_rate = hal2_compute_rate(adc, 8000);
- hal2_set_adc_rate(hal2);
- err = hal2_alloc_adc_dmabuf(adc);
- if (err)
- return err;
- hal2_setup_adc(hal2);
- adc->usecount++;
- }
- if (file->f_mode & FMODE_WRITE) {
- struct hal2_codec *dac = &hal2->dac;
-
- if (dac->usecount)
- return -EBUSY;
- dac->format = AFMT_S16_BE;
- dac->voices = 1;
- dac->sample_rate = hal2_compute_rate(dac, 8000);
- hal2_set_dac_rate(hal2);
- err = hal2_alloc_dac_dmabuf(dac);
- if (err)
- return err;
- hal2_setup_dac(hal2);
- dac->usecount++;
- }
-
- return nonseekable_open(inode, file);
-}
-
-static int hal2_release(struct inode *inode, struct file *file)
-{
- struct hal2_card *hal2 = (struct hal2_card *) file->private_data;
-
- if (file->f_mode & FMODE_READ) {
- struct hal2_codec *adc = &hal2->adc;
-
- mutex_lock(&adc->sem);
- hal2_stop_adc(hal2);
- hal2_free_adc_dmabuf(adc);
- adc->usecount--;
- mutex_unlock(&adc->sem);
- }
- if (file->f_mode & FMODE_WRITE) {
- struct hal2_codec *dac = &hal2->dac;
-
- mutex_lock(&dac->sem);
- hal2_sync_dac(hal2);
- hal2_free_dac_dmabuf(dac);
- dac->usecount--;
- mutex_unlock(&dac->sem);
- }
-
- return 0;
-}
-
-static const struct file_operations hal2_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = hal2_read,
- .write = hal2_write,
- .poll = hal2_poll,
- .ioctl = hal2_ioctl,
- .open = hal2_open,
- .release = hal2_release,
-};
-
-static const struct file_operations hal2_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = hal2_ioctl_mixdev,
- .open = hal2_open_mixdev,
- .release = hal2_release_mixdev,
-};
-
-static void hal2_init_codec(struct hal2_codec *codec, struct hpc3_regs *hpc3,
- int index)
-{
- codec->pbus.pbusnr = index;
- codec->pbus.pbus = &hpc3->pbdma[index];
- init_waitqueue_head(&codec->dma_wait);
- mutex_init(&codec->sem);
- spin_lock_init(&codec->lock);
-}
-
-static int hal2_detect(struct hal2_card *hal2)
-{
- unsigned short board, major, minor;
- unsigned short rev;
-
- /* reset HAL2 */
- hal2_isr_write(hal2, 0);
- /* release reset */
- hal2_isr_write(hal2, H2_ISR_GLOBAL_RESET_N | H2_ISR_CODEC_RESET_N);
-
- hal2_i_write16(hal2, H2I_RELAY_C, H2I_RELAY_C_STATE);
- if ((rev = hal2_rev_look(hal2)) & H2_REV_AUDIO_PRESENT)
- return -ENODEV;
-
- board = (rev & H2_REV_BOARD_M) >> 12;
- major = (rev & H2_REV_MAJOR_CHIP_M) >> 4;
- minor = (rev & H2_REV_MINOR_CHIP_M);
-
- printk(KERN_INFO "SGI HAL2 revision %i.%i.%i\n",
- board, major, minor);
-
- return 0;
-}
-
-static int hal2_init_card(struct hal2_card **phal2, struct hpc3_regs *hpc3)
-{
- int ret = 0;
- struct hal2_card *hal2;
-
- hal2 = kzalloc(sizeof(struct hal2_card), GFP_KERNEL);
- if (!hal2)
- return -ENOMEM;
-
- hal2->ctl_regs = (struct hal2_ctl_regs *)hpc3->pbus_extregs[0];
- hal2->aes_regs = (struct hal2_aes_regs *)hpc3->pbus_extregs[1];
- hal2->vol_regs = (struct hal2_vol_regs *)hpc3->pbus_extregs[2];
- hal2->syn_regs = (struct hal2_syn_regs *)hpc3->pbus_extregs[3];
-
- if (hal2_detect(hal2) < 0) {
- ret = -ENODEV;
- goto free_card;
- }
-
- hal2_init_codec(&hal2->dac, hpc3, 0);
- hal2_init_codec(&hal2->adc, hpc3, 1);
-
- /*
- * All DMA channel interfaces in HAL2 are designed to operate with
- * PBUS programmed for 2 cycles in D3, 2 cycles in D4 and 2 cycles
- * in D5. HAL2 is a 16-bit device which can accept both big and little
- * endian format. It assumes that even address bytes are on high
- * portion of PBUS (15:8) and assumes that HPC3 is programmed to
- * accept a live (unsynchronized) version of P_DREQ_N from HAL2.
- */
-#define HAL2_PBUS_DMACFG ((0 << HPC3_DMACFG_D3R_SHIFT) | \
- (2 << HPC3_DMACFG_D4R_SHIFT) | \
- (2 << HPC3_DMACFG_D5R_SHIFT) | \
- (0 << HPC3_DMACFG_D3W_SHIFT) | \
- (2 << HPC3_DMACFG_D4W_SHIFT) | \
- (2 << HPC3_DMACFG_D5W_SHIFT) | \
- HPC3_DMACFG_DS16 | \
- HPC3_DMACFG_EVENHI | \
- HPC3_DMACFG_RTIME | \
- (8 << HPC3_DMACFG_BURST_SHIFT) | \
- HPC3_DMACFG_DRQLIVE)
- /*
- * Ignore what's mentioned in the specification and write value which
- * works in The Real World (TM)
- */
- hpc3->pbus_dmacfg[hal2->dac.pbus.pbusnr][0] = 0x8208844;
- hpc3->pbus_dmacfg[hal2->adc.pbus.pbusnr][0] = 0x8208844;
-
- if (request_irq(SGI_HPCDMA_IRQ, hal2_interrupt, IRQF_SHARED,
- hal2str, hal2)) {
- printk(KERN_ERR "HAL2: Can't get irq %d\n", SGI_HPCDMA_IRQ);
- ret = -EAGAIN;
- goto free_card;
- }
-
- hal2->dev_dsp = register_sound_dsp(&hal2_audio_fops, -1);
- if (hal2->dev_dsp < 0) {
- ret = hal2->dev_dsp;
- goto free_irq;
- }
-
- hal2->dev_mixer = register_sound_mixer(&hal2_mixer_fops, -1);
- if (hal2->dev_mixer < 0) {
- ret = hal2->dev_mixer;
- goto unregister_dsp;
- }
-
- hal2_init_mixer(hal2);
-
- *phal2 = hal2;
- return 0;
-unregister_dsp:
- unregister_sound_dsp(hal2->dev_dsp);
-free_irq:
- free_irq(SGI_HPCDMA_IRQ, hal2);
-free_card:
- kfree(hal2);
-
- return ret;
-}
-
-extern void (*indy_volume_button)(int);
-
-/*
- * Assuming only one HAL2 card. Mail me if you ever meet machine with
- * more than one.
- */
-static int __init init_hal2(void)
-{
- int i, error;
-
- for (i = 0; i < MAXCARDS; i++)
- hal2_card[i] = NULL;
-
- error = hal2_init_card(&hal2_card[0], hpc3c0);
-
- /* let Indy's volume buttons work */
- if (!error && !ip22_is_fullhouse())
- indy_volume_button = hal2_volume_control;
-
- return error;
-
-}
-
-static void __exit exit_hal2(void)
-{
- int i;
-
- /* unregister volume butons callback function */
- indy_volume_button = NULL;
-
- for (i = 0; i < MAXCARDS; i++)
- if (hal2_card[i]) {
- free_irq(SGI_HPCDMA_IRQ, hal2_card[i]);
- unregister_sound_dsp(hal2_card[i]->dev_dsp);
- unregister_sound_mixer(hal2_card[i]->dev_mixer);
- kfree(hal2_card[i]);
- }
-}
-
-module_init(init_hal2);
-module_exit(exit_hal2);
-
-MODULE_DESCRIPTION("OSS compatible driver for SGI HAL2 audio");
-MODULE_AUTHOR("Ladislav Michl");
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/hal2.h b/sound/oss/hal2.h
deleted file mode 100644
index 2bd3b52d8a3..00000000000
--- a/sound/oss/hal2.h
+++ /dev/null
@@ -1,248 +0,0 @@
-#ifndef __HAL2_H
-#define __HAL2_H
-
-/*
- * Driver for HAL2 sound processors
- * Copyright (c) 1999 Ulf Carlsson <ulfc@bun.falkenberg.se>
- * Copyright (c) 2001, 2002, 2003 Ladislav Michl <ladis@linux-mips.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- *
- */
-
-#include <asm/addrspace.h>
-#include <asm/sgi/hpc3.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-/* Indirect status register */
-
-#define H2_ISR_TSTATUS 0x01 /* RO: transaction status 1=busy */
-#define H2_ISR_USTATUS 0x02 /* RO: utime status bit 1=armed */
-#define H2_ISR_QUAD_MODE 0x04 /* codec mode 0=indigo 1=quad */
-#define H2_ISR_GLOBAL_RESET_N 0x08 /* chip global reset 0=reset */
-#define H2_ISR_CODEC_RESET_N 0x10 /* codec/synth reset 0=reset */
-
-/* Revision register */
-
-#define H2_REV_AUDIO_PRESENT 0x8000 /* RO: audio present 0=present */
-#define H2_REV_BOARD_M 0x7000 /* RO: bits 14:12, board revision */
-#define H2_REV_MAJOR_CHIP_M 0x00F0 /* RO: bits 7:4, major chip revision */
-#define H2_REV_MINOR_CHIP_M 0x000F /* RO: bits 3:0, minor chip revision */
-
-/* Indirect address register */
-
-/*
- * Address of indirect internal register to be accessed. A write to this
- * register initiates read or write access to the indirect registers in the
- * HAL2. Note that there af four indirect data registers for write access to
- * registers larger than 16 byte.
- */
-
-#define H2_IAR_TYPE_M 0xF000 /* bits 15:12, type of functional */
- /* block the register resides in */
- /* 1=DMA Port */
- /* 9=Global DMA Control */
- /* 2=Bresenham */
- /* 3=Unix Timer */
-#define H2_IAR_NUM_M 0x0F00 /* bits 11:8 instance of the */
- /* blockin which the indirect */
- /* register resides */
- /* If IAR_TYPE_M=DMA Port: */
- /* 1=Synth In */
- /* 2=AES In */
- /* 3=AES Out */
- /* 4=DAC Out */
- /* 5=ADC Out */
- /* 6=Synth Control */
- /* If IAR_TYPE_M=Global DMA Control: */
- /* 1=Control */
- /* If IAR_TYPE_M=Bresenham: */
- /* 1=Bresenham Clock Gen 1 */
- /* 2=Bresenham Clock Gen 2 */
- /* 3=Bresenham Clock Gen 3 */
- /* If IAR_TYPE_M=Unix Timer: */
- /* 1=Unix Timer */
-#define H2_IAR_ACCESS_SELECT 0x0080 /* 1=read 0=write */
-#define H2_IAR_PARAM 0x000C /* Parameter Select */
-#define H2_IAR_RB_INDEX_M 0x0003 /* Read Back Index */
- /* 00:word0 */
- /* 01:word1 */
- /* 10:word2 */
- /* 11:word3 */
-/*
- * HAL2 internal addressing
- *
- * The HAL2 has "indirect registers" (idr) which are accessed by writing to the
- * Indirect Data registers. Write the address to the Indirect Address register
- * to transfer the data.
- *
- * We define the H2IR_* to the read address and H2IW_* to the write address and
- * H2I_* to be fields in whatever register is referred to.
- *
- * When we write to indirect registers which are larger than one word (16 bit)
- * we have to fill more than one indirect register before writing. When we read
- * back however we have to read several times, each time with different Read
- * Back Indexes (there are defs for doing this easily).
- */
-
-/*
- * Relay Control
- */
-#define H2I_RELAY_C 0x9100
-#define H2I_RELAY_C_STATE 0x01 /* state of RELAY pin signal */
-
-/* DMA port enable */
-
-#define H2I_DMA_PORT_EN 0x9104
-#define H2I_DMA_PORT_EN_SY_IN 0x01 /* Synth_in DMA port */
-#define H2I_DMA_PORT_EN_AESRX 0x02 /* AES receiver DMA port */
-#define H2I_DMA_PORT_EN_AESTX 0x04 /* AES transmitter DMA port */
-#define H2I_DMA_PORT_EN_CODECTX 0x08 /* CODEC transmit DMA port */
-#define H2I_DMA_PORT_EN_CODECR 0x10 /* CODEC receive DMA port */
-
-#define H2I_DMA_END 0x9108 /* global dma endian select */
-#define H2I_DMA_END_SY_IN 0x01 /* Synth_in DMA port */
-#define H2I_DMA_END_AESRX 0x02 /* AES receiver DMA port */
-#define H2I_DMA_END_AESTX 0x04 /* AES transmitter DMA port */
-#define H2I_DMA_END_CODECTX 0x08 /* CODEC transmit DMA port */
-#define H2I_DMA_END_CODECR 0x10 /* CODEC receive DMA port */
- /* 0=b_end 1=l_end */
-
-#define H2I_DMA_DRV 0x910C /* global PBUS DMA enable */
-
-#define H2I_SYNTH_C 0x1104 /* Synth DMA control */
-
-#define H2I_AESRX_C 0x1204 /* AES RX dma control */
-
-#define H2I_C_TS_EN 0x20 /* Timestamp enable */
-#define H2I_C_TS_FRMT 0x40 /* Timestamp format */
-#define H2I_C_NAUDIO 0x80 /* Sign extend */
-
-/* AESRX CTL, 16 bit */
-
-#define H2I_AESTX_C 0x1304 /* AES TX DMA control */
-#define H2I_AESTX_C_CLKID_SHIFT 3 /* Bresenham Clock Gen 1-3 */
-#define H2I_AESTX_C_CLKID_M 0x18
-#define H2I_AESTX_C_DATAT_SHIFT 8 /* 1=mono 2=stereo (3=quad) */
-#define H2I_AESTX_C_DATAT_M 0x300
-
-/* CODEC registers */
-
-#define H2I_DAC_C1 0x1404 /* DAC DMA control, 16 bit */
-#define H2I_DAC_C2 0x1408 /* DAC DMA control, 32 bit */
-#define H2I_ADC_C1 0x1504 /* ADC DMA control, 16 bit */
-#define H2I_ADC_C2 0x1508 /* ADC DMA control, 32 bit */
-
-/* Bits in CTL1 register */
-
-#define H2I_C1_DMA_SHIFT 0 /* DMA channel */
-#define H2I_C1_DMA_M 0x7
-#define H2I_C1_CLKID_SHIFT 3 /* Bresenham Clock Gen 1-3 */
-#define H2I_C1_CLKID_M 0x18
-#define H2I_C1_DATAT_SHIFT 8 /* 1=mono 2=stereo (3=quad) */
-#define H2I_C1_DATAT_M 0x300
-
-/* Bits in CTL2 register */
-
-#define H2I_C2_R_GAIN_SHIFT 0 /* right a/d input gain */
-#define H2I_C2_R_GAIN_M 0xf
-#define H2I_C2_L_GAIN_SHIFT 4 /* left a/d input gain */
-#define H2I_C2_L_GAIN_M 0xf0
-#define H2I_C2_R_SEL 0x100 /* right input select */
-#define H2I_C2_L_SEL 0x200 /* left input select */
-#define H2I_C2_MUTE 0x400 /* mute */
-#define H2I_C2_DO1 0x00010000 /* digital output port bit 0 */
-#define H2I_C2_DO2 0x00020000 /* digital output port bit 1 */
-#define H2I_C2_R_ATT_SHIFT 18 /* right d/a output - */
-#define H2I_C2_R_ATT_M 0x007c0000 /* attenuation */
-#define H2I_C2_L_ATT_SHIFT 23 /* left d/a output - */
-#define H2I_C2_L_ATT_M 0x0f800000 /* attenuation */
-
-#define H2I_SYNTH_MAP_C 0x1104 /* synth dma handshake ctrl */
-
-/* Clock generator CTL 1, 16 bit */
-
-#define H2I_BRES1_C1 0x2104
-#define H2I_BRES2_C1 0x2204
-#define H2I_BRES3_C1 0x2304
-
-#define H2I_BRES_C1_SHIFT 0 /* 0=48.0 1=44.1 2=aes_rx */
-#define H2I_BRES_C1_M 0x03
-
-/* Clock generator CTL 2, 32 bit */
-
-#define H2I_BRES1_C2 0x2108
-#define H2I_BRES2_C2 0x2208
-#define H2I_BRES3_C2 0x2308
-
-#define H2I_BRES_C2_INC_SHIFT 0 /* increment value */
-#define H2I_BRES_C2_INC_M 0xffff
-#define H2I_BRES_C2_MOD_SHIFT 16 /* modcontrol value */
-#define H2I_BRES_C2_MOD_M 0xffff0000 /* modctrl=0xffff&(modinc-1) */
-
-/* Unix timer, 64 bit */
-
-#define H2I_UTIME 0x3104
-#define H2I_UTIME_0_LD 0xffff /* microseconds, LSB's */
-#define H2I_UTIME_1_LD0 0x0f /* microseconds, MSB's */
-#define H2I_UTIME_1_LD1 0xf0 /* tenths of microseconds */
-#define H2I_UTIME_2_LD 0xffff /* seconds, LSB's */
-#define H2I_UTIME_3_LD 0xffff /* seconds, MSB's */
-
-struct hal2_ctl_regs {
- u32 _unused0[4];
- volatile u32 isr; /* 0x10 Status Register */
- u32 _unused1[3];
- volatile u32 rev; /* 0x20 Revision Register */
- u32 _unused2[3];
- volatile u32 iar; /* 0x30 Indirect Address Register */
- u32 _unused3[3];
- volatile u32 idr0; /* 0x40 Indirect Data Register 0 */
- u32 _unused4[3];
- volatile u32 idr1; /* 0x50 Indirect Data Register 1 */
- u32 _unused5[3];
- volatile u32 idr2; /* 0x60 Indirect Data Register 2 */
- u32 _unused6[3];
- volatile u32 idr3; /* 0x70 Indirect Data Register 3 */
-};
-
-struct hal2_aes_regs {
- volatile u32 rx_stat[2]; /* Status registers */
- volatile u32 rx_cr[2]; /* Control registers */
- volatile u32 rx_ud[4]; /* User data window */
- volatile u32 rx_st[24]; /* Channel status data */
-
- volatile u32 tx_stat[1]; /* Status register */
- volatile u32 tx_cr[3]; /* Control registers */
- volatile u32 tx_ud[4]; /* User data window */
- volatile u32 tx_st[24]; /* Channel status data */
-};
-
-struct hal2_vol_regs {
- volatile u32 right; /* Right volume */
- volatile u32 left; /* Left volume */
-};
-
-struct hal2_syn_regs {
- u32 _unused0[2];
- volatile u32 page; /* DOC Page register */
- volatile u32 regsel; /* DOC Register selection */
- volatile u32 dlow; /* DOC Data low */
- volatile u32 dhigh; /* DOC Data high */
- volatile u32 irq; /* IRQ Status */
- volatile u32 dram; /* DRAM Access */
-};
-
-#endif /* __HAL2_H */
diff --git a/sound/oss/hex2hex.c b/sound/oss/hex2hex.c
index 5460faae98c..041ef5c52bc 100644
--- a/sound/oss/hex2hex.c
+++ b/sound/oss/hex2hex.c
@@ -12,7 +12,7 @@
#define MAX_SIZE (256*1024)
unsigned char buf[MAX_SIZE];
-int loadhex(FILE *inf, unsigned char *buf)
+static int loadhex(FILE *inf, unsigned char *buf)
{
int l=0, c, i;
diff --git a/sound/oss/i810_audio.c b/sound/oss/i810_audio.c
deleted file mode 100644
index f5e31f11973..00000000000
--- a/sound/oss/i810_audio.c
+++ /dev/null
@@ -1,3656 +0,0 @@
-/*
- * Intel i810 and friends ICH driver for Linux
- * Alan Cox <alan@redhat.com>
- *
- * Built from:
- * Low level code: Zach Brown (original nonworking i810 OSS driver)
- * Jaroslav Kysela <perex@suse.cz> (working ALSA driver)
- *
- * Framework: Thomas Sailer <sailer@ife.ee.ethz.ch>
- * Extended by: Zach Brown <zab@redhat.com>
- * and others..
- *
- * Hardware Provided By:
- * Analog Devices (A major AC97 codec maker)
- * Intel Corp (you've probably heard of them already)
- *
- * AC97 clues and assistance provided by
- * Analog Devices
- * Zach 'Fufu' Brown
- * Jeff Garzik
- *
- * 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.
- *
- *
- * Intel 810 theory of operation
- *
- * The chipset provides three DMA channels that talk to an AC97
- * CODEC (AC97 is a digital/analog mixer standard). At its simplest
- * you get 48Khz audio with basic volume and mixer controls. At the
- * best you get rate adaption in the codec. We set the card up so
- * that we never take completion interrupts but instead keep the card
- * chasing its tail around a ring buffer. This is needed for mmap
- * mode audio and happens to work rather well for non-mmap modes too.
- *
- * The board has one output channel for PCM audio (supported) and
- * a stereo line in and mono microphone input. Again these are normally
- * locked to 48Khz only. Right now recording is not finished.
- *
- * There is no midi support, no synth support. Use timidity. To get
- * esd working you need to use esd -r 48000 as it won't probe 48KHz
- * by default. mpg123 can't handle 48Khz only audio so use xmms.
- *
- * Fix The Sound On Dell
- *
- * Not everyone uses 48KHz. We know of no way to detect this reliably
- * and certainly not to get the right data. If your i810 audio sounds
- * stupid you may need to investigate other speeds. According to Analog
- * they tend to use a 14.318MHz clock which gives you a base rate of
- * 41194Hz.
- *
- * This is available via the 'ftsodell=1' option.
- *
- * If you need to force a specific rate set the clocking= option
- *
- * This driver is cursed. (Ben LaHaise)
- *
- * ICH 3 caveats
- * Intel errata #7 for ICH3 IO. We need to disable SMI stuff
- * when codec probing. [Not Yet Done]
- *
- * ICH 4 caveats
- *
- * The ICH4 has the feature, that the codec ID doesn't have to be
- * congruent with the IO connection.
- *
- * Therefore, from driver version 0.23 on, there is a "codec ID" <->
- * "IO register base offset" mapping (card->ac97_id_map) field.
- *
- * Juergen "George" Sawinski (jsaw)
- */
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ctype.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/interrupt.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/ac97_codec.h>
-#include <linux/bitops.h>
-#include <linux/mutex.h>
-#include <linux/mm.h>
-
-#include <asm/uaccess.h>
-
-#define DRIVER_VERSION "1.01"
-
-#define MODULOP2(a, b) ((a) & ((b) - 1))
-#define MASKP2(a, b) ((a) & ~((b) - 1))
-
-static int ftsodell;
-static int strict_clocking;
-static unsigned int clocking;
-static int spdif_locked;
-static int ac97_quirk = AC97_TUNE_DEFAULT;
-
-//#define DEBUG
-//#define DEBUG2
-//#define DEBUG_INTERRUPTS
-//#define DEBUG_MMAP
-//#define DEBUG_MMIO
-
-#define ADC_RUNNING 1
-#define DAC_RUNNING 2
-
-#define I810_FMT_16BIT 1
-#define I810_FMT_STEREO 2
-#define I810_FMT_MASK 3
-
-#define SPDIF_ON 0x0004
-#define SURR_ON 0x0010
-#define CENTER_LFE_ON 0x0020
-#define VOL_MUTED 0x8000
-
-/* the 810's array of pointers to data buffers */
-
-struct sg_item {
-#define BUSADDR_MASK 0xFFFFFFFE
- u32 busaddr;
-#define CON_IOC 0x80000000 /* interrupt on completion */
-#define CON_BUFPAD 0x40000000 /* pad underrun with last sample, else 0 */
-#define CON_BUFLEN_MASK 0x0000ffff /* buffer length in samples */
- u32 control;
-};
-
-/* an instance of the i810 channel */
-#define SG_LEN 32
-struct i810_channel
-{
- /* these sg guys should probably be allocated
- separately as nocache. Must be 8 byte aligned */
- struct sg_item sg[SG_LEN]; /* 32*8 */
- u32 offset; /* 4 */
- u32 port; /* 4 */
- u32 used;
- u32 num;
-};
-
-/*
- * we have 3 separate dma engines. pcm in, pcm out, and mic.
- * each dma engine has controlling registers. These goofy
- * names are from the datasheet, but make it easy to write
- * code while leafing through it.
- *
- * ICH4 has 6 dma engines, pcm in, pcm out, mic, pcm in 2,
- * mic in 2, s/pdif. Of special interest is the fact that
- * the upper 3 DMA engines on the ICH4 *must* be accessed
- * via mmio access instead of pio access.
- */
-
-#define ENUM_ENGINE(PRE,DIG) \
-enum { \
- PRE##_BASE = 0x##DIG##0, /* Base Address */ \
- PRE##_BDBAR = 0x##DIG##0, /* Buffer Descriptor list Base Address */ \
- PRE##_CIV = 0x##DIG##4, /* Current Index Value */ \
- PRE##_LVI = 0x##DIG##5, /* Last Valid Index */ \
- PRE##_SR = 0x##DIG##6, /* Status Register */ \
- PRE##_PICB = 0x##DIG##8, /* Position In Current Buffer */ \
- PRE##_PIV = 0x##DIG##a, /* Prefetched Index Value */ \
- PRE##_CR = 0x##DIG##b /* Control Register */ \
-}
-
-ENUM_ENGINE(OFF,0); /* Offsets */
-ENUM_ENGINE(PI,0); /* PCM In */
-ENUM_ENGINE(PO,1); /* PCM Out */
-ENUM_ENGINE(MC,2); /* Mic In */
-
-enum {
- GLOB_CNT = 0x2c, /* Global Control */
- GLOB_STA = 0x30, /* Global Status */
- CAS = 0x34 /* Codec Write Semaphore Register */
-};
-
-ENUM_ENGINE(MC2,4); /* Mic In 2 */
-ENUM_ENGINE(PI2,5); /* PCM In 2 */
-ENUM_ENGINE(SP,6); /* S/PDIF */
-
-enum {
- SDM = 0x80 /* SDATA_IN Map Register */
-};
-
-/* interrupts for a dma engine */
-#define DMA_INT_FIFO (1<<4) /* fifo under/over flow */
-#define DMA_INT_COMPLETE (1<<3) /* buffer read/write complete and ioc set */
-#define DMA_INT_LVI (1<<2) /* last valid done */
-#define DMA_INT_CELV (1<<1) /* last valid is current */
-#define DMA_INT_DCH (1) /* DMA Controller Halted (happens on LVI interrupts) */
-#define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI)
-
-/* interrupts for the whole chip */
-#define INT_SEC (1<<11)
-#define INT_PRI (1<<10)
-#define INT_MC (1<<7)
-#define INT_PO (1<<6)
-#define INT_PI (1<<5)
-#define INT_MO (1<<2)
-#define INT_NI (1<<1)
-#define INT_GPI (1<<0)
-#define INT_MASK (INT_SEC|INT_PRI|INT_MC|INT_PO|INT_PI|INT_MO|INT_NI|INT_GPI)
-
-/* magic numbers to protect our data structures */
-#define I810_CARD_MAGIC 0x5072696E /* "Prin" */
-#define I810_STATE_MAGIC 0x63657373 /* "cess" */
-#define I810_DMA_MASK 0xffffffff /* DMA buffer mask for pci_alloc_consist */
-#define NR_HW_CH 3
-
-/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
-#define NR_AC97 4
-
-/* Please note that an 8bit mono stream is not valid on this card, you must have a 16bit */
-/* stream at a minimum for this card to be happy */
-static const unsigned sample_size[] = { 1, 2, 2, 4 };
-/* Samples are 16bit values, so we are shifting to a word, not to a byte, hence shift */
-/* values are one less than might be expected */
-static const unsigned sample_shift[] = { -1, 0, 0, 1 };
-
-enum {
- ICH82801AA = 0,
- ICH82901AB,
- INTEL440MX,
- INTELICH2,
- INTELICH3,
- INTELICH4,
- INTELICH5,
- SI7012,
- NVIDIA_NFORCE,
- AMD768,
- AMD8111
-};
-
-static char * card_names[] = {
- "Intel ICH 82801AA",
- "Intel ICH 82901AB",
- "Intel 440MX",
- "Intel ICH2",
- "Intel ICH3",
- "Intel ICH4",
- "Intel ICH5",
- "SiS 7012",
- "NVIDIA nForce Audio",
- "AMD 768",
- "AMD-8111 IOHub"
-};
-
-/* These are capabilities (and bugs) the chipsets _can_ have */
-static struct {
- int16_t nr_ac97;
-#define CAP_MMIO 0x0001
-#define CAP_20BIT_AUDIO_SUPPORT 0x0002
- u_int16_t flags;
-} card_cap[] = {
- { 1, 0x0000 }, /* ICH82801AA */
- { 1, 0x0000 }, /* ICH82901AB */
- { 1, 0x0000 }, /* INTEL440MX */
- { 1, 0x0000 }, /* INTELICH2 */
- { 2, 0x0000 }, /* INTELICH3 */
- { 3, 0x0003 }, /* INTELICH4 */
- { 3, 0x0003 }, /* INTELICH5 */
- /*@FIXME to be verified*/ { 2, 0x0000 }, /* SI7012 */
- /*@FIXME to be verified*/ { 2, 0x0000 }, /* NVIDIA_NFORCE */
- /*@FIXME to be verified*/ { 2, 0x0000 }, /* AMD768 */
- /*@FIXME to be verified*/ { 3, 0x0001 }, /* AMD8111 */
-};
-
-static struct pci_device_id i810_pci_tbl [] = {
- {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_5,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82801AA},
- {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_5,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82901AB},
- {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_440MX,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTEL440MX},
- {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_4,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH2},
- {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_5,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH3},
- {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_5,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH4},
- {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_5,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH5},
- {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7012,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, SI7012},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE},
- {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7445,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD768},
- {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_AUDIO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD8111},
- {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_5,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH4},
- {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_18,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH4},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_AUDIO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE},
- {0,}
-};
-
-MODULE_DEVICE_TABLE (pci, i810_pci_tbl);
-
-#ifdef CONFIG_PM
-#define PM_SUSPENDED(card) (card->pm_suspended)
-#else
-#define PM_SUSPENDED(card) (0)
-#endif
-
-/* "software" or virtual channel, an instance of opened /dev/dsp */
-struct i810_state {
- unsigned int magic;
- struct i810_card *card; /* Card info */
-
- /* single open lock mechanism, only used for recording */
- struct mutex open_mutex;
- wait_queue_head_t open_wait;
-
- /* file mode */
- mode_t open_mode;
-
- /* virtual channel number */
- int virt;
-
-#ifdef CONFIG_PM
- unsigned int pm_saved_dac_rate,pm_saved_adc_rate;
-#endif
- struct dmabuf {
- /* wave sample stuff */
- unsigned int rate;
- unsigned char fmt, enable, trigger;
-
- /* hardware channel */
- struct i810_channel *read_channel;
- struct i810_channel *write_channel;
-
- /* OSS buffer management stuff */
- void *rawbuf;
- dma_addr_t dma_handle;
- unsigned buforder;
- unsigned numfrag;
- unsigned fragshift;
-
- /* our buffer acts like a circular ring */
- unsigned hwptr; /* where dma last started, updated by update_ptr */
- unsigned swptr; /* where driver last clear/filled, updated by read/write */
- int count; /* bytes to be consumed or been generated by dma machine */
- unsigned total_bytes; /* total bytes dmaed by hardware */
-
- unsigned error; /* number of over/underruns */
- wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */
-
- /* redundant, but makes calculations easier */
- /* what the hardware uses */
- unsigned dmasize;
- unsigned fragsize;
- unsigned fragsamples;
-
- /* what we tell the user to expect */
- unsigned userfrags;
- unsigned userfragsize;
-
- /* OSS stuff */
- unsigned mapped:1;
- unsigned ready:1;
- unsigned update_flag;
- unsigned ossfragsize;
- unsigned ossmaxfrags;
- unsigned subdivision;
- } dmabuf;
-};
-
-
-struct i810_card {
- unsigned int magic;
-
- /* We keep i810 cards in a linked list */
- struct i810_card *next;
-
- /* The i810 has a certain amount of cross channel interaction
- so we use a single per card lock */
- spinlock_t lock;
-
- /* Control AC97 access serialization */
- spinlock_t ac97_lock;
-
- /* PCI device stuff */
- struct pci_dev * pci_dev;
- u16 pci_id;
- u16 pci_id_internal; /* used to access card_cap[] */
-#ifdef CONFIG_PM
- u16 pm_suspended;
- int pm_saved_mixer_settings[SOUND_MIXER_NRDEVICES][NR_AC97];
-#endif
- /* soundcore stuff */
- int dev_audio;
-
- /* structures for abstraction of hardware facilities, codecs, banks and channels*/
- u16 ac97_id_map[NR_AC97];
- struct ac97_codec *ac97_codec[NR_AC97];
- struct i810_state *states[NR_HW_CH];
- struct i810_channel *channel; /* 1:1 to states[] but diff. lifetime */
- dma_addr_t chandma;
-
- u16 ac97_features;
- u16 ac97_status;
- u16 channels;
-
- /* hardware resources */
- unsigned long ac97base;
- unsigned long iobase;
- u32 irq;
-
- unsigned long ac97base_mmio_phys;
- unsigned long iobase_mmio_phys;
- u_int8_t __iomem *ac97base_mmio;
- u_int8_t __iomem *iobase_mmio;
-
- int use_mmio;
-
- /* Function support */
- struct i810_channel *(*alloc_pcm_channel)(struct i810_card *);
- struct i810_channel *(*alloc_rec_pcm_channel)(struct i810_card *);
- struct i810_channel *(*alloc_rec_mic_channel)(struct i810_card *);
- void (*free_pcm_channel)(struct i810_card *, int chan);
-
- /* We have a *very* long init time possibly, so use this to block */
- /* attempts to open our devices before we are ready (stops oops'es) */
- int initializing;
-};
-
-/* extract register offset from codec struct */
-#define IO_REG_OFF(codec) (((struct i810_card *) codec->private_data)->ac97_id_map[codec->id])
-
-#define I810_IOREAD(size, type, card, off) \
-({ \
- type val; \
- if (card->use_mmio) \
- val=read##size(card->iobase_mmio+off); \
- else \
- val=in##size(card->iobase+off); \
- val; \
-})
-
-#define I810_IOREADL(card, off) I810_IOREAD(l, u32, card, off)
-#define I810_IOREADW(card, off) I810_IOREAD(w, u16, card, off)
-#define I810_IOREADB(card, off) I810_IOREAD(b, u8, card, off)
-
-#define I810_IOWRITE(size, val, card, off) \
-({ \
- if (card->use_mmio) \
- write##size(val, card->iobase_mmio+off); \
- else \
- out##size(val, card->iobase+off); \
-})
-
-#define I810_IOWRITEL(val, card, off) I810_IOWRITE(l, val, card, off)
-#define I810_IOWRITEW(val, card, off) I810_IOWRITE(w, val, card, off)
-#define I810_IOWRITEB(val, card, off) I810_IOWRITE(b, val, card, off)
-
-#define GET_CIV(card, port) MODULOP2(I810_IOREADB((card), (port) + OFF_CIV), SG_LEN)
-#define GET_LVI(card, port) MODULOP2(I810_IOREADB((card), (port) + OFF_LVI), SG_LEN)
-
-/* set LVI from CIV */
-#define CIV_TO_LVI(card, port, off) \
- I810_IOWRITEB(MODULOP2(GET_CIV((card), (port)) + (off), SG_LEN), (card), (port) + OFF_LVI)
-
-static struct ac97_quirk ac97_quirks[] __devinitdata = {
- {
- .vendor = 0x0e11,
- .device = 0x00b8,
- .name = "Compaq Evo D510C",
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x1028,
- .device = 0x00d8,
- .name = "Dell Precision 530", /* AD1885 */
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x1028,
- .device = 0x0126,
- .name = "Dell Optiplex GX260", /* AD1981A */
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x1028,
- .device = 0x012d,
- .name = "Dell Precision 450", /* AD1981B*/
- .type = AC97_TUNE_HP_ONLY
- },
- { /* FIXME: which codec? */
- .vendor = 0x103c,
- .device = 0x00c3,
- .name = "Hewlett-Packard onboard",
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x103c,
- .device = 0x12f1,
- .name = "HP xw8200", /* AD1981B*/
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x103c,
- .device = 0x3008,
- .name = "HP xw4200", /* AD1981B*/
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x10f1,
- .device = 0x2665,
- .name = "Fujitsu-Siemens Celsius", /* AD1981? */
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x10f1,
- .device = 0x2885,
- .name = "AMD64 Mobo", /* ALC650 */
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x110a,
- .device = 0x0056,
- .name = "Fujitsu-Siemens Scenic", /* AD1981? */
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x11d4,
- .device = 0x5375,
- .name = "ADI AD1985 (discrete)",
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x1462,
- .device = 0x5470,
- .name = "MSI P4 ATX 645 Ultra",
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x1734,
- .device = 0x0088,
- .name = "Fujitsu-Siemens D1522", /* AD1981 */
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x8086,
- .device = 0x4856,
- .name = "Intel D845WN (82801BA)",
- .type = AC97_TUNE_SWAP_HP
- },
- {
- .vendor = 0x8086,
- .device = 0x4d44,
- .name = "Intel D850EMV2", /* AD1885 */
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x8086,
- .device = 0x4d56,
- .name = "Intel ICH/AD1885",
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x1028,
- .device = 0x012d,
- .name = "Dell Precision 450", /* AD1981B*/
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x103c,
- .device = 0x3008,
- .name = "HP xw4200", /* AD1981B*/
- .type = AC97_TUNE_HP_ONLY
- },
- {
- .vendor = 0x103c,
- .device = 0x12f1,
- .name = "HP xw8200", /* AD1981B*/
- .type = AC97_TUNE_HP_ONLY
- },
- { } /* terminator */
-};
-
-static struct i810_card *devs = NULL;
-
-static int i810_open_mixdev(struct inode *inode, struct file *file);
-static int i810_ioctl_mixdev(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
-static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg);
-static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
-static u16 i810_ac97_get_mmio(struct ac97_codec *dev, u8 reg);
-static void i810_ac97_set_mmio(struct ac97_codec *dev, u8 reg, u16 data);
-static u16 i810_ac97_get_io(struct ac97_codec *dev, u8 reg);
-static void i810_ac97_set_io(struct ac97_codec *dev, u8 reg, u16 data);
-
-static struct i810_channel *i810_alloc_pcm_channel(struct i810_card *card)
-{
- if(card->channel[1].used==1)
- return NULL;
- card->channel[1].used=1;
- return &card->channel[1];
-}
-
-static struct i810_channel *i810_alloc_rec_pcm_channel(struct i810_card *card)
-{
- if(card->channel[0].used==1)
- return NULL;
- card->channel[0].used=1;
- return &card->channel[0];
-}
-
-static struct i810_channel *i810_alloc_rec_mic_channel(struct i810_card *card)
-{
- if(card->channel[2].used==1)
- return NULL;
- card->channel[2].used=1;
- return &card->channel[2];
-}
-
-static void i810_free_pcm_channel(struct i810_card *card, int channel)
-{
- card->channel[channel].used=0;
-}
-
-static int i810_valid_spdif_rate ( struct ac97_codec *codec, int rate )
-{
- unsigned long id = 0L;
-
- id = (i810_ac97_get(codec, AC97_VENDOR_ID1) << 16);
- id |= i810_ac97_get(codec, AC97_VENDOR_ID2) & 0xffff;
-#ifdef DEBUG
- printk ( "i810_audio: codec = %s, codec_id = 0x%08lx\n", codec->name, id);
-#endif
- switch ( id ) {
- case 0x41445361: /* AD1886 */
- if (rate == 48000) {
- return 1;
- }
- break;
- default: /* all other codecs, until we know otherwiae */
- if (rate == 48000 || rate == 44100 || rate == 32000) {
- return 1;
- }
- break;
- }
- return (0);
-}
-
-/* i810_set_spdif_output
- *
- * Configure the S/PDIF output transmitter. When we turn on
- * S/PDIF, we turn off the analog output. This may not be
- * the right thing to do.
- *
- * Assumptions:
- * The DSP sample rate must already be set to a supported
- * S/PDIF rate (32kHz, 44.1kHz, or 48kHz) or we abort.
- */
-static int i810_set_spdif_output(struct i810_state *state, int slots, int rate)
-{
- int vol;
- int aud_reg;
- int r = 0;
- struct ac97_codec *codec = state->card->ac97_codec[0];
-
- if(!codec->codec_ops->digital) {
- state->card->ac97_status &= ~SPDIF_ON;
- } else {
- if ( slots == -1 ) { /* Turn off S/PDIF */
- codec->codec_ops->digital(codec, 0, 0, 0);
- /* If the volume wasn't muted before we turned on S/PDIF, unmute it */
- if ( !(state->card->ac97_status & VOL_MUTED) ) {
- aud_reg = i810_ac97_get(codec, AC97_MASTER_VOL_STEREO);
- i810_ac97_set(codec, AC97_MASTER_VOL_STEREO, (aud_reg & ~VOL_MUTED));
- }
- state->card->ac97_status &= ~(VOL_MUTED | SPDIF_ON);
- return 0;
- }
-
- vol = i810_ac97_get(codec, AC97_MASTER_VOL_STEREO);
- state->card->ac97_status = vol & VOL_MUTED;
-
- r = codec->codec_ops->digital(codec, slots, rate, 0);
-
- if(r)
- state->card->ac97_status |= SPDIF_ON;
- else
- state->card->ac97_status &= ~SPDIF_ON;
-
- /* Mute the analog output */
- /* Should this only mute the PCM volume??? */
- i810_ac97_set(codec, AC97_MASTER_VOL_STEREO, (vol | VOL_MUTED));
- }
- return r;
-}
-
-/* i810_set_dac_channels
- *
- * Configure the codec's multi-channel DACs
- *
- * The logic is backwards. Setting the bit to 1 turns off the DAC.
- *
- * What about the ICH? We currently configure it using the
- * SNDCTL_DSP_CHANNELS ioctl. If we're turnning on the DAC,
- * does that imply that we want the ICH set to support
- * these channels?
- *
- * TODO:
- * vailidate that the codec really supports these DACs
- * before turning them on.
- */
-static void i810_set_dac_channels(struct i810_state *state, int channel)
-{
- int aud_reg;
- struct ac97_codec *codec = state->card->ac97_codec[0];
-
- /* No codec, no setup */
-
- if(codec == NULL)
- return;
-
- aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS);
- aud_reg |= AC97_EA_PRI | AC97_EA_PRJ | AC97_EA_PRK;
- state->card->ac97_status &= ~(SURR_ON | CENTER_LFE_ON);
-
- switch ( channel ) {
- case 2: /* always enabled */
- break;
- case 4:
- aud_reg &= ~AC97_EA_PRJ;
- state->card->ac97_status |= SURR_ON;
- break;
- case 6:
- aud_reg &= ~(AC97_EA_PRJ | AC97_EA_PRI | AC97_EA_PRK);
- state->card->ac97_status |= SURR_ON | CENTER_LFE_ON;
- break;
- default:
- break;
- }
- i810_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
-
-}
-
-
-/* set playback sample rate */
-static unsigned int i810_set_dac_rate(struct i810_state * state, unsigned int rate)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- u32 new_rate;
- struct ac97_codec *codec=state->card->ac97_codec[0];
-
- if(!(state->card->ac97_features&0x0001))
- {
- dmabuf->rate = clocking;
-#ifdef DEBUG
- printk("Asked for %d Hz, but ac97_features says we only do %dHz. Sorry!\n",
- rate,clocking);
-#endif
- return clocking;
- }
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 8000)
- rate = 8000;
- dmabuf->rate = rate;
-
- /*
- * Adjust for misclocked crap
- */
- rate = ( rate * clocking)/48000;
- if(strict_clocking && rate < 8000) {
- rate = 8000;
- dmabuf->rate = (rate * 48000)/clocking;
- }
-
- new_rate=ac97_set_dac_rate(codec, rate);
- if(new_rate != rate) {
- dmabuf->rate = (new_rate * 48000)/clocking;
- }
-#ifdef DEBUG
- printk("i810_audio: called i810_set_dac_rate : asked for %d, got %d\n", rate, dmabuf->rate);
-#endif
- rate = new_rate;
- return dmabuf->rate;
-}
-
-/* set recording sample rate */
-static unsigned int i810_set_adc_rate(struct i810_state * state, unsigned int rate)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- u32 new_rate;
- struct ac97_codec *codec=state->card->ac97_codec[0];
-
- if(!(state->card->ac97_features&0x0001))
- {
- dmabuf->rate = clocking;
- return clocking;
- }
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 8000)
- rate = 8000;
- dmabuf->rate = rate;
-
- /*
- * Adjust for misclocked crap
- */
-
- rate = ( rate * clocking)/48000;
- if(strict_clocking && rate < 8000) {
- rate = 8000;
- dmabuf->rate = (rate * 48000)/clocking;
- }
-
- new_rate = ac97_set_adc_rate(codec, rate);
-
- if(new_rate != rate) {
- dmabuf->rate = (new_rate * 48000)/clocking;
- rate = new_rate;
- }
-#ifdef DEBUG
- printk("i810_audio: called i810_set_adc_rate : rate = %d/%d\n", dmabuf->rate, rate);
-#endif
- return dmabuf->rate;
-}
-
-/* get current playback/recording dma buffer pointer (byte offset from LBA),
- called with spinlock held! */
-
-static inline unsigned i810_get_dma_addr(struct i810_state *state, int rec)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned int civ, offset, port, port_picb, bytes = 2;
-
- if (!dmabuf->enable)
- return 0;
-
- if (rec)
- port = dmabuf->read_channel->port;
- else
- port = dmabuf->write_channel->port;
-
- if(state->card->pci_id == PCI_DEVICE_ID_SI_7012) {
- port_picb = port + OFF_SR;
- bytes = 1;
- } else
- port_picb = port + OFF_PICB;
-
- do {
- civ = GET_CIV(state->card, port);
- offset = I810_IOREADW(state->card, port_picb);
- /* Must have a delay here! */
- if(offset == 0)
- udelay(1);
- /* Reread both registers and make sure that that total
- * offset from the first reading to the second is 0.
- * There is an issue with SiS hardware where it will count
- * picb down to 0, then update civ to the next value,
- * then set the new picb to fragsize bytes. We can catch
- * it between the civ update and the picb update, making
- * it look as though we are 1 fragsize ahead of where we
- * are. The next to we get the address though, it will
- * be back in the right place, and we will suddenly think
- * we just went forward dmasize - fragsize bytes, causing
- * totally stupid *huge* dma overrun messages. We are
- * assuming that the 1us delay is more than long enough
- * that we won't have to worry about the chip still being
- * out of sync with reality ;-)
- */
- } while (civ != GET_CIV(state->card, port) || offset != I810_IOREADW(state->card, port_picb));
-
- return (((civ + 1) * dmabuf->fragsize - (bytes * offset))
- % dmabuf->dmasize);
-}
-
-/* Stop recording (lock held) */
-static inline void __stop_adc(struct i810_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct i810_card *card = state->card;
-
- dmabuf->enable &= ~ADC_RUNNING;
- I810_IOWRITEB(0, card, PI_CR);
- // wait for the card to acknowledge shutdown
- while( I810_IOREADB(card, PI_CR) != 0 ) ;
- // now clear any latent interrupt bits (like the halt bit)
- if(card->pci_id == PCI_DEVICE_ID_SI_7012)
- I810_IOWRITEB( I810_IOREADB(card, PI_PICB), card, PI_PICB );
- else
- I810_IOWRITEB( I810_IOREADB(card, PI_SR), card, PI_SR );
- I810_IOWRITEL( I810_IOREADL(card, GLOB_STA) & INT_PI, card, GLOB_STA);
-}
-
-static void stop_adc(struct i810_state *state)
-{
- struct i810_card *card = state->card;
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
- __stop_adc(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static inline void __start_adc(struct i810_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
-
- if (dmabuf->count < dmabuf->dmasize && dmabuf->ready && !dmabuf->enable &&
- (dmabuf->trigger & PCM_ENABLE_INPUT)) {
- dmabuf->enable |= ADC_RUNNING;
- // Interrupt enable, LVI enable, DMA enable
- I810_IOWRITEB(0x10 | 0x04 | 0x01, state->card, PI_CR);
- }
-}
-
-static void start_adc(struct i810_state *state)
-{
- struct i810_card *card = state->card;
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
- __start_adc(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/* stop playback (lock held) */
-static inline void __stop_dac(struct i810_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct i810_card *card = state->card;
-
- dmabuf->enable &= ~DAC_RUNNING;
- I810_IOWRITEB(0, card, PO_CR);
- // wait for the card to acknowledge shutdown
- while( I810_IOREADB(card, PO_CR) != 0 ) ;
- // now clear any latent interrupt bits (like the halt bit)
- if(card->pci_id == PCI_DEVICE_ID_SI_7012)
- I810_IOWRITEB( I810_IOREADB(card, PO_PICB), card, PO_PICB );
- else
- I810_IOWRITEB( I810_IOREADB(card, PO_SR), card, PO_SR );
- I810_IOWRITEL( I810_IOREADL(card, GLOB_STA) & INT_PO, card, GLOB_STA);
-}
-
-static void stop_dac(struct i810_state *state)
-{
- struct i810_card *card = state->card;
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
- __stop_dac(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static inline void __start_dac(struct i810_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
-
- if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
- (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
- dmabuf->enable |= DAC_RUNNING;
- // Interrupt enable, LVI enable, DMA enable
- I810_IOWRITEB(0x10 | 0x04 | 0x01, state->card, PO_CR);
- }
-}
-static void start_dac(struct i810_state *state)
-{
- struct i810_card *card = state->card;
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
- __start_dac(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-/* allocate DMA buffer, playback and recording buffer should be allocated separately */
-static int alloc_dmabuf(struct i810_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- void *rawbuf= NULL;
- int order, size;
- struct page *page, *pend;
-
- /* If we don't have any oss frag params, then use our default ones */
- if(dmabuf->ossmaxfrags == 0)
- dmabuf->ossmaxfrags = 4;
- if(dmabuf->ossfragsize == 0)
- dmabuf->ossfragsize = (PAGE_SIZE<<DMABUF_DEFAULTORDER)/dmabuf->ossmaxfrags;
- size = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
-
- if(dmabuf->rawbuf && (PAGE_SIZE << dmabuf->buforder) == size)
- return 0;
- /* alloc enough to satisfy the oss params */
- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
- if ( (PAGE_SIZE<<order) > size )
- continue;
- if ((rawbuf = pci_alloc_consistent(state->card->pci_dev,
- PAGE_SIZE << order,
- &dmabuf->dma_handle)))
- break;
- }
- if (!rawbuf)
- return -ENOMEM;
-
-
-#ifdef DEBUG
- printk("i810_audio: allocated %ld (order = %d) bytes at %p\n",
- PAGE_SIZE << order, order, rawbuf);
-#endif
-
- dmabuf->ready = dmabuf->mapped = 0;
- dmabuf->rawbuf = rawbuf;
- dmabuf->buforder = order;
-
- /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
- pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
- for (page = virt_to_page(rawbuf); page <= pend; page++)
- SetPageReserved(page);
-
- return 0;
-}
-
-/* free DMA buffer */
-static void dealloc_dmabuf(struct i810_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct page *page, *pend;
-
- if (dmabuf->rawbuf) {
- /* undo marking the pages as reserved */
- pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
- for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++)
- ClearPageReserved(page);
- pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder,
- dmabuf->rawbuf, dmabuf->dma_handle);
- }
- dmabuf->rawbuf = NULL;
- dmabuf->mapped = dmabuf->ready = 0;
-}
-
-static int prog_dmabuf(struct i810_state *state, unsigned rec)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct i810_channel *c;
- struct sg_item *sg;
- unsigned long flags;
- int ret;
- unsigned fragint;
- int i;
-
- spin_lock_irqsave(&state->card->lock, flags);
- if(dmabuf->enable & DAC_RUNNING)
- __stop_dac(state);
- if(dmabuf->enable & ADC_RUNNING)
- __stop_adc(state);
- dmabuf->total_bytes = 0;
- dmabuf->count = dmabuf->error = 0;
- dmabuf->swptr = dmabuf->hwptr = 0;
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- /* allocate DMA buffer, let alloc_dmabuf determine if we are already
- * allocated well enough or if we should replace the current buffer
- * (assuming one is already allocated, if it isn't, then allocate it).
- */
- if ((ret = alloc_dmabuf(state)))
- return ret;
-
- /* FIXME: figure out all this OSS fragment stuff */
- /* I did, it now does what it should according to the OSS API. DL */
- /* We may not have realloced our dmabuf, but the fragment size to
- * fragment number ratio may have changed, so go ahead and reprogram
- * things
- */
- dmabuf->dmasize = PAGE_SIZE << dmabuf->buforder;
- dmabuf->numfrag = SG_LEN;
- dmabuf->fragsize = dmabuf->dmasize/dmabuf->numfrag;
- dmabuf->fragsamples = dmabuf->fragsize >> 1;
- dmabuf->fragshift = ffs(dmabuf->fragsize) - 1;
- dmabuf->userfragsize = dmabuf->ossfragsize;
- dmabuf->userfrags = dmabuf->dmasize/dmabuf->ossfragsize;
-
- memset(dmabuf->rawbuf, 0, dmabuf->dmasize);
-
- if(dmabuf->ossmaxfrags == 4) {
- fragint = 8;
- } else if (dmabuf->ossmaxfrags == 8) {
- fragint = 4;
- } else if (dmabuf->ossmaxfrags == 16) {
- fragint = 2;
- } else {
- fragint = 1;
- }
- /*
- * Now set up the ring
- */
- if(dmabuf->read_channel)
- c = dmabuf->read_channel;
- else
- c = dmabuf->write_channel;
- while(c != NULL) {
- sg=&c->sg[0];
- /*
- * Load up 32 sg entries and take an interrupt at half
- * way (we might want more interrupts later..)
- */
-
- for(i=0;i<dmabuf->numfrag;i++)
- {
- sg->busaddr=(u32)dmabuf->dma_handle+dmabuf->fragsize*i;
- // the card will always be doing 16bit stereo
- sg->control=dmabuf->fragsamples;
- if(state->card->pci_id == PCI_DEVICE_ID_SI_7012)
- sg->control <<= 1;
- sg->control|=CON_BUFPAD;
- // set us up to get IOC interrupts as often as needed to
- // satisfy numfrag requirements, no more
- if( ((i+1) % fragint) == 0) {
- sg->control|=CON_IOC;
- }
- sg++;
- }
- spin_lock_irqsave(&state->card->lock, flags);
- I810_IOWRITEB(2, state->card, c->port+OFF_CR); /* reset DMA machine */
- while( I810_IOREADB(state->card, c->port+OFF_CR) & 0x02 ) ;
- I810_IOWRITEL((u32)state->card->chandma +
- c->num*sizeof(struct i810_channel),
- state->card, c->port+OFF_BDBAR);
- CIV_TO_LVI(state->card, c->port, 0);
-
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- if(c != dmabuf->write_channel)
- c = dmabuf->write_channel;
- else
- c = NULL;
- }
-
- /* set the ready flag for the dma buffer */
- dmabuf->ready = 1;
-
-#ifdef DEBUG
- printk("i810_audio: prog_dmabuf, sample rate = %d, format = %d,\n\tnumfrag = %d, "
- "fragsize = %d dmasize = %d\n",
- dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
- dmabuf->fragsize, dmabuf->dmasize);
-#endif
-
- return 0;
-}
-
-static void __i810_update_lvi(struct i810_state *state, int rec)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- int x, port;
- int trigger;
- int count, fragsize;
- void (*start)(struct i810_state *);
-
- count = dmabuf->count;
- if (rec) {
- port = dmabuf->read_channel->port;
- trigger = PCM_ENABLE_INPUT;
- start = __start_adc;
- count = dmabuf->dmasize - count;
- } else {
- port = dmabuf->write_channel->port;
- trigger = PCM_ENABLE_OUTPUT;
- start = __start_dac;
- }
-
- /* Do not process partial fragments. */
- fragsize = dmabuf->fragsize;
- if (count < fragsize)
- return;
-
- /* if we are currently stopped, then our CIV is actually set to our
- * *last* sg segment and we are ready to wrap to the next. However,
- * if we set our LVI to the last sg segment, then it won't wrap to
- * the next sg segment, it won't even get a start. So, instead, when
- * we are stopped, we set both the LVI value and also we increment
- * the CIV value to the next sg segment to be played so that when
- * we call start, things will operate properly. Since the CIV can't
- * be written to directly for this purpose, we set the LVI to CIV + 1
- * temporarily. Once the engine has started we set the LVI to its
- * final value.
- */
- if (!dmabuf->enable && dmabuf->ready) {
- if (!(dmabuf->trigger & trigger))
- return;
-
- CIV_TO_LVI(state->card, port, 1);
-
- start(state);
- while (!(I810_IOREADB(state->card, port + OFF_CR) & ((1<<4) | (1<<2))))
- ;
- }
-
- /* MASKP2(swptr, fragsize) - 1 is the tail of our transfer */
- x = MODULOP2(MASKP2(dmabuf->swptr, fragsize) - 1, dmabuf->dmasize);
- x >>= dmabuf->fragshift;
- I810_IOWRITEB(x, state->card, port + OFF_LVI);
-}
-
-static void i810_update_lvi(struct i810_state *state, int rec)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned long flags;
-
- if(!dmabuf->ready)
- return;
- spin_lock_irqsave(&state->card->lock, flags);
- __i810_update_lvi(state, rec);
- spin_unlock_irqrestore(&state->card->lock, flags);
-}
-
-/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */
-static void i810_update_ptr(struct i810_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned hwptr;
- unsigned fragmask, dmamask;
- int diff;
-
- fragmask = MASKP2(~0, dmabuf->fragsize);
- dmamask = MODULOP2(~0, dmabuf->dmasize);
-
- /* error handling and process wake up for ADC */
- if (dmabuf->enable == ADC_RUNNING) {
- /* update hardware pointer */
- hwptr = i810_get_dma_addr(state, 1) & fragmask;
- diff = (hwptr - dmabuf->hwptr) & dmamask;
-#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP)
- printk("ADC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
-#endif
- dmabuf->hwptr = hwptr;
- dmabuf->total_bytes += diff;
- dmabuf->count += diff;
- if (dmabuf->count > dmabuf->dmasize) {
- /* buffer underrun or buffer overrun */
- /* this is normal for the end of a read */
- /* only give an error if we went past the */
- /* last valid sg entry */
- if (GET_CIV(state->card, PI_BASE) !=
- GET_LVI(state->card, PI_BASE)) {
- printk(KERN_WARNING "i810_audio: DMA overrun on read\n");
- dmabuf->error++;
- }
- }
- if (diff)
- wake_up(&dmabuf->wait);
- }
- /* error handling and process wake up for DAC */
- if (dmabuf->enable == DAC_RUNNING) {
- /* update hardware pointer */
- hwptr = i810_get_dma_addr(state, 0) & fragmask;
- diff = (hwptr - dmabuf->hwptr) & dmamask;
-#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP)
- printk("DAC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
-#endif
- dmabuf->hwptr = hwptr;
- dmabuf->total_bytes += diff;
- dmabuf->count -= diff;
- if (dmabuf->count < 0) {
- /* buffer underrun or buffer overrun */
- /* this is normal for the end of a write */
- /* only give an error if we went past the */
- /* last valid sg entry */
- if (GET_CIV(state->card, PO_BASE) !=
- GET_LVI(state->card, PO_BASE)) {
- printk(KERN_WARNING "i810_audio: DMA overrun on write\n");
- printk("i810_audio: CIV %d, LVI %d, hwptr %x, "
- "count %d\n",
- GET_CIV(state->card, PO_BASE),
- GET_LVI(state->card, PO_BASE),
- dmabuf->hwptr, dmabuf->count);
- dmabuf->error++;
- }
- }
- if (diff)
- wake_up(&dmabuf->wait);
- }
-}
-
-static inline int i810_get_free_write_space(struct i810_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- int free;
-
- i810_update_ptr(state);
- // catch underruns during playback
- if (dmabuf->count < 0) {
- dmabuf->count = 0;
- dmabuf->swptr = dmabuf->hwptr;
- }
- free = dmabuf->dmasize - dmabuf->count;
- if(free < 0)
- return(0);
- return(free);
-}
-
-static inline int i810_get_available_read_data(struct i810_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- int avail;
-
- i810_update_ptr(state);
- // catch overruns during record
- if (dmabuf->count > dmabuf->dmasize) {
- dmabuf->count = dmabuf->dmasize;
- dmabuf->swptr = dmabuf->hwptr;
- }
- avail = dmabuf->count;
- if(avail < 0)
- return(0);
- return(avail);
-}
-
-static inline void fill_partial_frag(struct dmabuf *dmabuf)
-{
- unsigned fragsize;
- unsigned swptr, len;
-
- fragsize = dmabuf->fragsize;
- swptr = dmabuf->swptr;
- len = fragsize - MODULOP2(dmabuf->swptr, fragsize);
- if (len == fragsize)
- return;
-
- memset(dmabuf->rawbuf + swptr, '\0', len);
- dmabuf->swptr = MODULOP2(swptr + len, dmabuf->dmasize);
- dmabuf->count += len;
-}
-
-static int drain_dac(struct i810_state *state, int signals_allowed)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned long flags;
- unsigned long tmo;
- int count;
-
- if (!dmabuf->ready)
- return 0;
- if(dmabuf->mapped) {
- stop_dac(state);
- return 0;
- }
-
- spin_lock_irqsave(&state->card->lock, flags);
-
- fill_partial_frag(dmabuf);
-
- /*
- * This will make sure that our LVI is correct, that our
- * pointer is updated, and that the DAC is running. We
- * have to force the setting of dmabuf->trigger to avoid
- * any possible deadlocks.
- */
- dmabuf->trigger = PCM_ENABLE_OUTPUT;
- __i810_update_lvi(state, 0);
-
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- add_wait_queue(&dmabuf->wait, &wait);
- for (;;) {
-
- spin_lock_irqsave(&state->card->lock, flags);
- i810_update_ptr(state);
- count = dmabuf->count;
-
- /* It seems that we have to set the current state to
- * TASK_INTERRUPTIBLE every time to make the process
- * really go to sleep. This also has to be *after* the
- * update_ptr() call because update_ptr is likely to
- * do a wake_up() which will unset this before we ever
- * try to sleep, resuling in a tight loop in this code
- * instead of actually sleeping and waiting for an
- * interrupt to wake us up!
- */
- __set_current_state(signals_allowed ?
- TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- if (count <= 0)
- break;
-
- if (signal_pending(current) && signals_allowed) {
- break;
- }
-
- /*
- * set the timeout to significantly longer than it *should*
- * take for the DAC to drain the DMA buffer
- */
- tmo = (count * HZ) / (dmabuf->rate);
- if (!schedule_timeout(tmo >= 2 ? tmo : 2)){
- printk(KERN_ERR "i810_audio: drain_dac, dma timeout?\n");
- count = 0;
- break;
- }
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&dmabuf->wait, &wait);
- if(count > 0 && signal_pending(current) && signals_allowed)
- return -ERESTARTSYS;
- stop_dac(state);
- return 0;
-}
-
-static void i810_channel_interrupt(struct i810_card *card)
-{
- int i, count;
-
-#ifdef DEBUG_INTERRUPTS
- printk("CHANNEL ");
-#endif
- for(i=0;i<NR_HW_CH;i++)
- {
- struct i810_state *state = card->states[i];
- struct i810_channel *c;
- struct dmabuf *dmabuf;
- unsigned long port;
- u16 status;
-
- if(!state)
- continue;
- if(!state->dmabuf.ready)
- continue;
- dmabuf = &state->dmabuf;
- if(dmabuf->enable & DAC_RUNNING) {
- c=dmabuf->write_channel;
- } else if(dmabuf->enable & ADC_RUNNING) {
- c=dmabuf->read_channel;
- } else /* This can occur going from R/W to close */
- continue;
-
- port = c->port;
-
- if(card->pci_id == PCI_DEVICE_ID_SI_7012)
- status = I810_IOREADW(card, port + OFF_PICB);
- else
- status = I810_IOREADW(card, port + OFF_SR);
-
-#ifdef DEBUG_INTERRUPTS
- printk("NUM %d PORT %X IRQ ( ST%d ", c->num, c->port, status);
-#endif
- if(status & DMA_INT_COMPLETE)
- {
- /* only wake_up() waiters if this interrupt signals
- * us being beyond a userfragsize of data open or
- * available, and i810_update_ptr() does that for
- * us
- */
- i810_update_ptr(state);
-#ifdef DEBUG_INTERRUPTS
- printk("COMP %d ", dmabuf->hwptr /
- dmabuf->fragsize);
-#endif
- }
- if(status & (DMA_INT_LVI | DMA_INT_DCH))
- {
- /* wake_up() unconditionally on LVI and DCH */
- i810_update_ptr(state);
- wake_up(&dmabuf->wait);
-#ifdef DEBUG_INTERRUPTS
- if(status & DMA_INT_LVI)
- printk("LVI ");
- if(status & DMA_INT_DCH)
- printk("DCH -");
-#endif
- count = dmabuf->count;
- if(dmabuf->enable & ADC_RUNNING)
- count = dmabuf->dmasize - count;
- if (count >= (int)dmabuf->fragsize) {
- I810_IOWRITEB(I810_IOREADB(card, port+OFF_CR) | 1, card, port+OFF_CR);
-#ifdef DEBUG_INTERRUPTS
- printk(" CONTINUE ");
-#endif
- } else {
- if (dmabuf->enable & DAC_RUNNING)
- __stop_dac(state);
- if (dmabuf->enable & ADC_RUNNING)
- __stop_adc(state);
- dmabuf->enable = 0;
-#ifdef DEBUG_INTERRUPTS
- printk(" STOP ");
-#endif
- }
- }
- if(card->pci_id == PCI_DEVICE_ID_SI_7012)
- I810_IOWRITEW(status & DMA_INT_MASK, card, port + OFF_PICB);
- else
- I810_IOWRITEW(status & DMA_INT_MASK, card, port + OFF_SR);
- }
-#ifdef DEBUG_INTERRUPTS
- printk(")\n");
-#endif
-}
-
-static irqreturn_t i810_interrupt(int irq, void *dev_id)
-{
- struct i810_card *card = dev_id;
- u32 status;
-
- spin_lock(&card->lock);
-
- status = I810_IOREADL(card, GLOB_STA);
-
- if(!(status & INT_MASK))
- {
- spin_unlock(&card->lock);
- return IRQ_NONE; /* not for us */
- }
-
- if(status & (INT_PO|INT_PI|INT_MC))
- i810_channel_interrupt(card);
-
- /* clear 'em */
- I810_IOWRITEL(status & INT_MASK, card, GLOB_STA);
- spin_unlock(&card->lock);
- return IRQ_HANDLED;
-}
-
-/* in this loop, dmabuf.count signifies the amount of data that is
- waiting to be copied to the user's buffer. It is filled by the dma
- machine and drained by this loop. */
-
-static ssize_t i810_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct i810_state *state = (struct i810_state *)file->private_data;
- struct i810_card *card=state ? state->card : NULL;
- struct dmabuf *dmabuf = &state->dmabuf;
- ssize_t ret;
- unsigned long flags;
- unsigned int swptr;
- int cnt;
- int pending;
- DECLARE_WAITQUEUE(waita, current);
-
-#ifdef DEBUG2
- printk("i810_audio: i810_read called, count = %d\n", count);
-#endif
-
- if (dmabuf->mapped)
- return -ENXIO;
- if (dmabuf->enable & DAC_RUNNING)
- return -ENODEV;
- if (!dmabuf->read_channel) {
- dmabuf->ready = 0;
- dmabuf->read_channel = card->alloc_rec_pcm_channel(card);
- if (!dmabuf->read_channel) {
- return -EBUSY;
- }
- }
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
- return ret;
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- ret = 0;
-
- pending = 0;
-
- add_wait_queue(&dmabuf->wait, &waita);
- while (count > 0) {
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&card->lock, flags);
- if (PM_SUSPENDED(card)) {
- spin_unlock_irqrestore(&card->lock, flags);
- schedule();
- if (signal_pending(current)) {
- if (!ret) ret = -EAGAIN;
- break;
- }
- continue;
- }
- cnt = i810_get_available_read_data(state);
- swptr = dmabuf->swptr;
- // this is to make the copy_to_user simpler below
- if(cnt > (dmabuf->dmasize - swptr))
- cnt = dmabuf->dmasize - swptr;
- spin_unlock_irqrestore(&card->lock, flags);
-
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- unsigned long tmo;
- /*
- * Don't let us deadlock. The ADC won't start if
- * dmabuf->trigger isn't set. A call to SETTRIGGER
- * could have turned it off after we set it to on
- * previously.
- */
- dmabuf->trigger = PCM_ENABLE_INPUT;
- /*
- * This does three things. Updates LVI to be correct,
- * makes sure the ADC is running, and updates the
- * hwptr.
- */
- i810_update_lvi(state,1);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret) ret = -EAGAIN;
- goto done;
- }
- /* Set the timeout to how long it would take to fill
- * two of our buffers. If we haven't been woke up
- * by then, then we know something is wrong.
- */
- tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4);
- /* There are two situations when sleep_on_timeout returns, one is when
- the interrupt is serviced correctly and the process is waked up by
- ISR ON TIME. Another is when timeout is expired, which means that
- either interrupt is NOT serviced correctly (pending interrupt) or it
- is TOO LATE for the process to be scheduled to run (scheduler latency)
- which results in a (potential) buffer overrun. And worse, there is
- NOTHING we can do to prevent it. */
- if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
-#ifdef DEBUG
- printk(KERN_ERR "i810_audio: recording schedule timeout, "
- "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
- dmabuf->hwptr, dmabuf->swptr);
-#endif
- /* a buffer overrun, we delay the recovery until next time the
- while loop begin and we REALLY have space to record */
- }
- if (signal_pending(current)) {
- ret = ret ? ret : -ERESTARTSYS;
- goto done;
- }
- continue;
- }
-
- if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
- if (!ret) ret = -EFAULT;
- goto done;
- }
-
- swptr = MODULOP2(swptr + cnt, dmabuf->dmasize);
-
- spin_lock_irqsave(&card->lock, flags);
-
- if (PM_SUSPENDED(card)) {
- spin_unlock_irqrestore(&card->lock, flags);
- continue;
- }
- dmabuf->swptr = swptr;
- pending = dmabuf->count -= cnt;
- spin_unlock_irqrestore(&card->lock, flags);
-
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- }
- done:
- pending = dmabuf->dmasize - pending;
- if (dmabuf->enable || pending >= dmabuf->userfragsize)
- i810_update_lvi(state, 1);
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&dmabuf->wait, &waita);
-
- return ret;
-}
-
-/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to
- the soundcard. it is drained by the dma machine and filled by this loop. */
-static ssize_t i810_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct i810_state *state = (struct i810_state *)file->private_data;
- struct i810_card *card=state ? state->card : NULL;
- struct dmabuf *dmabuf = &state->dmabuf;
- ssize_t ret;
- unsigned long flags;
- unsigned int swptr = 0;
- int pending;
- int cnt;
- DECLARE_WAITQUEUE(waita, current);
-
-#ifdef DEBUG2
- printk("i810_audio: i810_write called, count = %d\n", count);
-#endif
-
- if (dmabuf->mapped)
- return -ENXIO;
- if (dmabuf->enable & ADC_RUNNING)
- return -ENODEV;
- if (!dmabuf->write_channel) {
- dmabuf->ready = 0;
- dmabuf->write_channel = card->alloc_pcm_channel(card);
- if(!dmabuf->write_channel)
- return -EBUSY;
- }
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
- return ret;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- ret = 0;
-
- pending = 0;
-
- add_wait_queue(&dmabuf->wait, &waita);
- while (count > 0) {
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&state->card->lock, flags);
- if (PM_SUSPENDED(card)) {
- spin_unlock_irqrestore(&card->lock, flags);
- schedule();
- if (signal_pending(current)) {
- if (!ret) ret = -EAGAIN;
- break;
- }
- continue;
- }
-
- cnt = i810_get_free_write_space(state);
- swptr = dmabuf->swptr;
- /* Bound the maximum size to how much we can copy to the
- * dma buffer before we hit the end. If we have more to
- * copy then it will get done in a second pass of this
- * loop starting from the beginning of the buffer.
- */
- if(cnt > (dmabuf->dmasize - swptr))
- cnt = dmabuf->dmasize - swptr;
- spin_unlock_irqrestore(&state->card->lock, flags);
-
-#ifdef DEBUG2
- printk(KERN_INFO "i810_audio: i810_write: %d bytes available space\n", cnt);
-#endif
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- unsigned long tmo;
- // There is data waiting to be played
- /*
- * Force the trigger setting since we would
- * deadlock with it set any other way
- */
- dmabuf->trigger = PCM_ENABLE_OUTPUT;
- i810_update_lvi(state,0);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret) ret = -EAGAIN;
- goto ret;
- }
- /* Not strictly correct but works */
- tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4);
- /* There are two situations when sleep_on_timeout returns, one is when
- the interrupt is serviced correctly and the process is waked up by
- ISR ON TIME. Another is when timeout is expired, which means that
- either interrupt is NOT serviced correctly (pending interrupt) or it
- is TOO LATE for the process to be scheduled to run (scheduler latency)
- which results in a (potential) buffer underrun. And worse, there is
- NOTHING we can do to prevent it. */
- if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
-#ifdef DEBUG
- printk(KERN_ERR "i810_audio: playback schedule timeout, "
- "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
- dmabuf->hwptr, dmabuf->swptr);
-#endif
- /* a buffer underrun, we delay the recovery until next time the
- while loop begin and we REALLY have data to play */
- //return ret;
- }
- if (signal_pending(current)) {
- if (!ret) ret = -ERESTARTSYS;
- goto ret;
- }
- continue;
- }
- if (copy_from_user(dmabuf->rawbuf+swptr,buffer,cnt)) {
- if (!ret) ret = -EFAULT;
- goto ret;
- }
-
- swptr = MODULOP2(swptr + cnt, dmabuf->dmasize);
-
- spin_lock_irqsave(&state->card->lock, flags);
- if (PM_SUSPENDED(card)) {
- spin_unlock_irqrestore(&card->lock, flags);
- continue;
- }
-
- dmabuf->swptr = swptr;
- pending = dmabuf->count += cnt;
-
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
-ret:
- if (dmabuf->enable || pending >= dmabuf->userfragsize)
- i810_update_lvi(state, 0);
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&dmabuf->wait, &waita);
-
- return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int i810_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct i810_state *state = (struct i810_state *)file->private_data;
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned long flags;
- unsigned int mask = 0;
-
- if(!dmabuf->ready)
- return 0;
- poll_wait(file, &dmabuf->wait, wait);
- spin_lock_irqsave(&state->card->lock, flags);
- if (dmabuf->enable & ADC_RUNNING ||
- dmabuf->trigger & PCM_ENABLE_INPUT) {
- if (i810_get_available_read_data(state) >=
- (signed)dmabuf->userfragsize)
- mask |= POLLIN | POLLRDNORM;
- }
- if (dmabuf->enable & DAC_RUNNING ||
- dmabuf->trigger & PCM_ENABLE_OUTPUT) {
- if (i810_get_free_write_space(state) >=
- (signed)dmabuf->userfragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
- spin_unlock_irqrestore(&state->card->lock, flags);
- return mask;
-}
-
-static int i810_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct i810_state *state = (struct i810_state *)file->private_data;
- struct dmabuf *dmabuf = &state->dmabuf;
- int ret = -EINVAL;
- unsigned long size;
-
- lock_kernel();
- if (vma->vm_flags & VM_WRITE) {
- if (!dmabuf->write_channel &&
- (dmabuf->write_channel =
- state->card->alloc_pcm_channel(state->card)) == NULL) {
- ret = -EBUSY;
- goto out;
- }
- }
- if (vma->vm_flags & VM_READ) {
- if (!dmabuf->read_channel &&
- (dmabuf->read_channel =
- state->card->alloc_rec_pcm_channel(state->card)) == NULL) {
- ret = -EBUSY;
- goto out;
- }
- }
- if ((ret = prog_dmabuf(state, 0)) != 0)
- goto out;
-
- ret = -EINVAL;
- if (vma->vm_pgoff != 0)
- goto out;
- size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << dmabuf->buforder))
- goto out;
- ret = -EAGAIN;
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- goto out;
- dmabuf->mapped = 1;
- dmabuf->trigger = 0;
- ret = 0;
-#ifdef DEBUG_MMAP
- printk("i810_audio: mmap'ed %ld bytes of data space\n", size);
-#endif
-out:
- unlock_kernel();
- return ret;
-}
-
-static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct i810_state *state = (struct i810_state *)file->private_data;
- struct i810_channel *c = NULL;
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- unsigned int i_glob_cnt;
- int val = 0, ret;
- struct ac97_codec *codec = state->card->ac97_codec[0];
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
-#ifdef DEBUG
- printk("i810_audio: i810_ioctl, arg=0x%x, cmd=", arg ? *p : 0);
-#endif
-
- switch (cmd)
- {
- case OSS_GETVERSION:
-#ifdef DEBUG
- printk("OSS_GETVERSION\n");
-#endif
- return put_user(SOUND_VERSION, p);
-
- case SNDCTL_DSP_RESET:
-#ifdef DEBUG
- printk("SNDCTL_DSP_RESET\n");
-#endif
- spin_lock_irqsave(&state->card->lock, flags);
- if (dmabuf->enable == DAC_RUNNING) {
- c = dmabuf->write_channel;
- __stop_dac(state);
- }
- if (dmabuf->enable == ADC_RUNNING) {
- c = dmabuf->read_channel;
- __stop_adc(state);
- }
- if (c != NULL) {
- I810_IOWRITEB(2, state->card, c->port+OFF_CR); /* reset DMA machine */
- while ( I810_IOREADB(state->card, c->port+OFF_CR) & 2 )
- cpu_relax();
- I810_IOWRITEL((u32)state->card->chandma +
- c->num*sizeof(struct i810_channel),
- state->card, c->port+OFF_BDBAR);
- CIV_TO_LVI(state->card, c->port, 0);
- }
-
- spin_unlock_irqrestore(&state->card->lock, flags);
- synchronize_irq(state->card->pci_dev->irq);
- dmabuf->ready = 0;
- dmabuf->swptr = dmabuf->hwptr = 0;
- dmabuf->count = dmabuf->total_bytes = 0;
- return 0;
-
- case SNDCTL_DSP_SYNC:
-#ifdef DEBUG
- printk("SNDCTL_DSP_SYNC\n");
-#endif
- if (dmabuf->enable != DAC_RUNNING || file->f_flags & O_NONBLOCK)
- return 0;
- if((val = drain_dac(state, 1)))
- return val;
- dmabuf->total_bytes = 0;
- return 0;
-
- case SNDCTL_DSP_SPEED: /* set smaple rate */
-#ifdef DEBUG
- printk("SNDCTL_DSP_SPEED\n");
-#endif
- if (get_user(val, p))
- return -EFAULT;
- if (val >= 0) {
- if (file->f_mode & FMODE_WRITE) {
- if ( (state->card->ac97_status & SPDIF_ON) ) { /* S/PDIF Enabled */
- /* AD1886 only supports 48000, need to check that */
- if ( i810_valid_spdif_rate ( codec, val ) ) {
- /* Set DAC rate */
- i810_set_spdif_output ( state, -1, 0 );
- stop_dac(state);
- dmabuf->ready = 0;
- spin_lock_irqsave(&state->card->lock, flags);
- i810_set_dac_rate(state, val);
- spin_unlock_irqrestore(&state->card->lock, flags);
- /* Set S/PDIF transmitter rate. */
- i810_set_spdif_output ( state, AC97_EA_SPSA_3_4, val );
- if ( ! (state->card->ac97_status & SPDIF_ON) ) {
- val = dmabuf->rate;
- }
- } else { /* Not a valid rate for S/PDIF, ignore it */
- val = dmabuf->rate;
- }
- } else {
- stop_dac(state);
- dmabuf->ready = 0;
- spin_lock_irqsave(&state->card->lock, flags);
- i810_set_dac_rate(state, val);
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(state);
- dmabuf->ready = 0;
- spin_lock_irqsave(&state->card->lock, flags);
- i810_set_adc_rate(state, val);
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
- }
- return put_user(dmabuf->rate, p);
-
- case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
-#ifdef DEBUG
- printk("SNDCTL_DSP_STEREO\n");
-#endif
- if (dmabuf->enable & DAC_RUNNING) {
- stop_dac(state);
- }
- if (dmabuf->enable & ADC_RUNNING) {
- stop_adc(state);
- }
- return put_user(1, p);
-
- case SNDCTL_DSP_GETBLKSIZE:
- if (file->f_mode & FMODE_WRITE) {
- if (!dmabuf->ready && (val = prog_dmabuf(state, 0)))
- return val;
- }
- if (file->f_mode & FMODE_READ) {
- if (!dmabuf->ready && (val = prog_dmabuf(state, 1)))
- return val;
- }
-#ifdef DEBUG
- printk("SNDCTL_DSP_GETBLKSIZE %d\n", dmabuf->userfragsize);
-#endif
- return put_user(dmabuf->userfragsize, p);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
-#ifdef DEBUG
- printk("SNDCTL_DSP_GETFMTS\n");
-#endif
- return put_user(AFMT_S16_LE, p);
-
- case SNDCTL_DSP_SETFMT: /* Select sample format */
-#ifdef DEBUG
- printk("SNDCTL_DSP_SETFMT\n");
-#endif
- return put_user(AFMT_S16_LE, p);
-
- case SNDCTL_DSP_CHANNELS:
-#ifdef DEBUG
- printk("SNDCTL_DSP_CHANNELS\n");
-#endif
- if (get_user(val, p))
- return -EFAULT;
-
- if (val > 0) {
- if (dmabuf->enable & DAC_RUNNING) {
- stop_dac(state);
- }
- if (dmabuf->enable & ADC_RUNNING) {
- stop_adc(state);
- }
- } else {
- return put_user(state->card->channels, p);
- }
-
- /* ICH and ICH0 only support 2 channels */
- if ( state->card->pci_id == PCI_DEVICE_ID_INTEL_82801AA_5
- || state->card->pci_id == PCI_DEVICE_ID_INTEL_82801AB_5)
- return put_user(2, p);
-
- /* Multi-channel support was added with ICH2. Bits in */
- /* Global Status and Global Control register are now */
- /* used to indicate this. */
-
- i_glob_cnt = I810_IOREADL(state->card, GLOB_CNT);
-
- /* Current # of channels enabled */
- if ( i_glob_cnt & 0x0100000 )
- ret = 4;
- else if ( i_glob_cnt & 0x0200000 )
- ret = 6;
- else
- ret = 2;
-
- switch ( val ) {
- case 2: /* 2 channels is always supported */
- I810_IOWRITEL(i_glob_cnt & 0xffcfffff,
- state->card, GLOB_CNT);
- /* Do we need to change mixer settings???? */
- break;
- case 4: /* Supported on some chipsets, better check first */
- if ( state->card->channels >= 4 ) {
- I810_IOWRITEL((i_glob_cnt & 0xffcfffff) | 0x100000,
- state->card, GLOB_CNT);
- /* Do we need to change mixer settings??? */
- } else {
- val = ret;
- }
- break;
- case 6: /* Supported on some chipsets, better check first */
- if ( state->card->channels >= 6 ) {
- I810_IOWRITEL((i_glob_cnt & 0xffcfffff) | 0x200000,
- state->card, GLOB_CNT);
- /* Do we need to change mixer settings??? */
- } else {
- val = ret;
- }
- break;
- default: /* nothing else is ever supported by the chipset */
- val = ret;
- break;
- }
-
- return put_user(val, p);
-
- case SNDCTL_DSP_POST: /* the user has sent all data and is notifying us */
- /* we update the swptr to the end of the last sg segment then return */
-#ifdef DEBUG
- printk("SNDCTL_DSP_POST\n");
-#endif
- if(!dmabuf->ready || (dmabuf->enable != DAC_RUNNING))
- return 0;
- if((dmabuf->swptr % dmabuf->fragsize) != 0) {
- val = dmabuf->fragsize - (dmabuf->swptr % dmabuf->fragsize);
- dmabuf->swptr += val;
- dmabuf->count += val;
- }
- return 0;
-
- case SNDCTL_DSP_SUBDIVIDE:
- if (dmabuf->subdivision)
- return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- if (val != 1 && val != 2 && val != 4)
- return -EINVAL;
-#ifdef DEBUG
- printk("SNDCTL_DSP_SUBDIVIDE %d\n", val);
-#endif
- dmabuf->subdivision = val;
- dmabuf->ready = 0;
- return 0;
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, p))
- return -EFAULT;
-
- dmabuf->ossfragsize = 1<<(val & 0xffff);
- dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
- if (!dmabuf->ossfragsize || !dmabuf->ossmaxfrags)
- return -EINVAL;
- /*
- * Bound the frag size into our allowed range of 256 - 4096
- */
- if (dmabuf->ossfragsize < 256)
- dmabuf->ossfragsize = 256;
- else if (dmabuf->ossfragsize > 4096)
- dmabuf->ossfragsize = 4096;
- /*
- * The numfrags could be something reasonable, or it could
- * be 0xffff meaning "Give me as much as possible". So,
- * we check the numfrags * fragsize doesn't exceed our
- * 64k buffer limit, nor is it less than our 8k minimum.
- * If it fails either one of these checks, then adjust the
- * number of fragments, not the size of them. It's OK if
- * our number of fragments doesn't equal 32 or anything
- * like our hardware based number now since we are using
- * a different frag count for the hardware. Before we get
- * into this though, bound the maxfrags to avoid overflow
- * issues. A reasonable bound would be 64k / 256 since our
- * maximum buffer size is 64k and our minimum frag size is
- * 256. On the other end, our minimum buffer size is 8k and
- * our maximum frag size is 4k, so the lower bound should
- * be 2.
- */
-
- if(dmabuf->ossmaxfrags > 256)
- dmabuf->ossmaxfrags = 256;
- else if (dmabuf->ossmaxfrags < 2)
- dmabuf->ossmaxfrags = 2;
-
- val = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
- while (val < 8192) {
- val <<= 1;
- dmabuf->ossmaxfrags <<= 1;
- }
- while (val > 65536) {
- val >>= 1;
- dmabuf->ossmaxfrags >>= 1;
- }
- dmabuf->ready = 0;
-#ifdef DEBUG
- printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val,
- dmabuf->ossfragsize, dmabuf->ossmaxfrags);
-#endif
-
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
- return val;
- spin_lock_irqsave(&state->card->lock, flags);
- i810_update_ptr(state);
- abinfo.fragsize = dmabuf->userfragsize;
- abinfo.fragstotal = dmabuf->userfrags;
- if (dmabuf->mapped)
- abinfo.bytes = dmabuf->dmasize;
- else
- abinfo.bytes = i810_get_free_write_space(state);
- abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
- spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
- printk("SNDCTL_DSP_GETOSPACE %d, %d, %d, %d\n", abinfo.bytes,
- abinfo.fragsize, abinfo.fragments, abinfo.fragstotal);
-#endif
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
- return val;
- spin_lock_irqsave(&state->card->lock, flags);
- val = i810_get_free_write_space(state);
- cinfo.bytes = dmabuf->total_bytes;
- cinfo.ptr = dmabuf->hwptr;
- cinfo.blocks = val/dmabuf->userfragsize;
- if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
- dmabuf->count += val;
- dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
- __i810_update_lvi(state, 0);
- }
- spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
- printk("SNDCTL_DSP_GETOPTR %d, %d, %d, %d\n", cinfo.bytes,
- cinfo.blocks, cinfo.ptr, dmabuf->count);
-#endif
- return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)
- return val;
- spin_lock_irqsave(&state->card->lock, flags);
- abinfo.bytes = i810_get_available_read_data(state);
- abinfo.fragsize = dmabuf->userfragsize;
- abinfo.fragstotal = dmabuf->userfrags;
- abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
- spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
- printk("SNDCTL_DSP_GETISPACE %d, %d, %d, %d\n", abinfo.bytes,
- abinfo.fragsize, abinfo.fragments, abinfo.fragstotal);
-#endif
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
- return val;
- spin_lock_irqsave(&state->card->lock, flags);
- val = i810_get_available_read_data(state);
- cinfo.bytes = dmabuf->total_bytes;
- cinfo.blocks = val/dmabuf->userfragsize;
- cinfo.ptr = dmabuf->hwptr;
- if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
- dmabuf->count -= val;
- dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
- __i810_update_lvi(state, 1);
- }
- spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
- printk("SNDCTL_DSP_GETIPTR %d, %d, %d, %d\n", cinfo.bytes,
- cinfo.blocks, cinfo.ptr, dmabuf->count);
-#endif
- return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_NONBLOCK:
-#ifdef DEBUG
- printk("SNDCTL_DSP_NONBLOCK\n");
-#endif
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_GETCAPS:
-#ifdef DEBUG
- printk("SNDCTL_DSP_GETCAPS\n");
-#endif
- return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP|DSP_CAP_BIND,
- p);
-
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
-#ifdef DEBUG
- printk("SNDCTL_DSP_GETTRIGGER 0x%x\n", dmabuf->trigger);
-#endif
- return put_user(dmabuf->trigger, p);
-
- case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, p))
- return -EFAULT;
-#if defined(DEBUG) || defined(DEBUG_MMAP)
- printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val);
-#endif
- /* silently ignore invalid PCM_ENABLE_xxx bits,
- * like the other drivers do
- */
- if (!(file->f_mode & FMODE_READ ))
- val &= ~PCM_ENABLE_INPUT;
- if (!(file->f_mode & FMODE_WRITE ))
- val &= ~PCM_ENABLE_OUTPUT;
- if((file->f_mode & FMODE_READ) && !(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) {
- stop_adc(state);
- }
- if((file->f_mode & FMODE_WRITE) && !(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) {
- stop_dac(state);
- }
- dmabuf->trigger = val;
- if((val & PCM_ENABLE_OUTPUT) && !(dmabuf->enable & DAC_RUNNING)) {
- if (!dmabuf->write_channel) {
- dmabuf->ready = 0;
- dmabuf->write_channel = state->card->alloc_pcm_channel(state->card);
- if (!dmabuf->write_channel)
- return -EBUSY;
- }
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
- return ret;
- if (dmabuf->mapped) {
- spin_lock_irqsave(&state->card->lock, flags);
- i810_update_ptr(state);
- dmabuf->count = 0;
- dmabuf->swptr = dmabuf->hwptr;
- dmabuf->count = i810_get_free_write_space(state);
- dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
- i810_update_lvi(state, 0);
- start_dac(state);
- }
- if((val & PCM_ENABLE_INPUT) && !(dmabuf->enable & ADC_RUNNING)) {
- if (!dmabuf->read_channel) {
- dmabuf->ready = 0;
- dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card);
- if (!dmabuf->read_channel)
- return -EBUSY;
- }
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
- return ret;
- if (dmabuf->mapped) {
- spin_lock_irqsave(&state->card->lock, flags);
- i810_update_ptr(state);
- dmabuf->swptr = dmabuf->hwptr;
- dmabuf->count = 0;
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
- i810_update_lvi(state, 1);
- start_adc(state);
- }
- return 0;
-
- case SNDCTL_DSP_SETDUPLEX:
-#ifdef DEBUG
- printk("SNDCTL_DSP_SETDUPLEX\n");
-#endif
- return -EINVAL;
-
- case SNDCTL_DSP_GETODELAY:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- spin_lock_irqsave(&state->card->lock, flags);
- i810_update_ptr(state);
- val = dmabuf->count;
- spin_unlock_irqrestore(&state->card->lock, flags);
-#ifdef DEBUG
- printk("SNDCTL_DSP_GETODELAY %d\n", dmabuf->count);
-#endif
- return put_user(val, p);
-
- case SOUND_PCM_READ_RATE:
-#ifdef DEBUG
- printk("SOUND_PCM_READ_RATE %d\n", dmabuf->rate);
-#endif
- return put_user(dmabuf->rate, p);
-
- case SOUND_PCM_READ_CHANNELS:
-#ifdef DEBUG
- printk("SOUND_PCM_READ_CHANNELS\n");
-#endif
- return put_user(2, p);
-
- case SOUND_PCM_READ_BITS:
-#ifdef DEBUG
- printk("SOUND_PCM_READ_BITS\n");
-#endif
- return put_user(AFMT_S16_LE, p);
-
- case SNDCTL_DSP_SETSPDIF: /* Set S/PDIF Control register */
-#ifdef DEBUG
- printk("SNDCTL_DSP_SETSPDIF\n");
-#endif
- if (get_user(val, p))
- return -EFAULT;
-
- /* Check to make sure the codec supports S/PDIF transmitter */
-
- if((state->card->ac97_features & 4)) {
- /* mask out the transmitter speed bits so the user can't set them */
- val &= ~0x3000;
-
- /* Add the current transmitter speed bits to the passed value */
- ret = i810_ac97_get(codec, AC97_SPDIF_CONTROL);
- val |= (ret & 0x3000);
-
- i810_ac97_set(codec, AC97_SPDIF_CONTROL, val);
- if(i810_ac97_get(codec, AC97_SPDIF_CONTROL) != val ) {
- printk(KERN_ERR "i810_audio: Unable to set S/PDIF configuration to 0x%04x.\n", val);
- return -EFAULT;
- }
- }
-#ifdef DEBUG
- else
- printk(KERN_WARNING "i810_audio: S/PDIF transmitter not avalible.\n");
-#endif
- return put_user(val, p);
-
- case SNDCTL_DSP_GETSPDIF: /* Get S/PDIF Control register */
-#ifdef DEBUG
- printk("SNDCTL_DSP_GETSPDIF\n");
-#endif
- if (get_user(val, p))
- return -EFAULT;
-
- /* Check to make sure the codec supports S/PDIF transmitter */
-
- if(!(state->card->ac97_features & 4)) {
-#ifdef DEBUG
- printk(KERN_WARNING "i810_audio: S/PDIF transmitter not avalible.\n");
-#endif
- val = 0;
- } else {
- val = i810_ac97_get(codec, AC97_SPDIF_CONTROL);
- }
- //return put_user((val & 0xcfff), p);
- return put_user(val, p);
-
- case SNDCTL_DSP_GETCHANNELMASK:
-#ifdef DEBUG
- printk("SNDCTL_DSP_GETCHANNELMASK\n");
-#endif
- if (get_user(val, p))
- return -EFAULT;
-
- /* Based on AC'97 DAC support, not ICH hardware */
- val = DSP_BIND_FRONT;
- if ( state->card->ac97_features & 0x0004 )
- val |= DSP_BIND_SPDIF;
-
- if ( state->card->ac97_features & 0x0080 )
- val |= DSP_BIND_SURR;
- if ( state->card->ac97_features & 0x0140 )
- val |= DSP_BIND_CENTER_LFE;
-
- return put_user(val, p);
-
- case SNDCTL_DSP_BIND_CHANNEL:
-#ifdef DEBUG
- printk("SNDCTL_DSP_BIND_CHANNEL\n");
-#endif
- if (get_user(val, p))
- return -EFAULT;
- if ( val == DSP_BIND_QUERY ) {
- val = DSP_BIND_FRONT; /* Always report this as being enabled */
- if ( state->card->ac97_status & SPDIF_ON )
- val |= DSP_BIND_SPDIF;
- else {
- if ( state->card->ac97_status & SURR_ON )
- val |= DSP_BIND_SURR;
- if ( state->card->ac97_status & CENTER_LFE_ON )
- val |= DSP_BIND_CENTER_LFE;
- }
- } else { /* Not a query, set it */
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if ( dmabuf->enable == DAC_RUNNING ) {
- stop_dac(state);
- }
- if ( val & DSP_BIND_SPDIF ) { /* Turn on SPDIF */
- /* Ok, this should probably define what slots
- * to use. For now, we'll only set it to the
- * defaults:
- *
- * non multichannel codec maps to slots 3&4
- * 2 channel codec maps to slots 7&8
- * 4 channel codec maps to slots 6&9
- * 6 channel codec maps to slots 10&11
- *
- * there should be some way for the app to
- * select the slot assignment.
- */
-
- i810_set_spdif_output ( state, AC97_EA_SPSA_3_4, dmabuf->rate );
- if ( !(state->card->ac97_status & SPDIF_ON) )
- val &= ~DSP_BIND_SPDIF;
- } else {
- int mask;
- int channels;
-
- /* Turn off S/PDIF if it was on */
- if ( state->card->ac97_status & SPDIF_ON )
- i810_set_spdif_output ( state, -1, 0 );
-
- mask = val & (DSP_BIND_FRONT | DSP_BIND_SURR | DSP_BIND_CENTER_LFE);
- switch (mask) {
- case DSP_BIND_FRONT:
- channels = 2;
- break;
- case DSP_BIND_FRONT|DSP_BIND_SURR:
- channels = 4;
- break;
- case DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE:
- channels = 6;
- break;
- default:
- val = DSP_BIND_FRONT;
- channels = 2;
- break;
- }
- i810_set_dac_channels ( state, channels );
-
- /* check that they really got turned on */
- if (!(state->card->ac97_status & SURR_ON))
- val &= ~DSP_BIND_SURR;
- if (!(state->card->ac97_status & CENTER_LFE_ON))
- val &= ~DSP_BIND_CENTER_LFE;
- }
- }
- return put_user(val, p);
-
- case SNDCTL_DSP_MAPINBUF:
- case SNDCTL_DSP_MAPOUTBUF:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_WRITE_FILTER:
- case SOUND_PCM_READ_FILTER:
-#ifdef DEBUG
- printk("SNDCTL_* -EINVAL\n");
-#endif
- return -EINVAL;
- }
- return -EINVAL;
-}
-
-static int i810_open(struct inode *inode, struct file *file)
-{
- int i = 0;
- struct i810_card *card = devs;
- struct i810_state *state = NULL;
- struct dmabuf *dmabuf = NULL;
-
- /* find an avaiable virtual channel (instance of /dev/dsp) */
- while (card != NULL) {
- /*
- * If we are initializing and then fail, card could go
- * away unuexpectedly while we are in the for() loop.
- * So, check for card on each iteration before we check
- * for card->initializing to avoid a possible oops.
- * This usually only matters for times when the driver is
- * autoloaded by kmod.
- */
- for (i = 0; i < 50 && card && card->initializing; i++) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/20);
- }
- for (i = 0; i < NR_HW_CH && card && !card->initializing; i++) {
- if (card->states[i] == NULL) {
- state = card->states[i] = (struct i810_state *)
- kzalloc(sizeof(struct i810_state), GFP_KERNEL);
- if (state == NULL)
- return -ENOMEM;
- dmabuf = &state->dmabuf;
- goto found_virt;
- }
- }
- card = card->next;
- }
- /* no more virtual channel avaiable */
- if (!state)
- return -ENODEV;
-
-found_virt:
- /* initialize the virtual channel */
- state->virt = i;
- state->card = card;
- state->magic = I810_STATE_MAGIC;
- init_waitqueue_head(&dmabuf->wait);
- mutex_init(&state->open_mutex);
- file->private_data = state;
- dmabuf->trigger = 0;
-
- /* allocate hardware channels */
- if(file->f_mode & FMODE_READ) {
- if((dmabuf->read_channel = card->alloc_rec_pcm_channel(card)) == NULL) {
- kfree (card->states[i]);
- card->states[i] = NULL;
- return -EBUSY;
- }
- dmabuf->trigger |= PCM_ENABLE_INPUT;
- i810_set_adc_rate(state, 8000);
- }
- if(file->f_mode & FMODE_WRITE) {
- if((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) {
- /* make sure we free the record channel allocated above */
- if(file->f_mode & FMODE_READ)
- card->free_pcm_channel(card,dmabuf->read_channel->num);
- kfree (card->states[i]);
- card->states[i] = NULL;
- return -EBUSY;
- }
- /* Initialize to 8kHz? What if we don't support 8kHz? */
- /* Let's change this to check for S/PDIF stuff */
-
- dmabuf->trigger |= PCM_ENABLE_OUTPUT;
- if ( spdif_locked ) {
- i810_set_dac_rate(state, spdif_locked);
- i810_set_spdif_output(state, AC97_EA_SPSA_3_4, spdif_locked);
- } else {
- i810_set_dac_rate(state, 8000);
- /* Put the ACLink in 2 channel mode by default */
- i = I810_IOREADL(card, GLOB_CNT);
- I810_IOWRITEL(i & 0xffcfffff, card, GLOB_CNT);
- }
- }
-
- /* set default sample format. According to OSS Programmer's Guide /dev/dsp
- should be default to unsigned 8-bits, mono, with sample rate 8kHz and
- /dev/dspW will accept 16-bits sample, but we don't support those so we
- set it immediately to stereo and 16bit, which is all we do support */
- dmabuf->fmt |= I810_FMT_16BIT | I810_FMT_STEREO;
- dmabuf->ossfragsize = 0;
- dmabuf->ossmaxfrags = 0;
- dmabuf->subdivision = 0;
-
- state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-
- return nonseekable_open(inode, file);
-}
-
-static int i810_release(struct inode *inode, struct file *file)
-{
- struct i810_state *state = (struct i810_state *)file->private_data;
- struct i810_card *card = state->card;
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned long flags;
-
- lock_kernel();
-
- /* stop DMA state machine and free DMA buffers/channels */
- if(dmabuf->trigger & PCM_ENABLE_OUTPUT) {
- drain_dac(state, 0);
- }
- if(dmabuf->trigger & PCM_ENABLE_INPUT) {
- stop_adc(state);
- }
- spin_lock_irqsave(&card->lock, flags);
- dealloc_dmabuf(state);
- if (file->f_mode & FMODE_WRITE) {
- state->card->free_pcm_channel(state->card, dmabuf->write_channel->num);
- }
- if (file->f_mode & FMODE_READ) {
- state->card->free_pcm_channel(state->card, dmabuf->read_channel->num);
- }
-
- state->card->states[state->virt] = NULL;
- kfree(state);
- spin_unlock_irqrestore(&card->lock, flags);
- unlock_kernel();
-
- return 0;
-}
-
-static /*const*/ struct file_operations i810_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = i810_read,
- .write = i810_write,
- .poll = i810_poll,
- .ioctl = i810_ioctl,
- .mmap = i810_mmap,
- .open = i810_open,
- .release = i810_release,
-};
-
-/* Write AC97 codec registers */
-
-static u16 i810_ac97_get_mmio(struct ac97_codec *dev, u8 reg)
-{
- struct i810_card *card = dev->private_data;
- int count = 100;
- u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
-
- while(count-- && (readb(card->iobase_mmio + CAS) & 1))
- udelay(1);
-
-#ifdef DEBUG_MMIO
- {
- u16 ans = readw(card->ac97base_mmio + reg_set);
- printk(KERN_DEBUG "i810_audio: ac97_get_mmio(%d) -> 0x%04X\n", ((int) reg_set) & 0xffff, (u32) ans);
- return ans;
- }
-#else
- return readw(card->ac97base_mmio + reg_set);
-#endif
-}
-
-static u16 i810_ac97_get_io(struct ac97_codec *dev, u8 reg)
-{
- struct i810_card *card = dev->private_data;
- int count = 100;
- u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
-
- while(count-- && (I810_IOREADB(card, CAS) & 1))
- udelay(1);
-
- return inw(card->ac97base + reg_set);
-}
-
-static void i810_ac97_set_mmio(struct ac97_codec *dev, u8 reg, u16 data)
-{
- struct i810_card *card = dev->private_data;
- int count = 100;
- u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
-
- while(count-- && (readb(card->iobase_mmio + CAS) & 1))
- udelay(1);
-
- writew(data, card->ac97base_mmio + reg_set);
-
-#ifdef DEBUG_MMIO
- printk(KERN_DEBUG "i810_audio: ac97_set_mmio(0x%04X, %d)\n", (u32) data, ((int) reg_set) & 0xffff);
-#endif
-}
-
-static void i810_ac97_set_io(struct ac97_codec *dev, u8 reg, u16 data)
-{
- struct i810_card *card = dev->private_data;
- int count = 100;
- u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
-
- while(count-- && (I810_IOREADB(card, CAS) & 1))
- udelay(1);
-
- outw(data, card->ac97base + reg_set);
-}
-
-static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg)
-{
- struct i810_card *card = dev->private_data;
- u16 ret;
-
- spin_lock(&card->ac97_lock);
- if (card->use_mmio) {
- ret = i810_ac97_get_mmio(dev, reg);
- }
- else {
- ret = i810_ac97_get_io(dev, reg);
- }
- spin_unlock(&card->ac97_lock);
-
- return ret;
-}
-
-static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data)
-{
- struct i810_card *card = dev->private_data;
-
- spin_lock(&card->ac97_lock);
- if (card->use_mmio) {
- i810_ac97_set_mmio(dev, reg, data);
- }
- else {
- i810_ac97_set_io(dev, reg, data);
- }
- spin_unlock(&card->ac97_lock);
-}
-
-
-/* OSS /dev/mixer file operation methods */
-
-static int i810_open_mixdev(struct inode *inode, struct file *file)
-{
- int i;
- int minor = iminor(inode);
- struct i810_card *card = devs;
-
- for (card = devs; card != NULL; card = card->next) {
- /*
- * If we are initializing and then fail, card could go
- * away unuexpectedly while we are in the for() loop.
- * So, check for card on each iteration before we check
- * for card->initializing to avoid a possible oops.
- * This usually only matters for times when the driver is
- * autoloaded by kmod.
- */
- for (i = 0; i < 50 && card && card->initializing; i++) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/20);
- }
- for (i = 0; i < NR_AC97 && card && !card->initializing; i++)
- if (card->ac97_codec[i] != NULL &&
- card->ac97_codec[i]->dev_mixer == minor) {
- file->private_data = card->ac97_codec[i];
- return nonseekable_open(inode, file);
- }
- }
- return -ENODEV;
-}
-
-static int i810_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
-
- return codec->mixer_ioctl(codec, cmd, arg);
-}
-
-static /*const*/ struct file_operations i810_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = i810_ioctl_mixdev,
- .open = i810_open_mixdev,
-};
-
-/* AC97 codec initialisation. These small functions exist so we don't
- duplicate code between module init and apm resume */
-
-static inline int i810_ac97_exists(struct i810_card *card, int ac97_number)
-{
- u32 reg = I810_IOREADL(card, GLOB_STA);
- switch (ac97_number) {
- case 0:
- return reg & (1<<8);
- case 1:
- return reg & (1<<9);
- case 2:
- return reg & (1<<28);
- }
- return 0;
-}
-
-static inline int i810_ac97_enable_variable_rate(struct ac97_codec *codec)
-{
- i810_ac97_set(codec, AC97_EXTENDED_STATUS, 9);
- i810_ac97_set(codec,AC97_EXTENDED_STATUS,
- i810_ac97_get(codec, AC97_EXTENDED_STATUS)|0xE800);
-
- return (i810_ac97_get(codec, AC97_EXTENDED_STATUS)&1);
-}
-
-
-static int i810_ac97_probe_and_powerup(struct i810_card *card,struct ac97_codec *codec)
-{
- /* Returns 0 on failure */
- int i;
-
- if (ac97_probe_codec(codec) == 0) return 0;
-
- /* power it all up */
- i810_ac97_set(codec, AC97_POWER_CONTROL,
- i810_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00);
-
- /* wait for analog ready */
- for (i=100; i && ((i810_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); i--)
- {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/20);
- }
- return i;
-}
-
-static int is_new_ich(u16 pci_id)
-{
- switch (pci_id) {
- case PCI_DEVICE_ID_INTEL_82801DB_5:
- case PCI_DEVICE_ID_INTEL_82801EB_5:
- case PCI_DEVICE_ID_INTEL_ESB_5:
- case PCI_DEVICE_ID_INTEL_ICH6_18:
- return 1;
- default:
- break;
- }
-
- return 0;
-}
-
-static inline int ich_use_mmio(struct i810_card *card)
-{
- return is_new_ich(card->pci_id) && card->use_mmio;
-}
-
-/**
- * i810_ac97_power_up_bus - bring up AC97 link
- * @card : ICH audio device to power up
- *
- * Bring up the ACLink AC97 codec bus
- */
-
-static int i810_ac97_power_up_bus(struct i810_card *card)
-{
- u32 reg = I810_IOREADL(card, GLOB_CNT);
- int i;
- int primary_codec_id = 0;
-
- if((reg&2)==0) /* Cold required */
- reg|=2;
- else
- reg|=4; /* Warm */
-
- reg&=~8; /* ACLink on */
-
- /* At this point we deassert AC_RESET # */
- I810_IOWRITEL(reg , card, GLOB_CNT);
-
- /* We must now allow time for the Codec initialisation.
- 600mS is the specified time */
-
- for(i=0;i<10;i++)
- {
- if((I810_IOREADL(card, GLOB_CNT)&4)==0)
- break;
-
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/20);
- }
- if(i==10)
- {
- printk(KERN_ERR "i810_audio: AC'97 reset failed.\n");
- return 0;
- }
-
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/2);
-
- /*
- * See if the primary codec comes ready. This must happen
- * before we start doing DMA stuff
- */
- /* see i810_ac97_init for the next 10 lines (jsaw) */
- if (card->use_mmio)
- readw(card->ac97base_mmio);
- else
- inw(card->ac97base);
- if (ich_use_mmio(card)) {
- primary_codec_id = (int) readl(card->iobase_mmio + SDM) & 0x3;
- printk(KERN_INFO "i810_audio: Primary codec has ID %d\n",
- primary_codec_id);
- }
-
- if(! i810_ac97_exists(card, primary_codec_id))
- {
- printk(KERN_INFO "i810_audio: Codec not ready.. wait.. ");
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ); /* actually 600mS by the spec */
-
- if(i810_ac97_exists(card, primary_codec_id))
- printk("OK\n");
- else
- printk("no response.\n");
- }
- if (card->use_mmio)
- readw(card->ac97base_mmio);
- else
- inw(card->ac97base);
- return 1;
-}
-
-static int __devinit i810_ac97_init(struct i810_card *card)
-{
- int num_ac97 = 0;
- int ac97_id;
- int total_channels = 0;
- int nr_ac97_max = card_cap[card->pci_id_internal].nr_ac97;
- struct ac97_codec *codec;
- u16 eid;
- u32 reg;
-
- if(!i810_ac97_power_up_bus(card)) return 0;
-
- /* Number of channels supported */
- /* What about the codec? Just because the ICH supports */
- /* multiple channels doesn't mean the codec does. */
- /* we'll have to modify this in the codec section below */
- /* to reflect what the codec has. */
- /* ICH and ICH0 only support 2 channels so don't bother */
- /* to check.... */
-
- card->channels = 2;
- reg = I810_IOREADL(card, GLOB_STA);
- if ( reg & 0x0200000 )
- card->channels = 6;
- else if ( reg & 0x0100000 )
- card->channels = 4;
- printk(KERN_INFO "i810_audio: Audio Controller supports %d channels.\n", card->channels);
- printk(KERN_INFO "i810_audio: Defaulting to base 2 channel mode.\n");
- reg = I810_IOREADL(card, GLOB_CNT);
- I810_IOWRITEL(reg & 0xffcfffff, card, GLOB_CNT);
-
- for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++)
- card->ac97_codec[num_ac97] = NULL;
-
- /*@FIXME I don't know, if I'm playing to safe here... (jsaw) */
- if ((nr_ac97_max > 2) && !card->use_mmio) nr_ac97_max = 2;
-
- for (num_ac97 = 0; num_ac97 < nr_ac97_max; num_ac97++) {
- /* codec reset */
- printk(KERN_INFO "i810_audio: Resetting connection %d\n", num_ac97);
- if (card->use_mmio)
- readw(card->ac97base_mmio + 0x80*num_ac97);
- else
- inw(card->ac97base + 0x80*num_ac97);
-
- /* If we have the SDATA_IN Map Register, as on ICH4, we
- do not loop thru all possible codec IDs but thru all
- possible IO channels. Bit 0:1 of SDM then holds the
- last codec ID spoken to.
- */
- if (ich_use_mmio(card)) {
- ac97_id = (int) readl(card->iobase_mmio + SDM) & 0x3;
- printk(KERN_INFO "i810_audio: Connection %d with codec id %d\n",
- num_ac97, ac97_id);
- }
- else {
- ac97_id = num_ac97;
- }
-
- /* The ICH programmer's reference says you should */
- /* check the ready status before probing. So we chk */
- /* What do we do if it's not ready? Wait and try */
- /* again, or abort? */
- if (!i810_ac97_exists(card, ac97_id)) {
- if(num_ac97 == 0)
- printk(KERN_ERR "i810_audio: Primary codec not ready.\n");
- }
-
- if ((codec = ac97_alloc_codec()) == NULL)
- return -ENOMEM;
-
- /* initialize some basic codec information, other fields will be filled
- in ac97_probe_codec */
- codec->private_data = card;
- codec->id = ac97_id;
- card->ac97_id_map[ac97_id] = num_ac97 * 0x80;
-
- if (card->use_mmio) {
- codec->codec_read = i810_ac97_get_mmio;
- codec->codec_write = i810_ac97_set_mmio;
- }
- else {
- codec->codec_read = i810_ac97_get_io;
- codec->codec_write = i810_ac97_set_io;
- }
-
- if(!i810_ac97_probe_and_powerup(card,codec)) {
- printk(KERN_ERR "i810_audio: timed out waiting for codec %d analog ready.\n", ac97_id);
- ac97_release_codec(codec);
- break; /* it didn't work */
- }
- /* Store state information about S/PDIF transmitter */
- card->ac97_status = 0;
-
- /* Don't attempt to get eid until powerup is complete */
- eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
-
- if(eid==0xFFFF)
- {
- printk(KERN_WARNING "i810_audio: no codec attached ?\n");
- ac97_release_codec(codec);
- break;
- }
-
- /* Check for an AC97 1.0 soft modem (ID1) */
-
- if(codec->modem)
- {
- printk(KERN_WARNING "i810_audio: codec %d is a softmodem - skipping.\n", ac97_id);
- ac97_release_codec(codec);
- continue;
- }
-
- card->ac97_features = eid;
-
- /* Now check the codec for useful features to make up for
- the dumbness of the 810 hardware engine */
-
- if(!(eid&0x0001))
- printk(KERN_WARNING "i810_audio: only 48Khz playback available.\n");
- else
- {
- if(!i810_ac97_enable_variable_rate(codec)) {
- printk(KERN_WARNING "i810_audio: Codec refused to allow VRA, using 48Khz only.\n");
- card->ac97_features&=~1;
- }
- }
-
- /* Turn on the amplifier */
-
- codec->codec_write(codec, AC97_POWER_CONTROL,
- codec->codec_read(codec, AC97_POWER_CONTROL) & ~0x8000);
-
- /* Determine how many channels the codec(s) support */
- /* - The primary codec always supports 2 */
- /* - If the codec supports AMAP, surround DACs will */
- /* automaticlly get assigned to slots. */
- /* * Check for surround DACs and increment if */
- /* found. */
- /* - Else check if the codec is revision 2.2 */
- /* * If surround DACs exist, assign them to slots */
- /* and increment channel count. */
-
- /* All of this only applies to ICH2 and above. ICH */
- /* and ICH0 only support 2 channels. ICH2 will only */
- /* support multiple codecs in a "split audio" config. */
- /* as described above. */
-
- /* TODO: Remove all the debugging messages! */
-
- if((eid & 0xc000) == 0) /* primary codec */
- total_channels += 2;
-
- if(eid & 0x200) { /* GOOD, AMAP support */
- if (eid & 0x0080) /* L/R Surround channels */
- total_channels += 2;
- if (eid & 0x0140) /* LFE and Center channels */
- total_channels += 2;
- printk("i810_audio: AC'97 codec %d supports AMAP, total channels = %d\n", ac97_id, total_channels);
- } else if (eid & 0x0400) { /* this only works on 2.2 compliant codecs */
- eid &= 0xffcf;
- if((eid & 0xc000) != 0) {
- switch ( total_channels ) {
- case 2:
- /* Set dsa1, dsa0 to 01 */
- eid |= 0x0010;
- break;
- case 4:
- /* Set dsa1, dsa0 to 10 */
- eid |= 0x0020;
- break;
- case 6:
- /* Set dsa1, dsa0 to 11 */
- eid |= 0x0030;
- break;
- }
- total_channels += 2;
- }
- i810_ac97_set(codec, AC97_EXTENDED_ID, eid);
- eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
- printk("i810_audio: AC'97 codec %d, new EID value = 0x%04x\n", ac97_id, eid);
- if (eid & 0x0080) /* L/R Surround channels */
- total_channels += 2;
- if (eid & 0x0140) /* LFE and Center channels */
- total_channels += 2;
- printk("i810_audio: AC'97 codec %d, DAC map configured, total channels = %d\n", ac97_id, total_channels);
- } else {
- printk("i810_audio: AC'97 codec %d Unable to map surround DAC's (or DAC's not present), total channels = %d\n", ac97_id, total_channels);
- }
-
- if ((codec->dev_mixer = register_sound_mixer(&i810_mixer_fops, -1)) < 0) {
- printk(KERN_ERR "i810_audio: couldn't register mixer!\n");
- ac97_release_codec(codec);
- break;
- }
-
- card->ac97_codec[num_ac97] = codec;
- }
-
- /* tune up the primary codec */
- ac97_tune_hardware(card->pci_dev, ac97_quirks, ac97_quirk);
-
- /* pick the minimum of channels supported by ICHx or codec(s) */
- card->channels = (card->channels > total_channels)?total_channels:card->channels;
-
- return num_ac97;
-}
-
-static void __devinit i810_configure_clocking (void)
-{
- struct i810_card *card;
- struct i810_state *state;
- struct dmabuf *dmabuf;
- unsigned int i, offset, new_offset;
- unsigned long flags;
-
- card = devs;
- /* We could try to set the clocking for multiple cards, but can you even have
- * more than one i810 in a machine? Besides, clocking is global, so unless
- * someone actually thinks more than one i810 in a machine is possible and
- * decides to rewrite that little bit, setting the rate for more than one card
- * is a waste of time.
- */
- if(card != NULL) {
- state = card->states[0] = (struct i810_state *)
- kzalloc(sizeof(struct i810_state), GFP_KERNEL);
- if (state == NULL)
- return;
- dmabuf = &state->dmabuf;
-
- dmabuf->write_channel = card->alloc_pcm_channel(card);
- state->virt = 0;
- state->card = card;
- state->magic = I810_STATE_MAGIC;
- init_waitqueue_head(&dmabuf->wait);
- mutex_init(&state->open_mutex);
- dmabuf->fmt = I810_FMT_STEREO | I810_FMT_16BIT;
- dmabuf->trigger = PCM_ENABLE_OUTPUT;
- i810_set_spdif_output(state, -1, 0);
- i810_set_dac_channels(state, 2);
- i810_set_dac_rate(state, 48000);
- if(prog_dmabuf(state, 0) != 0) {
- goto config_out_nodmabuf;
- }
- if(dmabuf->dmasize < 16384) {
- goto config_out;
- }
- dmabuf->count = dmabuf->dmasize;
- CIV_TO_LVI(card, dmabuf->write_channel->port, -1);
- local_irq_save(flags);
- start_dac(state);
- offset = i810_get_dma_addr(state, 0);
- mdelay(50);
- new_offset = i810_get_dma_addr(state, 0);
- stop_dac(state);
- local_irq_restore(flags);
- i = new_offset - offset;
-#ifdef DEBUG_INTERRUPTS
- printk("i810_audio: %d bytes in 50 milliseconds\n", i);
-#endif
- if(i == 0)
- goto config_out;
- i = i / 4 * 20;
- if (i > 48500 || i < 47500) {
- clocking = clocking * clocking / i;
- printk("i810_audio: setting clocking to %d\n", clocking);
- }
-config_out:
- dealloc_dmabuf(state);
-config_out_nodmabuf:
- state->card->free_pcm_channel(state->card,state->dmabuf.write_channel->num);
- kfree(state);
- card->states[0] = NULL;
- }
-}
-
-/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered
- until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
-
-static int __devinit i810_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
-{
- struct i810_card *card;
-
- if (pci_enable_device(pci_dev))
- return -EIO;
-
- if (pci_set_dma_mask(pci_dev, I810_DMA_MASK)) {
- printk(KERN_ERR "i810_audio: architecture does not support"
- " 32bit PCI busmaster DMA\n");
- return -ENODEV;
- }
-
- if ((card = kzalloc(sizeof(struct i810_card), GFP_KERNEL)) == NULL) {
- printk(KERN_ERR "i810_audio: out of memory\n");
- return -ENOMEM;
- }
-
- card->initializing = 1;
- card->pci_dev = pci_dev;
- card->pci_id = pci_id->device;
- card->ac97base = pci_resource_start (pci_dev, 0);
- card->iobase = pci_resource_start (pci_dev, 1);
-
- if (!(card->ac97base) || !(card->iobase)) {
- card->ac97base = 0;
- card->iobase = 0;
- }
-
- /* if chipset could have mmio capability, check it */
- if (card_cap[pci_id->driver_data].flags & CAP_MMIO) {
- card->ac97base_mmio_phys = pci_resource_start (pci_dev, 2);
- card->iobase_mmio_phys = pci_resource_start (pci_dev, 3);
-
- if ((card->ac97base_mmio_phys) && (card->iobase_mmio_phys)) {
- card->use_mmio = 1;
- }
- else {
- card->ac97base_mmio_phys = 0;
- card->iobase_mmio_phys = 0;
- }
- }
-
- if (!(card->use_mmio) && (!(card->iobase) || !(card->ac97base))) {
- printk(KERN_ERR "i810_audio: No I/O resources available.\n");
- goto out_mem;
- }
-
- card->irq = pci_dev->irq;
- card->next = devs;
- card->magic = I810_CARD_MAGIC;
-#ifdef CONFIG_PM
- card->pm_suspended=0;
-#endif
- spin_lock_init(&card->lock);
- spin_lock_init(&card->ac97_lock);
- devs = card;
-
- pci_set_master(pci_dev);
-
- printk(KERN_INFO "i810: %s found at IO 0x%04lx and 0x%04lx, "
- "MEM 0x%04lx and 0x%04lx, IRQ %d\n",
- card_names[pci_id->driver_data],
- card->iobase, card->ac97base,
- card->ac97base_mmio_phys, card->iobase_mmio_phys,
- card->irq);
-
- card->alloc_pcm_channel = i810_alloc_pcm_channel;
- card->alloc_rec_pcm_channel = i810_alloc_rec_pcm_channel;
- card->alloc_rec_mic_channel = i810_alloc_rec_mic_channel;
- card->free_pcm_channel = i810_free_pcm_channel;
-
- if ((card->channel = pci_alloc_consistent(pci_dev,
- sizeof(struct i810_channel)*NR_HW_CH, &card->chandma)) == NULL) {
- printk(KERN_ERR "i810: cannot allocate channel DMA memory\n");
- goto out_mem;
- }
-
- { /* We may dispose of this altogether some time soon, so... */
- struct i810_channel *cp = card->channel;
-
- cp[0].offset = 0;
- cp[0].port = 0x00;
- cp[0].num = 0;
- cp[1].offset = 0;
- cp[1].port = 0x10;
- cp[1].num = 1;
- cp[2].offset = 0;
- cp[2].port = 0x20;
- cp[2].num = 2;
- }
-
- /* claim our iospace and irq */
- if (!request_region(card->iobase, 64, card_names[pci_id->driver_data])) {
- printk(KERN_ERR "i810_audio: unable to allocate region %lx\n", card->iobase);
- goto out_region1;
- }
- if (!request_region(card->ac97base, 256, card_names[pci_id->driver_data])) {
- printk(KERN_ERR "i810_audio: unable to allocate region %lx\n", card->ac97base);
- goto out_region2;
- }
-
- if (card->use_mmio) {
- if (request_mem_region(card->ac97base_mmio_phys, 512, "ich_audio MMBAR")) {
- if ((card->ac97base_mmio = ioremap(card->ac97base_mmio_phys, 512))) { /*@FIXME can ioremap fail? don't know (jsaw) */
- if (request_mem_region(card->iobase_mmio_phys, 256, "ich_audio MBBAR")) {
- if ((card->iobase_mmio = ioremap(card->iobase_mmio_phys, 256))) {
- printk(KERN_INFO "i810: %s mmio at 0x%04lx and 0x%04lx\n",
- card_names[pci_id->driver_data],
- (unsigned long) card->ac97base_mmio,
- (unsigned long) card->iobase_mmio);
- }
- else {
- iounmap(card->ac97base_mmio);
- release_mem_region(card->ac97base_mmio_phys, 512);
- release_mem_region(card->iobase_mmio_phys, 512);
- card->use_mmio = 0;
- }
- }
- else {
- iounmap(card->ac97base_mmio);
- release_mem_region(card->ac97base_mmio_phys, 512);
- card->use_mmio = 0;
- }
- }
- }
- else {
- card->use_mmio = 0;
- }
- }
-
- /* initialize AC97 codec and register /dev/mixer */
- if (i810_ac97_init(card) <= 0)
- goto out_iospace;
- pci_set_drvdata(pci_dev, card);
-
- if(clocking == 0) {
- clocking = 48000;
- i810_configure_clocking();
- }
-
- /* register /dev/dsp */
- if ((card->dev_audio = register_sound_dsp(&i810_audio_fops, -1)) < 0) {
- int i;
- printk(KERN_ERR "i810_audio: couldn't register DSP device!\n");
- for (i = 0; i < NR_AC97; i++)
- if (card->ac97_codec[i] != NULL) {
- unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
- ac97_release_codec(card->ac97_codec[i]);
- }
- goto out_iospace;
- }
-
- if (request_irq(card->irq, &i810_interrupt, IRQF_SHARED,
- card_names[pci_id->driver_data], card)) {
- printk(KERN_ERR "i810_audio: unable to allocate irq %d\n", card->irq);
- goto out_iospace;
- }
-
-
- card->initializing = 0;
- return 0;
-
-out_iospace:
- if (card->use_mmio) {
- iounmap(card->ac97base_mmio);
- iounmap(card->iobase_mmio);
- release_mem_region(card->ac97base_mmio_phys, 512);
- release_mem_region(card->iobase_mmio_phys, 256);
- }
- release_region(card->ac97base, 256);
-out_region2:
- release_region(card->iobase, 64);
-out_region1:
- pci_free_consistent(pci_dev, sizeof(struct i810_channel)*NR_HW_CH,
- card->channel, card->chandma);
-out_mem:
- kfree(card);
- return -ENODEV;
-}
-
-static void __devexit i810_remove(struct pci_dev *pci_dev)
-{
- int i;
- struct i810_card *card = pci_get_drvdata(pci_dev);
- /* free hardware resources */
- free_irq(card->irq, devs);
- release_region(card->iobase, 64);
- release_region(card->ac97base, 256);
- pci_free_consistent(pci_dev, sizeof(struct i810_channel)*NR_HW_CH,
- card->channel, card->chandma);
- if (card->use_mmio) {
- iounmap(card->ac97base_mmio);
- iounmap(card->iobase_mmio);
- release_mem_region(card->ac97base_mmio_phys, 512);
- release_mem_region(card->iobase_mmio_phys, 256);
- }
-
- /* unregister audio devices */
- for (i = 0; i < NR_AC97; i++)
- if (card->ac97_codec[i] != NULL) {
- unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
- ac97_release_codec(card->ac97_codec[i]);
- card->ac97_codec[i] = NULL;
- }
- unregister_sound_dsp(card->dev_audio);
- kfree(card);
-}
-
-#ifdef CONFIG_PM
-static int i810_pm_suspend(struct pci_dev *dev, pm_message_t pm_state)
-{
- struct i810_card *card = pci_get_drvdata(dev);
- struct i810_state *state;
- unsigned long flags;
- struct dmabuf *dmabuf;
- int i,num_ac97;
-#ifdef DEBUG
- printk("i810_audio: i810_pm_suspend called\n");
-#endif
- if(!card) return 0;
- spin_lock_irqsave(&card->lock, flags);
- card->pm_suspended=1;
- for(i=0;i<NR_HW_CH;i++) {
- state = card->states[i];
- if(!state) continue;
- /* this happens only if there are open files */
- dmabuf = &state->dmabuf;
- if(dmabuf->enable & DAC_RUNNING ||
- (dmabuf->count && (dmabuf->trigger & PCM_ENABLE_OUTPUT))) {
- state->pm_saved_dac_rate=dmabuf->rate;
- stop_dac(state);
- } else {
- state->pm_saved_dac_rate=0;
- }
- if(dmabuf->enable & ADC_RUNNING) {
- state->pm_saved_adc_rate=dmabuf->rate;
- stop_adc(state);
- } else {
- state->pm_saved_adc_rate=0;
- }
- dmabuf->ready = 0;
- dmabuf->swptr = dmabuf->hwptr = 0;
- dmabuf->count = dmabuf->total_bytes = 0;
- }
-
- spin_unlock_irqrestore(&card->lock, flags);
-
- /* save mixer settings */
- for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
- struct ac97_codec *codec = card->ac97_codec[num_ac97];
- if(!codec) continue;
- for(i=0;i< SOUND_MIXER_NRDEVICES ;i++) {
- if((supported_mixer(codec,i)) &&
- (codec->read_mixer)) {
- card->pm_saved_mixer_settings[i][num_ac97]=
- codec->read_mixer(codec,i);
- }
- }
- }
- pci_save_state(dev); /* XXX do we need this? */
- pci_disable_device(dev); /* disable busmastering */
- pci_set_power_state(dev,3); /* Zzz. */
-
- return 0;
-}
-
-
-static int i810_pm_resume(struct pci_dev *dev)
-{
- int num_ac97,i=0;
- struct i810_card *card=pci_get_drvdata(dev);
- pci_enable_device(dev);
- pci_restore_state (dev);
-
- /* observation of a toshiba portege 3440ct suggests that the
- hardware has to be more or less completely reinitialized from
- scratch after an apm suspend. Works For Me. -dan */
-
- i810_ac97_power_up_bus(card);
-
- for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
- struct ac97_codec *codec = card->ac97_codec[num_ac97];
- /* check they haven't stolen the hardware while we were
- away */
- if(!codec || !i810_ac97_exists(card,num_ac97)) {
- if(num_ac97) continue;
- else BUG();
- }
- if(!i810_ac97_probe_and_powerup(card,codec)) BUG();
-
- if((card->ac97_features&0x0001)) {
- /* at probe time we found we could do variable
- rates, but APM suspend has made it forget
- its magical powers */
- if(!i810_ac97_enable_variable_rate(codec)) BUG();
- }
- /* we lost our mixer settings, so restore them */
- for(i=0;i< SOUND_MIXER_NRDEVICES ;i++) {
- if(supported_mixer(codec,i)){
- int val=card->
- pm_saved_mixer_settings[i][num_ac97];
- codec->mixer_state[i]=val;
- codec->write_mixer(codec,i,
- (val & 0xff) ,
- ((val >> 8) & 0xff) );
- }
- }
- }
-
- /* we need to restore the sample rate from whatever it was */
- for(i=0;i<NR_HW_CH;i++) {
- struct i810_state * state=card->states[i];
- if(state) {
- if(state->pm_saved_adc_rate)
- i810_set_adc_rate(state,state->pm_saved_adc_rate);
- if(state->pm_saved_dac_rate)
- i810_set_dac_rate(state,state->pm_saved_dac_rate);
- }
- }
-
-
- card->pm_suspended = 0;
-
- /* any processes that were reading/writing during the suspend
- probably ended up here */
- for(i=0;i<NR_HW_CH;i++) {
- struct i810_state *state = card->states[i];
- if(state) wake_up(&state->dmabuf.wait);
- }
-
- return 0;
-}
-#endif /* CONFIG_PM */
-
-MODULE_AUTHOR("The Linux kernel team");
-MODULE_DESCRIPTION("Intel 810 audio support");
-MODULE_LICENSE("GPL");
-module_param(ftsodell, int, 0444);
-module_param(clocking, uint, 0444);
-module_param(strict_clocking, int, 0444);
-module_param(spdif_locked, int, 0444);
-
-#define I810_MODULE_NAME "i810_audio"
-
-static struct pci_driver i810_pci_driver = {
- .name = I810_MODULE_NAME,
- .id_table = i810_pci_tbl,
- .probe = i810_probe,
- .remove = __devexit_p(i810_remove),
-#ifdef CONFIG_PM
- .suspend = i810_pm_suspend,
- .resume = i810_pm_resume,
-#endif /* CONFIG_PM */
-};
-
-
-static int __init i810_init_module (void)
-{
- int retval;
-
- printk(KERN_INFO "Intel 810 + AC97 Audio, version "
- DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
-
- retval = pci_register_driver(&i810_pci_driver);
- if (retval)
- return retval;
-
- if(ftsodell != 0) {
- printk("i810_audio: ftsodell is now a deprecated option.\n");
- }
- if(spdif_locked > 0 ) {
- if(spdif_locked == 32000 || spdif_locked == 44100 || spdif_locked == 48000) {
- printk("i810_audio: Enabling S/PDIF at sample rate %dHz.\n", spdif_locked);
- } else {
- printk("i810_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
- spdif_locked = 0;
- }
- }
-
- return 0;
-}
-
-static void __exit i810_cleanup_module (void)
-{
- pci_unregister_driver(&i810_pci_driver);
-}
-
-module_init(i810_init_module);
-module_exit(i810_cleanup_module);
-
-/*
-Local Variables:
-c-basic-offset: 8
-End:
-*/
diff --git a/sound/oss/kahlua.c b/sound/oss/kahlua.c
index dfe670f12e6..12be1fb512d 100644
--- a/sound/oss/kahlua.c
+++ b/sound/oss/kahlua.c
@@ -1,7 +1,7 @@
/*
* Initialisation code for Cyrix/NatSemi VSA1 softaudio
*
- * (C) Copyright 2003 Red Hat Inc <alan@redhat.com>
+ * (C) Copyright 2003 Red Hat Inc <alan@lxorguk.ukuu.org.uk>
*
* XpressAudio(tm) is used on the Cyrix MediaGX (now NatSemi Geode) systems.
* The older version (VSA1) provides fairly good soundblaster emulation
@@ -31,6 +31,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/slab.h>
#include "sound_config.h"
@@ -42,7 +43,7 @@
* not real hardware.
*/
-static u8 __devinit mixer_read(unsigned long io, u8 reg)
+static u8 mixer_read(unsigned long io, u8 reg)
{
outb(reg, io + 4);
udelay(20);
@@ -51,7 +52,7 @@ static u8 __devinit mixer_read(unsigned long io, u8 reg)
return reg;
}
-static int __devinit probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct address_info *hw_config;
unsigned long base;
@@ -67,7 +68,7 @@ static int __devinit probe_one(struct pci_dev *pdev, const struct pci_device_id
return 1;
mem = ioremap(base, 128);
- if(mem == 0UL)
+ if (!mem)
return 1;
map = readw(mem + 0x18); /* Read the SMI enables */
iounmap(mem);
@@ -177,16 +178,14 @@ static int __devinit probe_one(struct pci_dev *pdev, const struct pci_device_id
return 0;
err_out_free:
- pci_set_drvdata(pdev, NULL);
kfree(hw_config);
return 1;
}
-static void __devexit remove_one(struct pci_dev *pdev)
+static void remove_one(struct pci_dev *pdev)
{
struct address_info *hw_config = pci_get_drvdata(pdev);
sb_dsp_unload(hw_config, 0);
- pci_set_drvdata(pdev, NULL);
kfree(hw_config);
}
@@ -198,8 +197,8 @@ MODULE_LICENSE("GPL");
* 5530 only. The 5510/5520 decode is different.
*/
-static struct pci_device_id id_tbl[] = {
- { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+static DEFINE_PCI_DEVICE_TABLE(id_tbl) = {
+ { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO), 0 },
{ }
};
@@ -209,7 +208,7 @@ static struct pci_driver kahlua_driver = {
.name = "kahlua",
.id_table = id_tbl,
.probe = probe_one,
- .remove = __devexit_p(remove_one),
+ .remove = remove_one,
};
@@ -219,7 +218,7 @@ static int __init kahlua_init_module(void)
return pci_register_driver(&kahlua_driver);
}
-static void __devexit kahlua_cleanup_module(void)
+static void kahlua_cleanup_module(void)
{
pci_unregister_driver(&kahlua_driver);
}
diff --git a/sound/oss/midi_synth.c b/sound/oss/midi_synth.c
index 9e450988ed3..2292c230d7e 100644
--- a/sound/oss/midi_synth.c
+++ b/sound/oss/midi_synth.c
@@ -426,7 +426,7 @@ midi_synth_open(int dev, int mode)
int err;
struct midi_input_info *inc;
- if (orig_dev < 0 || orig_dev > num_midis || midi_devs[orig_dev] == NULL)
+ if (orig_dev < 0 || orig_dev >= num_midis || midi_devs[orig_dev] == NULL)
return -ENXIO;
midi2synth[orig_dev] = dev;
@@ -476,7 +476,7 @@ EXPORT_SYMBOL(midi_synth_hw_control);
int
midi_synth_load_patch(int dev, int format, const char __user *addr,
- int offs, int count, int pmgr_flag)
+ int count, int pmgr_flag)
{
int orig_dev = synth_devs[dev]->midi_dev;
@@ -491,39 +491,37 @@ midi_synth_load_patch(int dev, int format, const char __user *addr,
if (!prefix_cmd(orig_dev, 0xf0))
return 0;
+ /* Invalid patch format */
if (format != SYSEX_PATCH)
- {
-/* printk("MIDI Error: Invalid patch format (key) 0x%x\n", format);*/
return -EINVAL;
- }
+
+ /* Patch header too short */
if (count < hdr_size)
- {
-/* printk("MIDI Error: Patch header too short\n");*/
return -EINVAL;
- }
+
count -= hdr_size;
/*
- * Copy the header from user space but ignore the first bytes which have
- * been transferred already.
+ * Copy the header from user space
*/
- if(copy_from_user(&((char *) &sysex)[offs], &(addr)[offs], hdr_size - offs))
+ if (copy_from_user(&sysex, addr, hdr_size))
return -EFAULT;
-
- if (count < sysex.len)
- {
-/* printk(KERN_WARNING "MIDI Warning: Sysex record too short (%d<%d)\n", count, (int) sysex.len);*/
+
+ /* Sysex record too short */
+ if ((unsigned)count < (unsigned)sysex.len)
sysex.len = count;
- }
- left = sysex.len;
- src_offs = 0;
+
+ left = sysex.len;
+ src_offs = 0;
for (i = 0; i < left && !signal_pending(current); i++)
{
unsigned char data;
- get_user(*(unsigned char *) &data, (unsigned char __user *) &((addr)[hdr_size + i]));
+ if (get_user(data,
+ (unsigned char __user *)(addr + hdr_size + i)))
+ return -EFAULT;
eox_seen = (i > 0 && data & 0x80); /* End of sysex */
diff --git a/sound/oss/midi_synth.h b/sound/oss/midi_synth.h
index 6bc9d00bc77..b64ddd6c4ab 100644
--- a/sound/oss/midi_synth.h
+++ b/sound/oss/midi_synth.h
@@ -8,7 +8,7 @@ int midi_synth_open (int dev, int mode);
void midi_synth_close (int dev);
void midi_synth_hw_control (int dev, unsigned char *event);
int midi_synth_load_patch (int dev, int format, const char __user * addr,
- int offs, int count, int pmgr_flag);
+ int count, int pmgr_flag);
void midi_synth_panning (int dev, int channel, int pressure);
void midi_synth_aftertouch (int dev, int channel, int pressure);
void midi_synth_controller (int dev, int channel, int ctrl_num, int value);
diff --git a/sound/oss/midibuf.c b/sound/oss/midibuf.c
index a40be0cf1d9..8f45cd99996 100644
--- a/sound/oss/midibuf.c
+++ b/sound/oss/midibuf.c
@@ -86,9 +86,8 @@ static void drain_midi_queue(int dev)
*/
if (midi_devs[dev]->buffer_status != NULL)
- while (!signal_pending(current) && midi_devs[dev]->buffer_status(dev))
- interruptible_sleep_on_timeout(&midi_sleeper[dev],
- HZ/10);
+ wait_event_interruptible_timeout(midi_sleeper[dev],
+ !midi_devs[dev]->buffer_status(dev), HZ/10);
}
static void midi_input_intr(int dev, unsigned char data)
@@ -127,15 +126,16 @@ static void midi_poll(unsigned long dummy)
for (dev = 0; dev < num_midis; dev++)
if (midi_devs[dev] != NULL && midi_out_buf[dev] != NULL)
{
- int ok = 1;
-
- while (DATA_AVAIL(midi_out_buf[dev]) && ok)
+ while (DATA_AVAIL(midi_out_buf[dev]))
{
+ int ok;
int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head];
spin_unlock_irqrestore(&lock,flags);/* Give some time to others */
ok = midi_devs[dev]->outputc(dev, c);
spin_lock_irqsave(&lock, flags);
+ if (!ok)
+ break;
midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE;
midi_out_buf[dev]->len--;
}
@@ -177,7 +177,7 @@ int MIDIbuf_open(int dev, struct file *file)
return err;
parms[dev].prech_timeout = MAX_SCHEDULE_TIMEOUT;
- midi_in_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf));
+ midi_in_buf[dev] = vmalloc(sizeof(struct midi_buf));
if (midi_in_buf[dev] == NULL)
{
@@ -187,7 +187,7 @@ int MIDIbuf_open(int dev, struct file *file)
}
midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
- midi_out_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf));
+ midi_out_buf[dev] = vmalloc(sizeof(struct midi_buf));
if (midi_out_buf[dev] == NULL)
{
@@ -232,8 +232,8 @@ void MIDIbuf_release(int dev, struct file *file)
* devices
*/
- while (!signal_pending(current) && DATA_AVAIL(midi_out_buf[dev]))
- interruptible_sleep_on(&midi_sleeper[dev]);
+ wait_event_interruptible(midi_sleeper[dev],
+ !DATA_AVAIL(midi_out_buf[dev]));
/*
* Sync
*/
@@ -281,8 +281,8 @@ int MIDIbuf_write(int dev, struct file *file, const char __user *buf, int count)
goto out;
}
- interruptible_sleep_on(&midi_sleeper[dev]);
- if (signal_pending(current))
+ if (wait_event_interruptible(midi_sleeper[dev],
+ SPACE_AVAIL(midi_out_buf[dev])))
{
c = -EINTR;
goto out;
@@ -294,7 +294,7 @@ int MIDIbuf_write(int dev, struct file *file, const char __user *buf, int count)
for (i = 0; i < n; i++)
{
- /* BROKE BROKE BROKE - CANT DO THIS WITH CLI !! */
+ /* BROKE BROKE BROKE - CAN'T DO THIS WITH CLI !! */
/* yes, think the same, so I removed the cli() brackets
QUEUE_BYTE is protected against interrupts */
if (copy_from_user((char *) &tmp_data, &(buf)[c], 1)) {
@@ -324,8 +324,9 @@ int MIDIbuf_read(int dev, struct file *file, char __user *buf, int count)
c = -EAGAIN;
goto out;
}
- interruptible_sleep_on_timeout(&input_sleeper[dev],
- parms[dev].prech_timeout);
+ wait_event_interruptible_timeout(input_sleeper[dev],
+ DATA_AVAIL(midi_in_buf[dev]),
+ parms[dev].prech_timeout);
if (signal_pending(current))
c = -EINTR; /* The user is getting restless */
diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c
index a690ca57adb..3bbc3ec5be8 100644
--- a/sound/oss/mpu401.c
+++ b/sound/oss/mpu401.c
@@ -19,6 +19,7 @@
*/
#include <linux/module.h>
+#include <linux/slab.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
@@ -566,7 +567,6 @@ static int mpu401_out(int dev, unsigned char midi_byte)
static int mpu401_command(int dev, mpu_command_rec * cmd)
{
int i, timeout, ok;
- int ret = 0;
unsigned long flags;
struct mpu_config *devc;
@@ -643,7 +643,6 @@ retry:
}
}
}
- ret = 0;
cmd->data[0] = 0;
if (cmd->nr_returns)
@@ -665,7 +664,7 @@ retry:
}
}
spin_unlock_irqrestore(&devc->lock,flags);
- return ret;
+ return 0;
}
static int mpu_cmd(int dev, int cmd, int data)
@@ -770,7 +769,7 @@ static int mpu_synth_ioctl(int dev, unsigned int cmd, void __user *arg)
midi_dev = synth_devs[dev]->midi_dev;
- if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev] == NULL)
+ if (midi_dev < 0 || midi_dev >= num_midis || midi_devs[midi_dev] == NULL)
return -ENXIO;
devc = &dev_conf[midi_dev];
@@ -926,31 +925,21 @@ static struct midi_operations mpu401_midi_operations[MAX_MIDI_DEV];
static void mpu401_chk_version(int n, struct mpu_config *devc)
{
int tmp;
- unsigned long flags;
devc->version = devc->revision = 0;
- spin_lock_irqsave(&devc->lock,flags);
- if ((tmp = mpu_cmd(n, 0xAC, 0)) < 0)
- {
- spin_unlock_irqrestore(&devc->lock,flags);
+ tmp = mpu_cmd(n, 0xAC, 0);
+ if (tmp < 0)
return;
- }
if ((tmp & 0xf0) > 0x20) /* Why it's larger than 2.x ??? */
- {
- spin_unlock_irqrestore(&devc->lock,flags);
return;
- }
devc->version = tmp;
- if ((tmp = mpu_cmd(n, 0xAD, 0)) < 0)
- {
+ if ((tmp = mpu_cmd(n, 0xAD, 0)) < 0) {
devc->version = 0;
- spin_unlock_irqrestore(&devc->lock,flags);
return;
}
devc->revision = tmp;
- spin_unlock_irqrestore(&devc->lock,flags);
}
int attach_mpu401(struct address_info *hw_config, struct module *owner)
@@ -1015,7 +1004,7 @@ int attach_mpu401(struct address_info *hw_config, struct module *owner)
mpu401_chk_version(m, devc);
if (devc->version == 0)
mpu401_chk_version(m, devc);
- spin_unlock_irqrestore(&devc->lock,flags);
+ spin_unlock_irqrestore(&devc->lock, flags);
}
if (devc->version != 0)
@@ -1084,7 +1073,7 @@ int attach_mpu401(struct address_info *hw_config, struct module *owner)
sprintf(mpu_synth_info[m].name, "%s (MPU401)", hw_config->name);
else
sprintf(mpu_synth_info[m].name,
- "MPU-401 %d.%d%c Midi interface #%d",
+ "MPU-401 %d.%d%c MIDI #%d",
(int) (devc->version & 0xf0) >> 4,
devc->version & 0x0f,
revision_char,
diff --git a/sound/oss/msnd.c b/sound/oss/msnd.c
index ba38d620009..c0cc951ba97 100644
--- a/sound/oss/msnd.c
+++ b/sound/oss/msnd.c
@@ -20,13 +20,10 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Id: msnd.c,v 1.17 1999/03/21 16:50:09 andrewtv Exp $
- *
********************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/types.h>
#include <linux/delay.h>
@@ -102,7 +99,7 @@ void msnd_fifo_free(msnd_fifo *f)
int msnd_fifo_alloc(msnd_fifo *f, size_t n)
{
msnd_fifo_free(f);
- f->data = (char *)vmalloc(n);
+ f->data = vmalloc(n);
f->n = n;
f->tail = 0;
f->head = 0;
diff --git a/sound/oss/msnd.h b/sound/oss/msnd.h
index 05cf7865be5..c8be47ec2b7 100644
--- a/sound/oss/msnd.h
+++ b/sound/oss/msnd.h
@@ -24,8 +24,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Id: msnd.h,v 1.36 1999/03/21 17:05:42 andrewtv Exp $
- *
********************************************************************/
#ifndef __MSND_H
#define __MSND_H
@@ -213,7 +211,7 @@ typedef struct multisound_dev {
/* State variables */
enum { msndClassic, msndPinnacle } type;
- mode_t mode;
+ fmode_t mode;
unsigned long flags;
#define F_RESETTING 0
#define F_HAVEDIGITAL 1
@@ -233,8 +231,8 @@ typedef struct multisound_dev {
spinlock_t lock;
int nresets;
unsigned long recsrc;
- int left_levels[16];
- int right_levels[16];
+ int left_levels[32];
+ int right_levels[32];
int mixer_mod_count;
int calibrate_signal;
int play_sample_size, play_sample_rate, play_channels;
diff --git a/sound/oss/msnd_classic.h b/sound/oss/msnd_classic.h
index 7ffea5267f9..1a17dde2f65 100644
--- a/sound/oss/msnd_classic.h
+++ b/sound/oss/msnd_classic.h
@@ -24,8 +24,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Id: msnd_classic.h,v 1.10 1999/03/21 17:36:09 andrewtv Exp $
- *
********************************************************************/
#ifndef __MSND_CLASSIC_H
#define __MSND_CLASSIC_H
diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c
index f1f49ebf752..c23f9f95bfa 100644
--- a/sound/oss/msnd_pinnacle.c
+++ b/sound/oss/msnd_pinnacle.c
@@ -29,23 +29,18 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Id: msnd_pinnacle.c,v 1.8 2000/12/30 00:33:21 sycamore Exp $
- *
* 12-3-2000 Modified IO port validation Steve Sycamore
*
- *
- * $$$: msnd_pinnacle.c,v 1.75 1999/03/21 16:50:09 andrewtv $$$ $
- *
********************************************************************/
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/slab.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
+#include <linux/gfp.h>
#include <asm/irq.h>
#include <asm/io.h>
#include "sound_config.h"
@@ -84,6 +79,7 @@
dev.rec_sample_rate / \
dev.rec_channels)
+static DEFINE_MUTEX(msnd_pinnacle_mutex);
static multisound_dev_t dev;
#ifndef HAVE_DSPCODEH
@@ -644,31 +640,39 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg)
return -EINVAL;
}
-static int dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- int minor = iminor(inode);
+ int minor = iminor(file_inode(file));
+ int ret;
if (cmd == OSS_GETVERSION) {
int sound_version = SOUND_VERSION;
return put_user(sound_version, (int __user *)arg);
}
+ ret = -EINVAL;
+
+ mutex_lock(&msnd_pinnacle_mutex);
if (minor == dev.dsp_minor)
- return dsp_ioctl(file, cmd, arg);
+ ret = dsp_ioctl(file, cmd, arg);
else if (minor == dev.mixer_minor)
- return mixer_ioctl(cmd, arg);
+ ret = mixer_ioctl(cmd, arg);
+ mutex_unlock(&msnd_pinnacle_mutex);
- return -EINVAL;
+ return ret;
}
static void dsp_write_flush(void)
{
+ int timeout = get_play_delay_jiffies(dev.DAPF.len);
+
if (!(dev.mode & FMODE_WRITE) || !test_bit(F_WRITING, &dev.flags))
return;
set_bit(F_WRITEFLUSH, &dev.flags);
- interruptible_sleep_on_timeout(
- &dev.writeflush,
- get_play_delay_jiffies(dev.DAPF.len));
+ wait_event_interruptible_timeout(
+ dev.writeflush,
+ !test_bit(F_WRITEFLUSH, &dev.flags),
+ timeout);
clear_bit(F_WRITEFLUSH, &dev.flags);
if (!signal_pending(current)) {
current->state = TASK_INTERRUPTIBLE;
@@ -761,12 +765,15 @@ static int dev_open(struct inode *inode, struct file *file)
int minor = iminor(inode);
int err = 0;
+ mutex_lock(&msnd_pinnacle_mutex);
if (minor == dev.dsp_minor) {
if ((file->f_mode & FMODE_WRITE &&
test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) ||
(file->f_mode & FMODE_READ &&
- test_bit(F_AUDIO_READ_INUSE, &dev.flags)))
- return -EBUSY;
+ test_bit(F_AUDIO_READ_INUSE, &dev.flags))) {
+ err = -EBUSY;
+ goto out;
+ }
if ((err = dsp_open(file)) >= 0) {
dev.nresets = 0;
@@ -787,7 +794,8 @@ static int dev_open(struct inode *inode, struct file *file)
/* nothing */
} else
err = -EINVAL;
-
+out:
+ mutex_unlock(&msnd_pinnacle_mutex);
return err;
}
@@ -796,14 +804,14 @@ static int dev_release(struct inode *inode, struct file *file)
int minor = iminor(inode);
int err = 0;
- lock_kernel();
+ mutex_lock(&msnd_pinnacle_mutex);
if (minor == dev.dsp_minor)
err = dsp_release(file);
else if (minor == dev.mixer_minor) {
/* nothing */
} else
err = -EINVAL;
- unlock_kernel();
+ mutex_unlock(&msnd_pinnacle_mutex);
return err;
}
@@ -892,6 +900,7 @@ static int dsp_read(char __user *buf, size_t len)
{
int count = len;
char *page = (char *)__get_free_page(GFP_KERNEL);
+ int timeout = get_rec_delay_jiffies(DAR_BUFF_SIZE);
if (!page)
return -ENOMEM;
@@ -931,11 +940,11 @@ static int dsp_read(char __user *buf, size_t len)
if (count > 0) {
set_bit(F_READBLOCK, &dev.flags);
- if (!interruptible_sleep_on_timeout(
- &dev.readblock,
- get_rec_delay_jiffies(DAR_BUFF_SIZE)))
+ if (wait_event_interruptible_timeout(
+ dev.readblock,
+ test_bit(F_READBLOCK, &dev.flags),
+ timeout) <= 0)
clear_bit(F_READING, &dev.flags);
- clear_bit(F_READBLOCK, &dev.flags);
if (signal_pending(current)) {
free_page((unsigned long)page);
return -EINTR;
@@ -950,6 +959,7 @@ static int dsp_write(const char __user *buf, size_t len)
{
int count = len;
char *page = (char *)__get_free_page(GFP_KERNEL);
+ int timeout = get_play_delay_jiffies(DAP_BUFF_SIZE);
if (!page)
return -ENOMEM;
@@ -990,10 +1000,10 @@ static int dsp_write(const char __user *buf, size_t len)
if (count > 0) {
set_bit(F_WRITEBLOCK, &dev.flags);
- interruptible_sleep_on_timeout(
- &dev.writeblock,
- get_play_delay_jiffies(DAP_BUFF_SIZE));
- clear_bit(F_WRITEBLOCK, &dev.flags);
+ wait_event_interruptible_timeout(
+ dev.writeblock,
+ test_bit(F_WRITEBLOCK, &dev.flags),
+ timeout);
if (signal_pending(current)) {
free_page((unsigned long)page);
return -EINTR;
@@ -1007,7 +1017,7 @@ static int dsp_write(const char __user *buf, size_t len)
static ssize_t dev_read(struct file *file, char __user *buf, size_t count, loff_t *off)
{
- int minor = iminor(file->f_path.dentry->d_inode);
+ int minor = iminor(file_inode(file));
if (minor == dev.dsp_minor)
return dsp_read(buf, count);
else
@@ -1016,7 +1026,7 @@ static ssize_t dev_read(struct file *file, char __user *buf, size_t count, loff_
static ssize_t dev_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
{
- int minor = iminor(file->f_path.dentry->d_inode);
+ int minor = iminor(file_inode(file));
if (minor == dev.dsp_minor)
return dsp_write(buf, count);
else
@@ -1039,7 +1049,7 @@ static __inline__ void eval_dsp_msg(register WORD wMessage)
clear_bit(F_WRITING, &dev.flags);
}
- if (test_bit(F_WRITEBLOCK, &dev.flags))
+ if (test_and_clear_bit(F_WRITEBLOCK, &dev.flags))
wake_up_interruptible(&dev.writeblock);
break;
@@ -1050,7 +1060,7 @@ static __inline__ void eval_dsp_msg(register WORD wMessage)
pack_DARQ_to_DARF(dev.last_recbank);
- if (test_bit(F_READBLOCK, &dev.flags))
+ if (test_and_clear_bit(F_READBLOCK, &dev.flags))
wake_up_interruptible(&dev.readblock);
break;
@@ -1110,9 +1120,10 @@ static const struct file_operations dev_fileops = {
.owner = THIS_MODULE,
.read = dev_read,
.write = dev_write,
- .ioctl = dev_ioctl,
+ .unlocked_ioctl = dev_ioctl,
.open = dev_open,
.release = dev_release,
+ .llseek = noop_llseek,
};
static int reset_dsp(void)
@@ -1288,6 +1299,8 @@ static int __init calibrate_adc(WORD srate)
static int upload_dsp_code(void)
{
+ int ret = 0;
+
msnd_outb(HPBLKSEL_0, dev.io + HP_BLKS);
#ifndef HAVE_DSPCODEH
INITCODESIZE = mod_firmware_load(INITCODEFILE, &INITCODE);
@@ -1306,7 +1319,8 @@ static int upload_dsp_code(void)
memcpy_toio(dev.base, PERMCODE, PERMCODESIZE);
if (msnd_upload_host(&dev, INITCODE, INITCODESIZE) < 0) {
printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto out;
}
#ifdef HAVE_DSPCODEH
printk(KERN_INFO LOGNAME ": DSP firmware uploaded (resident)\n");
@@ -1314,12 +1328,13 @@ static int upload_dsp_code(void)
printk(KERN_INFO LOGNAME ": DSP firmware uploaded\n");
#endif
+out:
#ifndef HAVE_DSPCODEH
vfree(INITCODE);
vfree(PERMCODE);
#endif
- return 0;
+ return ret;
}
#ifdef MSND_CLASSIC
@@ -1396,9 +1411,13 @@ static int __init attach_multisound(void)
printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", dev.irq);
return err;
}
- request_region(dev.io, dev.numio, dev.name);
+ if (request_region(dev.io, dev.numio, dev.name) == NULL) {
+ free_irq(dev.irq, &dev);
+ return -EBUSY;
+ }
- if ((err = dsp_full_reset()) < 0) {
+ err = dsp_full_reset();
+ if (err < 0) {
release_region(dev.io, dev.numio);
free_irq(dev.irq, &dev);
return err;
@@ -1621,7 +1640,7 @@ static int ide_irq __initdata = 0;
static int joystick_io __initdata = 0;
/* If we have the digital daugherboard... */
-static int digital __initdata = 0;
+static bool digital __initdata = false;
#endif
static int fifosize __initdata = DEFFIFOSIZE;
@@ -1691,7 +1710,7 @@ static int joystick_io __initdata = CONFIG_MSNDPIN_JOYSTICK_IO;
#ifndef CONFIG_MSNDPIN_DIGITAL
# define CONFIG_MSNDPIN_DIGITAL 0
#endif
-static int digital __initdata = CONFIG_MSNDPIN_DIGITAL;
+static bool digital __initdata = CONFIG_MSNDPIN_DIGITAL;
#endif /* MSND_CLASSIC */
diff --git a/sound/oss/msnd_pinnacle.h b/sound/oss/msnd_pinnacle.h
index cce91148700..c18d66cbbe3 100644
--- a/sound/oss/msnd_pinnacle.h
+++ b/sound/oss/msnd_pinnacle.h
@@ -24,8 +24,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Id: msnd_pinnacle.h,v 1.11 1999/03/21 17:36:09 andrewtv Exp $
- *
********************************************************************/
#ifndef __MSND_PINNACLE_H
#define __MSND_PINNACLE_H
diff --git a/sound/oss/opl3.c b/sound/oss/opl3.c
index 7781c13c147..4709e592e2c 100644
--- a/sound/oss/opl3.c
+++ b/sound/oss/opl3.c
@@ -24,6 +24,7 @@
*/
#include <linux/init.h>
+#include <linux/slab.h>
#include <linux/module.h>
#include <linux/delay.h>
@@ -274,7 +275,6 @@ static int opl3_kill_note (int devno, int voice, int note, int velocity)
devc->v_alloc->map[voice] = 0;
map = &pv_map[devc->lv_map[voice]];
- DEB(printk("Kill note %d\n", voice));
if (map->voice_mode == 0)
return 0;
@@ -819,7 +819,7 @@ static void opl3_hw_control(int dev, unsigned char *event)
}
static int opl3_load_patch(int dev, int format, const char __user *addr,
- int offs, int count, int pmgr_flag)
+ int count, int pmgr_flag)
{
struct sbi_instrument ins;
@@ -829,11 +829,7 @@ static int opl3_load_patch(int dev, int format, const char __user *addr,
return -EINVAL;
}
- /*
- * What the fuck is going on here? We leave junk in the beginning
- * of ins and then check the field pretty close to that beginning?
- */
- if(copy_from_user(&((char *) &ins)[offs], addr + offs, sizeof(ins) - offs))
+ if (copy_from_user(&ins, addr, sizeof(ins)))
return -EFAULT;
if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR)
@@ -848,6 +844,10 @@ static int opl3_load_patch(int dev, int format, const char __user *addr,
static void opl3_panning(int dev, int voice, int value)
{
+
+ if (voice < 0 || voice >= devc->nr_voice)
+ return;
+
devc->voc[voice].panning = value;
}
@@ -872,8 +872,6 @@ static void opl3_aftertouch(int dev, int voice, int pressure)
map = &pv_map[devc->lv_map[voice]];
- DEB(printk("Aftertouch %d\n", voice));
-
if (map->voice_mode == 0)
return;
@@ -1065,8 +1063,15 @@ static int opl3_alloc_voice(int dev, int chn, int note, struct voice_alloc_info
static void opl3_setup_voice(int dev, int voice, int chn)
{
- struct channel_info *info =
- &synth_devs[dev]->chn_info[chn];
+ struct channel_info *info;
+
+ if (voice < 0 || voice >= devc->nr_voice)
+ return;
+
+ if (chn < 0 || chn > 15)
+ return;
+
+ info = &synth_devs[dev]->chn_info[chn];
opl3_set_instr(dev, voice, info->pgm_num);
@@ -1182,7 +1187,7 @@ static int opl3_init(int ioaddr, struct module *owner)
for (i = 0; i < 18; i++)
pv_map[i].ioaddr = devc->left_io;
- };
+ }
conf_printf2(devc->fm_info.name, ioaddr, 0, -1, -1);
for (i = 0; i < SBFM_MAXINSTR; i++)
diff --git a/sound/oss/os.h b/sound/oss/os.h
index a1a962d7f67..75ad0cd0c0a 100644
--- a/sound/oss/os.h
+++ b/sound/oss/os.h
@@ -16,7 +16,6 @@
#include <linux/slab.h>
#include <linux/ioport.h>
#include <asm/page.h>
-#include <asm/system.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
#include <linux/poll.h>
diff --git a/sound/oss/pas2.h b/sound/oss/pas2.h
index fa12c55f560..d19f757dbd7 100644
--- a/sound/oss/pas2.h
+++ b/sound/oss/pas2.h
@@ -15,3 +15,6 @@ int pas_init_mixer(void);
/* From pas_midi.c */
void pas_midi_init(void);
void pas_midi_interrupt(void);
+
+/* From pas2_mixer.c*/
+void mix_write(unsigned char data, int ioaddr);
diff --git a/sound/oss/pas2_card.c b/sound/oss/pas2_card.c
index 25f3a22c52e..b07954a7953 100644
--- a/sound/oss/pas2_card.c
+++ b/sound/oss/pas2_card.c
@@ -41,19 +41,19 @@ static int pas_irq;
static int pas_sb_base;
DEFINE_SPINLOCK(pas_lock);
#ifndef CONFIG_PAS_JOYSTICK
-static int joystick;
+static bool joystick;
#else
-static int joystick = 1;
+static bool joystick = 1;
#endif
#ifdef SYMPHONY_PAS
-static int symphony = 1;
+static bool symphony = 1;
#else
-static int symphony;
+static bool symphony;
#endif
#ifdef BROKEN_BUS_CLOCK
-static int broken_bus_clock = 1;
+static bool broken_bus_clock = 1;
#else
-static int broken_bus_clock;
+static bool broken_bus_clock;
#endif
static struct address_info cfg;
@@ -74,8 +74,6 @@ static char *pas_model_names[] = {
* to support other than the default base address
*/
-extern void mix_write(unsigned char data, int ioaddr);
-
unsigned char pas_read(int ioaddr)
{
return inb(ioaddr + pas_translate_code);
@@ -156,9 +154,7 @@ static int __init config_pas_hw(struct address_info *hw_config)
* 0x80
*/ , 0xB88);
- pas_write(0x80
- | joystick?0x40:0
- ,0xF388);
+ pas_write(0x80 | (joystick ? 0x40 : 0), 0xF388);
if (pas_irq < 0 || pas_irq > 15)
{
@@ -335,6 +331,11 @@ static void __init attach_pas_card(struct address_info *hw_config)
{
char temp[100];
+ if (pas_model < 0 ||
+ pas_model >= ARRAY_SIZE(pas_model_names)) {
+ printk(KERN_ERR "pas2 unrecognized model.\n");
+ return;
+ }
sprintf(temp,
"%s rev %d", pas_model_names[(int) pas_model],
pas_read(0x2789));
diff --git a/sound/oss/pas2_mixer.c b/sound/oss/pas2_mixer.c
index a0bcb85c390..50b5bd50124 100644
--- a/sound/oss/pas2_mixer.c
+++ b/sound/oss/pas2_mixer.c
@@ -21,10 +21,6 @@
#include "pas2.h"
-#ifndef DEB
-#define DEB(what) /* (what) */
-#endif
-
extern int pas_translate_code;
extern char pas_model;
extern int *pas_osp;
@@ -120,8 +116,6 @@ pas_mixer_set(int whichDev, unsigned int level)
{
int left, right, devmask, changed, i, mixer = 0;
- DEB(printk("static int pas_mixer_set(int whichDev = %d, unsigned int level = %X)\n", whichDev, level));
-
left = level & 0x7f;
right = (level & 0x7f00) >> 8;
@@ -207,8 +201,6 @@ pas_mixer_reset(void)
{
int foo;
- DEB(printk("pas2_mixer.c: void pas_mixer_reset(void)\n"));
-
for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++)
pas_mixer_set(foo, levels[foo]);
@@ -220,7 +212,6 @@ static int pas_mixer_ioctl(int dev, unsigned int cmd, void __user *arg)
int level,v ;
int __user *p = (int __user *)arg;
- DEB(printk("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
if (cmd == SOUND_MIXER_PRIVATE1) { /* Set loudness bit */
if (get_user(level, p))
return -EFAULT;
diff --git a/sound/oss/pas2_pcm.c b/sound/oss/pas2_pcm.c
index 36c3ea62086..474803b52f7 100644
--- a/sound/oss/pas2_pcm.c
+++ b/sound/oss/pas2_pcm.c
@@ -17,15 +17,11 @@
#include <linux/init.h>
#include <linux/spinlock.h>
-#include <asm/timex.h>
+#include <linux/timex.h>
#include "sound_config.h"
#include "pas2.h"
-#ifndef DEB
-#define DEB(WHAT)
-#endif
-
#define PAS_PCM_INTRBITS (0x08)
/*
* Sample buffer timer interrupt enable
@@ -63,13 +59,13 @@ static int pcm_set_speed(int arg)
if (pcm_channels & 2)
{
- foo = ((CLOCK_TICK_RATE / 2) + (arg / 2)) / arg;
- arg = ((CLOCK_TICK_RATE / 2) + (foo / 2)) / foo;
+ foo = ((PIT_TICK_RATE / 2) + (arg / 2)) / arg;
+ arg = ((PIT_TICK_RATE / 2) + (foo / 2)) / foo;
}
else
{
- foo = (CLOCK_TICK_RATE + (arg / 2)) / arg;
- arg = (CLOCK_TICK_RATE + (foo / 2)) / foo;
+ foo = (PIT_TICK_RATE + (arg / 2)) / arg;
+ arg = (PIT_TICK_RATE + (foo / 2)) / foo;
}
pcm_speed = arg;
@@ -156,8 +152,6 @@ static int pas_audio_ioctl(int dev, unsigned int cmd, void __user *arg)
int val, ret;
int __user *p = arg;
- DEB(printk("pas2_pcm.c: static int pas_audio_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
-
switch (cmd)
{
case SOUND_PCM_WRITE_RATE:
@@ -204,8 +198,6 @@ static int pas_audio_ioctl(int dev, unsigned int cmd, void __user *arg)
static void pas_audio_reset(int dev)
{
- DEB(printk("pas2_pcm.c: static void pas_audio_reset(void)\n"));
-
pas_write(pas_read(0xF8A) & ~0x40, 0xF8A); /* Disable PCM */
}
@@ -214,8 +206,6 @@ static int pas_audio_open(int dev, int mode)
int err;
unsigned long flags;
- DEB(printk("pas2_pcm.c: static int pas_audio_open(int mode = %X)\n", mode));
-
spin_lock_irqsave(&pas_lock, flags);
if (pcm_busy)
{
@@ -239,8 +229,6 @@ static void pas_audio_close(int dev)
{
unsigned long flags;
- DEB(printk("pas2_pcm.c: static void pas_audio_close(void)\n"));
-
spin_lock_irqsave(&pas_lock, flags);
pas_audio_reset(dev);
@@ -256,8 +244,6 @@ static void pas_audio_output_block(int dev, unsigned long buf, int count,
{
unsigned long flags, cnt;
- DEB(printk("pas2_pcm.c: static void pas_audio_output_block(char *buf = %P, int count = %X)\n", buf, count));
-
cnt = count;
if (audio_devs[dev]->dmap_out->dma > 3)
cnt >>= 1;
@@ -303,8 +289,6 @@ static void pas_audio_start_input(int dev, unsigned long buf, int count,
unsigned long flags;
int cnt;
- DEB(printk("pas2_pcm.c: static void pas_audio_start_input(char *buf = %P, int count = %X)\n", buf, count));
-
cnt = count;
if (audio_devs[dev]->dmap_out->dma > 3)
cnt >>= 1;
@@ -388,8 +372,6 @@ static struct audio_driver pas_audio_driver =
void __init pas_pcm_init(struct address_info *hw_config)
{
- DEB(printk("pas2_pcm.c: long pas_pcm_init()\n"));
-
pcm_bitsok = 8;
if (pas_read(0xEF8B) & 0x08)
pcm_bitsok |= 16;
diff --git a/sound/oss/pss.c b/sound/oss/pss.c
index ece428b2ba9..145e36b2cfd 100644
--- a/sound/oss/pss.c
+++ b/sound/oss/pss.c
@@ -46,7 +46,7 @@
* load the driver as it did in previous versions.
* 04-07-1999: Anthony Barbachan <barbcode@xmen.cis.fordham.edu>
* Added module parameter pss_firmware to allow the user to tell
- * the driver where the fireware file is located. The default
+ * the driver where the firmware file is located. The default
* setting is the previous hardcoded setting "/etc/sound/pss_synth".
* 00-03-03: Christoph Hellwig <chhellwig@infradead.org>
* Adapted to module_init/module_exit
@@ -117,9 +117,9 @@
/* If compiled into kernel, it enable or disable pss mixer */
#ifdef CONFIG_PSS_MIXER
-static int pss_mixer = 1;
+static bool pss_mixer = 1;
#else
-static int pss_mixer;
+static bool pss_mixer;
#endif
@@ -147,7 +147,7 @@ static DEFINE_SPINLOCK(lock);
static int pss_initialized;
static int nonstandard_microcode;
static int pss_cdrom_port = -1; /* Parameter for the PSS cdrom port */
-static int pss_enable_joystick; /* Parameter for enabling the joystick */
+static bool pss_enable_joystick; /* Parameter for enabling the joystick */
static coproc_operations pss_coproc_operations;
static void pss_write(pss_confdata *devc, int data)
@@ -232,14 +232,12 @@ static int set_irq(pss_confdata * devc, int dev, int irq)
return 1;
}
-static int set_io_base(pss_confdata * devc, int dev, int base)
+static void set_io_base(pss_confdata * devc, int dev, int base)
{
unsigned short tmp = inw(REG(dev)) & 0x003f;
unsigned short bits = (base & 0x0ffc) << 4;
outw(bits | tmp, REG(dev));
-
- return 1;
}
static int set_dma(pss_confdata * devc, int dev, int dma)
@@ -271,7 +269,7 @@ static int pss_reset_dsp(pss_confdata * devc)
unsigned long i, limit = jiffies + HZ/10;
outw(0x2000, REG(PSS_CONTROL));
- for (i = 0; i < 32768 && (limit-jiffies >= 0); i++)
+ for (i = 0; i < 32768 && time_after_eq(limit, jiffies); i++)
inw(REG(PSS_CONTROL));
outw(0x0000, REG(PSS_CONTROL));
return 1;
@@ -361,7 +359,7 @@ static int pss_download_boot(pss_confdata * devc, unsigned char *block, int size
{
/*_____ Send the next byte */
outw (*block++, REG (PSS_DATA));
- };
+ }
count++;
}
@@ -371,11 +369,11 @@ static int pss_download_boot(pss_confdata * devc, unsigned char *block, int size
outw(0, REG(PSS_DATA));
limit = jiffies + HZ/10;
- for (i = 0; i < 32768 && (limit - jiffies >= 0); i++)
+ for (i = 0; i < 32768 && time_after_eq(limit, jiffies); i++)
val = inw(REG(PSS_STATUS));
limit = jiffies + HZ/10;
- for (i = 0; i < 32768 && (limit-jiffies >= 0); i++)
+ for (i = 0; i < 32768 && time_after_eq(limit, jiffies); i++)
{
val = inw(REG(PSS_STATUS));
if (val & 0x4000)
@@ -459,10 +457,9 @@ static void pss_mixer_reset(pss_confdata *devc)
}
}
-static int set_volume_mono(unsigned __user *p, int *aleft)
+static int set_volume_mono(unsigned __user *p, unsigned int *aleft)
{
- int left;
- unsigned volume;
+ unsigned int left, volume;
if (get_user(volume, p))
return -EFAULT;
@@ -473,10 +470,11 @@ static int set_volume_mono(unsigned __user *p, int *aleft)
return 0;
}
-static int set_volume_stereo(unsigned __user *p, int *aleft, int *aright)
+static int set_volume_stereo(unsigned __user *p,
+ unsigned int *aleft,
+ unsigned int *aright)
{
- int left, right;
- unsigned volume;
+ unsigned int left, right, volume;
if (get_user(volume, p))
return -EFAULT;
@@ -673,20 +671,13 @@ static void configure_nonsound_components(void)
/* Configure CDROM port */
- if(pss_cdrom_port == -1) /* If cdrom port enablation wasn't requested */
- {
+ if (pss_cdrom_port == -1) { /* If cdrom port enablation wasn't requested */
printk(KERN_INFO "PSS: CDROM port not enabled.\n");
- }
- else if(check_region(pss_cdrom_port, 2))
- {
+ } else if (!request_region(pss_cdrom_port, 2, "PSS CDROM")) {
+ pss_cdrom_port = -1;
printk(KERN_ERR "PSS: CDROM I/O port conflict.\n");
- }
- else if(!set_io_base(devc, CONF_CDROM, pss_cdrom_port))
- {
- printk(KERN_ERR "PSS: CDROM I/O port could not be set.\n");
- }
- else /* CDROM port successfully configured */
- {
+ } else {
+ set_io_base(devc, CONF_CDROM, pss_cdrom_port);
printk(KERN_INFO "PSS: CDROM I/O port set to 0x%x.\n", pss_cdrom_port);
}
}
@@ -758,10 +749,7 @@ static int __init probe_pss_mpu(struct address_info *hw_config)
printk(KERN_ERR "PSS: MPU I/O port conflict\n");
return 0;
}
- if (!set_io_base(devc, CONF_MIDI, hw_config->io_base)) {
- printk(KERN_ERR "PSS: MIDI base could not be set.\n");
- goto fail;
- }
+ set_io_base(devc, CONF_MIDI, hw_config->io_base);
if (!set_irq(devc, CONF_MIDI, hw_config->irq)) {
printk(KERN_ERR "PSS: MIDI IRQ allocation error.\n");
goto fail;
@@ -872,7 +860,7 @@ static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg,
return 0;
case SNDCTL_COPR_LOAD:
- buf = (copr_buffer *) vmalloc(sizeof(copr_buffer));
+ buf = vmalloc(sizeof(copr_buffer));
if (buf == NULL)
return -ENOSPC;
if (copy_from_user(buf, arg, sizeof(copr_buffer))) {
@@ -884,7 +872,7 @@ static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg,
return err;
case SNDCTL_COPR_SENDMSG:
- mbuf = (copr_msg *)vmalloc(sizeof(copr_msg));
+ mbuf = vmalloc(sizeof(copr_msg));
if (mbuf == NULL)
return -ENOSPC;
if (copy_from_user(mbuf, arg, sizeof(copr_msg))) {
@@ -908,7 +896,7 @@ static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg,
case SNDCTL_COPR_RCVMSG:
err = 0;
- mbuf = (copr_msg *)vmalloc(sizeof(copr_msg));
+ mbuf = vmalloc(sizeof(copr_msg));
if (mbuf == NULL)
return -ENOSPC;
data = (unsigned short *)mbuf->data;
@@ -1057,10 +1045,7 @@ static int __init probe_pss_mss(struct address_info *hw_config)
release_region(hw_config->io_base, 4);
return 0;
}
- if (!set_io_base(devc, CONF_WSS, hw_config->io_base)) {
- printk("PSS: WSS base not settable.\n");
- goto fail;
- }
+ set_io_base(devc, CONF_WSS, hw_config->io_base);
if (!set_irq(devc, CONF_WSS, hw_config->irq)) {
printk("PSS: WSS IRQ allocation error.\n");
goto fail;
@@ -1148,8 +1133,8 @@ static int mss_irq __initdata = -1;
static int mss_dma __initdata = -1;
static int mpu_io __initdata = -1;
static int mpu_irq __initdata = -1;
-static int pss_no_sound = 0; /* Just configure non-sound components */
-static int pss_keep_settings = 1; /* Keep hardware settings at module exit */
+static bool pss_no_sound = 0; /* Just configure non-sound components */
+static bool pss_keep_settings = 1; /* Keep hardware settings at module exit */
static char *pss_firmware = "/etc/sound/pss_synth";
module_param(pss_io, int, 0);
@@ -1248,7 +1233,8 @@ static void __exit cleanup_pss(void)
if(pssmpu)
unload_pss_mpu(&cfg_mpu);
unload_pss(&cfg);
- }
+ } else if (pss_cdrom_port != -1)
+ release_region(pss_cdrom_port, 2);
if(!pss_keep_settings) /* Keep hardware settings if asked */
{
diff --git a/sound/oss/sb_audio.c b/sound/oss/sb_audio.c
index 733b014ec7d..048439a1600 100644
--- a/sound/oss/sb_audio.c
+++ b/sound/oss/sb_audio.c
@@ -442,7 +442,7 @@ static int sb201_audio_set_speed(int dev, int speed)
{
sb_devc *devc = audio_devs[dev]->devc;
int tmp;
- int s = speed * devc->channels;
+ int s;
if (speed > 0)
{
@@ -452,6 +452,7 @@ static int sb201_audio_set_speed(int dev, int speed)
speed = 44100;
if (devc->opened & OPEN_READ && speed > 15000)
speed = 15000;
+ s = speed * devc->channels;
devc->tconst = (256 - ((1000000 + s / 2) / s)) & 0xff;
tmp = 256 - devc->tconst;
speed = ((1000000 + tmp / 2) / tmp) / devc->channels;
@@ -575,13 +576,15 @@ static int jazz16_audio_set_speed(int dev, int speed)
if (speed > 0)
{
int tmp;
- int s = speed * devc->channels;
+ int s;
if (speed < 5000)
speed = 5000;
if (speed > 44100)
speed = 44100;
+ s = speed * devc->channels;
+
devc->tconst = (256 - ((1000000 + s / 2) / s)) & 0xff;
tmp = 256 - devc->tconst;
diff --git a/sound/oss/sb_card.c b/sound/oss/sb_card.c
index 7de18b58f2c..fb5d7250de3 100644
--- a/sound/oss/sb_card.c
+++ b/sound/oss/sb_card.c
@@ -1,7 +1,7 @@
/*
* sound/oss/sb_card.c
*
- * Detection routine for the ISA Sound Blaster and compatable sound
+ * Detection routine for the ISA Sound Blaster and compatible sound
* cards.
*
* This file is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
@@ -24,6 +24,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/slab.h>
#include <linux/init.h>
#include "sound_config.h"
#include "sb_mixer.h"
diff --git a/sound/oss/sb_common.c b/sound/oss/sb_common.c
index 07cbacf6382..3d50fb4236e 100644
--- a/sound/oss/sb_common.c
+++ b/sound/oss/sb_common.c
@@ -31,6 +31,7 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
+#include <linux/slab.h>
#include "sound_config.h"
#include "sound_firmware.h"
@@ -157,7 +158,7 @@ static void sb_intr (sb_devc *devc)
break;
default:
- /* printk(KERN_WARN "Sound Blaster: Unexpected interrupt\n"); */
+ /* printk(KERN_WARNING "Sound Blaster: Unexpected interrupt\n"); */
;
}
}
@@ -177,7 +178,7 @@ static void sb_intr (sb_devc *devc)
break;
default:
- /* printk(KERN_WARN "Sound Blaster: Unexpected interrupt\n"); */
+ /* printk(KERN_WARNING "Sound Blaster: Unexpected interrupt\n"); */
;
}
}
@@ -225,8 +226,6 @@ int sb_dsp_reset(sb_devc * devc)
{
int loopc;
- DEB(printk("Entered sb_dsp_reset()\n"));
-
if (devc->model == MDL_ESS) return ess_dsp_reset (devc);
/* This is only for non-ESS chips */
@@ -245,8 +244,6 @@ int sb_dsp_reset(sb_devc * devc)
return 0; /* Sorry */
}
- DEB(printk("sb_dsp_reset() OK\n"));
-
return 1;
}
@@ -625,13 +622,12 @@ int sb_dsp_detect(struct address_info *hw_config, int pci, int pciio, struct sb_
*/
- detected_devc = kmalloc(sizeof(sb_devc), GFP_KERNEL);
+ detected_devc = kmemdup(devc, sizeof(sb_devc), GFP_KERNEL);
if (detected_devc == NULL)
{
printk(KERN_ERR "sb: Can't allocate memory for device information\n");
return 0;
}
- memcpy(detected_devc, devc, sizeof(sb_devc));
MDB(printk(KERN_INFO "SB %d.%02d detected OK (%x)\n", devc->major, devc->minor, hw_config->io_base));
return 1;
}
@@ -1228,7 +1224,8 @@ int probe_sbmpu(struct address_info *hw_config, struct module *owner)
}
attach_mpu401(hw_config, owner);
if (last_sb->irq == -hw_config->irq)
- last_sb->midi_irq_cookie=(void *)hw_config->slots[1];
+ last_sb->midi_irq_cookie =
+ (void *)(long) hw_config->slots[1];
return 1;
}
#endif
diff --git a/sound/oss/sb_ess.c b/sound/oss/sb_ess.c
index 180e95c87e3..b47a69026f1 100644
--- a/sound/oss/sb_ess.c
+++ b/sound/oss/sb_ess.c
@@ -168,7 +168,7 @@
* corresponding playback levels, unless recmask says they aren't recorded. In
* the latter case the recording volumes are 0.
* Now recording levels of inputs can be controlled, by changing the playback
- * levels. Futhermore several devices can be recorded together (which is not
+ * levels. Furthermore several devices can be recorded together (which is not
* possible with the ES1688).
* Besides the separate recording level control for each input, the common
* recording level can also be controlled by RECLEV as described above.
@@ -782,7 +782,7 @@ printk(KERN_INFO "FKS: ess_handle_channel %s irq_mode=%d\n", channel, irq_mode);
break;
default:;
- /* printk(KERN_WARN "ESS: Unexpected interrupt\n"); */
+ /* printk(KERN_WARNING "ESS: Unexpected interrupt\n"); */
}
}
@@ -865,8 +865,6 @@ printk(KERN_INFO "FKS: ess_dsp_reset 1\n");
ess_show_mixerregs (devc);
#endif
- DEB(printk("Entered ess_dsp_reset()\n"));
-
outb(3, DSP_RESET); /* Reset FIFO too */
udelay(10);
@@ -881,8 +879,6 @@ ess_show_mixerregs (devc);
}
ess_extended (devc);
- DEB(printk("sb_dsp_reset() OK\n"));
-
#ifdef FKS_LOGGING
printk(KERN_INFO "FKS: dsp_reset 2\n");
ess_show_mixerregs (devc);
@@ -1104,15 +1100,15 @@ int ess_init(sb_devc * devc, struct address_info *hw_config)
default:
printk (KERN_ERR "Invalid esstype=%d specified\n", devc->sbmo.esstype);
return 0;
- };
+ }
if (submodel != -1) {
devc->submodel = submodel;
sprintf (modelname, "ES%d", devc->sbmo.esstype);
chip = modelname;
- };
+ }
if (chip == NULL && (ess_minor & 0x0f) < 8) {
chip = "ES688";
- };
+ }
#ifdef FKS_TEST
FKS_test (devc);
#endif
@@ -1122,7 +1118,7 @@ FKS_test (devc);
*/
if (chip == NULL && devc->sbmo.esstype == ESSTYPE_LIKE20) {
chip = "ES1688";
- };
+ }
if (chip == NULL) {
int type;
@@ -1150,8 +1146,8 @@ FKS_test (devc);
if ((type & 0x00ff) != ((type >> 8) & 0x00ff)) {
printk ("ess_init: Unrecognized %04x\n", type);
}
- };
- };
+ }
+ }
#if 0
/*
* this one failed:
@@ -1182,10 +1178,10 @@ FKS_test (devc);
chip = "ES1788";
devc->submodel = SUBMDL_ES1788;
}
- };
+ }
if (chip == NULL) {
chip = "ES1688";
- };
+ }
printk ( KERN_INFO "ESS chip %s %s%s\n"
, chip
@@ -1293,7 +1289,7 @@ printk(KERN_INFO "ess_set_dma_hw: dma8=%d,dma16=%d,dup=%d\n"
default:
printk(KERN_ERR "ESS1887: Invalid DMA16 %d\n", dma);
return 0;
- };
+ }
ess_chgmixer (devc, 0x78, 0x20, dma16_bits);
ess_chgmixer (devc, 0x7d, 0x07, dma_bits);
}
@@ -1544,7 +1540,7 @@ static int ess_has_rec_mixer (int submodel)
return 1;
default:
return 0;
- };
+ }
};
#ifdef FKS_LOGGING
@@ -1584,7 +1580,7 @@ printk(KERN_INFO "FKS: write mixer %x: %x\n", port, value);
udelay(20);
outb(((unsigned char) (value & 0xff)), MIXER_DATA);
udelay(20);
- };
+ }
spin_unlock_irqrestore(&devc->lock, flags);
}
@@ -1722,7 +1718,6 @@ printk (KERN_INFO "FKS: es_rec_set_recmask mask = %x\n", mask);
right = (value & 0x0000ff00) >> 8;
} else { /* Turn it off (3) */
left = 0;
- left = 0;
right = 0;
}
sb_common_mixer_set(devc, i + ES_REC_MIXER_RECDIFF, left, right);
@@ -1762,7 +1757,7 @@ int ess_mixer_reset (sb_devc * devc)
ess_chgmixer(devc, 0x7a, 0x18, 0x08);
ess_chgmixer(devc, 0x1c, 0x07, 0x07);
break;
- };
+ }
/*
* Call set_recmask for proper initialization
*/
diff --git a/sound/oss/sb_midi.c b/sound/oss/sb_midi.c
index 8b796704e11..f139028e85c 100644
--- a/sound/oss/sb_midi.c
+++ b/sound/oss/sb_midi.c
@@ -12,6 +12,7 @@
*/
#include <linux/spinlock.h>
+#include <linux/slab.h>
#include "sound_config.h"
diff --git a/sound/oss/sb_mixer.c b/sound/oss/sb_mixer.c
index fad1a4f25ad..acf7586aeb4 100644
--- a/sound/oss/sb_mixer.c
+++ b/sound/oss/sb_mixer.c
@@ -16,6 +16,8 @@
* Stanislav Voronyi <stas@esc.kharkov.com> : Support for AWE 3DSE device (Jun 7 1999)
*/
+#include <linux/slab.h>
+
#include "sound_config.h"
#define __SB_MIXER_C__
@@ -230,7 +232,7 @@ static int detect_mixer(sb_devc * devc)
return 1;
}
-static void change_bits(sb_devc * devc, unsigned char *regval, int dev, int chn, int newval)
+static void oss_change_bits(sb_devc *devc, unsigned char *regval, int dev, int chn, int newval)
{
unsigned char mask;
int shift;
@@ -282,7 +284,7 @@ int sb_common_mixer_set(sb_devc * devc, int dev, int left, int right)
return -EINVAL;
val = sb_getmixer(devc, regoffs);
- change_bits(devc, &val, dev, LEFT_CHN, left);
+ oss_change_bits(devc, &val, dev, LEFT_CHN, left);
if ((*devc->iomap)[dev][RIGHT_CHN].regno != regoffs) /*
* Change register
@@ -302,7 +304,7 @@ int sb_common_mixer_set(sb_devc * devc, int dev, int left, int right)
* Read the new one
*/
}
- change_bits(devc, &val, dev, RIGHT_CHN, right);
+ oss_change_bits(devc, &val, dev, RIGHT_CHN, right);
sb_setmixer(devc, regoffs, val);
@@ -408,7 +410,7 @@ static int set_recmask(sb_devc * devc, int mask)
case MDL_SMW:
if (devc->model == MDL_ESS && ess_set_recmask (devc, &devmask)) {
break;
- };
+ }
if (devmask != SOUND_MASK_MIC &&
devmask != SOUND_MASK_LINE &&
devmask != SOUND_MASK_CD)
@@ -664,7 +666,7 @@ static void sb_mixer_reset(sb_devc * devc)
if (devc->model != MDL_ESS || !ess_mixer_reset (devc)) {
set_recmask(devc, SOUND_MASK_MIC);
- };
+ }
}
int sb_mixer_init(sb_devc * devc, struct module *owner)
diff --git a/sound/oss/sequencer.c b/sound/oss/sequencer.c
index 5c215f787ca..c0eea1dfe90 100644
--- a/sound/oss/sequencer.c
+++ b/sound/oss/sequencer.c
@@ -19,6 +19,7 @@
#include "sound_config.h"
#include "midi_ctrl.h"
+#include "sleep.h"
static int sequencer_ok;
static struct sound_timer_operations *tmr;
@@ -100,8 +101,7 @@ int sequencer_read(int dev, struct file *file, char __user *buf, int count)
return -EAGAIN;
}
- interruptible_sleep_on_timeout(&midi_sleeper,
- pre_event_timeout);
+ oss_broken_sleep_on(&midi_sleeper, pre_event_timeout);
spin_lock_irqsave(&lock,flags);
if (!iqlen)
{
@@ -212,13 +212,10 @@ int sequencer_write(int dev, struct file *file, const char __user *buf, int coun
{
unsigned char event_rec[EV_SZ], ev_code;
int p = 0, c, ev_size;
- int err;
int mode = translate_mode(file);
dev = dev >> 4;
- DEB(printk("sequencer_write(dev=%d, count=%d)\n", dev, count));
-
if (mode == OPEN_READ)
return -EIO;
@@ -242,7 +239,7 @@ int sequencer_write(int dev, struct file *file, const char __user *buf, int coun
return -ENXIO;
fmt = (*(short *) &event_rec[0]) & 0xffff;
- err = synth_devs[dev]->load_patch(dev, fmt, buf, p + 4, c, 0);
+ err = synth_devs[dev]->load_patch(dev, fmt, buf + p, c, 0);
if (err < 0)
return err;
@@ -285,7 +282,7 @@ int sequencer_write(int dev, struct file *file, const char __user *buf, int coun
{
if (!midi_opened[event_rec[2]])
{
- int mode;
+ int err, mode;
int dev = event_rec[2];
if (dev >= max_mididev || midi_devs[dev]==NULL)
@@ -344,7 +341,7 @@ static int seq_queue(unsigned char *note, char nonblock)
/*
* Sleep until there is enough space on the queue
*/
- interruptible_sleep_on(&seq_sleeper);
+ oss_broken_sleep_on(&seq_sleeper, MAX_SCHEDULE_TIMEOUT);
}
if (qlen >= SEQ_MAX_QUEUE)
{
@@ -546,6 +543,9 @@ static void seq_chn_common_event(unsigned char *event_rec)
case MIDI_PGM_CHANGE:
if (seq_mode == SEQ_2)
{
+ if (chn > 15)
+ break;
+
synth_devs[dev]->chn_info[chn].pgm_num = p1;
if ((int) dev >= num_synths)
synth_devs[dev]->set_instr(dev, chn, p1);
@@ -597,6 +597,9 @@ static void seq_chn_common_event(unsigned char *event_rec)
case MIDI_PITCH_BEND:
if (seq_mode == SEQ_2)
{
+ if (chn > 15)
+ break;
+
synth_devs[dev]->chn_info[chn].bender_value = w14;
if ((int) dev < num_synths)
@@ -954,8 +957,6 @@ int sequencer_open(int dev, struct file *file)
dev = dev >> 4;
mode = translate_mode(file);
- DEB(printk("sequencer_open(dev=%d)\n", dev));
-
if (!sequencer_ok)
{
/* printk("Sound card: sequencer not initialized\n");*/
@@ -1117,8 +1118,7 @@ static void seq_drain_midi_queues(void)
*/
if (n)
- interruptible_sleep_on_timeout(&seq_sleeper,
- HZ/10);
+ oss_broken_sleep_on(&seq_sleeper, HZ/10);
}
}
@@ -1129,8 +1129,6 @@ void sequencer_release(int dev, struct file *file)
dev = dev >> 4;
- DEB(printk("sequencer_release(dev=%d)\n", dev));
-
/*
* Wait until the queue is empty (if we don't have nonblock)
*/
@@ -1140,8 +1138,7 @@ void sequencer_release(int dev, struct file *file)
while (!signal_pending(current) && qlen > 0)
{
seq_sync();
- interruptible_sleep_on_timeout(&seq_sleeper,
- 3*HZ);
+ oss_broken_sleep_on(&seq_sleeper, 3*HZ);
/* Extra delay */
}
}
@@ -1196,7 +1193,7 @@ static int seq_sync(void)
seq_startplay();
if (qlen > 0)
- interruptible_sleep_on_timeout(&seq_sleeper, HZ);
+ oss_broken_sleep_on(&seq_sleeper, HZ);
return qlen;
}
@@ -1219,7 +1216,7 @@ static void midi_outc(int dev, unsigned char data)
spin_lock_irqsave(&lock,flags);
while (n && !midi_devs[dev]->outputc(dev, data)) {
- interruptible_sleep_on_timeout(&seq_sleeper, HZ/25);
+ oss_broken_sleep_on(&seq_sleeper, HZ/25);
n--;
}
spin_unlock_irqrestore(&lock,flags);
@@ -1632,8 +1629,6 @@ unsigned long compute_finetune(unsigned long base_freq, int bend, int range,
}
semitones = bend / 100;
- if (semitones > 99)
- semitones = 99;
cents = bend % 100;
amount = (int) (semitone_tuning[semitones] * multiplier * cent_tuning[cents]) / 10000;
@@ -1649,13 +1644,13 @@ void sequencer_init(void)
{
if (sequencer_ok)
return;
- queue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * EV_SZ);
+ queue = vmalloc(SEQ_MAX_QUEUE * EV_SZ);
if (queue == NULL)
{
printk(KERN_ERR "sequencer: Can't allocate memory for sequencer output queue\n");
return;
}
- iqueue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * IEV_SZ);
+ iqueue = vmalloc(SEQ_MAX_QUEUE * IEV_SZ);
if (iqueue == NULL)
{
printk(KERN_ERR "sequencer: Can't allocate memory for sequencer input queue\n");
diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c
deleted file mode 100644
index b493660deb3..00000000000
--- a/sound/oss/sh_dac_audio.c
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * sound/oss/sh_dac_audio.c
- *
- * SH DAC based sound :(
- *
- * Copyright (C) 2004,2005 Andriy Skulysh
- *
- * 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/init.h>
-#include <linux/sched.h>
-#include <linux/linkage.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-#include <asm/delay.h>
-#include <asm/clock.h>
-#include <asm/cpu/dac.h>
-#include <asm/cpu/timer.h>
-#include <asm/machvec.h>
-#include <asm/hp6xx.h>
-#include <asm/hd64461.h>
-
-#define MODNAME "sh_dac_audio"
-
-#define TMU_TOCR_INIT 0x00
-
-#define TMU1_TCR_INIT 0x0020 /* Clock/4, rising edge; interrupt on */
-#define TMU1_TSTR_INIT 0x02 /* Bit to turn on TMU1 */
-
-#define BUFFER_SIZE 48000
-
-static int rate;
-static int empty;
-static char *data_buffer, *buffer_begin, *buffer_end;
-static int in_use, device_major;
-
-static void dac_audio_start_timer(void)
-{
- u8 tstr;
-
- tstr = ctrl_inb(TMU_TSTR);
- tstr |= TMU1_TSTR_INIT;
- ctrl_outb(tstr, TMU_TSTR);
-}
-
-static void dac_audio_stop_timer(void)
-{
- u8 tstr;
-
- tstr = ctrl_inb(TMU_TSTR);
- tstr &= ~TMU1_TSTR_INIT;
- ctrl_outb(tstr, TMU_TSTR);
-}
-
-static void dac_audio_reset(void)
-{
- dac_audio_stop_timer();
- buffer_begin = buffer_end = data_buffer;
- empty = 1;
-}
-
-static void dac_audio_sync(void)
-{
- while (!empty)
- schedule();
-}
-
-static void dac_audio_start(void)
-{
- if (mach_is_hp6xx()) {
- u16 v = inw(HD64461_GPADR);
- v &= ~HD64461_GPADR_SPEAKER;
- outw(v, HD64461_GPADR);
- }
-
- sh_dac_enable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
- ctrl_outw(TMU1_TCR_INIT, TMU1_TCR);
-}
-static void dac_audio_stop(void)
-{
- dac_audio_stop_timer();
-
- if (mach_is_hp6xx()) {
- u16 v = inw(HD64461_GPADR);
- v |= HD64461_GPADR_SPEAKER;
- outw(v, HD64461_GPADR);
- }
-
- sh_dac_output(0, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
- sh_dac_disable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
-}
-
-static void dac_audio_set_rate(void)
-{
- unsigned long interval;
- struct clk *clk;
-
- clk = clk_get(NULL, "module_clk");
- interval = (clk_get_rate(clk) / 4) / rate;
- clk_put(clk);
- ctrl_outl(interval, TMU1_TCOR);
- ctrl_outl(interval, TMU1_TCNT);
-}
-
-static int dac_audio_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int val;
-
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, (int *)arg);
-
- case SNDCTL_DSP_SYNC:
- dac_audio_sync();
- return 0;
-
- case SNDCTL_DSP_RESET:
- dac_audio_reset();
- return 0;
-
- case SNDCTL_DSP_GETFMTS:
- return put_user(AFMT_U8, (int *)arg);
-
- case SNDCTL_DSP_SETFMT:
- return put_user(AFMT_U8, (int *)arg);
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_GETCAPS:
- return 0;
-
- case SOUND_PCM_WRITE_RATE:
- val = *(int *)arg;
- if (val > 0) {
- rate = val;
- dac_audio_set_rate();
- }
- return put_user(rate, (int *)arg);
-
- case SNDCTL_DSP_STEREO:
- return put_user(0, (int *)arg);
-
- case SOUND_PCM_WRITE_CHANNELS:
- return put_user(1, (int *)arg);
-
- case SNDCTL_DSP_SETDUPLEX:
- return -EINVAL;
-
- case SNDCTL_DSP_PROFILE:
- return -EINVAL;
-
- case SNDCTL_DSP_GETBLKSIZE:
- return put_user(BUFFER_SIZE, (int *)arg);
-
- case SNDCTL_DSP_SETFRAGMENT:
- return 0;
-
- default:
- printk(KERN_ERR "sh_dac_audio: unimplemented ioctl=0x%x\n",
- cmd);
- return -EINVAL;
- }
- return -EINVAL;
-}
-
-static ssize_t dac_audio_write(struct file *file, const char *buf, size_t count,
- loff_t * ppos)
-{
- int free;
- int nbytes;
-
- if (count < 0)
- return -EINVAL;
-
- if (!count) {
- dac_audio_sync();
- return 0;
- }
-
- free = buffer_begin - buffer_end;
-
- if (free < 0)
- free += BUFFER_SIZE;
- if ((free == 0) && (empty))
- free = BUFFER_SIZE;
- if (count > free)
- count = free;
- if (buffer_begin > buffer_end) {
- if (copy_from_user((void *)buffer_end, buf, count))
- return -EFAULT;
-
- buffer_end += count;
- } else {
- nbytes = data_buffer + BUFFER_SIZE - buffer_end;
- if (nbytes > count) {
- if (copy_from_user((void *)buffer_end, buf, count))
- return -EFAULT;
- buffer_end += count;
- } else {
- if (copy_from_user((void *)buffer_end, buf, nbytes))
- return -EFAULT;
- if (copy_from_user
- ((void *)data_buffer, buf + nbytes, count - nbytes))
- return -EFAULT;
- buffer_end = data_buffer + count - nbytes;
- }
- }
-
- if (empty) {
- empty = 0;
- dac_audio_start_timer();
- }
-
- return count;
-}
-
-static ssize_t dac_audio_read(struct file *file, char *buf, size_t count,
- loff_t * ppos)
-{
- return -EINVAL;
-}
-
-static int dac_audio_open(struct inode *inode, struct file *file)
-{
- if (file->f_mode & FMODE_READ)
- return -ENODEV;
- if (in_use)
- return -EBUSY;
-
- in_use = 1;
-
- dac_audio_start();
-
- return 0;
-}
-
-static int dac_audio_release(struct inode *inode, struct file *file)
-{
- dac_audio_sync();
- dac_audio_stop();
- in_use = 0;
-
- return 0;
-}
-
-const struct file_operations dac_audio_fops = {
- .read = dac_audio_read,
- .write = dac_audio_write,
- .ioctl = dac_audio_ioctl,
- .open = dac_audio_open,
- .release = dac_audio_release,
-};
-
-static irqreturn_t timer1_interrupt(int irq, void *dev)
-{
- unsigned long timer_status;
-
- timer_status = ctrl_inw(TMU1_TCR);
- timer_status &= ~0x100;
- ctrl_outw(timer_status, TMU1_TCR);
-
- if (!empty) {
- sh_dac_output(*buffer_begin, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
- buffer_begin++;
-
- if (buffer_begin == data_buffer + BUFFER_SIZE)
- buffer_begin = data_buffer;
- if (buffer_begin == buffer_end) {
- empty = 1;
- dac_audio_stop_timer();
- }
- }
- return IRQ_HANDLED;
-}
-
-static int __init dac_audio_init(void)
-{
- int retval;
-
- if ((device_major = register_sound_dsp(&dac_audio_fops, -1)) < 0) {
- printk(KERN_ERR "Cannot register dsp device");
- return device_major;
- }
-
- in_use = 0;
-
- data_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
- if (data_buffer == NULL)
- return -ENOMEM;
-
- dac_audio_reset();
- rate = 8000;
- dac_audio_set_rate();
-
- retval =
- request_irq(TIMER1_IRQ, timer1_interrupt, IRQF_DISABLED, MODNAME, 0);
- if (retval < 0) {
- printk(KERN_ERR "sh_dac_audio: IRQ %d request failed\n",
- TIMER1_IRQ);
- return retval;
- }
-
- return 0;
-}
-
-static void __exit dac_audio_exit(void)
-{
- free_irq(TIMER1_IRQ, 0);
-
- unregister_sound_dsp(device_major);
- kfree((void *)data_buffer);
-}
-
-module_init(dac_audio_init);
-module_exit(dac_audio_exit);
-
-MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua");
-MODULE_DESCRIPTION("SH DAC sound driver");
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/sleep.h b/sound/oss/sleep.h
new file mode 100644
index 00000000000..a20fc925a5c
--- /dev/null
+++ b/sound/oss/sleep.h
@@ -0,0 +1,18 @@
+#include <linux/wait.h>
+
+/*
+ * Do not use. This is a replacement for the old
+ * "interruptible_sleep_on_timeout" function that has been
+ * deprecated for ages. All users should instead try to use
+ * wait_event_interruptible_timeout.
+ */
+
+static inline long
+oss_broken_sleep_on(wait_queue_head_t *q, long timeout)
+{
+ DEFINE_WAIT(wait);
+ prepare_to_wait(q, &wait, TASK_INTERRUPTIBLE);
+ timeout = schedule_timeout(timeout);
+ finish_wait(q, &wait);
+ return timeout;
+}
diff --git a/sound/oss/sound_config.h b/sound/oss/sound_config.h
index 1a00a321061..f2554ab78f5 100644
--- a/sound/oss/sound_config.h
+++ b/sound/oss/sound_config.h
@@ -110,31 +110,19 @@ struct channel_info {
#define OPEN_WRITE PCM_ENABLE_OUTPUT
#define OPEN_READWRITE (OPEN_READ|OPEN_WRITE)
-#if OPEN_READ == FMODE_READ && OPEN_WRITE == FMODE_WRITE
-
-static inline int translate_mode(struct file *file)
-{
- return file->f_mode;
-}
-
-#else
-
static inline int translate_mode(struct file *file)
{
- return ((file->f_mode & FMODE_READ) ? OPEN_READ : 0) |
- ((file->f_mode & FMODE_WRITE) ? OPEN_WRITE : 0);
+ if (OPEN_READ == (__force int)FMODE_READ &&
+ OPEN_WRITE == (__force int)FMODE_WRITE)
+ return (__force int)(file->f_mode & (FMODE_READ | FMODE_WRITE));
+ else
+ return ((file->f_mode & FMODE_READ) ? OPEN_READ : 0) |
+ ((file->f_mode & FMODE_WRITE) ? OPEN_WRITE : 0);
}
-#endif
-
-
#include "sound_calls.h"
#include "dev_table.h"
-#ifndef DEB
-#define DEB(x)
-#endif
-
#ifndef DDB
#define DDB(x) do {} while (0)
#endif
@@ -150,4 +138,6 @@ static inline int translate_mode(struct file *file)
#define TIMER_ARMED 121234
#define TIMER_NOT_ARMED 1
+#define MAX_MEM_BLOCKS 1024
+
#endif
diff --git a/sound/oss/sound_timer.c b/sound/oss/sound_timer.c
index f0f0c19fbff..8021c85f076 100644
--- a/sound/oss/sound_timer.c
+++ b/sound/oss/sound_timer.c
@@ -26,7 +26,7 @@ static unsigned long prev_event_time;
static volatile unsigned long usecs_per_tmr; /* Length of the current interval */
static struct sound_lowlev_timer *tmr;
-static spinlock_t lock;
+static DEFINE_SPINLOCK(lock);
static unsigned long tmr2ticks(int tmr_value)
{
@@ -320,7 +320,7 @@ void sound_timer_init(struct sound_lowlev_timer *t, char *name)
n = sound_alloc_timerdev();
if (n == -1)
n = 0; /* Overwrite the system timer */
- strcpy(sound_timer.info.name, name);
+ strlcpy(sound_timer.info.name, name, sizeof(sound_timer.info.name));
sound_timer_devs[n] = &sound_timer;
}
EXPORT_SYMBOL(sound_timer_init);
diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c
index a9c23b2502a..b70c7c8f9c5 100644
--- a/sound/oss/soundcard.c
+++ b/sound/oss/soundcard.c
@@ -36,12 +36,11 @@
#include <asm/dma.h>
#include <asm/io.h>
#include <linux/wait.h>
-#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/major.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/device.h>
@@ -56,7 +55,8 @@
/*
* Table for permanently allocated memory (used when unloading the module)
*/
-void * sound_mem_blocks[1024];
+void * sound_mem_blocks[MAX_MEM_BLOCKS];
+static DEFINE_MUTEX(soundcard_mutex);
int sound_nblocks = 0;
/* Persistent DMA buffers */
@@ -87,7 +87,7 @@ int *load_mixer_volumes(char *name, int *levels, int present)
int i, n;
for (i = 0; i < num_mixer_volumes; i++) {
- if (strcmp(name, mixer_vols[i].name) == 0) {
+ if (strncmp(name, mixer_vols[i].name, 32) == 0) {
if (present)
mixer_vols[i].num = i;
return mixer_vols[i].levels;
@@ -99,7 +99,7 @@ int *load_mixer_volumes(char *name, int *levels, int present)
}
n = num_mixer_volumes++;
- strcpy(mixer_vols[n].name, name);
+ strncpy(mixer_vols[n].name, name, 32);
if (present)
mixer_vols[n].num = n;
@@ -143,7 +143,7 @@ static int get_mixer_levels(void __user * arg)
static ssize_t sound_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
- int dev = iminor(file->f_path.dentry->d_inode);
+ int dev = iminor(file_inode(file));
int ret = -EINVAL;
/*
@@ -152,9 +152,8 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof
* big one anyway, we might as well bandage here..
*/
- lock_kernel();
+ mutex_lock(&soundcard_mutex);
- DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count));
switch (dev & 0x0f) {
case SND_DEV_DSP:
case SND_DEV_DSP16:
@@ -170,17 +169,16 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof
case SND_DEV_MIDIN:
ret = MIDIbuf_read(dev, file, buf, count);
}
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return ret;
}
static ssize_t sound_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
- int dev = iminor(file->f_path.dentry->d_inode);
+ int dev = iminor(file_inode(file));
int ret = -EINVAL;
- lock_kernel();
- DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count));
+ mutex_lock(&soundcard_mutex);
switch (dev & 0x0f) {
case SND_DEV_SEQ:
case SND_DEV_SEQ2:
@@ -197,7 +195,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou
ret = MIDIbuf_write(dev, file, buf, count);
break;
}
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return ret;
}
@@ -206,56 +204,56 @@ static int sound_open(struct inode *inode, struct file *file)
int dev = iminor(inode);
int retval;
- DEB(printk("sound_open(dev=%d)\n", dev));
if ((dev >= SND_NDEVS) || (dev < 0)) {
printk(KERN_ERR "Invalid minor device %d\n", dev);
return -ENXIO;
}
+ mutex_lock(&soundcard_mutex);
switch (dev & 0x0f) {
case SND_DEV_CTL:
dev >>= 4;
if (dev >= 0 && dev < MAX_MIXER_DEV && mixer_devs[dev] == NULL) {
request_module("mixer%d", dev);
}
+ retval = -ENXIO;
if (dev && (dev >= num_mixers || mixer_devs[dev] == NULL))
- return -ENXIO;
+ break;
if (!try_module_get(mixer_devs[dev]->owner))
- return -ENXIO;
+ break;
+
+ retval = 0;
break;
case SND_DEV_SEQ:
case SND_DEV_SEQ2:
- if ((retval = sequencer_open(dev, file)) < 0)
- return retval;
+ retval = sequencer_open(dev, file);
break;
case SND_DEV_MIDIN:
- if ((retval = MIDIbuf_open(dev, file)) < 0)
- return retval;
+ retval = MIDIbuf_open(dev, file);
break;
case SND_DEV_DSP:
case SND_DEV_DSP16:
case SND_DEV_AUDIO:
- if ((retval = audio_open(dev, file)) < 0)
- return retval;
+ retval = audio_open(dev, file);
break;
default:
printk(KERN_ERR "Invalid minor device %d\n", dev);
- return -ENXIO;
+ retval = -ENXIO;
}
- return 0;
+ mutex_unlock(&soundcard_mutex);
+ return retval;
}
static int sound_release(struct inode *inode, struct file *file)
{
int dev = iminor(inode);
- lock_kernel();
- DEB(printk("sound_release(dev=%d)\n", dev));
+ mutex_lock(&soundcard_mutex);
switch (dev & 0x0f) {
case SND_DEV_CTL:
module_put(mixer_devs[dev >> 4]->owner);
@@ -279,7 +277,7 @@ static int sound_release(struct inode *inode, struct file *file)
default:
printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev);
}
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return 0;
}
@@ -328,11 +326,11 @@ static int sound_mixer_ioctl(int mixdev, unsigned int cmd, void __user *arg)
return mixer_devs[mixdev]->ioctl(mixdev, cmd, arg);
}
-static int sound_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int len = 0, dtype;
- int dev = iminor(inode);
+ int dev = iminor(file_inode(file));
+ long ret = -EINVAL;
void __user *p = (void __user *)arg;
if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0) {
@@ -349,10 +347,10 @@ static int sound_ioctl(struct inode *inode, struct file *file,
if (!access_ok(VERIFY_WRITE, p, len))
return -EFAULT;
}
- DEB(printk("sound_ioctl(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
if (cmd == OSS_GETVERSION)
return __put_user(SOUND_VERSION, (int __user *)p);
+ mutex_lock(&soundcard_mutex);
if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */
(dev & 0x0f) != SND_DEV_CTL) {
dtype = dev & 0x0f;
@@ -360,45 +358,52 @@ static int sound_ioctl(struct inode *inode, struct file *file,
case SND_DEV_DSP:
case SND_DEV_DSP16:
case SND_DEV_AUDIO:
- return sound_mixer_ioctl(audio_devs[dev >> 4]->mixer_dev,
+ ret = sound_mixer_ioctl(audio_devs[dev >> 4]->mixer_dev,
cmd, p);
-
+ break;
default:
- return sound_mixer_ioctl(dev >> 4, cmd, p);
+ ret = sound_mixer_ioctl(dev >> 4, cmd, p);
+ break;
}
+ mutex_unlock(&soundcard_mutex);
+ return ret;
}
+
switch (dev & 0x0f) {
case SND_DEV_CTL:
if (cmd == SOUND_MIXER_GETLEVELS)
- return get_mixer_levels(p);
- if (cmd == SOUND_MIXER_SETLEVELS)
- return set_mixer_levels(p);
- return sound_mixer_ioctl(dev >> 4, cmd, p);
+ ret = get_mixer_levels(p);
+ else if (cmd == SOUND_MIXER_SETLEVELS)
+ ret = set_mixer_levels(p);
+ else
+ ret = sound_mixer_ioctl(dev >> 4, cmd, p);
+ break;
case SND_DEV_SEQ:
case SND_DEV_SEQ2:
- return sequencer_ioctl(dev, file, cmd, p);
+ ret = sequencer_ioctl(dev, file, cmd, p);
+ break;
case SND_DEV_DSP:
case SND_DEV_DSP16:
case SND_DEV_AUDIO:
- return audio_ioctl(dev, file, cmd, p);
+ ret = audio_ioctl(dev, file, cmd, p);
break;
case SND_DEV_MIDIN:
- return MIDIbuf_ioctl(dev, file, cmd, p);
+ ret = MIDIbuf_ioctl(dev, file, cmd, p);
break;
}
- return -EINVAL;
+ mutex_unlock(&soundcard_mutex);
+ return ret;
}
static unsigned int sound_poll(struct file *file, poll_table * wait)
{
- struct inode *inode = file->f_path.dentry->d_inode;
+ struct inode *inode = file_inode(file);
int dev = iminor(inode);
- DEB(printk("sound_poll(dev=%d)\n", dev));
switch (dev & 0x0f) {
case SND_DEV_SEQ:
case SND_DEV_SEQ2:
@@ -420,7 +425,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
int dev_class;
unsigned long size;
struct dma_buffparms *dmap = NULL;
- int dev = iminor(file->f_path.dentry->d_inode);
+ int dev = iminor(file_inode(file));
dev_class = dev & 0x0f;
dev >>= 4;
@@ -429,35 +434,35 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n");
return -EINVAL;
}
- lock_kernel();
+ mutex_lock(&soundcard_mutex);
if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */
dmap = audio_devs[dev]->dmap_out;
else if (vma->vm_flags & VM_READ)
dmap = audio_devs[dev]->dmap_in;
else {
printk(KERN_ERR "Sound: Undefined mmap() access\n");
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return -EINVAL;
}
if (dmap == NULL) {
printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n");
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return -EIO;
}
if (dmap->raw_buf == NULL) {
printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n");
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return -EIO;
}
if (dmap->mapping_flags) {
printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n");
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return -EIO;
}
if (vma->vm_pgoff != 0) {
printk(KERN_ERR "Sound: mmap() offset must be 0.\n");
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return -EINVAL;
}
size = vma->vm_end - vma->vm_start;
@@ -468,7 +473,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
if (remap_pfn_range(vma, vma->vm_start,
virt_to_phys(dmap->raw_buf) >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return -EAGAIN;
}
@@ -480,7 +485,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
memset(dmap->raw_buf,
dmap->neutral_byte,
dmap->bytes_in_use);
- unlock_kernel();
+ mutex_unlock(&soundcard_mutex);
return 0;
}
@@ -490,7 +495,7 @@ const struct file_operations oss_sound_fops = {
.read = sound_read,
.write = sound_write,
.poll = sound_poll,
- .ioctl = sound_ioctl,
+ .unlocked_ioctl = sound_ioctl,
.mmap = sound_mmap,
.open = sound_open,
.release = sound_release,
@@ -515,31 +520,21 @@ bad:
}
-/* These device names follow the official Linux device list,
- * Documentation/devices.txt. Let us know if there are other
- * common names we should support for compatibility.
- * Only those devices not created by the generic code in sound_core.c are
- * registered here.
- */
-static const struct {
- unsigned short minor;
- char *name;
- umode_t mode;
- int *num;
-} dev_list[] = { /* list of minor devices */
-/* seems to be some confusion here -- this device is not in the device list */
- {SND_DEV_DSP16, "dspW", S_IWUGO | S_IRUSR | S_IRGRP,
- &num_audiodevs},
- {SND_DEV_AUDIO, "audio", S_IWUGO | S_IRUSR | S_IRGRP,
- &num_audiodevs},
-};
-
static int dmabuf;
static int dmabug;
module_param(dmabuf, int, 0444);
module_param(dmabug, int, 0444);
+/* additional minors for compatibility */
+struct oss_minor_dev {
+ unsigned short minor;
+ unsigned int enabled;
+} dev_list[] = {
+ { SND_DEV_DSP16 },
+ { SND_DEV_AUDIO },
+};
+
static int __init oss_init(void)
{
int err;
@@ -560,20 +555,15 @@ static int __init oss_init(void)
sound_dmap_flag = (dmabuf > 0 ? 1 : 0);
for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
- device_create(sound_class, NULL,
- MKDEV(SOUND_MAJOR, dev_list[i].minor),
- "%s", dev_list[i].name);
-
- if (!dev_list[i].num)
- continue;
-
- for (j = 1; j < *dev_list[i].num; j++)
- device_create(sound_class, NULL,
- MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10)),
- "%s%d", dev_list[i].name, j);
+ j = 0;
+ do {
+ unsigned short minor = dev_list[i].minor + j * 0x10;
+ if (!register_sound_special(&oss_sound_fops, minor))
+ dev_list[i].enabled = (1 << j);
+ } while (++j < num_audiodevs);
}
- if (sound_nblocks >= 1024)
+ if (sound_nblocks >= MAX_MEM_BLOCKS - 1)
printk(KERN_ERR "Sound warning: Deallocation table was too small.\n");
return 0;
@@ -584,11 +574,11 @@ static void __exit oss_cleanup(void)
int i, j;
for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
- device_destroy(sound_class, MKDEV(SOUND_MAJOR, dev_list[i].minor));
- if (!dev_list[i].num)
- continue;
- for (j = 1; j < *dev_list[i].num; j++)
- device_destroy(sound_class, MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10)));
+ j = 0;
+ do {
+ if (dev_list[i].enabled & (1 << j))
+ unregister_sound_special(dev_list[i].minor);
+ } while (++j < num_audiodevs);
}
unregister_sound_special(1);
diff --git a/sound/oss/sscape.c b/sound/oss/sscape.c
deleted file mode 100644
index 30c36d1f35d..00000000000
--- a/sound/oss/sscape.c
+++ /dev/null
@@ -1,1480 +0,0 @@
-/*
- * sound/oss/sscape.c
- *
- * Low level driver for Ensoniq SoundScape
- *
- *
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- *
- *
- * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
- * Sergey Smitienko : ensoniq p'n'p support
- * Christoph Hellwig : adapted to module_init/module_exit
- * Bartlomiej Zolnierkiewicz : added __init to attach_sscape()
- * Chris Rankin : Specify that this module owns the coprocessor
- * Arnaldo C. de Melo : added missing restore_flags in sscape_pnp_upload_file
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include "sound_config.h"
-#include "sound_firmware.h"
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/ctype.h>
-#include <linux/stddef.h>
-#include <linux/kmod.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <linux/wait.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/proc_fs.h>
-#include <linux/mm.h>
-#include <linux/spinlock.h>
-
-#include "coproc.h"
-
-#include "ad1848.h"
-#include "mpu401.h"
-
-/*
- * I/O ports
- */
-#define MIDI_DATA 0
-#define MIDI_CTRL 1
-#define HOST_CTRL 2
-#define TX_READY 0x02
-#define RX_READY 0x01
-#define HOST_DATA 3
-#define ODIE_ADDR 4
-#define ODIE_DATA 5
-
-/*
- * Indirect registers
- */
-
-#define GA_INTSTAT_REG 0
-#define GA_INTENA_REG 1
-#define GA_DMAA_REG 2
-#define GA_DMAB_REG 3
-#define GA_INTCFG_REG 4
-#define GA_DMACFG_REG 5
-#define GA_CDCFG_REG 6
-#define GA_SMCFGA_REG 7
-#define GA_SMCFGB_REG 8
-#define GA_HMCTL_REG 9
-
-/*
- * DMA channel identifiers (A and B)
- */
-
-#define SSCAPE_DMA_A 0
-#define SSCAPE_DMA_B 1
-
-#define PORT(name) (devc->base+name)
-
-/*
- * Host commands recognized by the OBP microcode
- */
-
-#define CMD_GEN_HOST_ACK 0x80
-#define CMD_GEN_MPU_ACK 0x81
-#define CMD_GET_BOARD_TYPE 0x82
-#define CMD_SET_CONTROL 0x88 /* Old firmware only */
-#define CMD_GET_CONTROL 0x89 /* Old firmware only */
-#define CTL_MASTER_VOL 0
-#define CTL_MIC_MODE 2
-#define CTL_SYNTH_VOL 4
-#define CTL_WAVE_VOL 7
-#define CMD_SET_EXTMIDI 0x8a
-#define CMD_GET_EXTMIDI 0x8b
-#define CMD_SET_MT32 0x8c
-#define CMD_GET_MT32 0x8d
-
-#define CMD_ACK 0x80
-
-#define IC_ODIE 1
-#define IC_OPUS 2
-
-typedef struct sscape_info
-{
- int base, irq, dma;
-
- int codec, codec_irq; /* required to setup pnp cards*/
- int codec_type;
- int ic_type;
- char* raw_buf;
- unsigned long raw_buf_phys;
- int buffsize; /* -------------------------- */
- spinlock_t lock;
- int ok; /* Properly detected */
- int failed;
- int dma_allocated;
- int codec_audiodev;
- int opened;
- int *osp;
- int my_audiodev;
-} sscape_info;
-
-static struct sscape_info adev_info = {
- 0
-};
-
-static struct sscape_info *devc = &adev_info;
-static int sscape_mididev = -1;
-
-/* Some older cards have assigned interrupt bits differently than new ones */
-static char valid_interrupts_old[] = {
- 9, 7, 5, 15
-};
-
-static char valid_interrupts_new[] = {
- 9, 5, 7, 10
-};
-
-static char *valid_interrupts = valid_interrupts_new;
-
-/*
- * See the bottom of the driver. This can be set by spea =0/1.
- */
-
-#ifdef REVEAL_SPEA
-static char old_hardware = 1;
-#else
-static char old_hardware;
-#endif
-
-static void sleep(unsigned howlong)
-{
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(howlong);
-}
-
-static unsigned char sscape_read(struct sscape_info *devc, int reg)
-{
- unsigned long flags;
- unsigned char val;
-
- spin_lock_irqsave(&devc->lock,flags);
- outb(reg, PORT(ODIE_ADDR));
- val = inb(PORT(ODIE_DATA));
- spin_unlock_irqrestore(&devc->lock,flags);
- return val;
-}
-
-static void __sscape_write(int reg, int data)
-{
- outb(reg, PORT(ODIE_ADDR));
- outb(data, PORT(ODIE_DATA));
-}
-
-static void sscape_write(struct sscape_info *devc, int reg, int data)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&devc->lock,flags);
- __sscape_write(reg, data);
- spin_unlock_irqrestore(&devc->lock,flags);
-}
-
-static unsigned char sscape_pnp_read_codec(sscape_info* devc, unsigned char reg)
-{
- unsigned char res;
- unsigned long flags;
-
- spin_lock_irqsave(&devc->lock,flags);
- outb( reg, devc -> codec);
- res = inb (devc -> codec + 1);
- spin_unlock_irqrestore(&devc->lock,flags);
- return res;
-
-}
-
-static void sscape_pnp_write_codec(sscape_info* devc, unsigned char reg, unsigned char data)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&devc->lock,flags);
- outb( reg, devc -> codec);
- outb( data, devc -> codec + 1);
- spin_unlock_irqrestore(&devc->lock,flags);
-}
-
-static void host_open(struct sscape_info *devc)
-{
- outb((0x00), PORT(HOST_CTRL)); /* Put the board to the host mode */
-}
-
-static void host_close(struct sscape_info *devc)
-{
- outb((0x03), PORT(HOST_CTRL)); /* Put the board to the MIDI mode */
-}
-
-static int host_write(struct sscape_info *devc, unsigned char *data, int count)
-{
- unsigned long flags;
- int i, timeout_val;
-
- spin_lock_irqsave(&devc->lock,flags);
- /*
- * Send the command and data bytes
- */
-
- for (i = 0; i < count; i++)
- {
- for (timeout_val = 10000; timeout_val > 0; timeout_val--)
- if (inb(PORT(HOST_CTRL)) & TX_READY)
- break;
-
- if (timeout_val <= 0)
- {
- spin_unlock_irqrestore(&devc->lock,flags);
- return 0;
- }
- outb(data[i], PORT(HOST_DATA));
- }
- spin_unlock_irqrestore(&devc->lock,flags);
- return 1;
-}
-
-static int host_read(struct sscape_info *devc)
-{
- unsigned long flags;
- int timeout_val;
- unsigned char data;
-
- spin_lock_irqsave(&devc->lock,flags);
- /*
- * Read a byte
- */
-
- for (timeout_val = 10000; timeout_val > 0; timeout_val--)
- if (inb(PORT(HOST_CTRL)) & RX_READY)
- break;
-
- if (timeout_val <= 0)
- {
- spin_unlock_irqrestore(&devc->lock,flags);
- return -1;
- }
- data = inb(PORT(HOST_DATA));
- spin_unlock_irqrestore(&devc->lock,flags);
- return data;
-}
-
-#if 0 /* unused */
-static int host_command1(struct sscape_info *devc, int cmd)
-{
- unsigned char buf[10];
- buf[0] = (unsigned char) (cmd & 0xff);
- return host_write(devc, buf, 1);
-}
-#endif /* unused */
-
-
-static int host_command2(struct sscape_info *devc, int cmd, int parm1)
-{
- unsigned char buf[10];
-
- buf[0] = (unsigned char) (cmd & 0xff);
- buf[1] = (unsigned char) (parm1 & 0xff);
-
- return host_write(devc, buf, 2);
-}
-
-static int host_command3(struct sscape_info *devc, int cmd, int parm1, int parm2)
-{
- unsigned char buf[10];
-
- buf[0] = (unsigned char) (cmd & 0xff);
- buf[1] = (unsigned char) (parm1 & 0xff);
- buf[2] = (unsigned char) (parm2 & 0xff);
- return host_write(devc, buf, 3);
-}
-
-static void set_mt32(struct sscape_info *devc, int value)
-{
- host_open(devc);
- host_command2(devc, CMD_SET_MT32, value ? 1 : 0);
- if (host_read(devc) != CMD_ACK)
- {
- /* printk( "SNDSCAPE: Setting MT32 mode failed\n"); */
- }
- host_close(devc);
-}
-
-static void set_control(struct sscape_info *devc, int ctrl, int value)
-{
- host_open(devc);
- host_command3(devc, CMD_SET_CONTROL, ctrl, value);
- if (host_read(devc) != CMD_ACK)
- {
- /* printk( "SNDSCAPE: Setting control (%d) failed\n", ctrl); */
- }
- host_close(devc);
-}
-
-static void do_dma(struct sscape_info *devc, int dma_chan, unsigned long buf, int blk_size, int mode)
-{
- unsigned char temp;
-
- if (dma_chan != SSCAPE_DMA_A)
- {
- printk(KERN_WARNING "soundscape: Tried to use DMA channel != A. Why?\n");
- return;
- }
- audio_devs[devc->codec_audiodev]->flags &= ~DMA_AUTOMODE;
- DMAbuf_start_dma(devc->codec_audiodev, buf, blk_size, mode);
- audio_devs[devc->codec_audiodev]->flags |= DMA_AUTOMODE;
-
- temp = devc->dma << 4; /* Setup DMA channel select bits */
- if (devc->dma <= 3)
- temp |= 0x80; /* 8 bit DMA channel */
-
- temp |= 1; /* Trigger DMA */
- sscape_write(devc, GA_DMAA_REG, temp);
- temp &= 0xfe; /* Clear DMA trigger */
- sscape_write(devc, GA_DMAA_REG, temp);
-}
-
-static int verify_mpu(struct sscape_info *devc)
-{
- /*
- * The SoundScape board could be in three modes (MPU, 8250 and host).
- * If the card is not in the MPU mode, enabling the MPU driver will
- * cause infinite loop (the driver believes that there is always some
- * received data in the buffer.
- *
- * Detect this by looking if there are more than 10 received MIDI bytes
- * (0x00) in the buffer.
- */
-
- int i;
-
- for (i = 0; i < 10; i++)
- {
- if (inb(devc->base + HOST_CTRL) & 0x80)
- return 1;
-
- if (inb(devc->base) != 0x00)
- return 1;
- }
- printk(KERN_WARNING "SoundScape: The device is not in the MPU-401 mode\n");
- return 0;
-}
-
-static int sscape_coproc_open(void *dev_info, int sub_device)
-{
- if (sub_device == COPR_MIDI)
- {
- set_mt32(devc, 0);
- if (!verify_mpu(devc))
- return -EIO;
- }
- return 0;
-}
-
-static void sscape_coproc_close(void *dev_info, int sub_device)
-{
- struct sscape_info *devc = dev_info;
- unsigned long flags;
-
- spin_lock_irqsave(&devc->lock,flags);
- if (devc->dma_allocated)
- {
- __sscape_write(GA_DMAA_REG, 0x20); /* DMA channel disabled */
- devc->dma_allocated = 0;
- }
- spin_unlock_irqrestore(&devc->lock,flags);
- return;
-}
-
-static void sscape_coproc_reset(void *dev_info)
-{
-}
-
-static int sscape_download_boot(struct sscape_info *devc, unsigned char *block, int size, int flag)
-{
- unsigned long flags;
- unsigned char temp;
- volatile int done, timeout_val;
- static unsigned char codec_dma_bits;
-
- if (flag & CPF_FIRST)
- {
- /*
- * First block. Have to allocate DMA and to reset the board
- * before continuing.
- */
-
- spin_lock_irqsave(&devc->lock,flags);
- codec_dma_bits = sscape_read(devc, GA_CDCFG_REG);
-
- if (devc->dma_allocated == 0)
- devc->dma_allocated = 1;
-
- spin_unlock_irqrestore(&devc->lock,flags);
-
- sscape_write(devc, GA_HMCTL_REG,
- (temp = sscape_read(devc, GA_HMCTL_REG)) & 0x3f); /*Reset */
-
- for (timeout_val = 10000; timeout_val > 0; timeout_val--)
- sscape_read(devc, GA_HMCTL_REG); /* Delay */
-
- /* Take board out of reset */
- sscape_write(devc, GA_HMCTL_REG,
- (temp = sscape_read(devc, GA_HMCTL_REG)) | 0x80);
- }
- /*
- * Transfer one code block using DMA
- */
- if (audio_devs[devc->codec_audiodev]->dmap_out->raw_buf == NULL)
- {
- printk(KERN_WARNING "soundscape: DMA buffer not available\n");
- return 0;
- }
- memcpy(audio_devs[devc->codec_audiodev]->dmap_out->raw_buf, block, size);
-
- spin_lock_irqsave(&devc->lock,flags);
-
- /******** INTERRUPTS DISABLED NOW ********/
-
- do_dma(devc, SSCAPE_DMA_A,
- audio_devs[devc->codec_audiodev]->dmap_out->raw_buf_phys,
- size, DMA_MODE_WRITE);
-
- /*
- * Wait until transfer completes.
- */
-
- done = 0;
- timeout_val = 30;
- while (!done && timeout_val-- > 0)
- {
- int resid;
-
- if (HZ / 50)
- sleep(HZ / 50);
- clear_dma_ff(devc->dma);
- if ((resid = get_dma_residue(devc->dma)) == 0)
- done = 1;
- }
-
- spin_unlock_irqrestore(&devc->lock,flags);
- if (!done)
- return 0;
-
- if (flag & CPF_LAST)
- {
- /*
- * Take the board out of reset
- */
- outb((0x00), PORT(HOST_CTRL));
- outb((0x00), PORT(MIDI_CTRL));
-
- temp = sscape_read(devc, GA_HMCTL_REG);
- temp |= 0x40;
- sscape_write(devc, GA_HMCTL_REG, temp); /* Kickstart the board */
-
- /*
- * Wait until the ODB wakes up
- */
- spin_lock_irqsave(&devc->lock,flags);
- done = 0;
- timeout_val = 5 * HZ;
- while (!done && timeout_val-- > 0)
- {
- unsigned char x;
-
- sleep(1);
- x = inb(PORT(HOST_DATA));
- if (x == 0xff || x == 0xfe) /* OBP startup acknowledge */
- {
- DDB(printk("Soundscape: Acknowledge = %x\n", x));
- done = 1;
- }
- }
- sscape_write(devc, GA_CDCFG_REG, codec_dma_bits);
-
- spin_unlock_irqrestore(&devc->lock,flags);
- if (!done)
- {
- printk(KERN_ERR "soundscape: The OBP didn't respond after code download\n");
- return 0;
- }
- spin_lock_irqsave(&devc->lock,flags);
- done = 0;
- timeout_val = 5 * HZ;
- while (!done && timeout_val-- > 0)
- {
- sleep(1);
- if (inb(PORT(HOST_DATA)) == 0xfe) /* Host startup acknowledge */
- done = 1;
- }
- spin_unlock_irqrestore(&devc->lock,flags);
- if (!done)
- {
- printk(KERN_ERR "soundscape: OBP Initialization failed.\n");
- return 0;
- }
- printk(KERN_INFO "SoundScape board initialized OK\n");
- set_control(devc, CTL_MASTER_VOL, 100);
- set_control(devc, CTL_SYNTH_VOL, 100);
-
-#ifdef SSCAPE_DEBUG3
- /*
- * Temporary debugging aid. Print contents of the registers after
- * downloading the code.
- */
- {
- int i;
-
- for (i = 0; i < 13; i++)
- printk("I%d = %02x (new value)\n", i, sscape_read(devc, i));
- }
-#endif
-
- }
- return 1;
-}
-
-static int download_boot_block(void *dev_info, copr_buffer * buf)
-{
- if (buf->len <= 0 || buf->len > sizeof(buf->data))
- return -EINVAL;
-
- if (!sscape_download_boot(devc, buf->data, buf->len, buf->flags))
- {
- printk(KERN_ERR "soundscape: Unable to load microcode block to the OBP.\n");
- return -EIO;
- }
- return 0;
-}
-
-static int sscape_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg, int local)
-{
- copr_buffer *buf;
- int err;
-
- switch (cmd)
- {
- case SNDCTL_COPR_RESET:
- sscape_coproc_reset(dev_info);
- return 0;
-
- case SNDCTL_COPR_LOAD:
- buf = (copr_buffer *) vmalloc(sizeof(copr_buffer));
- if (buf == NULL)
- return -ENOSPC;
- if (copy_from_user(buf, arg, sizeof(copr_buffer)))
- {
- vfree(buf);
- return -EFAULT;
- }
- err = download_boot_block(dev_info, buf);
- vfree(buf);
- return err;
-
- default:
- return -EINVAL;
- }
-}
-
-static coproc_operations sscape_coproc_operations =
-{
- "SoundScape M68K",
- THIS_MODULE,
- sscape_coproc_open,
- sscape_coproc_close,
- sscape_coproc_ioctl,
- sscape_coproc_reset,
- &adev_info
-};
-
-static struct resource *sscape_ports;
-static int sscape_is_pnp;
-
-static void __init attach_sscape(struct address_info *hw_config)
-{
-#ifndef SSCAPE_REGS
- /*
- * Config register values for Spea/V7 Media FX and Ensoniq S-2000.
- * These values are card
- * dependent. If you have another SoundScape based card, you have to
- * find the correct values. Do the following:
- * - Compile this driver with SSCAPE_DEBUG1 defined.
- * - Shut down and power off your machine.
- * - Boot with DOS so that the SSINIT.EXE program is run.
- * - Warm boot to {Linux|SYSV|BSD} and write down the lines displayed
- * when detecting the SoundScape.
- * - Modify the following list to use the values printed during boot.
- * Undefine the SSCAPE_DEBUG1
- */
-#define SSCAPE_REGS { \
-/* I0 */ 0x00, \
-/* I1 */ 0xf0, /* Note! Ignored. Set always to 0xf0 */ \
-/* I2 */ 0x20, /* Note! Ignored. Set always to 0x20 */ \
-/* I3 */ 0x20, /* Note! Ignored. Set always to 0x20 */ \
-/* I4 */ 0xf5, /* Ignored */ \
-/* I5 */ 0x10, \
-/* I6 */ 0x00, \
-/* I7 */ 0x2e, /* I7 MEM config A. Likely to vary between models */ \
-/* I8 */ 0x00, /* I8 MEM config B. Likely to vary between models */ \
-/* I9 */ 0x40 /* Ignored */ \
- }
-#endif
-
- unsigned long flags;
- static unsigned char regs[10] = SSCAPE_REGS;
-
- int i, irq_bits = 0xff;
-
- if (old_hardware)
- {
- valid_interrupts = valid_interrupts_old;
- conf_printf("Ensoniq SoundScape (old)", hw_config);
- }
- else
- conf_printf("Ensoniq SoundScape", hw_config);
-
- for (i = 0; i < 4; i++)
- {
- if (hw_config->irq == valid_interrupts[i])
- {
- irq_bits = i;
- break;
- }
- }
- if (hw_config->irq > 15 || (regs[4] = irq_bits == 0xff))
- {
- printk(KERN_ERR "Invalid IRQ%d\n", hw_config->irq);
- release_region(devc->base, 2);
- release_region(devc->base + 2, 6);
- if (sscape_is_pnp)
- release_region(devc->codec, 2);
- return;
- }
-
- if (!sscape_is_pnp) {
-
- spin_lock_irqsave(&devc->lock,flags);
- /* Host interrupt enable */
- sscape_write(devc, 1, 0xf0); /* All interrupts enabled */
- /* DMA A status/trigger register */
- sscape_write(devc, 2, 0x20); /* DMA channel disabled */
- /* DMA B status/trigger register */
- sscape_write(devc, 3, 0x20); /* DMA channel disabled */
- /* Host interrupt config reg */
- sscape_write(devc, 4, 0xf0 | (irq_bits << 2) | irq_bits);
- /* Don't destroy CD-ROM DMA config bits (0xc0) */
- sscape_write(devc, 5, (regs[5] & 0x3f) | (sscape_read(devc, 5) & 0xc0));
- /* CD-ROM config (WSS codec actually) */
- sscape_write(devc, 6, regs[6]);
- sscape_write(devc, 7, regs[7]);
- sscape_write(devc, 8, regs[8]);
- /* Master control reg. Don't modify CR-ROM bits. Disable SB emul */
- sscape_write(devc, 9, (sscape_read(devc, 9) & 0xf0) | 0x08);
- spin_unlock_irqrestore(&devc->lock,flags);
- }
-#ifdef SSCAPE_DEBUG2
- /*
- * Temporary debugging aid. Print contents of the registers after
- * changing them.
- */
- {
- int i;
-
- for (i = 0; i < 13; i++)
- printk("I%d = %02x (new value)\n", i, sscape_read(devc, i));
- }
-#endif
-
- if (probe_mpu401(hw_config, sscape_ports))
- hw_config->always_detect = 1;
- hw_config->name = "SoundScape";
-
- hw_config->irq *= -1; /* Negative value signals IRQ sharing */
- attach_mpu401(hw_config, THIS_MODULE);
- hw_config->irq *= -1; /* Restore it */
-
- if (hw_config->slots[1] != -1) /* The MPU driver installed itself */
- {
- sscape_mididev = hw_config->slots[1];
- midi_devs[hw_config->slots[1]]->coproc = &sscape_coproc_operations;
- }
- sscape_write(devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */
- devc->ok = 1;
- devc->failed = 0;
-}
-
-static int detect_ga(sscape_info * devc)
-{
- unsigned char save;
-
- DDB(printk("Entered Soundscape detect_ga(%x)\n", devc->base));
-
- /*
- * First check that the address register of "ODIE" is
- * there and that it has exactly 4 writable bits.
- * First 4 bits
- */
-
- if ((save = inb(PORT(ODIE_ADDR))) & 0xf0)
- {
- DDB(printk("soundscape: Detect error A\n"));
- return 0;
- }
- outb((0x00), PORT(ODIE_ADDR));
- if (inb(PORT(ODIE_ADDR)) != 0x00)
- {
- DDB(printk("soundscape: Detect error B\n"));
- return 0;
- }
- outb((0xff), PORT(ODIE_ADDR));
- if (inb(PORT(ODIE_ADDR)) != 0x0f)
- {
- DDB(printk("soundscape: Detect error C\n"));
- return 0;
- }
- outb((save), PORT(ODIE_ADDR));
-
- /*
- * Now verify that some indirect registers return zero on some bits.
- * This may break the driver with some future revisions of "ODIE" but...
- */
-
- if (sscape_read(devc, 0) & 0x0c)
- {
- DDB(printk("soundscape: Detect error D (%x)\n", sscape_read(devc, 0)));
- return 0;
- }
- if (sscape_read(devc, 1) & 0x0f)
- {
- DDB(printk("soundscape: Detect error E\n"));
- return 0;
- }
- if (sscape_read(devc, 5) & 0x0f)
- {
- DDB(printk("soundscape: Detect error F\n"));
- return 0;
- }
- return 1;
-}
-
-static int sscape_read_host_ctrl(sscape_info* devc)
-{
- return host_read(devc);
-}
-
-static void sscape_write_host_ctrl2(sscape_info *devc, int a, int b)
-{
- host_command2(devc, a, b);
-}
-
-static int sscape_alloc_dma(sscape_info *devc)
-{
- char *start_addr, *end_addr;
- int dma_pagesize;
- int sz, size;
- struct page *page;
-
- if (devc->raw_buf != NULL) return 0; /* Already done */
- dma_pagesize = (devc->dma < 4) ? (64 * 1024) : (128 * 1024);
- devc->raw_buf = NULL;
- devc->buffsize = 8192*4;
- if (devc->buffsize > dma_pagesize) devc->buffsize = dma_pagesize;
- start_addr = NULL;
- /*
- * Now loop until we get a free buffer. Try to get smaller buffer if
- * it fails. Don't accept smaller than 8k buffer for performance
- * reasons.
- */
- while (start_addr == NULL && devc->buffsize > PAGE_SIZE) {
- for (sz = 0, size = PAGE_SIZE; size < devc->buffsize; sz++, size <<= 1);
- devc->buffsize = PAGE_SIZE * (1 << sz);
- start_addr = (char *) __get_free_pages(GFP_ATOMIC|GFP_DMA, sz);
- if (start_addr == NULL) devc->buffsize /= 2;
- }
-
- if (start_addr == NULL) {
- printk(KERN_ERR "sscape pnp init error: Couldn't allocate DMA buffer\n");
- return 0;
- } else {
- /* make some checks */
- end_addr = start_addr + devc->buffsize - 1;
- /* now check if it fits into the same dma-pagesize */
-
- if (((long) start_addr & ~(dma_pagesize - 1)) != ((long) end_addr & ~(dma_pagesize - 1))
- || end_addr >= (char *) (MAX_DMA_ADDRESS)) {
- printk(KERN_ERR "sscape pnp: Got invalid address 0x%lx for %db DMA-buffer\n", (long) start_addr, devc->buffsize);
- return 0;
- }
- }
- devc->raw_buf = start_addr;
- devc->raw_buf_phys = virt_to_bus(start_addr);
-
- for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++)
- SetPageReserved(page);
- return 1;
-}
-
-static void sscape_free_dma(sscape_info *devc)
-{
- int sz, size;
- unsigned long start_addr, end_addr;
- struct page *page;
-
- if (devc->raw_buf == NULL) return;
- for (sz = 0, size = PAGE_SIZE; size < devc->buffsize; sz++, size <<= 1);
- start_addr = (unsigned long) devc->raw_buf;
- end_addr = start_addr + devc->buffsize;
-
- for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++)
- ClearPageReserved(page);
-
- free_pages((unsigned long) devc->raw_buf, sz);
- devc->raw_buf = NULL;
-}
-
-/* Intel version !!!!!!!!! */
-
-static int sscape_start_dma(int chan, unsigned long physaddr, int count, int dma_mode)
-{
- unsigned long flags;
-
- flags = claim_dma_lock();
- disable_dma(chan);
- clear_dma_ff(chan);
- set_dma_mode(chan, dma_mode);
- set_dma_addr(chan, physaddr);
- set_dma_count(chan, count);
- enable_dma(chan);
- release_dma_lock(flags);
- return 0;
-}
-
-static void sscape_pnp_start_dma(sscape_info* devc, int arg )
-{
- int reg;
- if (arg == 0) reg = 2;
- else reg = 3;
-
- sscape_write(devc, reg, sscape_read( devc, reg) | 0x01);
- sscape_write(devc, reg, sscape_read( devc, reg) & 0xFE);
-}
-
-static int sscape_pnp_wait_dma (sscape_info* devc, int arg )
-{
- int reg;
- unsigned long i;
- unsigned char d;
-
- if (arg == 0) reg = 2;
- else reg = 3;
-
- sleep ( 1 );
- i = 0;
- do {
- d = sscape_read(devc, reg) & 1;
- if ( d == 1) break;
- i++;
- } while (i < 500000);
- d = sscape_read(devc, reg) & 1;
- return d;
-}
-
-static int sscape_pnp_alloc_dma(sscape_info* devc)
-{
- /* printk(KERN_INFO "sscape: requesting dma\n"); */
- if (request_dma(devc -> dma, "sscape")) return 0;
- /* printk(KERN_INFO "sscape: dma channel allocated\n"); */
- if (!sscape_alloc_dma(devc)) {
- free_dma(devc -> dma);
- return 0;
- };
- return 1;
-}
-
-static void sscape_pnp_free_dma(sscape_info* devc)
-{
- sscape_free_dma( devc);
- free_dma(devc -> dma );
- /* printk(KERN_INFO "sscape: dma released\n"); */
-}
-
-static int sscape_pnp_upload_file(sscape_info* devc, char* fn)
-{
- int done = 0;
- int timeout_val;
- char* data,*dt;
- int len,l;
- unsigned long flags;
-
- sscape_write( devc, 9, sscape_read(devc, 9 ) & 0x3F );
- sscape_write( devc, 2, (devc -> dma << 4) | 0x80 );
- sscape_write( devc, 3, 0x20 );
- sscape_write( devc, 9, sscape_read( devc, 9 ) | 0x80 );
-
- len = mod_firmware_load(fn, &data);
- if (len == 0) {
- printk(KERN_ERR "sscape: file not found: %s\n", fn);
- return 0;
- }
- dt = data;
- spin_lock_irqsave(&devc->lock,flags);
- while ( len > 0 ) {
- if (len > devc -> buffsize) l = devc->buffsize;
- else l = len;
- len -= l;
- memcpy(devc->raw_buf, dt, l); dt += l;
- sscape_start_dma(devc->dma, devc->raw_buf_phys, l, 0x48);
- sscape_pnp_start_dma ( devc, 0 );
- if (sscape_pnp_wait_dma ( devc, 0 ) == 0) {
- spin_unlock_irqrestore(&devc->lock,flags);
- return 0;
- }
- }
-
- spin_unlock_irqrestore(&devc->lock,flags);
- vfree(data);
-
- outb(0, devc -> base + 2);
- outb(0, devc -> base);
-
- sscape_write ( devc, 9, sscape_read( devc, 9 ) | 0x40);
-
- timeout_val = 5 * HZ;
- while (!done && timeout_val-- > 0)
- {
- unsigned char x;
- sleep(1);
- x = inb( devc -> base + 3);
- if (x == 0xff || x == 0xfe) /* OBP startup acknowledge */
- {
- //printk(KERN_ERR "Soundscape: Acknowledge = %x\n", x);
- done = 1;
- }
- }
- timeout_val = 5 * HZ;
- done = 0;
- while (!done && timeout_val-- > 0)
- {
- unsigned char x;
- sleep(1);
- x = inb( devc -> base + 3);
- if (x == 0xfe) /* OBP startup acknowledge */
- {
- //printk(KERN_ERR "Soundscape: Acknowledge = %x\n", x);
- done = 1;
- }
- }
-
- if ( !done ) printk(KERN_ERR "soundscape: OBP Initialization failed.\n");
-
- sscape_write( devc, 2, devc->ic_type == IC_ODIE ? 0x70 : 0x40);
- sscape_write( devc, 3, (devc -> dma << 4) + 0x80);
- return 1;
-}
-
-static void __init sscape_pnp_init_hw(sscape_info* devc)
-{
- unsigned char midi_irq = 0, sb_irq = 0;
- unsigned i;
- static char code_file_name[23] = "/sndscape/sndscape.cox";
-
- int sscape_joystic_enable = 0x7f;
- int sscape_mic_enable = 0;
- int sscape_ext_midi = 0;
-
- if ( !sscape_pnp_alloc_dma(devc) ) {
- printk(KERN_ERR "sscape: faild to allocate dma\n");
- return;
- }
-
- for (i = 0; i < 4; i++) {
- if ( devc -> irq == valid_interrupts[i] )
- midi_irq = i;
- if ( devc -> codec_irq == valid_interrupts[i] )
- sb_irq = i;
- }
-
- sscape_write( devc, 5, 0x50);
- sscape_write( devc, 7, 0x2e);
- sscape_write( devc, 8, 0x00);
-
- sscape_write( devc, 2, devc->ic_type == IC_ODIE ? 0x70 : 0x40);
- sscape_write( devc, 3, ( devc -> dma << 4) | 0x80);
-
- sscape_write (devc, 4, 0xF0 | (midi_irq<<2) | midi_irq);
-
- i = 0x10; //sscape_read(devc, 9) & (devc->ic_type == IC_ODIE ? 0xf0 : 0xc0);
- if (sscape_joystic_enable) i |= 8;
-
- sscape_write (devc, 9, i);
- sscape_write (devc, 6, 0x80);
- sscape_write (devc, 1, 0x80);
-
- if (devc -> codec_type == 2) {
- sscape_pnp_write_codec( devc, 0x0C, 0x50);
- sscape_pnp_write_codec( devc, 0x10, sscape_pnp_read_codec( devc, 0x10) & 0x3F);
- sscape_pnp_write_codec( devc, 0x11, sscape_pnp_read_codec( devc, 0x11) | 0xC0);
- sscape_pnp_write_codec( devc, 29, 0x20);
- }
-
- if (sscape_pnp_upload_file(devc, "/sndscape/scope.cod") == 0 ) {
- printk(KERN_ERR "sscape: faild to upload file /sndscape/scope.cod\n");
- sscape_pnp_free_dma(devc);
- return;
- }
-
- i = sscape_read_host_ctrl( devc );
-
- if ( (i & 0x0F) > 7 ) {
- printk(KERN_ERR "sscape: scope.cod faild\n");
- sscape_pnp_free_dma(devc);
- return;
- }
- if ( i & 0x10 ) sscape_write( devc, 7, 0x2F);
- code_file_name[21] = (char) ( i & 0x0F) + 0x30;
- if (sscape_pnp_upload_file( devc, code_file_name) == 0) {
- printk(KERN_ERR "sscape: faild to upload file %s\n", code_file_name);
- sscape_pnp_free_dma(devc);
- return;
- }
-
- if (devc->ic_type != IC_ODIE) {
- sscape_pnp_write_codec( devc, 10, (sscape_pnp_read_codec(devc, 10) & 0x7f) |
- ( sscape_mic_enable == 0 ? 0x00 : 0x80) );
- }
- sscape_write_host_ctrl2( devc, 0x84, 0x64 ); /* MIDI volume */
- sscape_write_host_ctrl2( devc, 0x86, 0x64 ); /* MIDI volume?? */
- sscape_write_host_ctrl2( devc, 0x8A, sscape_ext_midi);
-
- sscape_pnp_write_codec ( devc, 6, 0x3f ); //WAV_VOL
- sscape_pnp_write_codec ( devc, 7, 0x3f ); //WAV_VOL
- sscape_pnp_write_codec ( devc, 2, 0x1F ); //WD_CDXVOLL
- sscape_pnp_write_codec ( devc, 3, 0x1F ); //WD_CDXVOLR
-
- if (devc -> codec_type == 1) {
- sscape_pnp_write_codec ( devc, 4, 0x1F );
- sscape_pnp_write_codec ( devc, 5, 0x1F );
- sscape_write_host_ctrl2( devc, 0x88, sscape_mic_enable);
- } else {
- int t;
- sscape_pnp_write_codec ( devc, 0x10, 0x1F << 1);
- sscape_pnp_write_codec ( devc, 0x11, 0xC0 | (0x1F << 1));
-
- t = sscape_pnp_read_codec( devc, 0x00) & 0xDF;
- if ( (sscape_mic_enable == 0)) t |= 0;
- else t |= 0x20;
- sscape_pnp_write_codec ( devc, 0x00, t);
- t = sscape_pnp_read_codec( devc, 0x01) & 0xDF;
- if ( (sscape_mic_enable == 0) ) t |= 0;
- else t |= 0x20;
- sscape_pnp_write_codec ( devc, 0x01, t);
- sscape_pnp_write_codec ( devc, 0x40 | 29 , 0x20);
- outb(0, devc -> codec);
- }
- if (devc -> ic_type == IC_OPUS ) {
- int i = sscape_read( devc, 9 );
- sscape_write( devc, 9, i | 3 );
- sscape_write( devc, 3, 0x40);
-
- if (request_region(0x228, 1, "sscape setup junk")) {
- outb(0, 0x228);
- release_region(0x228,1);
- }
- sscape_write( devc, 3, (devc -> dma << 4) | 0x80);
- sscape_write( devc, 9, i );
- }
-
- host_close ( devc );
- sscape_pnp_free_dma(devc);
-}
-
-static int __init detect_sscape_pnp(sscape_info* devc)
-{
- long i, irq_bits = 0xff;
- unsigned int d;
-
- DDB(printk("Entered detect_sscape_pnp(%x)\n", devc->base));
-
- if (!request_region(devc->codec, 2, "sscape codec")) {
- printk(KERN_ERR "detect_sscape_pnp: port %x is not free\n", devc->codec);
- return 0;
- }
-
- if ((inb(devc->base + 2) & 0x78) != 0)
- goto fail;
-
- d = inb ( devc -> base + 4) & 0xF0;
- if (d & 0x80)
- goto fail;
-
- if (d == 0) {
- devc->codec_type = 1;
- devc->ic_type = IC_ODIE;
- } else if ( (d & 0x60) != 0) {
- devc->codec_type = 2;
- devc->ic_type = IC_OPUS;
- } else if ( (d & 0x40) != 0) { /* WTF? */
- devc->codec_type = 2;
- devc->ic_type = IC_ODIE;
- } else
- goto fail;
-
- sscape_is_pnp = 1;
-
- outb(0xFA, devc -> base+4);
- if ((inb( devc -> base+4) & 0x9F) != 0x0A)
- goto fail;
- outb(0xFE, devc -> base+4);
- if ( (inb(devc -> base+4) & 0x9F) != 0x0E)
- goto fail;
- if ( (inb(devc -> base+5) & 0x9F) != 0x0E)
- goto fail;
-
- if (devc->codec_type == 2) {
- if (devc->codec != devc->base + 8) {
- printk("soundscape warning: incorrect codec port specified\n");
- goto fail;
- }
- d = 0x10 | (sscape_read(devc, 9) & 0xCF);
- sscape_write(devc, 9, d);
- sscape_write(devc, 6, 0x80);
- } else {
- //todo: check codec is not base + 8
- }
-
- d = (sscape_read(devc, 9) & 0x3F) | 0xC0;
- sscape_write(devc, 9, d);
-
- for (i = 0; i < 550000; i++)
- if ( !(inb(devc -> codec) & 0x80) ) break;
-
- d = inb(devc -> codec);
- if (d & 0x80)
- goto fail;
- if ( inb(devc -> codec + 2) == 0xFF)
- goto fail;
-
- sscape_write(devc, 9, sscape_read(devc, 9) & 0x3F );
-
- d = inb(devc -> codec) & 0x80;
- if ( d == 0) {
- printk(KERN_INFO "soundscape: hardware detected\n");
- valid_interrupts = valid_interrupts_new;
- } else {
- printk(KERN_INFO "soundscape: board looks like media fx\n");
- valid_interrupts = valid_interrupts_old;
- old_hardware = 1;
- }
-
- sscape_write( devc, 9, 0xC0 | (sscape_read(devc, 9) & 0x3F) );
-
- for (i = 0; i < 550000; i++)
- if ( !(inb(devc -> codec) & 0x80))
- break;
-
- sscape_pnp_init_hw(devc);
-
- for (i = 0; i < 4; i++)
- {
- if (devc->codec_irq == valid_interrupts[i]) {
- irq_bits = i;
- break;
- }
- }
- sscape_write(devc, GA_INTENA_REG, 0x00);
- sscape_write(devc, GA_DMACFG_REG, 0x50);
- sscape_write(devc, GA_DMAA_REG, 0x70);
- sscape_write(devc, GA_DMAB_REG, 0x20);
- sscape_write(devc, GA_INTCFG_REG, 0xf0);
- sscape_write(devc, GA_CDCFG_REG, 0x89 | (devc->dma << 4) | (irq_bits << 1));
-
- sscape_pnp_write_codec( devc, 0, sscape_pnp_read_codec( devc, 0) | 0x20);
- sscape_pnp_write_codec( devc, 0, sscape_pnp_read_codec( devc, 1) | 0x20);
-
- return 1;
-fail:
- release_region(devc->codec, 2);
- return 0;
-}
-
-static int __init probe_sscape(struct address_info *hw_config)
-{
- devc->base = hw_config->io_base;
- devc->irq = hw_config->irq;
- devc->dma = hw_config->dma;
- devc->osp = hw_config->osp;
-
-#ifdef SSCAPE_DEBUG1
- /*
- * Temporary debugging aid. Print contents of the registers before
- * changing them.
- */
- {
- int i;
-
- for (i = 0; i < 13; i++)
- printk("I%d = %02x (old value)\n", i, sscape_read(devc, i));
- }
-#endif
- devc->failed = 1;
-
- sscape_ports = request_region(devc->base, 2, "mpu401");
- if (!sscape_ports)
- return 0;
-
- if (!request_region(devc->base + 2, 6, "SoundScape")) {
- release_region(devc->base, 2);
- return 0;
- }
-
- if (!detect_ga(devc)) {
- if (detect_sscape_pnp(devc))
- return 1;
- release_region(devc->base, 2);
- release_region(devc->base + 2, 6);
- return 0;
- }
-
- if (old_hardware) /* Check that it's really an old Spea/Reveal card. */
- {
- unsigned char tmp;
- int cc;
-
- if (!((tmp = sscape_read(devc, GA_HMCTL_REG)) & 0xc0))
- {
- sscape_write(devc, GA_HMCTL_REG, tmp | 0x80);
- for (cc = 0; cc < 200000; ++cc)
- inb(devc->base + ODIE_ADDR);
- }
- }
- return 1;
-}
-
-static int __init init_ss_ms_sound(struct address_info *hw_config)
-{
- int i, irq_bits = 0xff;
- int ad_flags = 0;
- struct resource *ports;
-
- if (devc->failed)
- {
- printk(KERN_ERR "soundscape: Card not detected\n");
- return 0;
- }
- if (devc->ok == 0)
- {
- printk(KERN_ERR "soundscape: Invalid initialization order.\n");
- return 0;
- }
- for (i = 0; i < 4; i++)
- {
- if (hw_config->irq == valid_interrupts[i])
- {
- irq_bits = i;
- break;
- }
- }
- if (irq_bits == 0xff) {
- printk(KERN_ERR "soundscape: Invalid MSS IRQ%d\n", hw_config->irq);
- return 0;
- }
-
- if (old_hardware)
- ad_flags = 0x12345677; /* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */
- else if (sscape_is_pnp)
- ad_flags = 0x87654321; /* Tell that we have a soundscape pnp with 1845 chip */
-
- ports = request_region(hw_config->io_base, 4, "ad1848");
- if (!ports) {
- printk(KERN_ERR "soundscape: ports busy\n");
- return 0;
- }
-
- if (!ad1848_detect(ports, &ad_flags, hw_config->osp)) {
- release_region(hw_config->io_base, 4);
- return 0;
- }
-
- if (!sscape_is_pnp) /*pnp is already setup*/
- {
- /*
- * Setup the DMA polarity.
- */
- sscape_write(devc, GA_DMACFG_REG, 0x50);
-
- /*
- * Take the gate-array off of the DMA channel.
- */
- sscape_write(devc, GA_DMAB_REG, 0x20);
-
- /*
- * Init the AD1848 (CD-ROM) config reg.
- */
- sscape_write(devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) | (irq_bits << 1));
- }
-
- if (hw_config->irq == devc->irq)
- printk(KERN_WARNING "soundscape: Warning! The WSS mode can't share IRQ with MIDI\n");
-
- hw_config->slots[0] = ad1848_init(
- sscape_is_pnp ? "SoundScape" : "SoundScape PNP",
- ports,
- hw_config->irq,
- hw_config->dma,
- hw_config->dma,
- 0,
- devc->osp,
- THIS_MODULE);
-
-
- if (hw_config->slots[0] != -1) /* The AD1848 driver installed itself */
- {
- audio_devs[hw_config->slots[0]]->coproc = &sscape_coproc_operations;
- devc->codec_audiodev = hw_config->slots[0];
- devc->my_audiodev = hw_config->slots[0];
-
- /* Set proper routings here (what are they) */
- AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE);
- }
-
-#ifdef SSCAPE_DEBUG5
- /*
- * Temporary debugging aid. Print contents of the registers
- * after the AD1848 device has been initialized.
- */
- {
- int i;
-
- for (i = 0; i < 13; i++)
- printk("I%d = %02x\n", i, sscape_read(devc, i));
- }
-#endif
- return 1;
-}
-
-static void __exit unload_sscape(struct address_info *hw_config)
-{
- release_region(devc->base + 2, 6);
- unload_mpu401(hw_config);
- if (sscape_is_pnp)
- release_region(devc->codec, 2);
-}
-
-static void __exit unload_ss_ms_sound(struct address_info *hw_config)
-{
- ad1848_unload(hw_config->io_base,
- hw_config->irq,
- devc->dma,
- devc->dma,
- 0);
- sound_unload_audiodev(hw_config->slots[0]);
-}
-
-static struct address_info cfg;
-static struct address_info cfg_mpu;
-
-static int __initdata spea = -1;
-static int mss = 0;
-static int __initdata dma = -1;
-static int __initdata irq = -1;
-static int __initdata io = -1;
-static int __initdata mpu_irq = -1;
-static int __initdata mpu_io = -1;
-
-module_param(dma, int, 0);
-module_param(irq, int, 0);
-module_param(io, int, 0);
-module_param(spea, int, 0); /* spea=0/1 set the old_hardware */
-module_param(mpu_irq, int, 0);
-module_param(mpu_io, int, 0);
-module_param(mss, int, 0);
-
-static int __init init_sscape(void)
-{
- printk(KERN_INFO "Soundscape driver Copyright (C) by Hannu Savolainen 1993-1996\n");
-
- cfg.irq = irq;
- cfg.dma = dma;
- cfg.io_base = io;
-
- cfg_mpu.irq = mpu_irq;
- cfg_mpu.io_base = mpu_io;
- /* WEH - Try to get right dma channel */
- cfg_mpu.dma = dma;
-
- devc->codec = cfg.io_base;
- devc->codec_irq = cfg.irq;
- devc->codec_type = 0;
- devc->ic_type = 0;
- devc->raw_buf = NULL;
- spin_lock_init(&devc->lock);
-
- if (cfg.dma == -1 || cfg.irq == -1 || cfg.io_base == -1) {
- printk(KERN_ERR "DMA, IRQ, and IO port must be specified.\n");
- return -EINVAL;
- }
-
- if (cfg_mpu.irq == -1 && cfg_mpu.io_base != -1) {
- printk(KERN_ERR "MPU_IRQ must be specified if MPU_IO is set.\n");
- return -EINVAL;
- }
-
- if(spea != -1) {
- old_hardware = spea;
- printk(KERN_INFO "Forcing %s hardware support.\n",
- spea?"new":"old");
- }
- if (probe_sscape(&cfg_mpu) == 0)
- return -ENODEV;
-
- attach_sscape(&cfg_mpu);
-
- mss = init_ss_ms_sound(&cfg);
-
- return 0;
-}
-
-static void __exit cleanup_sscape(void)
-{
- if (mss)
- unload_ss_ms_sound(&cfg);
- unload_sscape(&cfg_mpu);
-}
-
-module_init(init_sscape);
-module_exit(cleanup_sscape);
-
-#ifndef MODULE
-static int __init setup_sscape(char *str)
-{
- /* io, irq, dma, mpu_io, mpu_irq */
- int ints[6];
-
- str = get_options(str, ARRAY_SIZE(ints), ints);
-
- io = ints[1];
- irq = ints[2];
- dma = ints[3];
- mpu_io = ints[4];
- mpu_irq = ints[5];
-
- return 1;
-}
-
-__setup("sscape=", setup_sscape);
-#endif
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c
index a8057f25955..a33e8ce8085 100644
--- a/sound/oss/swarm_cs4297a.c
+++ b/sound/oss/swarm_cs4297a.c
@@ -69,7 +69,6 @@
#include <linux/sound.h>
#include <linux/slab.h>
#include <linux/soundcard.h>
-#include <linux/ac97_codec.h>
#include <linux/pci.h>
#include <linux/bitops.h>
#include <linux/interrupt.h>
@@ -91,8 +90,11 @@
#include <asm/sibyte/sb1250_mac.h>
#include <asm/sibyte/sb1250.h>
+#include "sleep.h"
+
struct cs4297a_state;
+static DEFINE_MUTEX(swarm_cs4297a_mutex);
static void stop_dac(struct cs4297a_state *s);
static void stop_adc(struct cs4297a_state *s);
static void start_dac(struct cs4297a_state *s);
@@ -110,9 +112,6 @@ static void start_adc(struct cs4297a_state *s);
// rather than 64k as some of the games work more responsively.
// log base 2( buff sz = 32k).
-//static unsigned long defaultorder = 3;
-//MODULE_PARM(defaultorder, "i");
-
//
// Turn on/off debugging compilation by commenting out "#define CSDEBUG"
//
@@ -201,6 +200,22 @@ static const char invalid_magic[] =
} \
})
+/* AC97 registers */
+#define AC97_MASTER_VOL_STEREO 0x0002 /* Line Out */
+#define AC97_PCBEEP_VOL 0x000a /* none */
+#define AC97_PHONE_VOL 0x000c /* TAD Input (mono) */
+#define AC97_MIC_VOL 0x000e /* MIC Input (mono) */
+#define AC97_LINEIN_VOL 0x0010 /* Line Input (stereo) */
+#define AC97_CD_VOL 0x0012 /* CD Input (stereo) */
+#define AC97_AUX_VOL 0x0016 /* Aux Input (stereo) */
+#define AC97_PCMOUT_VOL 0x0018 /* Wave Output (stereo) */
+#define AC97_RECORD_SELECT 0x001a /* */
+#define AC97_RECORD_GAIN 0x001c
+#define AC97_GENERAL_PURPOSE 0x0020
+#define AC97_3D_CONTROL 0x0022
+#define AC97_POWER_CONTROL 0x0026
+#define AC97_VENDOR_ID1 0x007c
+
struct list_head cs4297a_devs = { &cs4297a_devs, &cs4297a_devs };
typedef struct serdma_descr_s {
@@ -295,7 +310,7 @@ struct cs4297a_state {
struct mutex open_mutex;
struct mutex open_sem_adc;
struct mutex open_sem_dac;
- mode_t open_mode;
+ fmode_t open_mode;
wait_queue_head_t open_wait;
wait_queue_head_t open_wait_adc;
wait_queue_head_t open_wait_dac;
@@ -735,7 +750,7 @@ static int serdma_reg_access(struct cs4297a_state *s, u64 data)
/* Since a writer has the DSP open, we have to mux the
request in */
s->reg_request = data;
- interruptible_sleep_on(&s->dma_dac.reg_wait);
+ oss_broken_sleep_on(&s->dma_dac.reg_wait, MAX_SCHEDULE_TIMEOUT);
/* XXXKW how can I deal with the starvation case where
the opener isn't writing? */
} else {
@@ -777,7 +792,7 @@ static int cs4297a_read_ac97(struct cs4297a_state *s, u32 offset,
if (serdma_reg_access(s, (0xCLL << 60) | (1LL << 47) | ((u64)(offset & 0x7F) << 40)))
return -1;
- interruptible_sleep_on(&s->dma_adc.reg_wait);
+ oss_broken_sleep_on(&s->dma_adc.reg_wait, MAX_SCHEDULE_TIMEOUT);
*value = s->read_value;
CS_DBGOUT(CS_AC97, 2,
printk(KERN_INFO "cs4297a: rdr reg %x -> %x\n", s->read_reg, s->read_value));
@@ -877,7 +892,7 @@ static void start_adc(struct cs4297a_state *s)
if (s->prop_adc.fmt & AFMT_S8 || s->prop_adc.fmt & AFMT_U8) {
//
// now only use 16 bit capture, due to truncation issue
- // in the chip, noticable distortion occurs.
+ // in the chip, noticeable distortion occurs.
// allocate buffer and then convert from 16 bit to
// 8 bit for the user buffer.
//
@@ -1537,6 +1552,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n"));
+ mutex_lock(&swarm_cs4297a_mutex);
list_for_each(entry, &cs4297a_devs)
{
s = list_entry(entry, struct cs4297a_state, list);
@@ -1547,6 +1563,8 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
{
CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n"));
+
+ mutex_unlock(&swarm_cs4297a_mutex);
return -ENODEV;
}
VALIDATE_STATE(s);
@@ -1554,6 +1572,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n"));
+ mutex_unlock(&swarm_cs4297a_mutex);
return nonseekable_open(inode, file);
}
@@ -1569,21 +1588,25 @@ static int cs4297a_release_mixdev(struct inode *inode, struct file *file)
}
-static int cs4297a_ioctl_mixdev(struct inode *inode, struct file *file,
+static int cs4297a_ioctl_mixdev(struct file *file,
unsigned int cmd, unsigned long arg)
{
- return mixer_ioctl((struct cs4297a_state *) file->private_data, cmd,
+ int ret;
+ mutex_lock(&swarm_cs4297a_mutex);
+ ret = mixer_ioctl((struct cs4297a_state *) file->private_data, cmd,
arg);
+ mutex_unlock(&swarm_cs4297a_mutex);
+ return ret;
}
// ******************************************************************************************
// Mixer file operations struct.
// ******************************************************************************************
-static /*const */ struct file_operations cs4297a_mixer_fops = {
+static const struct file_operations cs4297a_mixer_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
- .ioctl = cs4297a_ioctl_mixdev,
+ .unlocked_ioctl = cs4297a_ioctl_mixdev,
.open = cs4297a_open_mixdev,
.release = cs4297a_release_mixdev,
};
@@ -1719,7 +1742,7 @@ static ssize_t cs4297a_read(struct file *file, char *buffer, size_t count,
start_adc(s);
if (file->f_flags & O_NONBLOCK)
return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&s->dma_adc.wait);
+ oss_broken_sleep_on(&s->dma_adc.wait, MAX_SCHEDULE_TIMEOUT);
if (signal_pending(current))
return ret ? ret : -ERESTARTSYS;
continue;
@@ -1815,7 +1838,7 @@ static ssize_t cs4297a_write(struct file *file, const char *buffer,
start_dac(s);
if (file->f_flags & O_NONBLOCK)
return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&d->wait);
+ oss_broken_sleep_on(&d->wait, MAX_SCHEDULE_TIMEOUT);
if (signal_pending(current))
return ret ? ret : -ERESTARTSYS;
continue;
@@ -1947,7 +1970,7 @@ static int cs4297a_mmap(struct file *file, struct vm_area_struct *vma)
}
-static int cs4297a_ioctl(struct inode *inode, struct file *file,
+static int cs4297a_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct cs4297a_state *s =
@@ -2200,7 +2223,9 @@ static int cs4297a_ioctl(struct inode *inode, struct file *file,
sizeof(abinfo)) ? -EFAULT : 0;
case SNDCTL_DSP_NONBLOCK:
+ spin_lock(&file->f_lock);
file->f_flags |= O_NONBLOCK;
+ spin_unlock(&file->f_lock);
return 0;
case SNDCTL_DSP_GETODELAY:
@@ -2338,6 +2363,16 @@ static int cs4297a_ioctl(struct inode *inode, struct file *file,
return mixer_ioctl(s, cmd, arg);
}
+static long cs4297a_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
+{
+ int ret;
+
+ mutex_lock(&swarm_cs4297a_mutex);
+ ret = cs4297a_ioctl(file, cmd, arg);
+ mutex_unlock(&swarm_cs4297a_mutex);
+
+ return ret;
+}
static int cs4297a_release(struct inode *inode, struct file *file)
{
@@ -2370,7 +2405,7 @@ static int cs4297a_release(struct inode *inode, struct file *file)
return 0;
}
-static int cs4297a_open(struct inode *inode, struct file *file)
+static int cs4297a_locked_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
struct cs4297a_state *s=NULL;
@@ -2419,7 +2454,7 @@ static int cs4297a_open(struct inode *inode, struct file *file)
return -EBUSY;
}
mutex_unlock(&s->open_sem_dac);
- interruptible_sleep_on(&s->open_wait_dac);
+ oss_broken_sleep_on(&s->open_wait_dac, MAX_SCHEDULE_TIMEOUT);
if (signal_pending(current)) {
printk("open - sig pending\n");
@@ -2436,7 +2471,7 @@ static int cs4297a_open(struct inode *inode, struct file *file)
return -EBUSY;
}
mutex_unlock(&s->open_sem_adc);
- interruptible_sleep_on(&s->open_wait_adc);
+ oss_broken_sleep_on(&s->open_wait_adc, MAX_SCHEDULE_TIMEOUT);
if (signal_pending(current)) {
printk("open - sig pending\n");
@@ -2487,17 +2522,27 @@ static int cs4297a_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file);
}
+static int cs4297a_open(struct inode *inode, struct file *file)
+{
+ int ret;
+
+ mutex_lock(&swarm_cs4297a_mutex);
+ ret = cs4297a_open(inode, file);
+ mutex_unlock(&swarm_cs4297a_mutex);
+
+ return ret;
+}
// ******************************************************************************************
// Wave (audio) file operations struct.
// ******************************************************************************************
-static /*const */ struct file_operations cs4297a_audio_fops = {
+static const struct file_operations cs4297a_audio_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = cs4297a_read,
.write = cs4297a_write,
.poll = cs4297a_poll,
- .ioctl = cs4297a_ioctl,
+ .unlocked_ioctl = cs4297a_unlocked_ioctl,
.mmap = cs4297a_mmap,
.open = cs4297a_open,
.release = cs4297a_release,
@@ -2580,15 +2625,12 @@ static int __init cs4297a_init(void)
u32 pwr, id;
mm_segment_t fs;
int rval;
-#ifndef CONFIG_BCM_CS4297A_CSWARM
u64 cfg;
int mdio_val;
-#endif
CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
"cs4297a: cs4297a_init_module()+ \n"));
-#ifndef CONFIG_BCM_CS4297A_CSWARM
mdio_val = __raw_readq(KSEG1 + A_MAC_REGISTER(2, R_MAC_MDIO)) &
(M_MAC_MDIO_DIR|M_MAC_MDIO_OUT);
@@ -2614,7 +2656,6 @@ static int __init cs4297a_init(void)
__raw_writeq(mdio_val | M_MAC_GENC, KSEG1+A_MAC_REGISTER(2, R_MAC_MDIO));
/* Give the codec some time to finish resetting (start the bit clock) */
udelay(100);
-#endif
if (!(s = kzalloc(sizeof(struct cs4297a_state), GFP_KERNEL))) {
CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
diff --git a/sound/oss/sys_timer.c b/sound/oss/sys_timer.c
index 107534477a2..9f039831114 100644
--- a/sound/oss/sys_timer.c
+++ b/sound/oss/sys_timer.c
@@ -57,7 +57,7 @@ poll_def_tmr(unsigned long dummy)
{
def_tmr.expires = (1) + jiffies;
add_timer(&def_tmr);
- };
+ }
if (tmr_running)
{
@@ -100,13 +100,10 @@ def_tmr_open(int dev, int mode)
curr_tempo = 60;
curr_timebase = 100;
opened = 1;
-
- ;
-
{
def_tmr.expires = (1) + jiffies;
add_timer(&def_tmr);
- };
+ }
return 0;
}
diff --git a/sound/oss/trident.c b/sound/oss/trident.c
deleted file mode 100644
index 96adc47917a..00000000000
--- a/sound/oss/trident.c
+++ /dev/null
@@ -1,4658 +0,0 @@
-/*
- * OSS driver for Linux 2.[46].x for
- *
- * Trident 4D-Wave
- * SiS 7018
- * ALi 5451
- * Tvia/IGST CyberPro 5050
- *
- * Driver: Alan Cox <alan@redhat.com>
- *
- * Built from:
- * Low level code: <audio@tridentmicro.com> from ALSA
- * Framework: Thomas Sailer <sailer@ife.ee.ethz.ch>
- * Extended by: Zach Brown <zab@redhat.com>
- *
- * Hacked up by:
- * Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
- * Ollie Lho <ollie@sis.com.tw> SiS 7018 Audio Core Support
- * Ching-Ling Lee <cling-li@ali.com.tw> ALi 5451 Audio Core Support
- * Matt Wu <mattwu@acersoftech.com.cn> ALi 5451 Audio Core Support
- * Peter Wächtler <pwaechtler@loewe-komp.de> CyberPro5050 support
- * Muli Ben-Yehuda <mulix@mulix.org>
- *
- *
- * 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.
- *
- * History
- * v0.14.10j
- * January 3 2004 Eugene Teo <eugeneteo@eugeneteo.net>
- * minor cleanup to use pr_debug instead of TRDBG since it is already
- * defined in linux/kernel.h.
- * v0.14.10i
- * December 29 2003 Muli Ben-Yehuda <mulix@mulix.org>
- * major cleanup for 2.6, fix a few error patch buglets
- * with returning without properly cleaning up first,
- * get rid of lock_kernel().
- * v0.14.10h
- * Sept 10 2002 Pascal Schmidt <der.eremit@email.de>
- * added support for ALi 5451 joystick port
- * v0.14.10g
- * Sept 05 2002 Alan Cox <alan@redhat.com>
- * adapt to new pci joystick attachment interface
- * v0.14.10f
- * July 24 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
- * patch from Eric Lemar (via Ian Soboroff): in suspend and resume,
- * fix wrong cast from pci_dev* to struct trident_card*.
- * v0.14.10e
- * July 19 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
- * rewrite the DMA buffer allocation/deallcoation functions, to make it
- * modular and fix a bug where we would call free_pages on memory
- * obtained with pci_alloc_consistent. Also remove unnecessary #ifdef
- * CONFIG_PROC_FS and various other cleanups.
- * v0.14.10d
- * July 19 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
- * made several printk(KERN_NOTICE...) into TRDBG(...), to avoid spamming
- * my syslog with hundreds of messages.
- * v0.14.10c
- * July 16 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
- * Cleaned up Lei Hu's 0.4.10 driver to conform to Documentation/CodingStyle
- * and the coding style used in the rest of the file.
- * v0.14.10b
- * June 23 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
- * add a missing unlock_set_fmt, remove a superflous lock/unlock pair
- * with nothing in between.
- * v0.14.10a
- * June 21 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
- * use a debug macro instead of #ifdef CONFIG_DEBUG, trim to 80 columns
- * per line, use 'do {} while (0)' in statement macros.
- * v0.14.10
- * June 6 2002 Lei Hu <Lei_hu@ali.com.tw>
- * rewrite the part to read/write registers of audio codec for Ali5451
- * v0.14.9e
- * January 2 2002 Vojtech Pavlik <vojtech@ucw.cz> added gameport
- * support to avoid resource conflict with pcigame.c
- * v0.14.9d
- * October 8 2001 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- * use set_current_state, properly release resources on failure in
- * trident_probe, get rid of check_region
- * v0.14.9c
- * August 10 2001 Peter Wächtler <pwaechtler@loewe-komp.de>
- * added support for Tvia (formerly Integraphics/IGST) CyberPro5050
- * this chip is often found in settop boxes (combined video+audio)
- * v0.14.9b
- * Switch to static inline not extern inline (gcc 3)
- * v0.14.9a
- * Aug 6 2001 Alan Cox
- * 0.14.9 crashed on rmmod due to a timer/bh left running. Simplified
- * the existing logic (the BH doesn't help as ac97 is lock_irqsave)
- * and used del_timer_sync to clean up
- * Fixed a problem where the ALi change broke my generic card
- * v0.14.9
- * Jul 10 2001 Matt Wu
- * Add H/W Volume Control
- * v0.14.8a
- * July 7 2001 Alan Cox
- * Moved Matt Wu's ac97 register cache into the card structure
- * v0.14.8
- * Apr 30 2001 Matt Wu
- * Set EBUF1 and EBUF2 to still mode
- * Add dc97/ac97 reset function
- * Fix power management: ali_restore_regs
- * unreleased
- * Mar 09 2001 Matt Wu
- * Add cache for ac97 access
- * v0.14.7
- * Feb 06 2001 Matt Wu
- * Fix ac97 initialization
- * Fix bug: an extra tail will be played when playing
- * Jan 05 2001 Matt Wu
- * Implement multi-channels and S/PDIF in support for ALi 1535+
- * v0.14.6
- * Nov 1 2000 Ching-Ling Lee
- * Fix the bug of memory leak when switching 5.1-channels to 2 channels.
- * Add lock protection into dynamic changing format of data.
- * Oct 18 2000 Ching-Ling Lee
- * 5.1-channels support for ALi
- * June 28 2000 Ching-Ling Lee
- * S/PDIF out/in(playback/record) support for ALi 1535+, using /proc to be selected by user
- * Simple Power Management support for ALi
- * v0.14.5 May 23 2000 Ollie Lho
- * Misc bug fix from the Net
- * v0.14.4 May 20 2000 Aaron Holtzman
- * Fix kfree'd memory access in release
- * Fix race in open while looking for a free virtual channel slot
- * remove open_wait wq (which appears to be unused)
- * v0.14.3 May 10 2000 Ollie Lho
- * fixed a small bug in trident_update_ptr, xmms 1.0.1 no longer uses 100% CPU
- * v0.14.2 Mar 29 2000 Ching-Ling Lee
- * Add clear to silence advance in trident_update_ptr
- * fix invalid data of the end of the sound
- * v0.14.1 Mar 24 2000 Ching-Ling Lee
- * ALi 5451 support added, playback and recording O.K.
- * ALi 5451 originally developed and structured based on sonicvibes, and
- * suggested to merge into this file by Alan Cox.
- * v0.14 Mar 15 2000 Ollie Lho
- * 5.1 channel output support with channel binding. What's the Matrix ?
- * v0.13.1 Mar 10 2000 Ollie Lho
- * few minor bugs on dual codec support, needs more testing
- * v0.13 Mar 03 2000 Ollie Lho
- * new pci_* for 2.4 kernel, back ported to 2.2
- * v0.12 Feb 23 2000 Ollie Lho
- * Preliminary Recording support
- * v0.11.2 Feb 19 2000 Ollie Lho
- * removed incomplete full-dulplex support
- * v0.11.1 Jan 28 2000 Ollie Lho
- * small bug in setting sample rate for 4d-nx (reported by Aaron)
- * v0.11 Jan 27 2000 Ollie Lho
- * DMA bug, scheduler latency, second try
- * v0.10 Jan 24 2000 Ollie Lho
- * DMA bug fixed, found kernel scheduling problem
- * v0.09 Jan 20 2000 Ollie Lho
- * Clean up of channel register access routine (prepare for channel binding)
- * v0.08 Jan 14 2000 Ollie Lho
- * Isolation of AC97 codec code
- * v0.07 Jan 13 2000 Ollie Lho
- * Get rid of ugly old low level access routines (e.g. CHRegs.lp****)
- * v0.06 Jan 11 2000 Ollie Lho
- * Preliminary support for dual (more ?) AC97 codecs
- * v0.05 Jan 08 2000 Luca Montecchiani <m.luca@iname.com>
- * adapt to 2.3.x new __setup/__init call
- * v0.04 Dec 31 1999 Ollie Lho
- * Multiple Open, using Middle Loop Interrupt to smooth playback
- * v0.03 Dec 24 1999 Ollie Lho
- * mem leak in prog_dmabuf and dealloc_dmabuf removed
- * v0.02 Dec 15 1999 Ollie Lho
- * SiS 7018 support added, playback O.K.
- * v0.01 Alan Cox et. al.
- * Initial Release in kernel 2.3.30, does not work
- *
- * ToDo
- * Clean up of low level channel register access code. (done)
- * Fix the bug on dma buffer management in update_ptr, read/write, drain_dac (done)
- * Dual AC97 codecs support (done)
- * Recording support (done)
- * Mmap support
- * "Channel Binding" ioctl extension (done)
- * new pci device driver interface for 2.4 kernel (done)
- *
- * Lock order (high->low)
- * lock - hardware lock
- * open_mutex - guard opens
- * sem - guard dmabuf, write re-entry etc
- */
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ctype.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/spinlock.h>
-#include <linux/ac97_codec.h>
-#include <linux/bitops.h>
-#include <linux/proc_fs.h>
-#include <linux/interrupt.h>
-#include <linux/pm.h>
-#include <linux/gameport.h>
-#include <linux/kernel.h>
-#include <linux/mutex.h>
-#include <linux/mm.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#if defined(CONFIG_ALPHA_NAUTILUS) || defined(CONFIG_ALPHA_GENERIC)
-#include <asm/hwrpb.h>
-#endif
-
-#include "trident.h"
-
-#define DRIVER_VERSION "0.14.10j-2.6"
-
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-#define SUPPORT_JOYSTICK 1
-#endif
-
-/* magic numbers to protect our data structures */
-#define TRIDENT_CARD_MAGIC 0x5072696E /* "Prin" */
-#define TRIDENT_STATE_MAGIC 0x63657373 /* "cess" */
-
-#define TRIDENT_DMA_MASK 0x3fffffff /* DMA buffer mask for pci_alloc_consist */
-#define ALI_DMA_MASK 0x7fffffff /* ALI Tridents have 31-bit DMA. Wow. */
-
-#define NR_HW_CH 32
-
-/* maximum number of AC97 codecs connected, AC97 2.0 defined 4, but 7018 and 4D-NX only
- have 2 SDATA_IN lines (currently) */
-#define NR_AC97 2
-
-/* minor number of /dev/swmodem (temporary, experimental) */
-#define SND_DEV_SWMODEM 7
-
-static const unsigned ali_multi_channels_5_1[] = {
- /*ALI_SURR_LEFT_CHANNEL, ALI_SURR_RIGHT_CHANNEL, */
- ALI_CENTER_CHANNEL,
- ALI_LEF_CHANNEL,
- ALI_SURR_LEFT_CHANNEL,
- ALI_SURR_RIGHT_CHANNEL
-};
-
-static const unsigned sample_size[] = { 1, 2, 2, 4 };
-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
-
-static const char invalid_magic[] = KERN_CRIT "trident: invalid magic value in %s\n";
-
-enum {
- TRIDENT_4D_DX = 0,
- TRIDENT_4D_NX,
- SIS_7018,
- ALI_5451,
- CYBER5050
-};
-
-static char *card_names[] = {
- "Trident 4DWave DX",
- "Trident 4DWave NX",
- "SiS 7018 PCI Audio",
- "ALi Audio Accelerator",
- "Tvia/IGST CyberPro 5050"
-};
-
-static struct pci_device_id trident_pci_tbl[] = {
- {PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX),
- PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, TRIDENT_4D_DX},
- {PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX),
- 0, 0, TRIDENT_4D_NX},
- {PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7018), 0, 0, SIS_7018},
- {PCI_DEVICE(PCI_VENDOR_ID_ALI, PCI_DEVICE_ID_ALI_5451), 0, 0, ALI_5451},
- {PCI_DEVICE(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5050),
- 0, 0, CYBER5050},
- {0,}
-};
-
-MODULE_DEVICE_TABLE(pci, trident_pci_tbl);
-
-/* "software" or virtual channel, an instance of opened /dev/dsp */
-struct trident_state {
- unsigned int magic;
- struct trident_card *card; /* Card info */
-
- /* file mode */
- mode_t open_mode;
-
- /* virtual channel number */
- int virt;
-
- struct dmabuf {
- /* wave sample stuff */
- unsigned int rate;
- unsigned char fmt, enable;
-
- /* hardware channel */
- struct trident_channel *channel;
-
- /* OSS buffer management stuff */
- void *rawbuf;
- dma_addr_t dma_handle;
- unsigned buforder;
- unsigned numfrag;
- unsigned fragshift;
-
- /* our buffer acts like a circular ring */
- unsigned hwptr; /* where dma last started, updated by update_ptr */
- unsigned swptr; /* where driver last clear/filled, updated by read/write */
- int count; /* bytes to be comsumed or been generated by dma machine */
- unsigned total_bytes; /* total bytes dmaed by hardware */
-
- unsigned error; /* number of over/underruns */
- /* put process on wait queue when no more space in buffer */
- 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 update_flag;
- unsigned ossfragshift;
- int ossmaxfrags;
- unsigned subdivision;
-
- } dmabuf;
-
- /* 5.1 channels */
- struct trident_state *other_states[4];
- int multi_channels_adjust_count;
- unsigned chans_num;
- unsigned long fmt_flag;
- /* Guard against mmap/write/read races */
- struct mutex sem;
-
-};
-
-/* hardware channels */
-struct trident_channel {
- int num; /* channel number */
- u32 lba; /* Loop Begine Address, where dma buffer starts */
- u32 eso; /* End Sample Offset, wehre dma buffer ends */
- /* (in the unit of samples) */
- u32 delta; /* delta value, sample rate / 48k for playback, */
- /* 48k/sample rate for recording */
- u16 attribute; /* control where PCM data go and come */
- u16 fm_vol;
- u32 control; /* signed/unsigned, 8/16 bits, mono/stereo */
-};
-
-struct trident_pcm_bank_address {
- u32 start;
- u32 stop;
- u32 aint;
- u32 aint_en;
-};
-
-static struct trident_pcm_bank_address bank_a_addrs = {
- T4D_START_A,
- T4D_STOP_A,
- T4D_AINT_A,
- T4D_AINTEN_A
-};
-
-static struct trident_pcm_bank_address bank_b_addrs = {
- T4D_START_B,
- T4D_STOP_B,
- T4D_AINT_B,
- T4D_AINTEN_B
-};
-
-struct trident_pcm_bank {
- /* register addresses to control bank operations */
- struct trident_pcm_bank_address *addresses;
- /* each bank has 32 channels */
- u32 bitmap; /* channel allocation bitmap */
- struct trident_channel channels[32];
-};
-
-struct trident_card {
- unsigned int magic;
-
- /* We keep trident cards in a linked list */
- struct trident_card *next;
-
- /* single open lock mechanism, only used for recording */
- struct mutex open_mutex;
-
- /* The trident has a certain amount of cross channel interaction
- so we use a single per card lock */
- spinlock_t lock;
-
- /* PCI device stuff */
- struct pci_dev *pci_dev;
- u16 pci_id;
- u8 revision;
-
- /* soundcore stuff */
- int dev_audio;
-
- /* structures for abstraction of hardware facilities, codecs, */
- /* banks and channels */
- struct ac97_codec *ac97_codec[NR_AC97];
- struct trident_pcm_bank banks[NR_BANKS];
- struct trident_state *states[NR_HW_CH];
-
- /* hardware resources */
- unsigned long iobase;
- u32 irq;
-
- /* Function support */
- struct trident_channel *(*alloc_pcm_channel) (struct trident_card *);
- struct trident_channel *(*alloc_rec_pcm_channel) (struct trident_card *);
- void (*free_pcm_channel) (struct trident_card *, unsigned int chan);
- void (*address_interrupt) (struct trident_card *);
-
- /* Added by Matt Wu 01-05-2001 for spdif in */
- int multi_channel_use_count;
- int rec_channel_use_count;
- u16 mixer_regs[64][NR_AC97]; /* Made card local by Alan */
- int mixer_regs_ready;
-
- /* Added for hardware volume control */
- int hwvolctl;
- struct timer_list timer;
-
- /* Game port support */
- struct gameport *gameport;
-};
-
-enum dmabuf_mode {
- DM_PLAYBACK = 0,
- DM_RECORD
-};
-
-/* table to map from CHANNELMASK to channel attribute for SiS 7018 */
-static u16 mask2attr[] = {
- PCM_LR, PCM_LR, SURR_LR, CENTER_LFE,
- HSET, MIC, MODEM_LINE1, MODEM_LINE2,
- I2S_LR, SPDIF_LR
-};
-
-/* table to map from channel attribute to CHANNELMASK for SiS 7018 */
-static int attr2mask[] = {
- DSP_BIND_MODEM1, DSP_BIND_MODEM2, DSP_BIND_FRONT, DSP_BIND_HANDSET,
- DSP_BIND_I2S, DSP_BIND_CENTER_LFE, DSP_BIND_SURR, DSP_BIND_SPDIF
-};
-
-/* Added by Matt Wu 01-05-2001 for spdif in */
-static int ali_close_multi_channels(void);
-static void ali_delay(struct trident_card *card, int interval);
-static void ali_detect_spdif_rate(struct trident_card *card);
-
-static void ali_ac97_write(struct ac97_codec *codec, u8 reg, u16 val);
-static u16 ali_ac97_read(struct ac97_codec *codec, u8 reg);
-
-static struct trident_card *devs;
-
-static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val);
-static u16 trident_ac97_get(struct ac97_codec *codec, u8 reg);
-
-static int trident_open_mixdev(struct inode *inode, struct file *file);
-static int trident_ioctl_mixdev(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
-
-static void ali_ac97_set(struct trident_card *card, int secondary, u8 reg, u16 val);
-static u16 ali_ac97_get(struct trident_card *card, int secondary, u8 reg);
-static void ali_set_spdif_out_rate(struct trident_card *card, unsigned int rate);
-static void ali_enable_special_channel(struct trident_state *stat);
-static struct trident_channel *ali_alloc_rec_pcm_channel(struct trident_card *card);
-static struct trident_channel *ali_alloc_pcm_channel(struct trident_card *card);
-static void ali_free_pcm_channel(struct trident_card *card, unsigned int channel);
-static int ali_setup_multi_channels(struct trident_card *card, int chan_nums);
-static unsigned int ali_get_spdif_in_rate(struct trident_card *card);
-static void ali_setup_spdif_in(struct trident_card *card);
-static void ali_disable_spdif_in(struct trident_card *card);
-static void ali_disable_special_channel(struct trident_card *card, int ch);
-static void ali_setup_spdif_out(struct trident_card *card, int flag);
-static int ali_write_5_1(struct trident_state *state,
- const char __user *buffer,
- int cnt_for_multi_channel, unsigned int *copy_count,
- unsigned int *state_cnt);
-static int ali_allocate_other_states_resources(struct trident_state *state,
- int chan_nums);
-static void ali_free_other_states_resources(struct trident_state *state);
-
-#define seek_offset(dma_ptr, buffer, cnt, offset, copy_count) do { \
- (dma_ptr) += (offset); \
- (buffer) += (offset); \
- (cnt) -= (offset); \
- (copy_count) += (offset); \
-} while (0)
-
-static inline int lock_set_fmt(struct trident_state* state)
-{
- if (test_and_set_bit(0, &state->fmt_flag))
- return -EFAULT;
-
- return 0;
-}
-
-static inline void unlock_set_fmt(struct trident_state* state)
-{
- clear_bit(0, &state->fmt_flag);
-}
-
-static int
-trident_enable_loop_interrupts(struct trident_card *card)
-{
- u32 global_control;
-
- global_control = inl(TRID_REG(card, T4D_LFO_GC_CIR));
-
- switch (card->pci_id) {
- case PCI_DEVICE_ID_SI_7018:
- global_control |= (ENDLP_IE | MIDLP_IE | BANK_B_EN);
- break;
- case PCI_DEVICE_ID_ALI_5451:
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
- case PCI_DEVICE_ID_INTERG_5050:
- global_control |= (ENDLP_IE | MIDLP_IE);
- break;
- default:
- return 0;
- }
-
- outl(global_control, TRID_REG(card, T4D_LFO_GC_CIR));
-
- pr_debug("trident: Enable Loop Interrupts, globctl = 0x%08X\n",
- inl(TRID_REG(card, T4D_LFO_GC_CIR)));
-
- return 1;
-}
-
-static int
-trident_disable_loop_interrupts(struct trident_card *card)
-{
- u32 global_control;
-
- global_control = inl(TRID_REG(card, T4D_LFO_GC_CIR));
- global_control &= ~(ENDLP_IE | MIDLP_IE);
- outl(global_control, TRID_REG(card, T4D_LFO_GC_CIR));
-
- pr_debug("trident: Disabled Loop Interrupts, globctl = 0x%08X\n",
- global_control);
-
- return 1;
-}
-
-static void
-trident_enable_voice_irq(struct trident_card *card, unsigned int channel)
-{
- unsigned int mask = 1 << (channel & 0x1f);
- struct trident_pcm_bank *bank = &card->banks[channel >> 5];
- u32 reg, addr = bank->addresses->aint_en;
-
- reg = inl(TRID_REG(card, addr));
- reg |= mask;
- outl(reg, TRID_REG(card, addr));
-
-#ifdef DEBUG
- reg = inl(TRID_REG(card, addr));
- pr_debug("trident: enabled IRQ on channel %d, %s = 0x%08x(addr:%X)\n",
- channel, addr == T4D_AINTEN_B ? "AINTEN_B" : "AINTEN_A",
- reg, addr);
-#endif /* DEBUG */
-}
-
-static void
-trident_disable_voice_irq(struct trident_card *card, unsigned int channel)
-{
- unsigned int mask = 1 << (channel & 0x1f);
- struct trident_pcm_bank *bank = &card->banks[channel >> 5];
- u32 reg, addr = bank->addresses->aint_en;
-
- reg = inl(TRID_REG(card, addr));
- reg &= ~mask;
- outl(reg, TRID_REG(card, addr));
-
- /* Ack the channel in case the interrupt was set before we disable it. */
- outl(mask, TRID_REG(card, bank->addresses->aint));
-
-#ifdef DEBUG
- reg = inl(TRID_REG(card, addr));
- pr_debug("trident: disabled IRQ on channel %d, %s = 0x%08x(addr:%X)\n",
- channel, addr == T4D_AINTEN_B ? "AINTEN_B" : "AINTEN_A",
- reg, addr);
-#endif /* DEBUG */
-}
-
-static void
-trident_start_voice(struct trident_card *card, unsigned int channel)
-{
- unsigned int mask = 1 << (channel & 0x1f);
- struct trident_pcm_bank *bank = &card->banks[channel >> 5];
- u32 addr = bank->addresses->start;
-
-#ifdef DEBUG
- u32 reg;
-#endif /* DEBUG */
-
- outl(mask, TRID_REG(card, addr));
-
-#ifdef DEBUG
- reg = inl(TRID_REG(card, addr));
- pr_debug("trident: start voice on channel %d, %s = 0x%08x(addr:%X)\n",
- channel, addr == T4D_START_B ? "START_B" : "START_A",
- reg, addr);
-#endif /* DEBUG */
-}
-
-static void
-trident_stop_voice(struct trident_card *card, unsigned int channel)
-{
- unsigned int mask = 1 << (channel & 0x1f);
- struct trident_pcm_bank *bank = &card->banks[channel >> 5];
- u32 addr = bank->addresses->stop;
-
-#ifdef DEBUG
- u32 reg;
-#endif /* DEBUG */
-
- outl(mask, TRID_REG(card, addr));
-
-#ifdef DEBUG
- reg = inl(TRID_REG(card, addr));
- pr_debug("trident: stop voice on channel %d, %s = 0x%08x(addr:%X)\n",
- channel, addr == T4D_STOP_B ? "STOP_B" : "STOP_A",
- reg, addr);
-#endif /* DEBUG */
-}
-
-static u32
-trident_get_interrupt_mask(struct trident_card *card, unsigned int channel)
-{
- struct trident_pcm_bank *bank = &card->banks[channel];
- u32 addr = bank->addresses->aint;
- return inl(TRID_REG(card, addr));
-}
-
-static int
-trident_check_channel_interrupt(struct trident_card *card, unsigned int channel)
-{
- unsigned int mask = 1 << (channel & 0x1f);
- u32 reg = trident_get_interrupt_mask(card, channel >> 5);
-
-#ifdef DEBUG
- if (reg & mask)
- pr_debug("trident: channel %d has interrupt, %s = 0x%08x\n",
- channel, reg == T4D_AINT_B ? "AINT_B" : "AINT_A",
- reg);
-#endif /* DEBUG */
- return (reg & mask) ? 1 : 0;
-}
-
-static void
-trident_ack_channel_interrupt(struct trident_card *card, unsigned int channel)
-{
- unsigned int mask = 1 << (channel & 0x1f);
- struct trident_pcm_bank *bank = &card->banks[channel >> 5];
- u32 reg, addr = bank->addresses->aint;
-
- reg = inl(TRID_REG(card, addr));
- reg &= mask;
- outl(reg, TRID_REG(card, addr));
-
-#ifdef DEBUG
- reg = inl(TRID_REG(card, T4D_AINT_B));
- pr_debug("trident: Ack channel %d interrupt, AINT_B = 0x%08x\n",
- channel, reg);
-#endif /* DEBUG */
-}
-
-static struct trident_channel *
-trident_alloc_pcm_channel(struct trident_card *card)
-{
- struct trident_pcm_bank *bank;
- int idx;
-
- bank = &card->banks[BANK_B];
-
- for (idx = 31; idx >= 0; idx--) {
- if (!(bank->bitmap & (1 << idx))) {
- struct trident_channel *channel = &bank->channels[idx];
- bank->bitmap |= 1 << idx;
- channel->num = idx + 32;
- return channel;
- }
- }
-
- /* no more free channels available */
- printk(KERN_ERR "trident: no more channels available on Bank B.\n");
- return NULL;
-}
-
-static void
-trident_free_pcm_channel(struct trident_card *card, unsigned int channel)
-{
- int bank;
- unsigned char b;
-
- if (channel < 31 || channel > 63)
- return;
-
- if (card->pci_id == PCI_DEVICE_ID_TRIDENT_4DWAVE_DX ||
- card->pci_id == PCI_DEVICE_ID_TRIDENT_4DWAVE_NX) {
- b = inb(TRID_REG(card, T4D_REC_CH));
- if ((b & ~0x80) == channel)
- outb(0x0, TRID_REG(card, T4D_REC_CH));
- }
-
- bank = channel >> 5;
- channel = channel & 0x1f;
-
- card->banks[bank].bitmap &= ~(1 << (channel));
-}
-
-static struct trident_channel *
-cyber_alloc_pcm_channel(struct trident_card *card)
-{
- struct trident_pcm_bank *bank;
- int idx;
-
- /* The cyberpro 5050 has only 32 voices and one bank */
- /* .. at least they are not documented (if you want to call that
- * crap documentation), perhaps broken ? */
-
- bank = &card->banks[BANK_A];
-
- for (idx = 31; idx >= 0; idx--) {
- if (!(bank->bitmap & (1 << idx))) {
- struct trident_channel *channel = &bank->channels[idx];
- bank->bitmap |= 1 << idx;
- channel->num = idx;
- return channel;
- }
- }
-
- /* no more free channels available */
- printk(KERN_ERR "cyberpro5050: no more channels available on Bank A.\n");
- return NULL;
-}
-
-static void
-cyber_free_pcm_channel(struct trident_card *card, unsigned int channel)
-{
- if (channel > 31)
- return;
- card->banks[BANK_A].bitmap &= ~(1 << (channel));
-}
-
-static inline void
-cyber_outidx(int port, int idx, int data)
-{
- outb(idx, port);
- outb(data, port + 1);
-}
-
-static inline int
-cyber_inidx(int port, int idx)
-{
- outb(idx, port);
- return inb(port + 1);
-}
-
-static int
-cyber_init_ritual(struct trident_card *card)
-{
- /* some black magic, taken from SDK samples */
- /* remove this and nothing will work */
- int portDat;
- int ret = 0;
- unsigned long flags;
-
- /*
- * Keep interrupts off for the configure - we don't want to
- * clash with another cyberpro config event
- */
-
- spin_lock_irqsave(&card->lock, flags);
- portDat = cyber_inidx(CYBER_PORT_AUDIO, CYBER_IDX_AUDIO_ENABLE);
- /* enable, if it was disabled */
- if ((portDat & CYBER_BMSK_AUENZ) != CYBER_BMSK_AUENZ_ENABLE) {
- printk(KERN_INFO "cyberpro5050: enabling audio controller\n");
- cyber_outidx(CYBER_PORT_AUDIO, CYBER_IDX_AUDIO_ENABLE,
- portDat | CYBER_BMSK_AUENZ_ENABLE);
- /* check again if hardware is enabled now */
- portDat = cyber_inidx(CYBER_PORT_AUDIO, CYBER_IDX_AUDIO_ENABLE);
- }
- if ((portDat & CYBER_BMSK_AUENZ) != CYBER_BMSK_AUENZ_ENABLE) {
- printk(KERN_ERR "cyberpro5050: initAudioAccess: no success\n");
- ret = -1;
- } else {
- cyber_outidx(CYBER_PORT_AUDIO, CYBER_IDX_IRQ_ENABLE,
- CYBER_BMSK_AUDIO_INT_ENABLE);
- cyber_outidx(CYBER_PORT_AUDIO, 0xbf, 0x01);
- cyber_outidx(CYBER_PORT_AUDIO, 0xba, 0x20);
- cyber_outidx(CYBER_PORT_AUDIO, 0xbb, 0x08);
- cyber_outidx(CYBER_PORT_AUDIO, 0xbf, 0x02);
- cyber_outidx(CYBER_PORT_AUDIO, 0xb3, 0x06);
- cyber_outidx(CYBER_PORT_AUDIO, 0xbf, 0x00);
- }
- spin_unlock_irqrestore(&card->lock, flags);
- return ret;
-}
-
-/* called with spin lock held */
-
-static int
-trident_load_channel_registers(struct trident_card *card, u32 * data,
- unsigned int channel)
-{
- int i;
-
- if (channel > 63)
- return 0;
-
- /* select hardware channel to write */
- outb(channel, TRID_REG(card, T4D_LFO_GC_CIR));
-
- /* Output the channel registers, but don't write register
- three to an ALI chip. */
- for (i = 0; i < CHANNEL_REGS; i++) {
- if (i == 3 && card->pci_id == PCI_DEVICE_ID_ALI_5451)
- continue;
- outl(data[i], TRID_REG(card, CHANNEL_START + 4 * i));
- }
- if (card->pci_id == PCI_DEVICE_ID_ALI_5451 ||
- card->pci_id == PCI_DEVICE_ID_INTERG_5050) {
- outl(ALI_EMOD_Still, TRID_REG(card, ALI_EBUF1));
- outl(ALI_EMOD_Still, TRID_REG(card, ALI_EBUF2));
- }
- return 1;
-}
-
-/* called with spin lock held */
-static int
-trident_write_voice_regs(struct trident_state *state)
-{
- unsigned int data[CHANNEL_REGS + 1];
- struct trident_channel *channel;
-
- channel = state->dmabuf.channel;
-
- data[1] = channel->lba;
- data[4] = channel->control;
-
- switch (state->card->pci_id) {
- case PCI_DEVICE_ID_ALI_5451:
- data[0] = 0; /* Current Sample Offset */
- data[2] = (channel->eso << 16) | (channel->delta & 0xffff);
- data[3] = 0;
- break;
- case PCI_DEVICE_ID_SI_7018:
- case PCI_DEVICE_ID_INTERG_5050:
- data[0] = 0; /* Current Sample Offset */
- data[2] = (channel->eso << 16) | (channel->delta & 0xffff);
- data[3] = (channel->attribute << 16) | (channel->fm_vol & 0xffff);
- break;
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
- data[0] = 0; /* Current Sample Offset */
- data[2] = (channel->eso << 16) | (channel->delta & 0xffff);
- data[3] = channel->fm_vol & 0xffff;
- break;
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
- data[0] = (channel->delta << 24);
- data[2] = ((channel->delta << 16) & 0xff000000) |
- (channel->eso & 0x00ffffff);
- data[3] = channel->fm_vol & 0xffff;
- break;
- default:
- return 0;
- }
-
- return trident_load_channel_registers(state->card, data, channel->num);
-}
-
-static int
-compute_rate_play(u32 rate)
-{
- int delta;
- /* We special case 44100 and 8000 since rounding with the equation
- does not give us an accurate enough value. For 11025 and 22050
- the equation gives us the best answer. All other frequencies will
- also use the equation. JDW */
- if (rate == 44100)
- delta = 0xeb3;
- else if (rate == 8000)
- delta = 0x2ab;
- else if (rate == 48000)
- delta = 0x1000;
- else
- delta = (((rate << 12) + rate) / 48000) & 0x0000ffff;
- return delta;
-}
-
-static int
-compute_rate_rec(u32 rate)
-{
- int delta;
-
- if (rate == 44100)
- delta = 0x116a;
- else if (rate == 8000)
- delta = 0x6000;
- else if (rate == 48000)
- delta = 0x1000;
- else
- delta = ((48000 << 12) / rate) & 0x0000ffff;
-
- return delta;
-}
-
-/* set playback sample rate */
-static unsigned int
-trident_set_dac_rate(struct trident_state *state, unsigned int rate)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 4000)
- rate = 4000;
-
- dmabuf->rate = rate;
- dmabuf->channel->delta = compute_rate_play(rate);
-
- trident_write_voice_regs(state);
-
- pr_debug("trident: called trident_set_dac_rate : rate = %d\n", rate);
-
- return rate;
-}
-
-/* set recording sample rate */
-static unsigned int
-trident_set_adc_rate(struct trident_state *state, unsigned int rate)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 4000)
- rate = 4000;
-
- dmabuf->rate = rate;
- dmabuf->channel->delta = compute_rate_rec(rate);
-
- trident_write_voice_regs(state);
-
- pr_debug("trident: called trident_set_adc_rate : rate = %d\n", rate);
-
- return rate;
-}
-
-/* prepare channel attributes for playback */
-static void
-trident_play_setup(struct trident_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct trident_channel *channel = dmabuf->channel;
-
- channel->lba = dmabuf->dma_handle;
- channel->delta = compute_rate_play(dmabuf->rate);
-
- channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt];
- channel->eso -= 1;
-
- if (state->card->pci_id != PCI_DEVICE_ID_SI_7018) {
- channel->attribute = 0;
- if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451) {
- if ((channel->num == ALI_SPDIF_IN_CHANNEL) ||
- (channel->num == ALI_PCM_IN_CHANNEL))
- ali_disable_special_channel(state->card, channel->num);
- else if ((inl(TRID_REG(state->card, ALI_GLOBAL_CONTROL))
- & ALI_SPDIF_OUT_CH_ENABLE)
- && (channel->num == ALI_SPDIF_OUT_CHANNEL)) {
- ali_set_spdif_out_rate(state->card,
- state->dmabuf.rate);
- state->dmabuf.channel->delta = 0x1000;
- }
- }
- }
-
- channel->fm_vol = 0x0;
-
- channel->control = CHANNEL_LOOP;
- if (dmabuf->fmt & TRIDENT_FMT_16BIT) {
- /* 16-bits */
- channel->control |= CHANNEL_16BITS;
- /* signed */
- channel->control |= CHANNEL_SIGNED;
- }
- if (dmabuf->fmt & TRIDENT_FMT_STEREO)
- /* stereo */
- channel->control |= CHANNEL_STEREO;
-
- pr_debug("trident: trident_play_setup, LBA = 0x%08x, Delta = 0x%08x, "
- "ESO = 0x%08x, Control = 0x%08x\n", channel->lba,
- channel->delta, channel->eso, channel->control);
-
- trident_write_voice_regs(state);
-}
-
-/* prepare channel attributes for recording */
-static void
-trident_rec_setup(struct trident_state *state)
-{
- u16 w;
- u8 bval;
-
- struct trident_card *card = state->card;
- struct dmabuf *dmabuf = &state->dmabuf;
- struct trident_channel *channel = dmabuf->channel;
- unsigned int rate;
-
- /* Enable AC-97 ADC (capture) */
- switch (card->pci_id) {
- case PCI_DEVICE_ID_ALI_5451:
- ali_enable_special_channel(state);
- break;
- case PCI_DEVICE_ID_SI_7018:
- /* for 7018, the ac97 is always in playback/record (duplex) mode */
- break;
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
- w = inb(TRID_REG(card, DX_ACR2_AC97_COM_STAT));
- outb(w | 0x48, TRID_REG(card, DX_ACR2_AC97_COM_STAT));
- /* enable and set record channel */
- outb(0x80 | channel->num, TRID_REG(card, T4D_REC_CH));
- break;
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
- w = inw(TRID_REG(card, T4D_MISCINT));
- outw(w | 0x1000, TRID_REG(card, T4D_MISCINT));
- /* enable and set record channel */
- outb(0x80 | channel->num, TRID_REG(card, T4D_REC_CH));
- break;
- case PCI_DEVICE_ID_INTERG_5050:
- /* don't know yet, using special channel 22 in GC1(0xd4)? */
- break;
- default:
- return;
- }
-
- channel->lba = dmabuf->dma_handle;
- channel->delta = compute_rate_rec(dmabuf->rate);
- if ((card->pci_id == PCI_DEVICE_ID_ALI_5451) &&
- (channel->num == ALI_SPDIF_IN_CHANNEL)) {
- rate = ali_get_spdif_in_rate(card);
- if (rate == 0) {
- printk(KERN_WARNING "trident: ALi 5451 "
- "S/PDIF input setup error!\n");
- rate = 48000;
- }
- bval = inb(TRID_REG(card, ALI_SPDIF_CTRL));
- if (bval & 0x10) {
- outb(bval, TRID_REG(card, ALI_SPDIF_CTRL));
- printk(KERN_WARNING "trident: cleared ALi "
- "5451 S/PDIF parity error flag.\n");
- }
-
- if (rate != 48000)
- channel->delta = ((rate << 12) / dmabuf->rate) & 0x0000ffff;
- }
-
- channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt];
- channel->eso -= 1;
-
- if (state->card->pci_id != PCI_DEVICE_ID_SI_7018) {
- channel->attribute = 0;
- }
-
- channel->fm_vol = 0x0;
-
- channel->control = CHANNEL_LOOP;
- if (dmabuf->fmt & TRIDENT_FMT_16BIT) {
- /* 16-bits */
- channel->control |= CHANNEL_16BITS;
- /* signed */
- channel->control |= CHANNEL_SIGNED;
- }
- if (dmabuf->fmt & TRIDENT_FMT_STEREO)
- /* stereo */
- channel->control |= CHANNEL_STEREO;
-
- pr_debug("trident: trident_rec_setup, LBA = 0x%08x, Delat = 0x%08x, "
- "ESO = 0x%08x, Control = 0x%08x\n", channel->lba,
- channel->delta, channel->eso, channel->control);
-
- trident_write_voice_regs(state);
-}
-
-/* get current playback/recording dma buffer pointer (byte offset from LBA),
- called with spinlock held! */
-static inline unsigned
-trident_get_dma_addr(struct trident_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- u32 cso;
-
- if (!dmabuf->enable)
- return 0;
-
- outb(dmabuf->channel->num, TRID_REG(state->card, T4D_LFO_GC_CIR));
-
- switch (state->card->pci_id) {
- case PCI_DEVICE_ID_ALI_5451:
- case PCI_DEVICE_ID_SI_7018:
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
- case PCI_DEVICE_ID_INTERG_5050:
- /* 16 bits ESO, CSO for 7018 and DX */
- cso = inw(TRID_REG(state->card, CH_DX_CSO_ALPHA_FMS + 2));
- break;
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
- /* 24 bits ESO, CSO for NX */
- cso = inl(TRID_REG(state->card, CH_NX_DELTA_CSO)) & 0x00ffffff;
- break;
- default:
- return 0;
- }
-
- pr_debug("trident: trident_get_dma_addr: chip reported channel: %d, "
- "cso = 0x%04x\n", dmabuf->channel->num, cso);
-
- /* ESO and CSO are in units of Samples, convert to byte offset */
- cso <<= sample_shift[dmabuf->fmt];
-
- return (cso % dmabuf->dmasize);
-}
-
-/* Stop recording (lock held) */
-static inline void
-__stop_adc(struct trident_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned int chan_num = dmabuf->channel->num;
- struct trident_card *card = state->card;
-
- dmabuf->enable &= ~ADC_RUNNING;
- trident_stop_voice(card, chan_num);
- trident_disable_voice_irq(card, chan_num);
-}
-
-static void
-stop_adc(struct trident_state *state)
-{
- struct trident_card *card = state->card;
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
- __stop_adc(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static void
-start_adc(struct trident_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned int chan_num = dmabuf->channel->num;
- struct trident_card *card = state->card;
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
- if ((dmabuf->mapped ||
- dmabuf->count < (signed) dmabuf->dmasize) &&
- dmabuf->ready) {
- dmabuf->enable |= ADC_RUNNING;
- trident_enable_voice_irq(card, chan_num);
- trident_start_voice(card, chan_num);
- }
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/* stop playback (lock held) */
-static inline void
-__stop_dac(struct trident_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned int chan_num = dmabuf->channel->num;
- struct trident_card *card = state->card;
-
- dmabuf->enable &= ~DAC_RUNNING;
- trident_stop_voice(card, chan_num);
- if (state->chans_num == 6) {
- trident_stop_voice(card, state->other_states[0]->
- dmabuf.channel->num);
- trident_stop_voice(card, state->other_states[1]->
- dmabuf.channel->num);
- trident_stop_voice(card, state->other_states[2]->
- dmabuf.channel->num);
- trident_stop_voice(card, state->other_states[3]->
- dmabuf.channel->num);
- }
- trident_disable_voice_irq(card, chan_num);
-}
-
-static void
-stop_dac(struct trident_state *state)
-{
- struct trident_card *card = state->card;
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
- __stop_dac(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static void
-start_dac(struct trident_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned int chan_num = dmabuf->channel->num;
- struct trident_card *card = state->card;
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
- if ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) {
- dmabuf->enable |= DAC_RUNNING;
- trident_enable_voice_irq(card, chan_num);
- trident_start_voice(card, chan_num);
- if (state->chans_num == 6) {
- trident_start_voice(card, state->other_states[0]->
- dmabuf.channel->num);
- trident_start_voice(card, state->other_states[1]->
- dmabuf.channel->num);
- trident_start_voice(card, state->other_states[2]->
- dmabuf.channel->num);
- trident_start_voice(card, state->other_states[3]->
- dmabuf.channel->num);
- }
- }
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-/* alloc a DMA buffer of with a buffer of this order */
-static int
-alloc_dmabuf(struct dmabuf *dmabuf, struct pci_dev *pci_dev, int order)
-{
- void *rawbuf = NULL;
- struct page *page, *pend;
-
- if (!(rawbuf = pci_alloc_consistent(pci_dev, PAGE_SIZE << order,
- &dmabuf->dma_handle)))
- return -ENOMEM;
-
- pr_debug("trident: allocated %ld (order = %d) bytes at %p\n",
- PAGE_SIZE << order, order, rawbuf);
-
- dmabuf->ready = dmabuf->mapped = 0;
- dmabuf->rawbuf = rawbuf;
- dmabuf->buforder = order;
-
- /* now mark the pages as reserved; otherwise */
- /* remap_pfn_range doesn't do what we want */
- pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
- for (page = virt_to_page(rawbuf); page <= pend; page++)
- SetPageReserved(page);
-
- return 0;
-}
-
-/* allocate the main DMA buffer, playback and recording buffer should be */
-/* allocated separately */
-static int
-alloc_main_dmabuf(struct trident_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- int order;
- int ret = -ENOMEM;
-
- /* alloc as big a chunk as we can, FIXME: is this necessary ?? */
- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
- if (!(ret = alloc_dmabuf(dmabuf, state->card->pci_dev, order)))
- return 0;
- /* else try again */
- }
- return ret;
-}
-
-/* deallocate a DMA buffer */
-static void
-dealloc_dmabuf(struct dmabuf *dmabuf, struct pci_dev *pci_dev)
-{
- struct page *page, *pend;
-
- if (dmabuf->rawbuf) {
- /* undo marking the pages as reserved */
- pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
- for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++)
- ClearPageReserved(page);
- pci_free_consistent(pci_dev, PAGE_SIZE << dmabuf->buforder,
- dmabuf->rawbuf, dmabuf->dma_handle);
- dmabuf->rawbuf = NULL;
- }
- dmabuf->mapped = dmabuf->ready = 0;
-}
-
-static int
-prog_dmabuf(struct trident_state *state, enum dmabuf_mode rec)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned bytepersec;
- struct trident_state *s = state;
- unsigned bufsize, dma_nums;
- unsigned long flags;
- int ret, i, order;
-
- if ((ret = lock_set_fmt(state)) < 0)
- return ret;
-
- if (state->chans_num == 6)
- dma_nums = 5;
- else
- dma_nums = 1;
-
- for (i = 0; i < dma_nums; i++) {
- if (i > 0) {
- s = state->other_states[i - 1];
- dmabuf = &s->dmabuf;
- dmabuf->fmt = state->dmabuf.fmt;
- dmabuf->rate = state->dmabuf.rate;
- }
-
- spin_lock_irqsave(&s->card->lock, flags);
- dmabuf->hwptr = dmabuf->swptr = dmabuf->total_bytes = 0;
- dmabuf->count = dmabuf->error = 0;
- spin_unlock_irqrestore(&s->card->lock, flags);
-
- /* allocate DMA buffer if not allocated yet */
- if (!dmabuf->rawbuf) {
- if (i == 0) {
- if ((ret = alloc_main_dmabuf(state))) {
- unlock_set_fmt(state);
- return ret;
- }
- } else {
- ret = -ENOMEM;
- order = state->dmabuf.buforder - 1;
- if (order >= DMABUF_MINORDER) {
- ret = alloc_dmabuf(dmabuf,
- state->card->pci_dev,
- order);
- }
- if (ret) {
- /* release the main DMA buffer */
- dealloc_dmabuf(&state->dmabuf, state->card->pci_dev);
- /* release the auxiliary DMA buffers */
- for (i -= 2; i >= 0; i--)
- dealloc_dmabuf(&state->other_states[i]->dmabuf,
- state->card->pci_dev);
- unlock_set_fmt(state);
- return ret;
- }
- }
- }
- /* FIXME: figure out all this OSS fragment stuff */
- bytepersec = dmabuf->rate << sample_shift[dmabuf->fmt];
- bufsize = PAGE_SIZE << dmabuf->buforder;
- if (dmabuf->ossfragshift) {
- if ((1000 << dmabuf->ossfragshift) < bytepersec)
- dmabuf->fragshift = ld2(bytepersec / 1000);
- else
- dmabuf->fragshift = dmabuf->ossfragshift;
- } else {
- /* lets hand out reasonable big ass buffers by default */
- dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT - 2);
- }
- dmabuf->numfrag = bufsize >> dmabuf->fragshift;
- while (dmabuf->numfrag < 4 && dmabuf->fragshift > 3) {
- dmabuf->fragshift--;
- dmabuf->numfrag = bufsize >> dmabuf->fragshift;
- }
- dmabuf->fragsize = 1 << dmabuf->fragshift;
- if (dmabuf->ossmaxfrags >= 4 && dmabuf->ossmaxfrags < dmabuf->numfrag)
- dmabuf->numfrag = dmabuf->ossmaxfrags;
- dmabuf->fragsamples = dmabuf->fragsize >> sample_shift[dmabuf->fmt];
- dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
-
- memset(dmabuf->rawbuf, (dmabuf->fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80,
- dmabuf->dmasize);
-
- spin_lock_irqsave(&s->card->lock, flags);
- if (rec == DM_RECORD)
- trident_rec_setup(s);
- else /* DM_PLAYBACK */
- trident_play_setup(s);
-
- spin_unlock_irqrestore(&s->card->lock, flags);
-
- /* set the ready flag for the dma buffer */
- dmabuf->ready = 1;
-
- pr_debug("trident: prog_dmabuf(%d), sample rate = %d, "
- "format = %d, numfrag = %d, fragsize = %d "
- "dmasize = %d\n", dmabuf->channel->num,
- dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
- dmabuf->fragsize, dmabuf->dmasize);
- }
- unlock_set_fmt(state);
- return 0;
-}
-
-
-static inline int prog_dmabuf_record(struct trident_state* state)
-{
- return prog_dmabuf(state, DM_RECORD);
-}
-
-static inline int prog_dmabuf_playback(struct trident_state* state)
-{
- return prog_dmabuf(state, DM_PLAYBACK);
-}
-
-/* we are doing quantum mechanics here, the buffer can only be empty, half or full filled i.e.
- |------------|------------| or |xxxxxxxxxxxx|------------| or |xxxxxxxxxxxx|xxxxxxxxxxxx|
- but we almost always get this
- |xxxxxx------|------------| or |xxxxxxxxxxxx|xxxxx-------|
- so we have to clear the tail space to "silence"
- |xxxxxx000000|------------| or |xxxxxxxxxxxx|xxxxxx000000|
-*/
-static void
-trident_clear_tail(struct trident_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned swptr;
- unsigned char silence = (dmabuf->fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80;
- unsigned int len;
- unsigned long flags;
-
- spin_lock_irqsave(&state->card->lock, flags);
- swptr = dmabuf->swptr;
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- if (swptr == 0 || swptr == dmabuf->dmasize / 2 ||
- swptr == dmabuf->dmasize)
- return;
-
- if (swptr < dmabuf->dmasize / 2)
- len = dmabuf->dmasize / 2 - swptr;
- else
- len = dmabuf->dmasize - swptr;
-
- memset(dmabuf->rawbuf + swptr, silence, len);
- if (state->card->pci_id != PCI_DEVICE_ID_ALI_5451) {
- spin_lock_irqsave(&state->card->lock, flags);
- dmabuf->swptr += len;
- dmabuf->count += len;
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
-
- /* restart the dma machine in case it is halted */
- start_dac(state);
-}
-
-static int
-drain_dac(struct trident_state *state, int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned long flags;
- unsigned long tmo;
- int count;
- unsigned long diff = 0;
-
- if (dmabuf->mapped || !dmabuf->ready)
- return 0;
-
- add_wait_queue(&dmabuf->wait, &wait);
- for (;;) {
- /* It seems that we have to set the current state to TASK_INTERRUPTIBLE
- every time to make the process really go to sleep */
- set_current_state(TASK_INTERRUPTIBLE);
-
- spin_lock_irqsave(&state->card->lock, flags);
- count = dmabuf->count;
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- if (count <= 0)
- break;
-
- if (signal_pending(current))
- break;
-
- if (nonblock) {
- remove_wait_queue(&dmabuf->wait, &wait);
- set_current_state(TASK_RUNNING);
- return -EBUSY;
- }
-
- /* No matter how much data is left in the buffer, we have to wait until
- CSO == ESO/2 or CSO == ESO when address engine interrupts */
- if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451 ||
- state->card->pci_id == PCI_DEVICE_ID_INTERG_5050) {
- diff = dmabuf->swptr - trident_get_dma_addr(state) + dmabuf->dmasize;
- diff = diff % (dmabuf->dmasize);
- tmo = (diff * HZ) / dmabuf->rate;
- } else {
- tmo = (dmabuf->dmasize * HZ) / dmabuf->rate;
- }
- tmo >>= sample_shift[dmabuf->fmt];
- if (!schedule_timeout(tmo ? tmo : 1) && tmo) {
- break;
- }
- }
- remove_wait_queue(&dmabuf->wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- return 0;
-}
-
-/* update buffer manangement pointers, especially, */
-/* dmabuf->count and dmabuf->hwptr */
-static void
-trident_update_ptr(struct trident_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned hwptr, swptr;
- int clear_cnt = 0;
- int diff;
- unsigned char silence;
- unsigned half_dmasize;
-
- /* update hardware pointer */
- hwptr = trident_get_dma_addr(state);
- diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
- dmabuf->hwptr = hwptr;
- dmabuf->total_bytes += diff;
-
- /* error handling and process wake up for ADC */
- if (dmabuf->enable == ADC_RUNNING) {
- if (dmabuf->mapped) {
- dmabuf->count -= diff;
- if (dmabuf->count >= (signed) dmabuf->fragsize)
- wake_up(&dmabuf->wait);
- } else {
- dmabuf->count += diff;
-
- if (dmabuf->count < 0 ||
- dmabuf->count > dmabuf->dmasize) {
- /* buffer underrun or buffer overrun, */
- /* we have no way to recover it here, just */
- /* stop the machine and let the process */
- /* force hwptr and swptr to sync */
- __stop_adc(state);
- dmabuf->error++;
- }
- if (dmabuf->count < (signed) dmabuf->dmasize / 2)
- wake_up(&dmabuf->wait);
- }
- }
-
- /* error handling and process wake up for DAC */
- if (dmabuf->enable == DAC_RUNNING) {
- if (dmabuf->mapped) {
- dmabuf->count += diff;
- if (dmabuf->count >= (signed) dmabuf->fragsize)
- wake_up(&dmabuf->wait);
- } else {
- dmabuf->count -= diff;
-
- if (dmabuf->count < 0 ||
- dmabuf->count > dmabuf->dmasize) {
- /* buffer underrun or buffer overrun, we have no way to recover
- it here, just stop the machine and let the process force hwptr
- and swptr to sync */
- __stop_dac(state);
- dmabuf->error++;
- } else if (!dmabuf->endcleared) {
- swptr = dmabuf->swptr;
- silence = (dmabuf->fmt & TRIDENT_FMT_16BIT ? 0 : 0x80);
- if (dmabuf->update_flag & ALI_ADDRESS_INT_UPDATE) {
- /* We must clear end data of 1/2 dmabuf if needed.
- According to 1/2 algorithm of Address Engine Interrupt,
- check the validation of the data of half dmasize. */
- half_dmasize = dmabuf->dmasize / 2;
- if ((diff = hwptr - half_dmasize) < 0)
- diff = hwptr;
- if ((dmabuf->count + diff) < half_dmasize) {
- //there is invalid data in the end of half buffer
- if ((clear_cnt = half_dmasize - swptr) < 0)
- clear_cnt += half_dmasize;
- //clear the invalid data
- memset(dmabuf->rawbuf + swptr, silence, clear_cnt);
- if (state->chans_num == 6) {
- clear_cnt = clear_cnt / 2;
- swptr = swptr / 2;
- memset(state->other_states[0]->dmabuf.rawbuf + swptr,
- silence, clear_cnt);
- memset(state->other_states[1]->dmabuf.rawbuf + swptr,
- silence, clear_cnt);
- memset(state->other_states[2]->dmabuf.rawbuf + swptr,
- silence, clear_cnt);
- memset(state->other_states[3]->dmabuf.rawbuf + swptr,
- silence, clear_cnt);
- }
- dmabuf->endcleared = 1;
- }
- } else if (dmabuf->count < (signed) dmabuf->fragsize) {
- clear_cnt = dmabuf->fragsize;
- if ((swptr + clear_cnt) > dmabuf->dmasize)
- clear_cnt = dmabuf->dmasize - swptr;
- memset(dmabuf->rawbuf + swptr, silence, clear_cnt);
- if (state->chans_num == 6) {
- clear_cnt = clear_cnt / 2;
- swptr = swptr / 2;
- memset(state->other_states[0]->dmabuf.rawbuf + swptr,
- silence, clear_cnt);
- memset(state->other_states[1]->dmabuf.rawbuf + swptr,
- silence, clear_cnt);
- memset(state->other_states[2]->dmabuf.rawbuf + swptr,
- silence, clear_cnt);
- memset(state->other_states[3]->dmabuf.rawbuf + swptr,
- silence, clear_cnt);
- }
- dmabuf->endcleared = 1;
- }
- }
- /* trident_update_ptr is called by interrupt handler or by process via
- ioctl/poll, we only wake up the waiting process when we have more
- than 1/2 buffer free (always true for interrupt handler) */
- if (dmabuf->count < (signed) dmabuf->dmasize / 2)
- wake_up(&dmabuf->wait);
- }
- }
- dmabuf->update_flag &= ~ALI_ADDRESS_INT_UPDATE;
-}
-
-static void
-trident_address_interrupt(struct trident_card *card)
-{
- int i;
- struct trident_state *state;
- unsigned int channel;
-
- /* Update the pointers for all channels we are running. */
- /* FIXME: should read interrupt status only once */
- for (i = 0; i < NR_HW_CH; i++) {
- channel = 63 - i;
- if (trident_check_channel_interrupt(card, channel)) {
- trident_ack_channel_interrupt(card, channel);
- if ((state = card->states[i]) != NULL) {
- trident_update_ptr(state);
- } else {
- printk(KERN_WARNING "trident: spurious channel "
- "irq %d.\n", channel);
- trident_stop_voice(card, channel);
- trident_disable_voice_irq(card, channel);
- }
- }
- }
-}
-
-static void
-ali_hwvol_control(struct trident_card *card, int opt)
-{
- u16 dwTemp, volume[2], mute, diff, *pVol[2];
-
- dwTemp = ali_ac97_read(card->ac97_codec[0], 0x02);
- mute = dwTemp & 0x8000;
- volume[0] = dwTemp & 0x001f;
- volume[1] = (dwTemp & 0x1f00) >> 8;
- if (volume[0] < volume[1]) {
- pVol[0] = &volume[0];
- pVol[1] = &volume[1];
- } else {
- pVol[1] = &volume[0];
- pVol[0] = &volume[1];
- }
- diff = *(pVol[1]) - *(pVol[0]);
-
- if (opt == 1) { // MUTE
- dwTemp ^= 0x8000;
- ali_ac97_write(card->ac97_codec[0],
- 0x02, dwTemp);
- } else if (opt == 2) { // Down
- if (mute)
- return;
- if (*(pVol[1]) < 0x001f) {
- (*pVol[1])++;
- *(pVol[0]) = *(pVol[1]) - diff;
- }
- dwTemp &= 0xe0e0;
- dwTemp |= (volume[0]) | (volume[1] << 8);
- ali_ac97_write(card->ac97_codec[0], 0x02, dwTemp);
- card->ac97_codec[0]->mixer_state[0] = ((32 - volume[0]) * 25 / 8) |
- (((32 - volume[1]) * 25 / 8) << 8);
- } else if (opt == 4) { // Up
- if (mute)
- return;
- if (*(pVol[0]) > 0) {
- (*pVol[0])--;
- *(pVol[1]) = *(pVol[0]) + diff;
- }
- dwTemp &= 0xe0e0;
- dwTemp |= (volume[0]) | (volume[1] << 8);
- ali_ac97_write(card->ac97_codec[0], 0x02, dwTemp);
- card->ac97_codec[0]->mixer_state[0] = ((32 - volume[0]) * 25 / 8) |
- (((32 - volume[1]) * 25 / 8) << 8);
- } else {
- /* Nothing needs doing */
- }
-}
-
-/*
- * Re-enable reporting of vol change after 0.1 seconds
- */
-
-static void
-ali_timeout(unsigned long ptr)
-{
- struct trident_card *card = (struct trident_card *) ptr;
- u16 temp = 0;
-
- /* Enable GPIO IRQ (MISCINT bit 18h) */
- temp = inw(TRID_REG(card, T4D_MISCINT + 2));
- temp |= 0x0004;
- outw(temp, TRID_REG(card, T4D_MISCINT + 2));
-}
-
-/*
- * Set up the timer to clear the vol change notification
- */
-
-static void
-ali_set_timer(struct trident_card *card)
-{
- /* Add Timer Routine to Enable GPIO IRQ */
- del_timer(&card->timer); /* Never queue twice */
- card->timer.function = ali_timeout;
- card->timer.data = (unsigned long) card;
- card->timer.expires = jiffies + HZ / 10;
- add_timer(&card->timer);
-}
-
-/*
- * Process a GPIO event
- */
-
-static void
-ali_queue_task(struct trident_card *card, int opt)
-{
- u16 temp;
-
- /* Disable GPIO IRQ (MISCINT bit 18h) */
- temp = inw(TRID_REG(card, T4D_MISCINT + 2));
- temp &= (u16) (~0x0004);
- outw(temp, TRID_REG(card, T4D_MISCINT + 2));
-
- /* Adjust the volume */
- ali_hwvol_control(card, opt);
-
- /* Set the timer for 1/10th sec */
- ali_set_timer(card);
-}
-
-static void
-cyber_address_interrupt(struct trident_card *card)
-{
- int i, irq_status;
- struct trident_state *state;
- unsigned int channel;
-
- /* Update the pointers for all channels we are running. */
- /* FIXED: read interrupt status only once */
- irq_status = inl(TRID_REG(card, T4D_AINT_A));
-
- pr_debug("cyber_address_interrupt: irq_status 0x%X\n", irq_status);
-
- for (i = 0; i < NR_HW_CH; i++) {
- channel = 31 - i;
- if (irq_status & (1 << channel)) {
- /* clear bit by writing a 1, zeroes are ignored */
- outl((1 << channel), TRID_REG(card, T4D_AINT_A));
-
- pr_debug("cyber_interrupt: channel %d\n", channel);
-
- if ((state = card->states[i]) != NULL) {
- trident_update_ptr(state);
- } else {
- printk(KERN_WARNING "cyber5050: spurious "
- "channel irq %d.\n", channel);
- trident_stop_voice(card, channel);
- trident_disable_voice_irq(card, channel);
- }
- }
- }
-}
-
-static irqreturn_t
-trident_interrupt(int irq, void *dev_id)
-{
- struct trident_card *card = (struct trident_card *) dev_id;
- u32 event;
- u32 gpio;
-
- spin_lock(&card->lock);
- event = inl(TRID_REG(card, T4D_MISCINT));
-
- pr_debug("trident: trident_interrupt called, MISCINT = 0x%08x\n",
- event);
-
- if (event & ADDRESS_IRQ) {
- card->address_interrupt(card);
- }
-
- if (card->pci_id == PCI_DEVICE_ID_ALI_5451) {
- /* GPIO IRQ (H/W Volume Control) */
- event = inl(TRID_REG(card, T4D_MISCINT));
- if (event & (1 << 25)) {
- gpio = inl(TRID_REG(card, ALI_GPIO));
- if (!timer_pending(&card->timer))
- ali_queue_task(card, gpio & 0x07);
- }
- event = inl(TRID_REG(card, T4D_MISCINT));
- outl(event | (ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW),
- TRID_REG(card, T4D_MISCINT));
- spin_unlock(&card->lock);
- return IRQ_HANDLED;
- }
-
- /* manually clear interrupt status, bad hardware design, blame T^2 */
- outl((ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW),
- TRID_REG(card, T4D_MISCINT));
- spin_unlock(&card->lock);
- return IRQ_HANDLED;
-}
-
-/* in this loop, dmabuf.count signifies the amount of data that is waiting */
-/* to be copied to the user's buffer. it is filled by the dma machine and */
-/* drained by this loop. */
-static ssize_t
-trident_read(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
-{
- struct trident_state *state = (struct trident_state *)file->private_data;
- struct dmabuf *dmabuf = &state->dmabuf;
- ssize_t ret = 0;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- pr_debug("trident: trident_read called, count = %zd\n", count);
-
- VALIDATE_STATE(state);
-
- if (dmabuf->mapped)
- return -ENXIO;
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
-
- mutex_lock(&state->sem);
- if (!dmabuf->ready && (ret = prog_dmabuf_record(state)))
- goto out;
-
- while (count > 0) {
- spin_lock_irqsave(&state->card->lock, flags);
- if (dmabuf->count > (signed) dmabuf->dmasize) {
- /* buffer overrun, we are recovering from */
- /* sleep_on_timeout, resync hwptr and swptr, */
- /* make process flush the buffer */
- dmabuf->count = dmabuf->dmasize;
- dmabuf->swptr = dmabuf->hwptr;
- }
- swptr = dmabuf->swptr;
- cnt = dmabuf->dmasize - swptr;
- if (dmabuf->count < cnt)
- cnt = dmabuf->count;
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- unsigned long tmo;
- /* buffer is empty, start the dma machine and */
- /* wait for data to be recorded */
- start_adc(state);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- goto out;
- }
-
- mutex_unlock(&state->sem);
- /* No matter how much space left in the buffer, */
- /* we have to wait until CSO == ESO/2 or CSO == ESO */
- /* when address engine interrupts */
- tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
- tmo >>= sample_shift[dmabuf->fmt];
- /* There are two situations when sleep_on_timeout returns, one is when
- the interrupt is serviced correctly and the process is waked up by
- ISR ON TIME. Another is when timeout is expired, which means that
- either interrupt is NOT serviced correctly (pending interrupt) or it
- is TOO LATE for the process to be scheduled to run (scheduler latency)
- which results in a (potential) buffer overrun. And worse, there is
- NOTHING we can do to prevent it. */
- if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
- pr_debug(KERN_ERR "trident: recording schedule timeout, "
- "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
- dmabuf->hwptr, dmabuf->swptr);
-
- /* a buffer overrun, we delay the recovery until next time the
- while loop begin and we REALLY have space to record */
- }
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- goto out;
- }
- mutex_lock(&state->sem);
- if (dmabuf->mapped) {
- if (!ret)
- ret = -ENXIO;
- goto out;
- }
- continue;
- }
-
- if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
- if (!ret)
- ret = -EFAULT;
- goto out;
- }
-
- swptr = (swptr + cnt) % dmabuf->dmasize;
-
- spin_lock_irqsave(&state->card->lock, flags);
- dmabuf->swptr = swptr;
- dmabuf->count -= cnt;
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- start_adc(state);
- }
-out:
- mutex_unlock(&state->sem);
- return ret;
-}
-
-/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to
- the soundcard. it is drained by the dma machine and filled by this loop. */
-
-static ssize_t
-trident_write(struct file *file, const char __user *buffer, size_t count, loff_t * ppos)
-{
- struct trident_state *state = (struct trident_state *)file->private_data;
- struct dmabuf *dmabuf = &state->dmabuf;
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
- unsigned int state_cnt;
- unsigned int copy_count;
- int lret; /* for lock_set_fmt */
-
- pr_debug("trident: trident_write called, count = %zd\n", count);
-
- VALIDATE_STATE(state);
-
- /*
- * Guard against an mmap or ioctl while writing
- */
-
- mutex_lock(&state->sem);
-
- if (dmabuf->mapped) {
- ret = -ENXIO;
- goto out;
- }
- if (!dmabuf->ready && (ret = prog_dmabuf_playback(state)))
- goto out;
-
- if (!access_ok(VERIFY_READ, buffer, count)) {
- ret = -EFAULT;
- goto out;
- }
-
- ret = 0;
-
- while (count > 0) {
- spin_lock_irqsave(&state->card->lock, flags);
- if (dmabuf->count < 0) {
- /* buffer underrun, we are recovering from */
- /* sleep_on_timeout, resync hwptr and swptr */
- dmabuf->count = 0;
- dmabuf->swptr = dmabuf->hwptr;
- }
- swptr = dmabuf->swptr;
- cnt = dmabuf->dmasize - swptr;
- if (dmabuf->count + cnt > dmabuf->dmasize)
- cnt = dmabuf->dmasize - dmabuf->count;
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- unsigned long tmo;
- /* buffer is full, start the dma machine and */
- /* wait for data to be played */
- start_dac(state);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- goto out;
- }
- /* No matter how much data left in the buffer, */
- /* we have to wait until CSO == ESO/2 or CSO == ESO */
- /* when address engine interrupts */
- lock_set_fmt(state);
- tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
- tmo >>= sample_shift[dmabuf->fmt];
- unlock_set_fmt(state);
- mutex_unlock(&state->sem);
-
- /* There are two situations when sleep_on_timeout */
- /* returns, one is when the interrupt is serviced */
- /* correctly and the process is waked up by ISR */
- /* ON TIME. Another is when timeout is expired, which */
- /* means that either interrupt is NOT serviced */
- /* correctly (pending interrupt) or it is TOO LATE */
- /* for the process to be scheduled to run */
- /* (scheduler latency) which results in a (potential) */
- /* buffer underrun. And worse, there is NOTHING we */
- /* can do to prevent it. */
- if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
- pr_debug(KERN_ERR "trident: playback schedule "
- "timeout, dmasz %u fragsz %u count %i "
- "hwptr %u swptr %u\n", dmabuf->dmasize,
- dmabuf->fragsize, dmabuf->count,
- dmabuf->hwptr, dmabuf->swptr);
-
- /* a buffer underrun, we delay the recovery */
- /* until next time the while loop begin and */
- /* we REALLY have data to play */
- }
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- goto out_nolock;
- }
- mutex_lock(&state->sem);
- if (dmabuf->mapped) {
- if (!ret)
- ret = -ENXIO;
- goto out;
- }
- continue;
- }
- if ((lret = lock_set_fmt(state)) < 0) {
- ret = lret;
- goto out;
- }
-
- if (state->chans_num == 6) {
- copy_count = 0;
- state_cnt = 0;
- if (ali_write_5_1(state, buffer, cnt, &copy_count,
- &state_cnt) == -EFAULT) {
- if (state_cnt) {
- swptr = (swptr + state_cnt) % dmabuf->dmasize;
- spin_lock_irqsave(&state->card->lock, flags);
- dmabuf->swptr = swptr;
- dmabuf->count += state_cnt;
- dmabuf->endcleared = 0;
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
- ret += copy_count;
- if (!ret)
- ret = -EFAULT;
- unlock_set_fmt(state);
- goto out;
- }
- } else {
- if (copy_from_user(dmabuf->rawbuf + swptr,
- buffer, cnt)) {
- if (!ret)
- ret = -EFAULT;
- unlock_set_fmt(state);
- goto out;
- }
- state_cnt = cnt;
- }
- unlock_set_fmt(state);
-
- swptr = (swptr + state_cnt) % dmabuf->dmasize;
-
- spin_lock_irqsave(&state->card->lock, flags);
- dmabuf->swptr = swptr;
- dmabuf->count += state_cnt;
- dmabuf->endcleared = 0;
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- start_dac(state);
- }
-out:
- mutex_unlock(&state->sem);
-out_nolock:
- return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int
-trident_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct trident_state *state = (struct trident_state *)file->private_data;
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned long flags;
- unsigned int mask = 0;
-
- VALIDATE_STATE(state);
-
- /*
- * Guard against a parallel poll and write causing multiple
- * prog_dmabuf events
- */
-
- mutex_lock(&state->sem);
-
- if (file->f_mode & FMODE_WRITE) {
- if (!dmabuf->ready && prog_dmabuf_playback(state)) {
- mutex_unlock(&state->sem);
- return 0;
- }
- poll_wait(file, &dmabuf->wait, wait);
- }
- if (file->f_mode & FMODE_READ) {
- if (!dmabuf->ready && prog_dmabuf_record(state)) {
- mutex_unlock(&state->sem);
- return 0;
- }
- poll_wait(file, &dmabuf->wait, wait);
- }
-
- mutex_unlock(&state->sem);
-
- spin_lock_irqsave(&state->card->lock, flags);
- trident_update_ptr(state);
- if (file->f_mode & FMODE_READ) {
- if (dmabuf->count >= (signed) dmabuf->fragsize)
- mask |= POLLIN | POLLRDNORM;
- }
- if (file->f_mode & FMODE_WRITE) {
- if (dmabuf->mapped) {
- if (dmabuf->count >= (signed) dmabuf->fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- if ((signed) dmabuf->dmasize >= dmabuf->count +
- (signed) dmabuf->fragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
- }
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- return mask;
-}
-
-static int
-trident_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct trident_state *state = (struct trident_state *)file->private_data;
- struct dmabuf *dmabuf = &state->dmabuf;
- int ret = -EINVAL;
- unsigned long size;
-
- VALIDATE_STATE(state);
-
- /*
- * Lock against poll read write or mmap creating buffers. Also lock
- * a read or write against an mmap.
- */
-
- mutex_lock(&state->sem);
-
- if (vma->vm_flags & VM_WRITE) {
- if ((ret = prog_dmabuf_playback(state)) != 0)
- goto out;
- } else if (vma->vm_flags & VM_READ) {
- if ((ret = prog_dmabuf_record(state)) != 0)
- goto out;
- } else
- goto out;
-
- ret = -EINVAL;
- if (vma->vm_pgoff != 0)
- goto out;
- size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << dmabuf->buforder))
- goto out;
- ret = -EAGAIN;
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- goto out;
- dmabuf->mapped = 1;
- ret = 0;
-out:
- mutex_unlock(&state->sem);
- return ret;
-}
-
-static int
-trident_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct trident_state *state = (struct trident_state *)file->private_data;
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int val, mapped, ret = 0;
- struct trident_card *card = state->card;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- VALIDATE_STATE(state);
-
-
- mapped = ((file->f_mode & (FMODE_WRITE | FMODE_READ)) && dmabuf->mapped);
-
- pr_debug("trident: trident_ioctl, command = %2d, arg = 0x%08x\n",
- _IOC_NR(cmd), arg ? *p : 0);
-
- switch (cmd) {
- case OSS_GETVERSION:
- ret = put_user(SOUND_VERSION, p);
- break;
-
- case SNDCTL_DSP_RESET:
- /* FIXME: spin_lock ? */
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(state);
- synchronize_irq(card->irq);
- dmabuf->ready = 0;
- dmabuf->swptr = dmabuf->hwptr = 0;
- dmabuf->count = dmabuf->total_bytes = 0;
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(state);
- synchronize_irq(card->irq);
- dmabuf->ready = 0;
- dmabuf->swptr = dmabuf->hwptr = 0;
- dmabuf->count = dmabuf->total_bytes = 0;
- }
- break;
-
- case SNDCTL_DSP_SYNC:
- if (file->f_mode & FMODE_WRITE)
- ret = drain_dac(state, file->f_flags & O_NONBLOCK);
- break;
-
- case SNDCTL_DSP_SPEED: /* set smaple rate */
- if (get_user(val, p)) {
- ret = -EFAULT;
- break;
- }
- if (val >= 0) {
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(state);
- dmabuf->ready = 0;
- spin_lock_irqsave(&state->card->lock, flags);
- trident_set_dac_rate(state, val);
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(state);
- dmabuf->ready = 0;
- spin_lock_irqsave(&state->card->lock, flags);
- trident_set_adc_rate(state, val);
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
- }
- ret = put_user(dmabuf->rate, p);
- break;
-
- case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
- if (get_user(val, p)) {
- ret = -EFAULT;
- break;
- }
- if ((ret = lock_set_fmt(state)) < 0)
- return ret;
-
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(state);
- dmabuf->ready = 0;
- if (val)
- dmabuf->fmt |= TRIDENT_FMT_STEREO;
- else
- dmabuf->fmt &= ~TRIDENT_FMT_STEREO;
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(state);
- dmabuf->ready = 0;
- if (val)
- dmabuf->fmt |= TRIDENT_FMT_STEREO;
- else
- dmabuf->fmt &= ~TRIDENT_FMT_STEREO;
- }
- unlock_set_fmt(state);
- break;
-
- case SNDCTL_DSP_GETBLKSIZE:
- if (file->f_mode & FMODE_WRITE) {
- if ((val = prog_dmabuf_playback(state)))
- ret = val;
- else
- ret = put_user(dmabuf->fragsize, p);
- break;
- }
- if (file->f_mode & FMODE_READ) {
- if ((val = prog_dmabuf_record(state)))
- ret = val;
- else
- ret = put_user(dmabuf->fragsize, p);
- break;
- }
- /* neither READ nor WRITE? is this even possible? */
- ret = -EINVAL;
- break;
-
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format */
- ret = put_user(AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 |
- AFMT_U8, p);
- break;
-
- case SNDCTL_DSP_SETFMT: /* Select sample format */
- if (get_user(val, p)) {
- ret = -EFAULT;
- break;
- }
- if ((ret = lock_set_fmt(state)) < 0)
- return ret;
-
- if (val != AFMT_QUERY) {
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(state);
- dmabuf->ready = 0;
- if (val == AFMT_S16_LE)
- dmabuf->fmt |= TRIDENT_FMT_16BIT;
- else
- dmabuf->fmt &= ~TRIDENT_FMT_16BIT;
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(state);
- dmabuf->ready = 0;
- if (val == AFMT_S16_LE)
- dmabuf->fmt |= TRIDENT_FMT_16BIT;
- else
- dmabuf->fmt &= ~TRIDENT_FMT_16BIT;
- }
- }
- unlock_set_fmt(state);
- ret = put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ? AFMT_S16_LE :
- AFMT_U8, p);
- break;
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, p)) {
- ret = -EFAULT;
- break;
- }
- if (val != 0) {
- if ((ret = lock_set_fmt(state)) < 0)
- return ret;
-
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(state);
- dmabuf->ready = 0;
-
- //prevent from memory leak
- if ((state->chans_num > 2) && (state->chans_num != val)) {
- ali_free_other_states_resources(state);
- state->chans_num = 1;
- }
-
- if (val >= 2) {
-
- dmabuf->fmt |= TRIDENT_FMT_STEREO;
- if ((val == 6) && (state->card->pci_id == PCI_DEVICE_ID_ALI_5451)) {
- if (card->rec_channel_use_count > 0) {
- printk(KERN_ERR "trident: Record is "
- "working on the card!\n");
- ret = -EBUSY;
- unlock_set_fmt(state);
- break;
- }
-
- ret = ali_setup_multi_channels(state->card, 6);
- if (ret < 0) {
- unlock_set_fmt(state);
- break;
- }
- mutex_lock(&state->card->open_mutex);
- ret = ali_allocate_other_states_resources(state, 6);
- if (ret < 0) {
- mutex_unlock(&state->card->open_mutex);
- unlock_set_fmt(state);
- break;
- }
- state->card->multi_channel_use_count++;
- mutex_unlock(&state->card->open_mutex);
- } else
- val = 2; /*yield to 2-channels */
- } else
- dmabuf->fmt &= ~TRIDENT_FMT_STEREO;
- state->chans_num = val;
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(state);
- dmabuf->ready = 0;
- if (val >= 2) {
- if (!((file->f_mode & FMODE_WRITE) &&
- (val == 6)))
- val = 2;
- dmabuf->fmt |= TRIDENT_FMT_STEREO;
- } else
- dmabuf->fmt &= ~TRIDENT_FMT_STEREO;
- state->chans_num = val;
- }
- unlock_set_fmt(state);
- }
- ret = put_user(val, p);
- break;
-
- case SNDCTL_DSP_POST:
- /* Cause the working fragment to be output */
- break;
-
- case SNDCTL_DSP_SUBDIVIDE:
- if (dmabuf->subdivision) {
- ret = -EINVAL;
- break;
- }
- if (get_user(val, p)) {
- ret = -EFAULT;
- break;
- }
- if (val != 1 && val != 2 && val != 4) {
- ret = -EINVAL;
- break;
- }
- dmabuf->subdivision = val;
- break;
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, p)) {
- ret = -EFAULT;
- break;
- }
-
- dmabuf->ossfragshift = val & 0xffff;
- dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
- if (dmabuf->ossfragshift < 4)
- dmabuf->ossfragshift = 4;
- if (dmabuf->ossfragshift > 15)
- dmabuf->ossfragshift = 15;
- if (dmabuf->ossmaxfrags < 4)
- dmabuf->ossmaxfrags = 4;
-
- break;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE)) {
- ret = -EINVAL;
- break;
- }
- if (!dmabuf->ready && (val = prog_dmabuf_playback(state)) != 0) {
- ret = val;
- break;
- }
- spin_lock_irqsave(&state->card->lock, flags);
- trident_update_ptr(state);
- abinfo.fragsize = dmabuf->fragsize;
- abinfo.bytes = dmabuf->dmasize - dmabuf->count;
- abinfo.fragstotal = dmabuf->numfrag;
- abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
- spin_unlock_irqrestore(&state->card->lock, flags);
- ret = copy_to_user(argp, &abinfo, sizeof (abinfo)) ?
- -EFAULT : 0;
- break;
-
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ)) {
- ret = -EINVAL;
- break;
- }
- if (!dmabuf->ready && (val = prog_dmabuf_record(state)) != 0) {
- ret = val;
- break;
- }
- spin_lock_irqsave(&state->card->lock, flags);
- trident_update_ptr(state);
- abinfo.fragsize = dmabuf->fragsize;
- abinfo.bytes = dmabuf->count;
- abinfo.fragstotal = dmabuf->numfrag;
- abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
- spin_unlock_irqrestore(&state->card->lock, flags);
- ret = copy_to_user(argp, &abinfo, sizeof (abinfo)) ?
- -EFAULT : 0;
- break;
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- break;
-
- case SNDCTL_DSP_GETCAPS:
- ret = put_user(DSP_CAP_REALTIME | DSP_CAP_TRIGGER |
- DSP_CAP_MMAP | DSP_CAP_BIND, p);
- break;
-
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
- if ((file->f_mode & FMODE_READ) && dmabuf->enable)
- val |= PCM_ENABLE_INPUT;
- if ((file->f_mode & FMODE_WRITE) && dmabuf->enable)
- val |= PCM_ENABLE_OUTPUT;
- ret = put_user(val, p);
- break;
-
- case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, p)) {
- ret = -EFAULT;
- break;
- }
- if (file->f_mode & FMODE_READ) {
- if (val & PCM_ENABLE_INPUT) {
- if (!dmabuf->ready &&
- (ret = prog_dmabuf_record(state)))
- break;
- start_adc(state);
- } else
- stop_adc(state);
- }
- if (file->f_mode & FMODE_WRITE) {
- if (val & PCM_ENABLE_OUTPUT) {
- if (!dmabuf->ready &&
- (ret = prog_dmabuf_playback(state)))
- break;
- start_dac(state);
- } else
- stop_dac(state);
- }
- break;
-
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ)) {
- ret = -EINVAL;
- break;
- }
- if (!dmabuf->ready && (val = prog_dmabuf_record(state))
- != 0) {
- ret = val;
- break;
- }
- spin_lock_irqsave(&state->card->lock, flags);
- trident_update_ptr(state);
- cinfo.bytes = dmabuf->total_bytes;
- cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
- cinfo.ptr = dmabuf->hwptr;
- if (dmabuf->mapped)
- dmabuf->count &= dmabuf->fragsize - 1;
- spin_unlock_irqrestore(&state->card->lock, flags);
- ret = copy_to_user(argp, &cinfo, sizeof (cinfo)) ?
- -EFAULT : 0;
- break;
-
- case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_WRITE)) {
- ret = -EINVAL;
- break;
- }
- if (!dmabuf->ready && (val = prog_dmabuf_playback(state))
- != 0) {
- ret = val;
- break;
- }
-
- spin_lock_irqsave(&state->card->lock, flags);
- trident_update_ptr(state);
- cinfo.bytes = dmabuf->total_bytes;
- cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
- cinfo.ptr = dmabuf->hwptr;
- if (dmabuf->mapped)
- dmabuf->count &= dmabuf->fragsize - 1;
- spin_unlock_irqrestore(&state->card->lock, flags);
- ret = copy_to_user(argp, &cinfo, sizeof (cinfo)) ?
- -EFAULT : 0;
- break;
-
- case SNDCTL_DSP_SETDUPLEX:
- ret = -EINVAL;
- break;
-
- case SNDCTL_DSP_GETODELAY:
- if (!(file->f_mode & FMODE_WRITE)) {
- ret = -EINVAL;
- break;
- }
- if (!dmabuf->ready && (val = prog_dmabuf_playback(state)) != 0) {
- ret = val;
- break;
- }
- spin_lock_irqsave(&state->card->lock, flags);
- trident_update_ptr(state);
- val = dmabuf->count;
- spin_unlock_irqrestore(&state->card->lock, flags);
- ret = put_user(val, p);
- break;
-
- case SOUND_PCM_READ_RATE:
- ret = put_user(dmabuf->rate, p);
- break;
-
- case SOUND_PCM_READ_CHANNELS:
- ret = put_user((dmabuf->fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
- p);
- break;
-
- case SOUND_PCM_READ_BITS:
- ret = put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ? AFMT_S16_LE :
- AFMT_U8, p);
- break;
-
- case SNDCTL_DSP_GETCHANNELMASK:
- ret = put_user(DSP_BIND_FRONT | DSP_BIND_SURR |
- DSP_BIND_CENTER_LFE, p);
- break;
-
- case SNDCTL_DSP_BIND_CHANNEL:
- if (state->card->pci_id != PCI_DEVICE_ID_SI_7018) {
- ret = -EINVAL;
- break;
- }
-
- if (get_user(val, p)) {
- ret = -EFAULT;
- break;
- }
- if (val == DSP_BIND_QUERY) {
- val = dmabuf->channel->attribute | 0x3c00;
- val = attr2mask[val >> 8];
- } else {
- dmabuf->ready = 0;
- if (file->f_mode & FMODE_READ)
- dmabuf->channel->attribute = (CHANNEL_REC |
- SRC_ENABLE);
- if (file->f_mode & FMODE_WRITE)
- dmabuf->channel->attribute = (CHANNEL_SPC_PB |
- SRC_ENABLE);
- dmabuf->channel->attribute |= mask2attr[ffs(val)];
- }
- ret = put_user(val, p);
- break;
-
- case SNDCTL_DSP_MAPINBUF:
- case SNDCTL_DSP_MAPOUTBUF:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_WRITE_FILTER:
- case SOUND_PCM_READ_FILTER:
- default:
- ret = -EINVAL;
- break;
-
- }
- return ret;
-}
-
-static int
-trident_open(struct inode *inode, struct file *file)
-{
- int i = 0;
- int minor = iminor(inode);
- struct trident_card *card = devs;
- struct trident_state *state = NULL;
- struct dmabuf *dmabuf = NULL;
- unsigned long flags;
-
- /* Added by Matt Wu 01-05-2001 */
- /* TODO: there's some redundacy here wrt the check below */
- /* for multi_use_count > 0. Should we return -EBUSY or find */
- /* a different card? for now, don't break current behaviour */
- /* -- mulix */
- if (file->f_mode & FMODE_READ) {
- if (card->pci_id == PCI_DEVICE_ID_ALI_5451) {
- if (card->multi_channel_use_count > 0)
- return -EBUSY;
- }
- }
-
- /* find an available virtual channel (instance of /dev/dsp) */
- while (card != NULL) {
- mutex_lock(&card->open_mutex);
- if (file->f_mode & FMODE_READ) {
- /* Skip opens on cards that are in 6 channel mode */
- if (card->multi_channel_use_count > 0) {
- mutex_unlock(&card->open_mutex);
- card = card->next;
- continue;
- }
- }
- for (i = 0; i < NR_HW_CH; i++) {
- if (card->states[i] == NULL) {
- state = card->states[i] = kzalloc(sizeof(*state), GFP_KERNEL);
- if (state == NULL) {
- mutex_unlock(&card->open_mutex);
- return -ENOMEM;
- }
- mutex_init(&state->sem);
- dmabuf = &state->dmabuf;
- goto found_virt;
- }
- }
- mutex_unlock(&card->open_mutex);
- card = card->next;
- }
- /* no more virtual channel avaiable */
- if (!state) {
- return -ENODEV;
- }
- found_virt:
- /* found a free virtual channel, allocate hardware channels */
- if (file->f_mode & FMODE_READ)
- dmabuf->channel = card->alloc_rec_pcm_channel(card);
- else
- dmabuf->channel = card->alloc_pcm_channel(card);
-
- if (dmabuf->channel == NULL) {
- kfree(card->states[i]);
- card->states[i] = NULL;
- return -ENODEV;
- }
-
- /* initialize the virtual channel */
- state->virt = i;
- state->card = card;
- state->magic = TRIDENT_STATE_MAGIC;
- init_waitqueue_head(&dmabuf->wait);
- file->private_data = state;
-
- /* set default sample format. According to OSS Programmer's */
- /* Guide /dev/dsp should be default to unsigned 8-bits, mono, */
- /* with sample rate 8kHz and /dev/dspW will accept 16-bits sample */
- if (file->f_mode & FMODE_WRITE) {
- dmabuf->fmt &= ~TRIDENT_FMT_MASK;
- if ((minor & 0x0f) == SND_DEV_DSP16)
- dmabuf->fmt |= TRIDENT_FMT_16BIT;
- dmabuf->ossfragshift = 0;
- dmabuf->ossmaxfrags = 0;
- dmabuf->subdivision = 0;
- if (card->pci_id == PCI_DEVICE_ID_SI_7018) {
- /* set default channel attribute to normal playback */
- dmabuf->channel->attribute = CHANNEL_PB;
- }
- spin_lock_irqsave(&card->lock, flags);
- trident_set_dac_rate(state, 8000);
- spin_unlock_irqrestore(&card->lock, flags);
- }
-
- if (file->f_mode & FMODE_READ) {
- /* FIXME: Trident 4d can only record in signed 16-bits stereo, */
- /* 48kHz sample, to be dealed with in trident_set_adc_rate() ?? */
- dmabuf->fmt &= ~TRIDENT_FMT_MASK;
- if ((minor & 0x0f) == SND_DEV_DSP16)
- dmabuf->fmt |= TRIDENT_FMT_16BIT;
- dmabuf->ossfragshift = 0;
- dmabuf->ossmaxfrags = 0;
- dmabuf->subdivision = 0;
- if (card->pci_id == PCI_DEVICE_ID_SI_7018) {
- /* set default channel attribute to 0x8a80, record from
- PCM L/R FIFO and mono = (left + right + 1)/2 */
- dmabuf->channel->attribute = (CHANNEL_REC | PCM_LR |
- MONO_MIX);
- }
- spin_lock_irqsave(&card->lock, flags);
- trident_set_adc_rate(state, 8000);
- spin_unlock_irqrestore(&card->lock, flags);
-
- /* Added by Matt Wu 01-05-2001 */
- if (card->pci_id == PCI_DEVICE_ID_ALI_5451)
- card->rec_channel_use_count++;
- }
-
- state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
- mutex_unlock(&card->open_mutex);
-
- pr_debug("trident: open virtual channel %d, hard channel %d\n",
- state->virt, dmabuf->channel->num);
-
- return nonseekable_open(inode, file);
-}
-
-static int
-trident_release(struct inode *inode, struct file *file)
-{
- struct trident_state *state = (struct trident_state *)file->private_data;
- struct trident_card *card;
- struct dmabuf *dmabuf;
-
- VALIDATE_STATE(state);
-
- card = state->card;
- dmabuf = &state->dmabuf;
-
- if (file->f_mode & FMODE_WRITE) {
- trident_clear_tail(state);
- drain_dac(state, file->f_flags & O_NONBLOCK);
- }
-
- pr_debug("trident: closing virtual channel %d, hard channel %d\n",
- state->virt, dmabuf->channel->num);
-
- /* stop DMA state machine and free DMA buffers/channels */
- mutex_lock(&card->open_mutex);
-
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(state);
- dealloc_dmabuf(&state->dmabuf, state->card->pci_dev);
- state->card->free_pcm_channel(state->card, dmabuf->channel->num);
-
- /* Added by Matt Wu */
- if (card->pci_id == PCI_DEVICE_ID_ALI_5451) {
- if (state->chans_num > 2) {
- if (card->multi_channel_use_count-- < 0)
- card->multi_channel_use_count = 0;
- if (card->multi_channel_use_count == 0)
- ali_close_multi_channels();
- ali_free_other_states_resources(state);
- }
- }
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(state);
- dealloc_dmabuf(&state->dmabuf, state->card->pci_dev);
- state->card->free_pcm_channel(state->card, dmabuf->channel->num);
-
- /* Added by Matt Wu */
- if (card->pci_id == PCI_DEVICE_ID_ALI_5451) {
- if (card->rec_channel_use_count-- < 0)
- card->rec_channel_use_count = 0;
- }
- }
-
- card->states[state->virt] = NULL;
- kfree(state);
-
- /* we're covered by the open_mutex */
- mutex_unlock(&card->open_mutex);
-
- return 0;
-}
-
-static /*const */ struct file_operations trident_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = trident_read,
- .write = trident_write,
- .poll = trident_poll,
- .ioctl = trident_ioctl,
- .mmap = trident_mmap,
- .open = trident_open,
- .release = trident_release,
-};
-
-/* trident specific AC97 functions */
-/* Write AC97 codec registers */
-static void
-trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val)
-{
- struct trident_card *card = (struct trident_card *)codec->private_data;
- unsigned int address, mask, busy;
- unsigned short count = 0xffff;
- unsigned long flags;
- u32 data;
-
- data = ((u32) val) << 16;
-
- switch (card->pci_id) {
- default:
- case PCI_DEVICE_ID_SI_7018:
- address = SI_AC97_WRITE;
- mask = SI_AC97_BUSY_WRITE | SI_AC97_AUDIO_BUSY;
- if (codec->id)
- mask |= SI_AC97_SECONDARY;
- busy = SI_AC97_BUSY_WRITE;
- break;
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
- address = DX_ACR0_AC97_W;
- mask = busy = DX_AC97_BUSY_WRITE;
- break;
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
- address = NX_ACR1_AC97_W;
- mask = NX_AC97_BUSY_WRITE;
- if (codec->id)
- mask |= NX_AC97_WRITE_SECONDARY;
- busy = NX_AC97_BUSY_WRITE;
- break;
- case PCI_DEVICE_ID_INTERG_5050:
- address = SI_AC97_WRITE;
- mask = busy = SI_AC97_BUSY_WRITE;
- if (codec->id)
- mask |= SI_AC97_SECONDARY;
- break;
- }
-
- spin_lock_irqsave(&card->lock, flags);
- do {
- if ((inw(TRID_REG(card, address)) & busy) == 0)
- break;
- } while (count--);
-
- data |= (mask | (reg & AC97_REG_ADDR));
-
- if (count == 0) {
- printk(KERN_ERR "trident: AC97 CODEC write timed out.\n");
- spin_unlock_irqrestore(&card->lock, flags);
- return;
- }
-
- outl(data, TRID_REG(card, address));
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/* Read AC97 codec registers */
-static u16
-trident_ac97_get(struct ac97_codec *codec, u8 reg)
-{
- struct trident_card *card = (struct trident_card *)codec->private_data;
- unsigned int address, mask, busy;
- unsigned short count = 0xffff;
- unsigned long flags;
- u32 data;
-
- switch (card->pci_id) {
- default:
- case PCI_DEVICE_ID_SI_7018:
- address = SI_AC97_READ;
- mask = SI_AC97_BUSY_READ | SI_AC97_AUDIO_BUSY;
- if (codec->id)
- mask |= SI_AC97_SECONDARY;
- busy = SI_AC97_BUSY_READ;
- break;
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
- address = DX_ACR1_AC97_R;
- mask = busy = DX_AC97_BUSY_READ;
- break;
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
- if (codec->id)
- address = NX_ACR3_AC97_R_SECONDARY;
- else
- address = NX_ACR2_AC97_R_PRIMARY;
- mask = NX_AC97_BUSY_READ;
- busy = NX_AC97_BUSY_READ | NX_AC97_BUSY_DATA;
- break;
- case PCI_DEVICE_ID_INTERG_5050:
- address = SI_AC97_READ;
- mask = busy = SI_AC97_BUSY_READ;
- if (codec->id)
- mask |= SI_AC97_SECONDARY;
- break;
- }
-
- data = (mask | (reg & AC97_REG_ADDR));
-
- spin_lock_irqsave(&card->lock, flags);
- outl(data, TRID_REG(card, address));
- do {
- data = inl(TRID_REG(card, address));
- if ((data & busy) == 0)
- break;
- } while (count--);
- spin_unlock_irqrestore(&card->lock, flags);
-
- if (count == 0) {
- printk(KERN_ERR "trident: AC97 CODEC read timed out.\n");
- data = 0;
- }
- return ((u16) (data >> 16));
-}
-
-/* rewrite ac97 read and write mixer register by hulei for ALI*/
-static int
-acquirecodecaccess(struct trident_card *card)
-{
- u16 wsemamask = 0x6000; /* bit 14..13 */
- u16 wsemabits;
- u16 wcontrol;
- int block = 0;
- int ncount = 25;
- while (1) {
- wcontrol = inw(TRID_REG(card, ALI_AC97_WRITE));
- wsemabits = wcontrol & wsemamask;
-
- if (wsemabits == 0x4000)
- return 1; /* 0x4000 is audio ,then success */
- if (ncount-- < 0)
- break;
- if (wsemabits == 0) {
- unlock:
- outl(((u32) (wcontrol & 0x1eff) | 0x00004000),
- TRID_REG(card, ALI_AC97_WRITE));
- continue;
- }
- udelay(20);
- }
- if (!block) {
- pr_debug("accesscodecsemaphore: try unlock\n");
- block = 1;
- goto unlock;
- }
- return 0;
-}
-
-static void
-releasecodecaccess(struct trident_card *card)
-{
- unsigned long wcontrol;
- wcontrol = inl(TRID_REG(card, ALI_AC97_WRITE));
- outl((wcontrol & 0xffff1eff), TRID_REG(card, ALI_AC97_WRITE));
-}
-
-static int
-waitforstimertick(struct trident_card *card)
-{
- unsigned long chk1, chk2;
- unsigned int wcount = 0xffff;
- chk1 = inl(TRID_REG(card, ALI_STIMER));
-
- while (1) {
- chk2 = inl(TRID_REG(card, ALI_STIMER));
- if ((wcount > 0) && chk1 != chk2)
- return 1;
- if (wcount <= 0)
- break;
- udelay(50);
- }
- return 0;
-}
-
-/* Read AC97 codec registers for ALi*/
-static u16
-ali_ac97_get(struct trident_card *card, int secondary, u8 reg)
-{
- unsigned int address, mask;
- unsigned int ncount;
- unsigned long aud_reg;
- u32 data;
- u16 wcontrol;
- unsigned long flags;
-
- if (!card)
- BUG();
-
- address = ALI_AC97_READ;
- if (card->revision == ALI_5451_V02) {
- address = ALI_AC97_WRITE;
- }
- mask = ALI_AC97_READ_ACTION | ALI_AC97_AUDIO_BUSY;
- if (secondary)
- mask |= ALI_AC97_SECONDARY;
-
- spin_lock_irqsave(&card->lock, flags);
-
- if (!acquirecodecaccess(card))
- printk(KERN_ERR "access codec fail\n");
-
- wcontrol = inw(TRID_REG(card, ALI_AC97_WRITE));
- wcontrol &= 0xfe00;
- wcontrol |= (0x8000 | reg);
- outw(wcontrol, TRID_REG(card, ALI_AC97_WRITE));
-
- data = (mask | (reg & AC97_REG_ADDR));
-
- if (!waitforstimertick(card)) {
- printk(KERN_ERR "ali_ac97_read: BIT_CLOCK is dead\n");
- goto releasecodec;
- }
-
- udelay(20);
-
- ncount = 10;
-
- while (1) {
- if ((inw(TRID_REG(card, ALI_AC97_WRITE)) & ALI_AC97_BUSY_READ)
- != 0)
- break;
- if (ncount <= 0)
- break;
- if (ncount-- == 1) {
- pr_debug("ali_ac97_read :try clear busy flag\n");
- aud_reg = inl(TRID_REG(card, ALI_AC97_WRITE));
- outl((aud_reg & 0xffff7fff),
- TRID_REG(card, ALI_AC97_WRITE));
- }
- udelay(10);
- }
-
- data = inl(TRID_REG(card, address));
-
- spin_unlock_irqrestore(&card->lock, flags);
-
- return ((u16) (data >> 16));
-
- releasecodec:
- releasecodecaccess(card);
- spin_unlock_irqrestore(&card->lock, flags);
- printk(KERN_ERR "ali_ac97_read: AC97 CODEC read timed out.\n");
- return 0;
-}
-
-/* Write AC97 codec registers for hulei*/
-static void
-ali_ac97_set(struct trident_card *card, int secondary, u8 reg, u16 val)
-{
- unsigned int address, mask;
- unsigned int ncount;
- u32 data;
- u16 wcontrol;
- unsigned long flags;
-
- data = ((u32) val) << 16;
-
- if (!card)
- BUG();
-
- address = ALI_AC97_WRITE;
- mask = ALI_AC97_WRITE_ACTION | ALI_AC97_AUDIO_BUSY;
- if (secondary)
- mask |= ALI_AC97_SECONDARY;
- if (card->revision == ALI_5451_V02)
- mask |= ALI_AC97_WRITE_MIXER_REGISTER;
-
- spin_lock_irqsave(&card->lock, flags);
- if (!acquirecodecaccess(card))
- printk(KERN_ERR "ali_ac97_write: access codec fail\n");
-
- wcontrol = inw(TRID_REG(card, ALI_AC97_WRITE));
- wcontrol &= 0xff00;
- wcontrol |= (0x8100 | reg); /* bit 8=1: (ali1535 )reserved/ */
- /* ali1535+ write */
- outl((data | wcontrol), TRID_REG(card, ALI_AC97_WRITE));
-
- if (!waitforstimertick(card)) {
- printk(KERN_ERR "BIT_CLOCK is dead\n");
- goto releasecodec;
- }
-
- ncount = 10;
- while (1) {
- wcontrol = inw(TRID_REG(card, ALI_AC97_WRITE));
- if (!(wcontrol & 0x8000))
- break;
- if (ncount <= 0)
- break;
- if (ncount-- == 1) {
- pr_debug("ali_ac97_set :try clear busy flag!!\n");
- outw(wcontrol & 0x7fff,
- TRID_REG(card, ALI_AC97_WRITE));
- }
- udelay(10);
- }
-
- releasecodec:
- releasecodecaccess(card);
- spin_unlock_irqrestore(&card->lock, flags);
- return;
-}
-
-static void
-ali_enable_special_channel(struct trident_state *stat)
-{
- struct trident_card *card = stat->card;
- unsigned long s_channels;
-
- s_channels = inl(TRID_REG(card, ALI_GLOBAL_CONTROL));
- s_channels |= (1 << stat->dmabuf.channel->num);
- outl(s_channels, TRID_REG(card, ALI_GLOBAL_CONTROL));
-}
-
-static u16
-ali_ac97_read(struct ac97_codec *codec, u8 reg)
-{
- int id;
- u16 data;
- struct trident_card *card = NULL;
-
- /* Added by Matt Wu */
- if (!codec)
- BUG();
-
- card = (struct trident_card *) codec->private_data;
-
- if (!card->mixer_regs_ready)
- return ali_ac97_get(card, codec->id, reg);
-
- /*
- * FIXME: need to stop this caching some registers
- */
- if (codec->id)
- id = 1;
- else
- id = 0;
-
- data = card->mixer_regs[reg / 2][id];
- return data;
-}
-
-static void
-ali_ac97_write(struct ac97_codec *codec, u8 reg, u16 val)
-{
- int id;
- struct trident_card *card;
-
- /* Added by Matt Wu */
- if (!codec)
- BUG();
-
- card = (struct trident_card *) codec->private_data;
-
- if (!card->mixer_regs_ready) {
- ali_ac97_set(card, codec->id, reg, val);
- return;
- }
-
- if (codec->id)
- id = 1;
- else
- id = 0;
-
- card->mixer_regs[reg / 2][id] = val;
- ali_ac97_set(card, codec->id, reg, val);
-}
-
-/*
-flag: ALI_SPDIF_OUT_TO_SPDIF_OUT
- ALI_PCM_TO_SPDIF_OUT
-*/
-
-static void
-ali_setup_spdif_out(struct trident_card *card, int flag)
-{
- unsigned long spdif;
- unsigned char ch;
-
- char temp;
- struct pci_dev *pci_dev = NULL;
-
- pci_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
- pci_dev);
- if (pci_dev == NULL)
- return;
- pci_read_config_byte(pci_dev, 0x61, &temp);
- temp |= 0x40;
- pci_write_config_byte(pci_dev, 0x61, temp);
- pci_read_config_byte(pci_dev, 0x7d, &temp);
- temp |= 0x01;
- pci_write_config_byte(pci_dev, 0x7d, temp);
- pci_read_config_byte(pci_dev, 0x7e, &temp);
- temp &= (~0x20);
- temp |= 0x10;
- pci_write_config_byte(pci_dev, 0x7e, temp);
-
- pci_dev_put(pci_dev);
-
- ch = inb(TRID_REG(card, ALI_SCTRL));
- outb(ch | ALI_SPDIF_OUT_ENABLE, TRID_REG(card, ALI_SCTRL));
- ch = inb(TRID_REG(card, ALI_SPDIF_CTRL));
- outb(ch & ALI_SPDIF_OUT_CH_STATUS, TRID_REG(card, ALI_SPDIF_CTRL));
-
- if (flag & ALI_SPDIF_OUT_TO_SPDIF_OUT) {
- spdif = inw(TRID_REG(card, ALI_GLOBAL_CONTROL));
- spdif |= ALI_SPDIF_OUT_CH_ENABLE;
- spdif &= ALI_SPDIF_OUT_SEL_SPDIF;
- outw(spdif, TRID_REG(card, ALI_GLOBAL_CONTROL));
- spdif = inw(TRID_REG(card, ALI_SPDIF_CS));
- if (flag & ALI_SPDIF_OUT_NON_PCM)
- spdif |= 0x0002;
- else
- spdif &= (~0x0002);
- outw(spdif, TRID_REG(card, ALI_SPDIF_CS));
- } else {
- spdif = inw(TRID_REG(card, ALI_GLOBAL_CONTROL));
- spdif |= ALI_SPDIF_OUT_SEL_PCM;
- outw(spdif, TRID_REG(card, ALI_GLOBAL_CONTROL));
- }
-}
-
-static void
-ali_disable_special_channel(struct trident_card *card, int ch)
-{
- unsigned long sc;
-
- sc = inl(TRID_REG(card, ALI_GLOBAL_CONTROL));
- sc &= ~(1 << ch);
- outl(sc, TRID_REG(card, ALI_GLOBAL_CONTROL));
-}
-
-static void
-ali_disable_spdif_in(struct trident_card *card)
-{
- unsigned long spdif;
-
- spdif = inl(TRID_REG(card, ALI_GLOBAL_CONTROL));
- spdif &= (~ALI_SPDIF_IN_SUPPORT);
- outl(spdif, TRID_REG(card, ALI_GLOBAL_CONTROL));
-
- ali_disable_special_channel(card, ALI_SPDIF_IN_CHANNEL);
-}
-
-static void
-ali_setup_spdif_in(struct trident_card *card)
-{
- unsigned long spdif;
-
- //Set SPDIF IN Supported
- spdif = inl(TRID_REG(card, ALI_GLOBAL_CONTROL));
- spdif |= ALI_SPDIF_IN_SUPPORT;
- outl(spdif, TRID_REG(card, ALI_GLOBAL_CONTROL));
-
- //Set SPDIF IN Rec
- spdif = inl(TRID_REG(card, ALI_GLOBAL_CONTROL));
- spdif |= ALI_SPDIF_IN_CH_ENABLE;
- outl(spdif, TRID_REG(card, ALI_GLOBAL_CONTROL));
-
- spdif = inb(TRID_REG(card, ALI_SPDIF_CTRL));
- spdif |= ALI_SPDIF_IN_CH_STATUS;
- outb(spdif, TRID_REG(card, ALI_SPDIF_CTRL));
-/*
- spdif = inb(TRID_REG(card, ALI_SPDIF_CTRL));
- spdif |= ALI_SPDIF_IN_FUNC_ENABLE;
- outb(spdif, TRID_REG(card, ALI_SPDIF_CTRL));
-*/
-}
-
-static void
-ali_delay(struct trident_card *card, int interval)
-{
- unsigned long begintimer, currenttimer;
-
- begintimer = inl(TRID_REG(card, ALI_STIMER));
- currenttimer = inl(TRID_REG(card, ALI_STIMER));
-
- while (currenttimer < begintimer + interval)
- currenttimer = inl(TRID_REG(card, ALI_STIMER));
-}
-
-static void
-ali_detect_spdif_rate(struct trident_card *card)
-{
- u16 wval = 0;
- u16 count = 0;
- u8 bval = 0, R1 = 0, R2 = 0;
-
- bval = inb(TRID_REG(card, ALI_SPDIF_CTRL));
- bval |= 0x02;
- outb(bval, TRID_REG(card, ALI_SPDIF_CTRL));
-
- bval = inb(TRID_REG(card, ALI_SPDIF_CTRL + 1));
- bval |= 0x1F;
- outb(bval, TRID_REG(card, ALI_SPDIF_CTRL + 1));
-
- while (((R1 < 0x0B) || (R1 > 0x0E)) && (R1 != 0x12) &&
- count <= 50000) {
- count++;
-
- ali_delay(card, 6);
-
- bval = inb(TRID_REG(card, ALI_SPDIF_CTRL + 1));
- R1 = bval & 0x1F;
- }
-
- if (count > 50000) {
- printk(KERN_WARNING "trident: Error in "
- "ali_detect_spdif_rate!\n");
- return;
- }
-
- count = 0;
-
- while (count <= 50000) {
- count++;
-
- ali_delay(card, 6);
-
- bval = inb(TRID_REG(card, ALI_SPDIF_CTRL + 1));
- R2 = bval & 0x1F;
-
- if (R2 != R1)
- R1 = R2;
- else
- break;
- }
-
- if (count > 50000) {
- printk(KERN_WARNING "trident: Error in "
- "ali_detect_spdif_rate!\n");
- return;
- }
-
- switch (R2) {
- case 0x0b:
- case 0x0c:
- case 0x0d:
- case 0x0e:
- wval = inw(TRID_REG(card, ALI_SPDIF_CTRL + 2));
- wval &= 0xE0F0;
- wval |= (u16) 0x09 << 8 | (u16) 0x05;
- outw(wval, TRID_REG(card, ALI_SPDIF_CTRL + 2));
-
- bval = inb(TRID_REG(card, ALI_SPDIF_CS + 3)) & 0xF0;
- outb(bval | 0x02, TRID_REG(card, ALI_SPDIF_CS + 3));
- break;
-
- case 0x12:
- wval = inw(TRID_REG(card, ALI_SPDIF_CTRL + 2));
- wval &= 0xE0F0;
- wval |= (u16) 0x0E << 8 | (u16) 0x08;
- outw(wval, TRID_REG(card, ALI_SPDIF_CTRL + 2));
-
- bval = inb(TRID_REG(card, ALI_SPDIF_CS + 3)) & 0xF0;
- outb(bval | 0x03, TRID_REG(card, ALI_SPDIF_CS + 3));
- break;
-
- default:
- break;
- }
-
-}
-
-static unsigned int
-ali_get_spdif_in_rate(struct trident_card *card)
-{
- u32 dwRate = 0;
- u8 bval = 0;
-
- ali_detect_spdif_rate(card);
-
- bval = inb(TRID_REG(card, ALI_SPDIF_CTRL));
- bval &= 0x7F;
- bval |= 0x40;
- outb(bval, TRID_REG(card, ALI_SPDIF_CTRL));
-
- bval = inb(TRID_REG(card, ALI_SPDIF_CS + 3));
- bval &= 0x0F;
-
- switch (bval) {
- case 0:
- dwRate = 44100;
- break;
- case 1:
- dwRate = 48000;
- break;
- case 2:
- dwRate = 32000;
- break;
- default:
- // Error occurs
- break;
- }
-
- return dwRate;
-
-}
-
-static int
-ali_close_multi_channels(void)
-{
- char temp = 0;
- struct pci_dev *pci_dev = NULL;
-
- pci_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
- pci_dev);
- if (pci_dev == NULL)
- return -1;
-
- pci_read_config_byte(pci_dev, 0x59, &temp);
- temp &= ~0x80;
- pci_write_config_byte(pci_dev, 0x59, temp);
-
- pci_dev_put(pci_dev);
-
- pci_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
- NULL);
- if (pci_dev == NULL)
- return -1;
-
- pci_read_config_byte(pci_dev, 0xB8, &temp);
- temp &= ~0x20;
- pci_write_config_byte(pci_dev, 0xB8, temp);
-
- pci_dev_put(pci_dev);
-
- return 0;
-}
-
-static int
-ali_setup_multi_channels(struct trident_card *card, int chan_nums)
-{
- unsigned long dwValue;
- char temp = 0;
- struct pci_dev *pci_dev = NULL;
-
- pci_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
- pci_dev);
- if (pci_dev == NULL)
- return -1;
- pci_read_config_byte(pci_dev, 0x59, &temp);
- temp |= 0x80;
- pci_write_config_byte(pci_dev, 0x59, temp);
-
- pci_dev_put(pci_dev);
-
- pci_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
- NULL);
- if (pci_dev == NULL)
- return -1;
- pci_read_config_byte(pci_dev, (int) 0xB8, &temp);
- temp |= 0x20;
- pci_write_config_byte(pci_dev, (int) 0xB8, (u8) temp);
-
- pci_dev_put(pci_dev);
-
- if (chan_nums == 6) {
- dwValue = inl(TRID_REG(card, ALI_SCTRL)) | 0x000f0000;
- outl(dwValue, TRID_REG(card, ALI_SCTRL));
- mdelay(4);
- dwValue = inl(TRID_REG(card, ALI_SCTRL));
- if (dwValue & 0x2000000) {
- ali_ac97_write(card->ac97_codec[0], 0x02, 8080);
- ali_ac97_write(card->ac97_codec[0], 0x36, 0);
- ali_ac97_write(card->ac97_codec[0], 0x38, 0);
- /*
- * On a board with a single codec you won't get the
- * surround. On other boards configure it.
- */
- if (card->ac97_codec[1] != NULL) {
- ali_ac97_write(card->ac97_codec[1], 0x36, 0);
- ali_ac97_write(card->ac97_codec[1], 0x38, 0);
- ali_ac97_write(card->ac97_codec[1], 0x02, 0x0606);
- ali_ac97_write(card->ac97_codec[1], 0x18, 0x0303);
- ali_ac97_write(card->ac97_codec[1], 0x74, 0x3);
- }
- return 1;
- }
- }
- return -EINVAL;
-}
-
-static void
-ali_free_pcm_channel(struct trident_card *card, unsigned int channel)
-{
- int bank;
-
- if (channel > 31)
- return;
-
- bank = channel >> 5;
- channel = channel & 0x1f;
-
- card->banks[bank].bitmap &= ~(1 << (channel));
-}
-
-static int
-ali_allocate_other_states_resources(struct trident_state *state, int chan_nums)
-{
- struct trident_card *card = state->card;
- struct trident_state *s;
- int i, state_count = 0;
- struct trident_pcm_bank *bank;
- struct trident_channel *channel;
- unsigned long num;
-
- bank = &card->banks[BANK_A];
-
- if (chan_nums != 6)
- return 0;
-
- for (i = 0; (i < ALI_CHANNELS) && (state_count != 4); i++) {
- if (card->states[i])
- continue;
-
- num = ali_multi_channels_5_1[state_count];
- if (!(bank->bitmap & (1 << num))) {
- bank->bitmap |= 1 << num;
- channel = &bank->channels[num];
- channel->num = num;
- } else {
- state_count--;
- for (; state_count >= 0; state_count--) {
- kfree(state->other_states[state_count]);
- num = ali_multi_channels_5_1[state_count];
- ali_free_pcm_channel(card, num);
- }
- return -EBUSY;
- }
- s = card->states[i] = kzalloc(sizeof(*state), GFP_KERNEL);
- if (!s) {
- num = ali_multi_channels_5_1[state_count];
- ali_free_pcm_channel(card, num);
- state_count--;
- for (; state_count >= 0; state_count--) {
- num = ali_multi_channels_5_1[state_count];
- ali_free_pcm_channel(card, num);
- kfree(state->other_states[state_count]);
- }
- return -ENOMEM;
- }
-
- s->dmabuf.channel = channel;
- s->dmabuf.ossfragshift = s->dmabuf.ossmaxfrags =
- s->dmabuf.subdivision = 0;
- init_waitqueue_head(&s->dmabuf.wait);
- s->magic = card->magic;
- s->card = card;
- s->virt = i;
- ali_enable_special_channel(s);
- state->other_states[state_count++] = s;
- }
-
- if (state_count != 4) {
- state_count--;
- for (; state_count >= 0; state_count--) {
- kfree(state->other_states[state_count]);
- num = ali_multi_channels_5_1[state_count];
- ali_free_pcm_channel(card, num);
- }
- return -EBUSY;
- }
- return 0;
-}
-
-#ifdef CONFIG_PM
-/* save registers for ALi Power Management */
-static struct ali_saved_registers {
- unsigned long global_regs[ALI_GLOBAL_REGS];
- unsigned long channel_regs[ALI_CHANNELS][ALI_CHANNEL_REGS];
- unsigned mixer_regs[ALI_MIXER_REGS];
-} ali_registers;
-
-static void
-ali_save_regs(struct trident_card *card)
-{
- unsigned long flags;
- int i, j;
-
- spin_lock_irqsave(&card->lock, flags);
-
- ali_registers.global_regs[0x2c] = inl(TRID_REG(card, T4D_MISCINT));
- //ali_registers.global_regs[0x20] = inl(TRID_REG(card,T4D_START_A));
- ali_registers.global_regs[0x21] = inl(TRID_REG(card, T4D_STOP_A));
-
- //disable all IRQ bits
- outl(ALI_DISABLE_ALL_IRQ, TRID_REG(card, T4D_MISCINT));
-
- for (i = 1; i < ALI_MIXER_REGS; i++)
- ali_registers.mixer_regs[i] = ali_ac97_read(card->ac97_codec[0],
- i * 2);
-
- for (i = 0; i < ALI_GLOBAL_REGS; i++) {
- if ((i * 4 == T4D_MISCINT) || (i * 4 == T4D_STOP_A))
- continue;
- ali_registers.global_regs[i] = inl(TRID_REG(card, i * 4));
- }
-
- for (i = 0; i < ALI_CHANNELS; i++) {
- outb(i, TRID_REG(card, T4D_LFO_GC_CIR));
- for (j = 0; j < ALI_CHANNEL_REGS; j++)
- ali_registers.channel_regs[i][j] = inl(TRID_REG(card,
- j * 4 + 0xe0));
- }
-
- //Stop all HW channel
- outl(ALI_STOP_ALL_CHANNELS, TRID_REG(card, T4D_STOP_A));
-
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static void
-ali_restore_regs(struct trident_card *card)
-{
- unsigned long flags;
- int i, j;
-
- spin_lock_irqsave(&card->lock, flags);
-
- for (i = 1; i < ALI_MIXER_REGS; i++)
- ali_ac97_write(card->ac97_codec[0], i * 2,
- ali_registers.mixer_regs[i]);
-
- for (i = 0; i < ALI_CHANNELS; i++) {
- outb(i, TRID_REG(card, T4D_LFO_GC_CIR));
- for (j = 0; j < ALI_CHANNEL_REGS; j++)
- outl(ali_registers.channel_regs[i][j],
- TRID_REG(card, j * 4 + 0xe0));
- }
-
- for (i = 0; i < ALI_GLOBAL_REGS; i++) {
- if ((i * 4 == T4D_MISCINT) || (i * 4 == T4D_STOP_A) ||
- (i * 4 == T4D_START_A))
- continue;
- outl(ali_registers.global_regs[i], TRID_REG(card, i * 4));
- }
-
- //start HW channel
- outl(ali_registers.global_regs[0x20], TRID_REG(card, T4D_START_A));
- //restore IRQ enable bits
- outl(ali_registers.global_regs[0x2c], TRID_REG(card, T4D_MISCINT));
-
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static int
-trident_suspend(struct pci_dev *dev, pm_message_t unused)
-{
- struct trident_card *card = pci_get_drvdata(dev);
-
- if (card->pci_id == PCI_DEVICE_ID_ALI_5451) {
- ali_save_regs(card);
- }
- return 0;
-}
-
-static int
-trident_resume(struct pci_dev *dev)
-{
- struct trident_card *card = pci_get_drvdata(dev);
-
- if (card->pci_id == PCI_DEVICE_ID_ALI_5451) {
- ali_restore_regs(card);
- }
- return 0;
-}
-#endif
-
-static struct trident_channel *
-ali_alloc_pcm_channel(struct trident_card *card)
-{
- struct trident_pcm_bank *bank;
- int idx;
-
- bank = &card->banks[BANK_A];
-
- if (inl(TRID_REG(card, ALI_GLOBAL_CONTROL)) &
- (ALI_SPDIF_OUT_CH_ENABLE)) {
- idx = ALI_SPDIF_OUT_CHANNEL;
- if (!(bank->bitmap & (1 << idx))) {
- struct trident_channel *channel = &bank->channels[idx];
- bank->bitmap |= 1 << idx;
- channel->num = idx;
- return channel;
- }
- }
-
- for (idx = ALI_PCM_OUT_CHANNEL_FIRST; idx <= ALI_PCM_OUT_CHANNEL_LAST;
- idx++) {
- if (!(bank->bitmap & (1 << idx))) {
- struct trident_channel *channel = &bank->channels[idx];
- bank->bitmap |= 1 << idx;
- channel->num = idx;
- return channel;
- }
- }
-
- /* no more free channels avaliable */
-#if 0
- printk(KERN_ERR "ali: no more channels available on Bank A.\n");
-#endif /* 0 */
- return NULL;
-}
-
-static struct trident_channel *
-ali_alloc_rec_pcm_channel(struct trident_card *card)
-{
- struct trident_pcm_bank *bank;
- int idx;
-
- if (inl(TRID_REG(card, ALI_GLOBAL_CONTROL)) & ALI_SPDIF_IN_SUPPORT)
- idx = ALI_SPDIF_IN_CHANNEL;
- else
- idx = ALI_PCM_IN_CHANNEL;
-
- bank = &card->banks[BANK_A];
-
- if (!(bank->bitmap & (1 << idx))) {
- struct trident_channel *channel = &bank->channels[idx];
- bank->bitmap |= 1 << idx;
- channel->num = idx;
- return channel;
- }
-
- /* no free recordable channels avaliable */
-#if 0
- printk(KERN_ERR "ali: no recordable channels available on Bank A.\n");
-#endif /* 0 */
- return NULL;
-}
-
-static void
-ali_set_spdif_out_rate(struct trident_card *card, unsigned int rate)
-{
- unsigned char ch_st_sel;
- unsigned short status_rate;
-
- switch (rate) {
- case 44100:
- status_rate = 0;
- break;
- case 32000:
- status_rate = 0x300;
- break;
- case 48000:
- default:
- status_rate = 0x200;
- break;
- }
-
- /* select spdif_out */
- ch_st_sel = inb(TRID_REG(card, ALI_SPDIF_CTRL)) & ALI_SPDIF_OUT_CH_STATUS;
-
- ch_st_sel |= 0x80; /* select right */
- outb(ch_st_sel, TRID_REG(card, ALI_SPDIF_CTRL));
- outb(status_rate | 0x20, TRID_REG(card, ALI_SPDIF_CS + 2));
-
- ch_st_sel &= (~0x80); /* select left */
- outb(ch_st_sel, TRID_REG(card, ALI_SPDIF_CTRL));
- outw(status_rate | 0x10, TRID_REG(card, ALI_SPDIF_CS + 2));
-}
-
-static void
-ali_address_interrupt(struct trident_card *card)
-{
- int i, channel;
- struct trident_state *state;
- u32 mask, channel_mask;
-
- mask = trident_get_interrupt_mask(card, 0);
- for (i = 0; i < NR_HW_CH; i++) {
- if ((state = card->states[i]) == NULL)
- continue;
- channel = state->dmabuf.channel->num;
- if ((channel_mask = 1 << channel) & mask) {
- mask &= ~channel_mask;
- trident_ack_channel_interrupt(card, channel);
- udelay(100);
- state->dmabuf.update_flag |= ALI_ADDRESS_INT_UPDATE;
- trident_update_ptr(state);
- }
- }
- if (mask) {
- for (i = 0; i < NR_HW_CH; i++) {
- if (mask & (1 << i)) {
- printk("ali: spurious channel irq %d.\n", i);
- trident_ack_channel_interrupt(card, i);
- trident_stop_voice(card, i);
- trident_disable_voice_irq(card, i);
- }
- }
- }
-}
-
-/* Updating the values of counters of other_states' DMAs without lock
-protection is no harm because all DMAs of multi-channels and interrupt
-depend on a master state's DMA, and changing the counters of the master
-state DMA is protected by a spinlock.
-*/
-static int
-ali_write_5_1(struct trident_state *state, const char __user *buf,
- int cnt_for_multi_channel, unsigned int *copy_count,
- unsigned int *state_cnt)
-{
-
- struct dmabuf *dmabuf = &state->dmabuf;
- struct dmabuf *dmabuf_temp;
- const char __user *buffer = buf;
- unsigned swptr, other_dma_nums, sample_s;
- unsigned int i, loop;
-
- other_dma_nums = 4;
- sample_s = sample_size[dmabuf->fmt] >> 1;
- swptr = dmabuf->swptr;
-
- if ((i = state->multi_channels_adjust_count) > 0) {
- if (i == 1) {
- if (copy_from_user(dmabuf->rawbuf + swptr,
- buffer, sample_s))
- return -EFAULT;
- seek_offset(swptr, buffer, cnt_for_multi_channel,
- sample_s, *copy_count);
- i--;
- (*state_cnt) += sample_s;
- state->multi_channels_adjust_count++;
- } else
- i = i - (state->chans_num - other_dma_nums);
- for (; (i < other_dma_nums) && (cnt_for_multi_channel > 0); i++) {
- dmabuf_temp = &state->other_states[i]->dmabuf;
- if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr,
- buffer, sample_s))
- return -EFAULT;
- seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel,
- sample_s, *copy_count);
- }
- if (cnt_for_multi_channel == 0)
- state->multi_channels_adjust_count += i;
- }
- if (cnt_for_multi_channel > 0) {
- loop = cnt_for_multi_channel / (state->chans_num * sample_s);
- for (i = 0; i < loop; i++) {
- if (copy_from_user(dmabuf->rawbuf + swptr, buffer,
- sample_s * 2))
- return -EFAULT;
- seek_offset(swptr, buffer, cnt_for_multi_channel,
- sample_s * 2, *copy_count);
- (*state_cnt) += (sample_s * 2);
-
- dmabuf_temp = &state->other_states[0]->dmabuf;
- if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr,
- buffer, sample_s))
- return -EFAULT;
- seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel,
- sample_s, *copy_count);
-
- dmabuf_temp = &state->other_states[1]->dmabuf;
- if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr,
- buffer, sample_s))
- return -EFAULT;
- seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel,
- sample_s, *copy_count);
-
- dmabuf_temp = &state->other_states[2]->dmabuf;
- if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr,
- buffer, sample_s))
- return -EFAULT;
- seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel,
- sample_s, *copy_count);
-
- dmabuf_temp = &state->other_states[3]->dmabuf;
- if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr,
- buffer, sample_s))
- return -EFAULT;
- seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel,
- sample_s, *copy_count);
- }
-
- if (cnt_for_multi_channel > 0) {
- state->multi_channels_adjust_count = cnt_for_multi_channel / sample_s;
-
- if (copy_from_user(dmabuf->rawbuf + swptr, buffer, sample_s))
- return -EFAULT;
- seek_offset(swptr, buffer, cnt_for_multi_channel,
- sample_s, *copy_count);
- (*state_cnt) += sample_s;
-
- if (cnt_for_multi_channel > 0) {
- if (copy_from_user(dmabuf->rawbuf + swptr,
- buffer, sample_s))
- return -EFAULT;
- seek_offset(swptr, buffer, cnt_for_multi_channel,
- sample_s, *copy_count);
- (*state_cnt) += sample_s;
-
- if (cnt_for_multi_channel > 0) {
- int diff = state->chans_num - other_dma_nums;
- loop = state->multi_channels_adjust_count - diff;
- for (i = 0; i < loop; i++) {
- dmabuf_temp = &state->other_states[i]->dmabuf;
- if (copy_from_user(dmabuf_temp->rawbuf +
- dmabuf_temp->swptr,
- buffer, sample_s))
- return -EFAULT;
- seek_offset(dmabuf_temp->swptr, buffer,
- cnt_for_multi_channel,
- sample_s, *copy_count);
- }
- }
- }
- } else
- state->multi_channels_adjust_count = 0;
- }
- for (i = 0; i < other_dma_nums; i++) {
- dmabuf_temp = &state->other_states[i]->dmabuf;
- dmabuf_temp->swptr = dmabuf_temp->swptr % dmabuf_temp->dmasize;
- }
- return *state_cnt;
-}
-
-static void
-ali_free_other_states_resources(struct trident_state *state)
-{
- int i;
- struct trident_card *card = state->card;
- struct trident_state *s;
- unsigned other_states_count;
-
- other_states_count = state->chans_num - 2; /* except PCM L/R channels */
- for (i = 0; i < other_states_count; i++) {
- s = state->other_states[i];
- dealloc_dmabuf(&s->dmabuf, card->pci_dev);
- ali_disable_special_channel(s->card, s->dmabuf.channel->num);
- state->card->free_pcm_channel(s->card, s->dmabuf.channel->num);
- card->states[s->virt] = NULL;
- kfree(s);
- }
-}
-
-static struct proc_dir_entry *res;
-
-static int
-ali_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data)
-{
- struct trident_card *card = (struct trident_card *) data;
- unsigned long flags;
- char c;
-
- if (count < 0)
- return -EINVAL;
- if (count == 0)
- return 0;
- if (get_user(c, buffer))
- return -EFAULT;
-
- spin_lock_irqsave(&card->lock, flags);
- switch (c) {
- case '0':
- ali_setup_spdif_out(card, ALI_PCM_TO_SPDIF_OUT);
- ali_disable_special_channel(card, ALI_SPDIF_OUT_CHANNEL);
- break;
- case '1':
- ali_setup_spdif_out(card, ALI_SPDIF_OUT_TO_SPDIF_OUT |
- ALI_SPDIF_OUT_PCM);
- break;
- case '2':
- ali_setup_spdif_out(card, ALI_SPDIF_OUT_TO_SPDIF_OUT |
- ALI_SPDIF_OUT_NON_PCM);
- break;
- case '3':
- ali_disable_spdif_in(card); //default
- break;
- case '4':
- ali_setup_spdif_in(card);
- break;
- }
- spin_unlock_irqrestore(&card->lock, flags);
-
- return count;
-}
-
-/* OSS /dev/mixer file operation methods */
-static int
-trident_open_mixdev(struct inode *inode, struct file *file)
-{
- int i = 0;
- int minor = iminor(inode);
- struct trident_card *card = devs;
-
- for (card = devs; card != NULL; card = card->next)
- for (i = 0; i < NR_AC97; i++)
- if (card->ac97_codec[i] != NULL &&
- card->ac97_codec[i]->dev_mixer == minor)
- goto match;
-
- if (!card) {
- return -ENODEV;
- }
- match:
- file->private_data = card->ac97_codec[i];
-
- return nonseekable_open(inode, file);
-}
-
-static int
-trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct ac97_codec *codec = (struct ac97_codec *) file->private_data;
-
- return codec->mixer_ioctl(codec, cmd, arg);
-}
-
-static /*const */ struct file_operations trident_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = trident_ioctl_mixdev,
- .open = trident_open_mixdev,
-};
-
-static int
-ali_reset_5451(struct trident_card *card)
-{
- struct pci_dev *pci_dev = NULL;
- unsigned int dwVal;
- unsigned short wCount, wReg;
-
- pci_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
- pci_dev);
- if (pci_dev == NULL)
- return -1;
-
- pci_read_config_dword(pci_dev, 0x7c, &dwVal);
- pci_write_config_dword(pci_dev, 0x7c, dwVal | 0x08000000);
- udelay(5000);
- pci_read_config_dword(pci_dev, 0x7c, &dwVal);
- pci_write_config_dword(pci_dev, 0x7c, dwVal & 0xf7ffffff);
- udelay(5000);
- pci_dev_put(pci_dev);
-
- pci_dev = card->pci_dev;
- if (pci_dev == NULL)
- return -1;
-
- pci_read_config_dword(pci_dev, 0x44, &dwVal);
- pci_write_config_dword(pci_dev, 0x44, dwVal | 0x000c0000);
- udelay(500);
- pci_read_config_dword(pci_dev, 0x44, &dwVal);
- pci_write_config_dword(pci_dev, 0x44, dwVal & 0xfffbffff);
- udelay(5000);
-
- /* TODO: recognize if we have a PM capable codec and only do this */
- /* if the codec is PM capable */
- wCount = 2000;
- while (wCount--) {
- wReg = ali_ac97_get(card, 0, AC97_POWER_CONTROL);
- if ((wReg & 0x000f) == 0x000f)
- return 0;
- udelay(5000);
- }
- /* This is non fatal if you have a non PM capable codec.. */
- return 0;
-}
-
-/* AC97 codec initialisation. */
-static int __devinit
-trident_ac97_init(struct trident_card *card)
-{
- int num_ac97 = 0;
- unsigned long ready_2nd = 0;
- struct ac97_codec *codec;
- int i = 0;
-
- /* initialize controller side of AC link, and find out if secondary codes
- really exist */
- switch (card->pci_id) {
- case PCI_DEVICE_ID_ALI_5451:
- if (ali_reset_5451(card)) {
- printk(KERN_ERR "trident_ac97_init: error "
- "resetting 5451.\n");
- return -1;
- }
- outl(0x80000001, TRID_REG(card, ALI_GLOBAL_CONTROL));
- outl(0x00000000, TRID_REG(card, T4D_AINTEN_A));
- outl(0xffffffff, TRID_REG(card, T4D_AINT_A));
- outl(0x00000000, TRID_REG(card, T4D_MUSICVOL_WAVEVOL));
- outb(0x10, TRID_REG(card, ALI_MPUR2));
- ready_2nd = inl(TRID_REG(card, ALI_SCTRL));
- ready_2nd &= 0x3fff;
- outl(ready_2nd | PCMOUT | 0x8000, TRID_REG(card, ALI_SCTRL));
- ready_2nd = inl(TRID_REG(card, ALI_SCTRL));
- ready_2nd &= SI_AC97_SECONDARY_READY;
- if (card->revision < ALI_5451_V02)
- ready_2nd = 0;
- break;
- case PCI_DEVICE_ID_SI_7018:
- /* disable AC97 GPIO interrupt */
- outl(0x00, TRID_REG(card, SI_AC97_GPIO));
- /* when power up the AC link is in cold reset mode so stop it */
- outl(PCMOUT | SURROUT | CENTEROUT | LFEOUT | SECONDARY_ID,
- TRID_REG(card, SI_SERIAL_INTF_CTRL));
- /* it take a long time to recover from a cold reset */
- /* (especially when you have more than one codec) */
- udelay(2000);
- ready_2nd = inl(TRID_REG(card, SI_SERIAL_INTF_CTRL));
- ready_2nd &= SI_AC97_SECONDARY_READY;
- break;
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
- /* playback on */
- outl(DX_AC97_PLAYBACK, TRID_REG(card, DX_ACR2_AC97_COM_STAT));
- break;
- case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
- /* enable AC97 Output Slot 3,4 (PCM Left/Right Playback) */
- outl(NX_AC97_PCM_OUTPUT, TRID_REG(card, NX_ACR0_AC97_COM_STAT));
- ready_2nd = inl(TRID_REG(card, NX_ACR0_AC97_COM_STAT));
- ready_2nd &= NX_AC97_SECONDARY_READY;
- break;
- case PCI_DEVICE_ID_INTERG_5050:
- /* disable AC97 GPIO interrupt */
- outl(0x00, TRID_REG(card, SI_AC97_GPIO));
- /* when power up, the AC link is in cold reset mode, so stop it */
- outl(PCMOUT | SURROUT | CENTEROUT | LFEOUT,
- TRID_REG(card, SI_SERIAL_INTF_CTRL));
- /* it take a long time to recover from a cold reset (especially */
- /* when you have more than one codec) */
- udelay(2000);
- ready_2nd = inl(TRID_REG(card, SI_SERIAL_INTF_CTRL));
- ready_2nd &= SI_AC97_SECONDARY_READY;
- break;
- }
-
- for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
- if ((codec = ac97_alloc_codec()) == NULL)
- return -ENOMEM;
-
- /* initialize some basic codec information, other fields */
- /* will be filled in ac97_probe_codec */
- codec->private_data = card;
- codec->id = num_ac97;
-
- if (card->pci_id == PCI_DEVICE_ID_ALI_5451) {
- codec->codec_read = ali_ac97_read;
- codec->codec_write = ali_ac97_write;
- } else {
- codec->codec_read = trident_ac97_get;
- codec->codec_write = trident_ac97_set;
- }
-
- if (ac97_probe_codec(codec) == 0)
- break;
-
- codec->dev_mixer = register_sound_mixer(&trident_mixer_fops, -1);
- if (codec->dev_mixer < 0) {
- printk(KERN_ERR "trident: couldn't register mixer!\n");
- ac97_release_codec(codec);
- break;
- }
-
- card->ac97_codec[num_ac97] = codec;
-
- /* if there is no secondary codec at all, don't probe any more */
- if (!ready_2nd)
- break;
- }
-
- if (card->pci_id == PCI_DEVICE_ID_ALI_5451) {
- for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
- if (card->ac97_codec[num_ac97] == NULL)
- break;
- for (i = 0; i < 64; i++) {
- u16 reg = ali_ac97_get(card, num_ac97, i * 2);
- card->mixer_regs[i][num_ac97] = reg;
- }
- }
- }
- return num_ac97 + 1;
-}
-
-#ifdef SUPPORT_JOYSTICK
-/* Gameport functions for the cards ADC gameport */
-
-static unsigned char trident_game_read(struct gameport *gameport)
-{
- struct trident_card *card = gameport->port_data;
-
- return inb(TRID_REG(card, T4D_GAME_LEG));
-}
-
-static void trident_game_trigger(struct gameport *gameport)
-{
- struct trident_card *card = gameport->port_data;
-
- outb(0xff, TRID_REG(card, T4D_GAME_LEG));
-}
-
-static int trident_game_cooked_read(struct gameport *gameport,
- int *axes, int *buttons)
-{
- struct trident_card *card = gameport->port_data;
- int i;
-
- *buttons = (~inb(TRID_REG(card, T4D_GAME_LEG)) >> 4) & 0xf;
-
- for (i = 0; i < 4; i++) {
- axes[i] = inw(TRID_REG(card, T4D_GAME_AXD) + i * sizeof (u16));
- if (axes[i] == 0xffff)
- axes[i] = -1;
- }
-
- return 0;
-}
-
-static int trident_game_open(struct gameport *gameport, int mode)
-{
- struct trident_card *card = gameport->port_data;
-
- switch (mode) {
- case GAMEPORT_MODE_COOKED:
- outb(0x80, TRID_REG(card, T4D_GAME_CR));
- msleep(20);
- return 0;
- case GAMEPORT_MODE_RAW:
- outb(0x00, TRID_REG(card, T4D_GAME_CR));
- return 0;
- default:
- return -1;
- }
-
- return 0;
-}
-
-static int __devinit trident_register_gameport(struct trident_card *card)
-{
- struct gameport *gp;
-
- card->gameport = gp = gameport_allocate_port();
- if (!gp) {
- printk(KERN_ERR "trident: can not allocate memory for gameport\n");
- return -ENOMEM;
- }
-
- gameport_set_name(gp, "Trident 4DWave");
- gameport_set_phys(gp, "pci%s/gameport0", pci_name(card->pci_dev));
- gp->read = trident_game_read;
- gp->trigger = trident_game_trigger;
- gp->cooked_read = trident_game_cooked_read;
- gp->open = trident_game_open;
- gp->fuzz = 64;
- gp->port_data = card;
-
- gameport_register_port(gp);
-
- return 0;
-}
-
-static inline void trident_unregister_gameport(struct trident_card *card)
-{
- if (card->gameport)
- gameport_unregister_port(card->gameport);
-}
-
-#else
-static inline int trident_register_gameport(struct trident_card *card) { return -ENOSYS; }
-static inline void trident_unregister_gameport(struct trident_card *card) { }
-#endif /* SUPPORT_JOYSTICK */
-
-/* install the driver, we do not allocate hardware channel nor DMA buffer */
-/* now, they are defered until "ACCESS" time (in prog_dmabuf called by */
-/* open/read/write/ioctl/mmap) */
-static int __devinit
-trident_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
-{
- unsigned long iobase;
- struct trident_card *card;
- u8 bits;
- u8 revision;
- int i = 0;
- u16 temp;
- struct pci_dev *pci_dev_m1533 = NULL;
- int rc = -ENODEV;
- u64 dma_mask;
-
- if (pci_enable_device(pci_dev))
- goto out;
-
- if (pci_dev->device == PCI_DEVICE_ID_ALI_5451)
- dma_mask = ALI_DMA_MASK;
- else
- dma_mask = TRIDENT_DMA_MASK;
- if (pci_set_dma_mask(pci_dev, dma_mask)) {
- printk(KERN_ERR "trident: architecture does not support"
- " %s PCI busmaster DMA\n",
- pci_dev->device == PCI_DEVICE_ID_ALI_5451 ?
- "32-bit" : "30-bit");
- goto out;
- }
- pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
-
- if (pci_id->device == PCI_DEVICE_ID_INTERG_5050)
- iobase = pci_resource_start(pci_dev, 1);
- else
- iobase = pci_resource_start(pci_dev, 0);
-
- if (!request_region(iobase, 256, card_names[pci_id->driver_data])) {
- printk(KERN_ERR "trident: can't allocate I/O space at "
- "0x%4.4lx\n", iobase);
- goto out;
- }
-
- rc = -ENOMEM;
- if ((card = kzalloc(sizeof(*card), GFP_KERNEL)) == NULL) {
- printk(KERN_ERR "trident: out of memory\n");
- goto out_release_region;
- }
-
- init_timer(&card->timer);
- card->iobase = iobase;
- card->pci_dev = pci_dev_get(pci_dev);
- card->pci_id = pci_id->device;
- card->revision = revision;
- card->irq = pci_dev->irq;
- card->next = devs;
- card->magic = TRIDENT_CARD_MAGIC;
- card->banks[BANK_A].addresses = &bank_a_addrs;
- card->banks[BANK_A].bitmap = 0UL;
- card->banks[BANK_B].addresses = &bank_b_addrs;
- card->banks[BANK_B].bitmap = 0UL;
-
- mutex_init(&card->open_mutex);
- spin_lock_init(&card->lock);
- init_timer(&card->timer);
-
- devs = card;
-
- pci_set_master(pci_dev);
-
- printk(KERN_INFO "trident: %s found at IO 0x%04lx, IRQ %d\n",
- card_names[pci_id->driver_data], card->iobase, card->irq);
-
- if (card->pci_id == PCI_DEVICE_ID_ALI_5451) {
- /* ALi channel Management */
- card->alloc_pcm_channel = ali_alloc_pcm_channel;
- card->alloc_rec_pcm_channel = ali_alloc_rec_pcm_channel;
- card->free_pcm_channel = ali_free_pcm_channel;
-
- card->address_interrupt = ali_address_interrupt;
-
- /* Added by Matt Wu 01-05-2001 for spdif in */
- card->multi_channel_use_count = 0;
- card->rec_channel_use_count = 0;
-
- /* ALi SPDIF OUT function */
- if (card->revision == ALI_5451_V02) {
- ali_setup_spdif_out(card, ALI_PCM_TO_SPDIF_OUT);
- res = create_proc_entry("ALi5451", 0, NULL);
- if (res) {
- res->write_proc = ali_write_proc;
- res->data = card;
- }
- }
-
- /* Add H/W Volume Control By Matt Wu Jul. 06, 2001 */
- card->hwvolctl = 0;
- pci_dev_m1533 = pci_get_device(PCI_VENDOR_ID_AL,
- PCI_DEVICE_ID_AL_M1533,
- pci_dev_m1533);
- rc = -ENODEV;
- if (pci_dev_m1533 == NULL)
- goto out_proc_fs;
- pci_read_config_byte(pci_dev_m1533, 0x63, &bits);
- if (bits & (1 << 5))
- card->hwvolctl = 1;
- if (card->hwvolctl) {
- /* Clear m1533 pci cfg 78h bit 30 to zero, which makes
- GPIO11/12/13 work as ACGP_UP/DOWN/MUTE. */
- pci_read_config_byte(pci_dev_m1533, 0x7b, &bits);
- bits &= 0xbf; /*clear bit 6 */
- pci_write_config_byte(pci_dev_m1533, 0x7b, bits);
- }
- pci_dev_put(pci_dev_m1533);
-
- } else if (card->pci_id == PCI_DEVICE_ID_INTERG_5050) {
- card->alloc_pcm_channel = cyber_alloc_pcm_channel;
- card->alloc_rec_pcm_channel = cyber_alloc_pcm_channel;
- card->free_pcm_channel = cyber_free_pcm_channel;
- card->address_interrupt = cyber_address_interrupt;
- cyber_init_ritual(card);
- } else {
- card->alloc_pcm_channel = trident_alloc_pcm_channel;
- card->alloc_rec_pcm_channel = trident_alloc_pcm_channel;
- card->free_pcm_channel = trident_free_pcm_channel;
- card->address_interrupt = trident_address_interrupt;
- }
-
- /* claim our irq */
- rc = -ENODEV;
- if (request_irq(card->irq, &trident_interrupt, IRQF_SHARED,
- card_names[pci_id->driver_data], card)) {
- printk(KERN_ERR "trident: unable to allocate irq %d\n",
- card->irq);
- goto out_proc_fs;
- }
- /* register /dev/dsp */
- if ((card->dev_audio = register_sound_dsp(&trident_audio_fops, -1)) < 0) {
- printk(KERN_ERR "trident: couldn't register DSP device!\n");
- goto out_free_irq;
- }
- card->mixer_regs_ready = 0;
- /* initialize AC97 codec and register /dev/mixer */
- if (trident_ac97_init(card) <= 0) {
- /* unregister audio devices */
- for (i = 0; i < NR_AC97; i++) {
- if (card->ac97_codec[i] != NULL) {
- struct ac97_codec* codec = card->ac97_codec[i];
- unregister_sound_mixer(codec->dev_mixer);
- ac97_release_codec(codec);
- }
- }
- goto out_unregister_sound_dsp;
- }
- card->mixer_regs_ready = 1;
- outl(0x00, TRID_REG(card, T4D_MUSICVOL_WAVEVOL));
-
- if (card->pci_id == PCI_DEVICE_ID_ALI_5451) {
- /* Add H/W Volume Control By Matt Wu Jul. 06, 2001 */
- if (card->hwvolctl) {
- /* Enable GPIO IRQ (MISCINT bit 18h) */
- temp = inw(TRID_REG(card, T4D_MISCINT + 2));
- temp |= 0x0004;
- outw(temp, TRID_REG(card, T4D_MISCINT + 2));
-
- /* Enable H/W Volume Control GLOVAL CONTROL bit 0 */
- temp = inw(TRID_REG(card, ALI_GLOBAL_CONTROL));
- temp |= 0x0001;
- outw(temp, TRID_REG(card, ALI_GLOBAL_CONTROL));
-
- }
- if (card->revision == ALI_5451_V02)
- ali_close_multi_channels();
- /* edited by HMSEO for GT sound */
-#if defined(CONFIG_ALPHA_NAUTILUS) || defined(CONFIG_ALPHA_GENERIC)
- {
- u16 ac97_data;
- extern struct hwrpb_struct *hwrpb;
-
- if ((hwrpb->sys_type) == 201) {
- printk(KERN_INFO "trident: Running on Alpha system "
- "type Nautilus\n");
- ac97_data = ali_ac97_get(card, 0, AC97_POWER_CONTROL);
- ali_ac97_set(card, 0, AC97_POWER_CONTROL,
- ac97_data | ALI_EAPD_POWER_DOWN);
- }
- }
-#endif /* CONFIG_ALPHA_NAUTILUS || CONFIG_ALPHA_GENERIC */
- /* edited by HMSEO for GT sound */
- }
- rc = 0;
- pci_set_drvdata(pci_dev, card);
-
- /* Enable Address Engine Interrupts */
- trident_enable_loop_interrupts(card);
-
- /* Register gameport */
- trident_register_gameport(card);
-
-out:
- return rc;
-
-out_unregister_sound_dsp:
- unregister_sound_dsp(card->dev_audio);
-out_free_irq:
- free_irq(card->irq, card);
-out_proc_fs:
- pci_dev_put(card->pci_dev);
- if (res) {
- remove_proc_entry("ALi5451", NULL);
- res = NULL;
- }
- kfree(card);
- devs = NULL;
-out_release_region:
- release_region(iobase, 256);
- return rc;
-}
-
-static void __devexit
-trident_remove(struct pci_dev *pci_dev)
-{
- int i;
- struct trident_card *card = pci_get_drvdata(pci_dev);
-
- /*
- * Kill running timers before unload. We can't have them
- * going off after rmmod!
- */
- if (card->hwvolctl)
- del_timer_sync(&card->timer);
-
- /* ALi S/PDIF and Power Management */
- if (card->pci_id == PCI_DEVICE_ID_ALI_5451) {
- ali_setup_spdif_out(card, ALI_PCM_TO_SPDIF_OUT);
- ali_disable_special_channel(card, ALI_SPDIF_OUT_CHANNEL);
- ali_disable_spdif_in(card);
- remove_proc_entry("ALi5451", NULL);
- }
-
- /* Unregister gameport */
- trident_unregister_gameport(card);
-
- /* Kill interrupts, and SP/DIF */
- trident_disable_loop_interrupts(card);
-
- /* free hardware resources */
- free_irq(card->irq, card);
- release_region(card->iobase, 256);
-
- /* unregister audio devices */
- for (i = 0; i < NR_AC97; i++)
- if (card->ac97_codec[i] != NULL) {
- unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
- ac97_release_codec(card->ac97_codec[i]);
- }
- unregister_sound_dsp(card->dev_audio);
-
- pci_set_drvdata(pci_dev, NULL);
- pci_dev_put(card->pci_dev);
- kfree(card);
-}
-
-MODULE_AUTHOR("Alan Cox, Aaron Holtzman, Ollie Lho, Ching Ling Lee, Muli Ben-Yehuda");
-MODULE_DESCRIPTION("Trident 4DWave/SiS 7018/ALi 5451 and Tvia/IGST CyberPro5050 PCI "
- "Audio Driver");
-MODULE_LICENSE("GPL");
-
-#define TRIDENT_MODULE_NAME "trident"
-
-static struct pci_driver trident_pci_driver = {
- .name = TRIDENT_MODULE_NAME,
- .id_table = trident_pci_tbl,
- .probe = trident_probe,
- .remove = __devexit_p(trident_remove),
-#ifdef CONFIG_PM
- .suspend = trident_suspend,
- .resume = trident_resume
-#endif
-};
-
-static int __init
-trident_init_module(void)
-{
- printk(KERN_INFO "Trident 4DWave/SiS 7018/ALi 5451,Tvia CyberPro "
- "5050 PCI Audio, version " DRIVER_VERSION ", " __TIME__ " "
- __DATE__ "\n");
-
- return pci_register_driver(&trident_pci_driver);
-}
-
-static void __exit
-trident_cleanup_module(void)
-{
- pci_unregister_driver(&trident_pci_driver);
-}
-
-module_init(trident_init_module);
-module_exit(trident_cleanup_module);
diff --git a/sound/oss/trident.h b/sound/oss/trident.h
deleted file mode 100644
index 4713b49fc91..00000000000
--- a/sound/oss/trident.h
+++ /dev/null
@@ -1,358 +0,0 @@
-#ifndef __TRID4DWAVE_H
-#define __TRID4DWAVE_H
-
-/*
- * audio@tridentmicro.com
- * Fri Feb 19 15:55:28 MST 1999
- * Definitions for Trident 4DWave DX/NX chips
- *
- *
- * 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.
- *
- */
-
-/* PCI vendor and device ID */
-#ifndef PCI_VENDOR_ID_TRIDENT
-#define PCI_VENDOR_ID_TRIDENT 0x1023
-#endif
-
-#ifndef PCI_VENDOR_ID_SI
-#define PCI_VENDOR_ID_SI 0x1039
-#endif
-
-#ifndef PCI_VENDOR_ID_ALI
-#define PCI_VENDOR_ID_ALI 0x10b9
-#endif
-
-#ifndef PCI_DEVICE_ID_TRIDENT_4DWAVE_DX
-#define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000
-#endif
-
-#ifndef PCI_DEVICE_ID_TRIDENT_4DWAVE_NX
-#define PCI_DEVICE_ID_TRIDENT_4DWAVE_NX 0x2001
-#endif
-
-#ifndef PCI_DEVICE_ID_SI_7018
-#define PCI_DEVICE_ID_SI_7018 0x7018
-#endif
-
-#ifndef PCI_DEVICE_ID_ALI_5451
-#define PCI_DEVICE_ID_ALI_5451 0x5451
-#endif
-
-#ifndef PCI_DEVICE_ID_ALI_1533
-#define PCI_DEVICE_ID_ALI_1533 0x1533
-#endif
-
-#define CHANNEL_REGS 5
-#define CHANNEL_START 0xe0 // The first bytes of the contiguous register space.
-
-#define BANK_A 0
-#define BANK_B 1
-#define NR_BANKS 2
-
-#define TRIDENT_FMT_STEREO 0x01
-#define TRIDENT_FMT_16BIT 0x02
-#define TRIDENT_FMT_MASK 0x03
-
-#define DAC_RUNNING 0x01
-#define ADC_RUNNING 0x02
-
-/* Register Addresses */
-
-/* operational registers common to DX, NX, 7018 */
-enum trident_op_registers {
- T4D_GAME_CR = 0x30, T4D_GAME_LEG = 0x31,
- T4D_GAME_AXD = 0x34,
- T4D_REC_CH = 0x70,
- T4D_START_A = 0x80, T4D_STOP_A = 0x84,
- T4D_DLY_A = 0x88, T4D_SIGN_CSO_A = 0x8c,
- T4D_CSPF_A = 0x90, T4D_CEBC_A = 0x94,
- T4D_AINT_A = 0x98, T4D_EINT_A = 0x9c,
- T4D_LFO_GC_CIR = 0xa0, T4D_AINTEN_A = 0xa4,
- T4D_MUSICVOL_WAVEVOL = 0xa8, T4D_SBDELTA_DELTA_R = 0xac,
- T4D_MISCINT = 0xb0, T4D_START_B = 0xb4,
- T4D_STOP_B = 0xb8, T4D_CSPF_B = 0xbc,
- T4D_SBBL_SBCL = 0xc0, T4D_SBCTRL_SBE2R_SBDD = 0xc4,
- T4D_STIMER = 0xc8, T4D_LFO_B_I2S_DELTA = 0xcc,
- T4D_AINT_B = 0xd8, T4D_AINTEN_B = 0xdc,
- ALI_MPUR2 = 0x22, ALI_GPIO = 0x7c,
- ALI_EBUF1 = 0xf4,
- ALI_EBUF2 = 0xf8
-};
-
-enum ali_op_registers {
- ALI_SCTRL = 0x48,
- ALI_GLOBAL_CONTROL = 0xd4,
- ALI_STIMER = 0xc8,
- ALI_SPDIF_CS = 0x70,
- ALI_SPDIF_CTRL = 0x74
-};
-
-enum ali_registers_number {
- ALI_GLOBAL_REGS = 56,
- ALI_CHANNEL_REGS = 8,
- ALI_MIXER_REGS = 20
-};
-
-enum ali_sctrl_control_bit {
- ALI_SPDIF_OUT_ENABLE = 0x20
-};
-
-enum ali_global_control_bit {
- ALI_SPDIF_OUT_SEL_PCM = 0x00000400,
- ALI_SPDIF_IN_SUPPORT = 0x00000800,
- ALI_SPDIF_OUT_CH_ENABLE = 0x00008000,
- ALI_SPDIF_IN_CH_ENABLE = 0x00080000,
- ALI_PCM_IN_DISABLE = 0x7fffffff,
- ALI_PCM_IN_ENABLE = 0x80000000,
- ALI_SPDIF_IN_CH_DISABLE = 0xfff7ffff,
- ALI_SPDIF_OUT_CH_DISABLE = 0xffff7fff,
- ALI_SPDIF_OUT_SEL_SPDIF = 0xfffffbff
-
-};
-
-enum ali_spdif_control_bit {
- ALI_SPDIF_IN_FUNC_ENABLE = 0x02,
- ALI_SPDIF_IN_CH_STATUS = 0x40,
- ALI_SPDIF_OUT_CH_STATUS = 0xbf
-
-};
-
-enum ali_control_all {
- ALI_DISABLE_ALL_IRQ = 0,
- ALI_CHANNELS = 32,
- ALI_STOP_ALL_CHANNELS = 0xffffffff,
- ALI_MULTI_CHANNELS_START_STOP = 0x07800000
-};
-
-enum ali_EMOD_control_bit {
- ALI_EMOD_DEC = 0x00000000,
- ALI_EMOD_INC = 0x10000000,
- ALI_EMOD_Delay = 0x20000000,
- ALI_EMOD_Still = 0x30000000
-};
-
-enum ali_pcm_in_channel_num {
- ALI_NORMAL_CHANNEL = 0,
- ALI_SPDIF_OUT_CHANNEL = 15,
- ALI_SPDIF_IN_CHANNEL = 19,
- ALI_LEF_CHANNEL = 23,
- ALI_CENTER_CHANNEL = 24,
- ALI_SURR_RIGHT_CHANNEL = 25,
- ALI_SURR_LEFT_CHANNEL = 26,
- ALI_PCM_IN_CHANNEL = 31
-};
-
-enum ali_pcm_out_channel_num {
- ALI_PCM_OUT_CHANNEL_FIRST = 0,
- ALI_PCM_OUT_CHANNEL_LAST = 31
-};
-
-enum ali_ac97_power_control_bit {
- ALI_EAPD_POWER_DOWN = 0x8000
-};
-
-enum ali_update_ptr_flags {
- ALI_ADDRESS_INT_UPDATE = 0x01
-};
-
-enum ali_revision {
- ALI_5451_V02 = 0x02
-};
-
-enum ali_spdif_out_control {
- ALI_PCM_TO_SPDIF_OUT = 0,
- ALI_SPDIF_OUT_TO_SPDIF_OUT = 1,
- ALI_SPDIF_OUT_PCM = 0,
- ALI_SPDIF_OUT_NON_PCM = 2
-};
-
-/* S/PDIF Operational Registers for 4D-NX */
-enum nx_spdif_registers {
- NX_SPCTRL_SPCSO = 0x24, NX_SPLBA = 0x28,
- NX_SPESO = 0x2c, NX_SPCSTATUS = 0x64
-};
-
-/* OP registers to access each hardware channel */
-enum channel_registers {
- CH_DX_CSO_ALPHA_FMS = 0xe0, CH_DX_ESO_DELTA = 0xe8,
- CH_DX_FMC_RVOL_CVOL = 0xec,
- CH_NX_DELTA_CSO = 0xe0, CH_NX_DELTA_ESO = 0xe8,
- CH_NX_ALPHA_FMS_FMC_RVOL_CVOL = 0xec,
- CH_LBA = 0xe4,
- CH_GVSEL_PAN_VOL_CTRL_EC = 0xf0
-};
-
-/* registers to read/write/control AC97 codec */
-enum dx_ac97_registers {
- DX_ACR0_AC97_W = 0x40, DX_ACR1_AC97_R = 0x44,
- DX_ACR2_AC97_COM_STAT = 0x48
-};
-
-enum nx_ac97_registers {
- NX_ACR0_AC97_COM_STAT = 0x40, NX_ACR1_AC97_W = 0x44,
- NX_ACR2_AC97_R_PRIMARY = 0x48, NX_ACR3_AC97_R_SECONDARY = 0x4c
-};
-
-enum si_ac97_registers {
- SI_AC97_WRITE = 0x40, SI_AC97_READ = 0x44,
- SI_SERIAL_INTF_CTRL = 0x48, SI_AC97_GPIO = 0x4c
-};
-
-enum ali_ac97_registers {
- ALI_AC97_WRITE = 0x40, ALI_AC97_READ = 0x44
-};
-
-/* Bit mask for operational registers */
-#define AC97_REG_ADDR 0x000000ff
-
-enum ali_ac97_bits {
- ALI_AC97_BUSY_WRITE = 0x8000, ALI_AC97_BUSY_READ = 0x8000,
- ALI_AC97_WRITE_ACTION = 0x8000, ALI_AC97_READ_ACTION = 0x8000,
- ALI_AC97_AUDIO_BUSY = 0x4000, ALI_AC97_SECONDARY = 0x0080,
- ALI_AC97_READ_MIXER_REGISTER = 0xfeff,
- ALI_AC97_WRITE_MIXER_REGISTER = 0x0100
-};
-
-enum sis7018_ac97_bits {
- SI_AC97_BUSY_WRITE = 0x8000, SI_AC97_BUSY_READ = 0x8000,
- SI_AC97_AUDIO_BUSY = 0x4000, SI_AC97_MODEM_BUSY = 0x2000,
- SI_AC97_SECONDARY = 0x0080
-};
-
-enum trident_dx_ac97_bits {
- DX_AC97_BUSY_WRITE = 0x8000, DX_AC97_BUSY_READ = 0x8000,
- DX_AC97_READY = 0x0010, DX_AC97_RECORD = 0x0008,
- DX_AC97_PLAYBACK = 0x0002
-};
-
-enum trident_nx_ac97_bits {
- /* ACR1-3 */
- NX_AC97_BUSY_WRITE = 0x0800, NX_AC97_BUSY_READ = 0x0800,
- NX_AC97_BUSY_DATA = 0x0400, NX_AC97_WRITE_SECONDARY = 0x0100,
- /* ACR0 */
- NX_AC97_SECONDARY_READY = 0x0040, NX_AC97_SECONDARY_RECORD = 0x0020,
- NX_AC97_SURROUND_OUTPUT = 0x0010,
- NX_AC97_PRIMARY_READY = 0x0008, NX_AC97_PRIMARY_RECORD = 0x0004,
- NX_AC97_PCM_OUTPUT = 0x0002,
- NX_AC97_WARM_RESET = 0x0001
-};
-
-enum serial_intf_ctrl_bits {
- WARM_REST = 0x00000001, COLD_RESET = 0x00000002,
- I2S_CLOCK = 0x00000004, PCM_SEC_AC97= 0x00000008,
- AC97_DBL_RATE = 0x00000010, SPDIF_EN = 0x00000020,
- I2S_OUTPUT_EN = 0x00000040, I2S_INPUT_EN = 0x00000080,
- PCMIN = 0x00000100, LINE1IN = 0x00000200,
- MICIN = 0x00000400, LINE2IN = 0x00000800,
- HEAD_SET_IN = 0x00001000, GPIOIN = 0x00002000,
- /* 7018 spec says id = 01 but the demo board routed to 10
- SECONDARY_ID= 0x00004000, */
- SECONDARY_ID= 0x00004000,
- PCMOUT = 0x00010000, SURROUT = 0x00020000,
- CENTEROUT = 0x00040000, LFEOUT = 0x00080000,
- LINE1OUT = 0x00100000, LINE2OUT = 0x00200000,
- GPIOOUT = 0x00400000,
- SI_AC97_PRIMARY_READY = 0x01000000,
- SI_AC97_SECONDARY_READY = 0x02000000,
-};
-
-enum global_control_bits {
- CHANNLE_IDX = 0x0000003f, PB_RESET = 0x00000100,
- PAUSE_ENG = 0x00000200,
- OVERRUN_IE = 0x00000400, UNDERRUN_IE = 0x00000800,
- ENDLP_IE = 0x00001000, MIDLP_IE = 0x00002000,
- ETOG_IE = 0x00004000,
- EDROP_IE = 0x00008000, BANK_B_EN = 0x00010000
-};
-
-enum channel_control_bits {
- CHANNEL_LOOP = 0x00001000, CHANNEL_SIGNED = 0x00002000,
- CHANNEL_STEREO = 0x00004000, CHANNEL_16BITS = 0x00008000,
-};
-
-enum channel_attribute {
- /* playback/record select */
- CHANNEL_PB = 0x0000, CHANNEL_SPC_PB = 0x4000,
- CHANNEL_REC = 0x8000, CHANNEL_REC_PB = 0xc000,
- /* playback destination/record source select */
- MODEM_LINE1 = 0x0000, MODEM_LINE2 = 0x0400,
- PCM_LR = 0x0800, HSET = 0x0c00,
- I2S_LR = 0x1000, CENTER_LFE = 0x1400,
- SURR_LR = 0x1800, SPDIF_LR = 0x1c00,
- MIC = 0x1400,
- /* mist stuff */
- MONO_LEFT = 0x0000, MONO_RIGHT = 0x0100,
- MONO_MIX = 0x0200, SRC_ENABLE = 0x0080,
-};
-
-enum miscint_bits {
- PB_UNDERRUN_IRO = 0x00000001, REC_OVERRUN_IRQ = 0x00000002,
- SB_IRQ = 0x00000004, MPU401_IRQ = 0x00000008,
- OPL3_IRQ = 0x00000010, ADDRESS_IRQ = 0x00000020,
- ENVELOPE_IRQ = 0x00000040, ST_IRQ = 0x00000080,
- PB_UNDERRUN = 0x00000100, REC_OVERRUN = 0x00000200,
- MIXER_UNDERFLOW = 0x00000400, MIXER_OVERFLOW = 0x00000800,
- ST_TARGET_REACHED = 0x00008000, PB_24K_MODE = 0x00010000,
- ST_IRQ_EN = 0x00800000, ACGPIO_IRQ = 0x01000000
-};
-
-#define TRID_REG( trident, x ) ( (trident) -> iobase + (x) )
-
-#define CYBER_PORT_AUDIO 0x3CE
-#define CYBER_IDX_AUDIO_ENABLE 0x7B
-#define CYBER_BMSK_AUDIO_INT_ENABLE 0x09
-#define CYBER_BMSK_AUENZ 0x01
-#define CYBER_BMSK_AUENZ_ENABLE 0x00
-#define CYBER_IDX_IRQ_ENABLE 0x12
-
-#define VALIDATE_MAGIC(FOO,MAG) \
-({ \
- if (!(FOO) || (FOO)->magic != MAG) { \
- printk(invalid_magic,__FUNCTION__); \
- return -ENXIO; \
- } \
-})
-
-#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,TRIDENT_STATE_MAGIC)
-#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,TRIDENT_CARD_MAGIC)
-
-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;
-}
-
-#endif /* __TRID4DWAVE_H */
diff --git a/sound/oss/trix.c b/sound/oss/trix.c
index e04169e8e3f..944e0c01548 100644
--- a/sound/oss/trix.c
+++ b/sound/oss/trix.c
@@ -31,7 +31,7 @@
static int mpu;
-static int joystick;
+static bool joystick;
static unsigned char trix_read(int addr)
{
diff --git a/sound/oss/uart401.c b/sound/oss/uart401.c
index a446b826d5f..62b8869f5a4 100644
--- a/sound/oss/uart401.c
+++ b/sound/oss/uart401.c
@@ -24,6 +24,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/slab.h>
#include <linux/spinlock.h>
#include "sound_config.h"
@@ -273,19 +274,12 @@ static int reset_uart401(uart401_devc * devc)
}
}
-
+ /* Flush input before enabling interrupts */
if (ok)
- {
- DEB(printk("Reset UART401 OK\n"));
- }
+ uart401_input_loop(devc);
else
DDB(printk("Reset UART401 failed - No hardware detected.\n"));
- if (ok)
- uart401_input_loop(devc); /*
- * Flush input before enabling interrupts
- */
-
return ok;
}
@@ -351,23 +345,26 @@ int probe_uart401(struct address_info *hw_config, struct module *owner)
goto cleanup_irq;
}
conf_printf(name, hw_config);
- midi_devs[devc->my_dev] = kmalloc(sizeof(struct midi_operations), GFP_KERNEL);
+ midi_devs[devc->my_dev] = kmemdup(&uart401_operations,
+ sizeof(struct midi_operations),
+ GFP_KERNEL);
if (!midi_devs[devc->my_dev]) {
printk(KERN_ERR "uart401: Failed to allocate memory\n");
goto cleanup_unload_mididev;
}
- memcpy(midi_devs[devc->my_dev], &uart401_operations, sizeof(struct midi_operations));
if (owner)
midi_devs[devc->my_dev]->owner = owner;
midi_devs[devc->my_dev]->devc = devc;
- midi_devs[devc->my_dev]->converter = kmalloc(sizeof(struct synth_operations), GFP_KERNEL);
+ midi_devs[devc->my_dev]->converter = kmemdup(&std_midi_synth,
+ sizeof(struct synth_operations),
+ GFP_KERNEL);
+
if (!midi_devs[devc->my_dev]->converter) {
printk(KERN_WARNING "uart401: Failed to allocate memory\n");
goto cleanup_midi_devs;
}
- memcpy(midi_devs[devc->my_dev]->converter, &std_midi_synth, sizeof(struct synth_operations));
strcpy(midi_devs[devc->my_dev]->info.name, name);
midi_devs[devc->my_dev]->converter->id = "UART401";
midi_devs[devc->my_dev]->converter->midi_dev = devc->my_dev;
diff --git a/sound/oss/uart6850.c b/sound/oss/uart6850.c
index f3f914aa92e..1079133dd6a 100644
--- a/sound/oss/uart6850.c
+++ b/sound/oss/uart6850.c
@@ -146,7 +146,7 @@ static int uart6850_open(int dev, int mode,
{
/* printk("Midi6850: Midi busy\n");*/
return -EBUSY;
- };
+ }
uart6850_cmd(UART_RESET);
uart6850_input_loop();
diff --git a/sound/oss/v_midi.c b/sound/oss/v_midi.c
index 103940fd5b4..f0b4151d9b1 100644
--- a/sound/oss/v_midi.c
+++ b/sound/oss/v_midi.c
@@ -21,6 +21,7 @@
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/slab.h>
#include <linux/spinlock.h>
#include "sound_config.h"
diff --git a/sound/oss/v_midi.h b/sound/oss/v_midi.h
index 1b86cb45c60..08e2185ee81 100644
--- a/sound/oss/v_midi.h
+++ b/sound/oss/v_midi.h
@@ -2,9 +2,9 @@ typedef struct vmidi_devc {
int dev;
/* State variables */
- int opened;
+ int opened;
spinlock_t lock;
-
+
/* MIDI fields */
int my_mididev;
int pair_mididev;
@@ -12,4 +12,3 @@ typedef struct vmidi_devc {
int intr_active;
void (*midi_input_intr) (int dev, unsigned char data);
} vmidi_devc;
-
diff --git a/sound/oss/via82cxxx_audio.c b/sound/oss/via82cxxx_audio.c
deleted file mode 100644
index 5d3c0372df3..00000000000
--- a/sound/oss/via82cxxx_audio.c
+++ /dev/null
@@ -1,3618 +0,0 @@
-/*
- * Support for VIA 82Cxxx Audio Codecs
- * Copyright 1999,2000 Jeff Garzik
- *
- * Updated to support the VIA 8233/8235 audio subsystem
- * Alan Cox <alan@redhat.com> (C) Copyright 2002, 2003 Red Hat Inc
- *
- * Distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2.
- * See the "COPYING" file distributed with this software for more info.
- * NO WARRANTY
- *
- * For a list of known bugs (errata) and documentation,
- * see via-audio.pdf in Documentation/DocBook.
- * If this documentation does not exist, run "make pdfdocs".
- */
-
-
-#define VIA_VERSION "1.9.1-ac4-2.5"
-
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/poison.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/sound.h>
-#include <linux/poll.h>
-#include <linux/soundcard.h>
-#include <linux/ac97_codec.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <linux/mutex.h>
-
-#include "sound_config.h"
-#include "dev_table.h"
-#include "mpu401.h"
-
-
-#undef VIA_DEBUG /* define to enable debugging output and checks */
-#ifdef VIA_DEBUG
-/* note: prints function name for you */
-#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
-#undef VIA_NDEBUG /* define to disable lightweight runtime checks */
-#ifdef VIA_NDEBUG
-#define assert(expr)
-#else
-#define assert(expr) \
- if(!(expr)) { \
- printk( "Assertion failed! %s,%s,%s,line=%d\n", \
- #expr,__FILE__,__FUNCTION__,__LINE__); \
- }
-#endif
-
-#define VIA_SUPPORT_MMAP 1 /* buggy, for now... */
-
-#define MAX_CARDS 1
-
-#define VIA_CARD_NAME "VIA 82Cxxx Audio driver " VIA_VERSION
-#define VIA_MODULE_NAME "via82cxxx"
-#define PFX VIA_MODULE_NAME ": "
-
-#define VIA_COUNTER_LIMIT 100000
-
-/* size of DMA buffers */
-#define VIA_MAX_BUFFER_DMA_PAGES 32
-
-/* buffering default values in ms */
-#define VIA_DEFAULT_FRAG_TIME 20
-#define VIA_DEFAULT_BUFFER_TIME 500
-
-/* the hardware has a 256 fragment limit */
-#define VIA_MIN_FRAG_NUMBER 2
-#define VIA_MAX_FRAG_NUMBER 128
-
-#define VIA_MAX_FRAG_SIZE PAGE_SIZE
-#define VIA_MIN_FRAG_SIZE (VIA_MAX_BUFFER_DMA_PAGES * PAGE_SIZE / VIA_MAX_FRAG_NUMBER)
-
-
-/* 82C686 function 5 (audio codec) PCI configuration registers */
-#define VIA_ACLINK_STATUS 0x40
-#define VIA_ACLINK_CTRL 0x41
-#define VIA_FUNC_ENABLE 0x42
-#define VIA_PNP_CONTROL 0x43
-#define VIA_FM_NMI_CTRL 0x48
-
-/*
- * controller base 0 (scatter-gather) registers
- *
- * NOTE: Via datasheet lists first channel as "read"
- * channel and second channel as "write" channel.
- * I changed the naming of the constants to be more
- * clear than I felt the datasheet to be.
- */
-
-#define VIA_BASE0_PCM_OUT_CHAN 0x00 /* output PCM to user */
-#define VIA_BASE0_PCM_OUT_CHAN_STATUS 0x00
-#define VIA_BASE0_PCM_OUT_CHAN_CTRL 0x01
-#define VIA_BASE0_PCM_OUT_CHAN_TYPE 0x02
-
-#define VIA_BASE0_PCM_IN_CHAN 0x10 /* input PCM from user */
-#define VIA_BASE0_PCM_IN_CHAN_STATUS 0x10
-#define VIA_BASE0_PCM_IN_CHAN_CTRL 0x11
-#define VIA_BASE0_PCM_IN_CHAN_TYPE 0x12
-
-/* offsets from base */
-#define VIA_PCM_STATUS 0x00
-#define VIA_PCM_CONTROL 0x01
-#define VIA_PCM_TYPE 0x02
-#define VIA_PCM_LEFTVOL 0x02
-#define VIA_PCM_RIGHTVOL 0x03
-#define VIA_PCM_TABLE_ADDR 0x04
-#define VIA_PCM_STOPRATE 0x08 /* 8233+ */
-#define VIA_PCM_BLOCK_COUNT 0x0C
-
-/* XXX unused DMA channel for FM PCM data */
-#define VIA_BASE0_FM_OUT_CHAN 0x20
-#define VIA_BASE0_FM_OUT_CHAN_STATUS 0x20
-#define VIA_BASE0_FM_OUT_CHAN_CTRL 0x21
-#define VIA_BASE0_FM_OUT_CHAN_TYPE 0x22
-
-/* Six channel audio output on 8233 */
-#define VIA_BASE0_MULTI_OUT_CHAN 0x40
-#define VIA_BASE0_MULTI_OUT_CHAN_STATUS 0x40
-#define VIA_BASE0_MULTI_OUT_CHAN_CTRL 0x41
-#define VIA_BASE0_MULTI_OUT_CHAN_TYPE 0x42
-
-#define VIA_BASE0_AC97_CTRL 0x80
-#define VIA_BASE0_SGD_STATUS_SHADOW 0x84
-#define VIA_BASE0_GPI_INT_ENABLE 0x8C
-#define VIA_INTR_OUT ((1<<0) | (1<<4) | (1<<8))
-#define VIA_INTR_IN ((1<<1) | (1<<5) | (1<<9))
-#define VIA_INTR_FM ((1<<2) | (1<<6) | (1<<10))
-#define VIA_INTR_MASK (VIA_INTR_OUT | VIA_INTR_IN | VIA_INTR_FM)
-
-/* Newer VIA we need to monitor the low 3 bits of each channel. This
- mask covers the channels we don't yet use as well
- */
-
-#define VIA_NEW_INTR_MASK 0x77077777UL
-
-/* VIA_BASE0_AUDIO_xxx_CHAN_TYPE bits */
-#define VIA_IRQ_ON_FLAG (1<<0) /* int on each flagged scatter block */
-#define VIA_IRQ_ON_EOL (1<<1) /* int at end of scatter list */
-#define VIA_INT_SEL_PCI_LAST_LINE_READ (0) /* int at PCI read of last line */
-#define VIA_INT_SEL_LAST_SAMPLE_SENT (1<<2) /* int at last sample sent */
-#define VIA_INT_SEL_ONE_LINE_LEFT (1<<3) /* int at less than one line to send */
-#define VIA_PCM_FMT_STEREO (1<<4) /* PCM stereo format (bit clear == mono) */
-#define VIA_PCM_FMT_16BIT (1<<5) /* PCM 16-bit format (bit clear == 8-bit) */
-#define VIA_PCM_REC_FIFO (1<<6) /* PCM Recording FIFO */
-#define VIA_RESTART_SGD_ON_EOL (1<<7) /* restart scatter-gather at EOL */
-#define VIA_PCM_FMT_MASK (VIA_PCM_FMT_STEREO|VIA_PCM_FMT_16BIT)
-#define VIA_CHAN_TYPE_MASK (VIA_RESTART_SGD_ON_EOL | \
- VIA_IRQ_ON_FLAG | \
- VIA_IRQ_ON_EOL)
-#define VIA_CHAN_TYPE_INT_SELECT (VIA_INT_SEL_LAST_SAMPLE_SENT)
-
-/* PCI configuration register bits and masks */
-#define VIA_CR40_AC97_READY 0x01
-#define VIA_CR40_AC97_LOW_POWER 0x02
-#define VIA_CR40_SECONDARY_READY 0x04
-
-#define VIA_CR41_AC97_ENABLE 0x80 /* enable AC97 codec */
-#define VIA_CR41_AC97_RESET 0x40 /* clear bit to reset AC97 */
-#define VIA_CR41_AC97_WAKEUP 0x20 /* wake up from power-down mode */
-#define VIA_CR41_AC97_SDO 0x10 /* force Serial Data Out (SDO) high */
-#define VIA_CR41_VRA 0x08 /* enable variable sample rate */
-#define VIA_CR41_PCM_ENABLE 0x04 /* AC Link SGD Read Channel PCM Data Output */
-#define VIA_CR41_FM_PCM_ENABLE 0x02 /* AC Link FM Channel PCM Data Out */
-#define VIA_CR41_SB_PCM_ENABLE 0x01 /* AC Link SB PCM Data Output */
-#define VIA_CR41_BOOT_MASK (VIA_CR41_AC97_ENABLE | \
- VIA_CR41_AC97_WAKEUP | \
- VIA_CR41_AC97_SDO)
-#define VIA_CR41_RUN_MASK (VIA_CR41_AC97_ENABLE | \
- VIA_CR41_AC97_RESET | \
- VIA_CR41_VRA | \
- VIA_CR41_PCM_ENABLE)
-
-#define VIA_CR42_SB_ENABLE 0x01
-#define VIA_CR42_MIDI_ENABLE 0x02
-#define VIA_CR42_FM_ENABLE 0x04
-#define VIA_CR42_GAME_ENABLE 0x08
-#define VIA_CR42_MIDI_IRQMASK 0x40
-#define VIA_CR42_MIDI_PNP 0x80
-
-#define VIA_CR44_SECOND_CODEC_SUPPORT (1 << 6)
-#define VIA_CR44_AC_LINK_ACCESS (1 << 7)
-
-#define VIA_CR48_FM_TRAP_TO_NMI (1 << 2)
-
-/* controller base 0 register bitmasks */
-#define VIA_INT_DISABLE_MASK (~(0x01|0x02))
-#define VIA_SGD_STOPPED (1 << 2)
-#define VIA_SGD_PAUSED (1 << 6)
-#define VIA_SGD_ACTIVE (1 << 7)
-#define VIA_SGD_TERMINATE (1 << 6)
-#define VIA_SGD_FLAG (1 << 0)
-#define VIA_SGD_EOL (1 << 1)
-#define VIA_SGD_START (1 << 7)
-
-#define VIA_CR80_FIRST_CODEC 0
-#define VIA_CR80_SECOND_CODEC (1 << 30)
-#define VIA_CR80_FIRST_CODEC_VALID (1 << 25)
-#define VIA_CR80_VALID (1 << 25)
-#define VIA_CR80_SECOND_CODEC_VALID (1 << 27)
-#define VIA_CR80_BUSY (1 << 24)
-#define VIA_CR83_BUSY (1)
-#define VIA_CR83_FIRST_CODEC_VALID (1 << 1)
-#define VIA_CR80_READ (1 << 23)
-#define VIA_CR80_WRITE_MODE 0
-#define VIA_CR80_REG_IDX(idx) ((((idx) & 0xFF) >> 1) << 16)
-
-/* capabilities we announce */
-#ifdef VIA_SUPPORT_MMAP
-#define VIA_DSP_CAP (DSP_CAP_REVISION | DSP_CAP_DUPLEX | DSP_CAP_MMAP | \
- DSP_CAP_TRIGGER | DSP_CAP_REALTIME)
-#else
-#define VIA_DSP_CAP (DSP_CAP_REVISION | DSP_CAP_DUPLEX | \
- DSP_CAP_TRIGGER | DSP_CAP_REALTIME)
-#endif
-
-/* scatter-gather DMA table entry, exactly as passed to hardware */
-struct via_sgd_table {
- u32 addr;
- u32 count; /* includes additional VIA_xxx bits also */
-};
-
-#define VIA_EOL (1 << 31)
-#define VIA_FLAG (1 << 30)
-#define VIA_STOP (1 << 29)
-
-
-enum via_channel_states {
- sgd_stopped = 0,
- sgd_in_progress = 1,
-};
-
-
-struct via_buffer_pgtbl {
- dma_addr_t handle;
- void *cpuaddr;
-};
-
-
-struct via_channel {
- atomic_t n_frags;
- atomic_t hw_ptr;
- wait_queue_head_t wait;
-
- unsigned int sw_ptr;
- unsigned int slop_len;
- unsigned int n_irqs;
- int bytes;
-
- unsigned is_active : 1;
- unsigned is_record : 1;
- unsigned is_mapped : 1;
- unsigned is_enabled : 1;
- unsigned is_multi: 1; /* 8233 6 channel */
- u8 pcm_fmt; /* VIA_PCM_FMT_xxx */
- u8 channels; /* Channel count */
-
- unsigned rate; /* sample rate */
- unsigned int frag_size;
- unsigned int frag_number;
-
- unsigned char intmask;
-
- volatile struct via_sgd_table *sgtable;
- dma_addr_t sgt_handle;
-
- unsigned int page_number;
- struct via_buffer_pgtbl pgtbl[VIA_MAX_BUFFER_DMA_PAGES];
-
- long iobase;
-
- const char *name;
-};
-
-
-/* data stored for each chip */
-struct via_info {
- struct pci_dev *pdev;
- long baseaddr;
-
- struct ac97_codec *ac97;
- spinlock_t ac97_lock;
- spinlock_t lock;
- int card_num; /* unique card number, from 0 */
-
- int dev_dsp; /* /dev/dsp index from register_sound_dsp() */
-
- unsigned rev_h : 1;
- unsigned legacy: 1; /* Has legacy ports */
- unsigned intmask: 1; /* Needs int bits */
- unsigned sixchannel: 1; /* 8233/35 with 6 channel support */
- unsigned volume: 1;
-
- unsigned locked_rate : 1;
-
- int mixer_vol; /* 8233/35 volume - not yet implemented */
-
- struct mutex syscall_mutex;
- struct mutex open_mutex;
-
- /* The 8233/8235 have 4 DX audio channels, two record and
- one six channel out. We bind ch_in to DX 1, ch_out to multichannel
- and ch_fm to DX 2. DX 3 and REC0/REC1 are unused at the
- moment */
-
- struct via_channel ch_in;
- struct via_channel ch_out;
- struct via_channel ch_fm;
-
-#ifdef CONFIG_MIDI_VIA82CXXX
- void *midi_devc;
- struct address_info midi_info;
-#endif
-};
-
-
-/* number of cards, used for assigning unique numbers to cards */
-static unsigned via_num_cards;
-
-
-
-/****************************************************************
- *
- * prototypes
- *
- *
- */
-
-static int via_init_one (struct pci_dev *dev, const struct pci_device_id *id);
-static void __devexit via_remove_one (struct pci_dev *pdev);
-
-static ssize_t via_dsp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos);
-static ssize_t via_dsp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos);
-static unsigned int via_dsp_poll(struct file *file, struct poll_table_struct *wait);
-static int via_dsp_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-static int via_dsp_open (struct inode *inode, struct file *file);
-static int via_dsp_release(struct inode *inode, struct file *file);
-static int via_dsp_mmap(struct file *file, struct vm_area_struct *vma);
-
-static u16 via_ac97_read_reg (struct ac97_codec *codec, u8 reg);
-static void via_ac97_write_reg (struct ac97_codec *codec, u8 reg, u16 value);
-static u8 via_ac97_wait_idle (struct via_info *card);
-
-static void via_chan_free (struct via_info *card, struct via_channel *chan);
-static void via_chan_clear (struct via_info *card, struct via_channel *chan);
-static void via_chan_pcm_fmt (struct via_channel *chan, int reset);
-static void via_chan_buffer_free (struct via_info *card, struct via_channel *chan);
-
-
-/****************************************************************
- *
- * Various data the driver needs
- *
- *
- */
-
-
-static struct pci_device_id via_pci_tbl[] = {
- { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_5,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { 0, }
-};
-MODULE_DEVICE_TABLE(pci,via_pci_tbl);
-
-
-static struct pci_driver via_driver = {
- .name = VIA_MODULE_NAME,
- .id_table = via_pci_tbl,
- .probe = via_init_one,
- .remove = __devexit_p(via_remove_one),
-};
-
-
-/****************************************************************
- *
- * Low-level base 0 register read/write helpers
- *
- *
- */
-
-/**
- * via_chan_stop - Terminate DMA on specified PCM channel
- * @iobase: PCI base address for SGD channel registers
- *
- * Terminate scatter-gather DMA operation for given
- * channel (derived from @iobase), if DMA is active.
- *
- * Note that @iobase is not the PCI base address,
- * but the PCI base address plus an offset to
- * one of three PCM channels supported by the chip.
- *
- */
-
-static inline void via_chan_stop (long iobase)
-{
- if (inb (iobase + VIA_PCM_STATUS) & VIA_SGD_ACTIVE)
- outb (VIA_SGD_TERMINATE, iobase + VIA_PCM_CONTROL);
-}
-
-
-/**
- * via_chan_status_clear - Clear status flags on specified DMA channel
- * @iobase: PCI base address for SGD channel registers
- *
- * Clear any pending status flags for the given
- * DMA channel (derived from @iobase), if any
- * flags are asserted.
- *
- * Note that @iobase is not the PCI base address,
- * but the PCI base address plus an offset to
- * one of three PCM channels supported by the chip.
- *
- */
-
-static inline void via_chan_status_clear (long iobase)
-{
- u8 tmp = inb (iobase + VIA_PCM_STATUS);
-
- if (tmp != 0)
- outb (tmp, iobase + VIA_PCM_STATUS);
-}
-
-
-/**
- * sg_begin - Begin recording or playback on a PCM channel
- * @chan: Channel for which DMA operation shall begin
- *
- * Start scatter-gather DMA for the given channel.
- *
- */
-
-static inline void sg_begin (struct via_channel *chan)
-{
- DPRINTK("Start with intmask %d\n", chan->intmask);
- DPRINTK("About to start from %d to %d\n",
- inl(chan->iobase + VIA_PCM_BLOCK_COUNT),
- inb(chan->iobase + VIA_PCM_STOPRATE + 3));
- outb (VIA_SGD_START|chan->intmask, chan->iobase + VIA_PCM_CONTROL);
- DPRINTK("Status is now %02X\n", inb(chan->iobase + VIA_PCM_STATUS));
- DPRINTK("Control is now %02X\n", inb(chan->iobase + VIA_PCM_CONTROL));
-}
-
-
-static int sg_active (long iobase)
-{
- u8 tmp = inb (iobase + VIA_PCM_STATUS);
- if ((tmp & VIA_SGD_STOPPED) || (tmp & VIA_SGD_PAUSED)) {
- printk(KERN_WARNING "via82cxxx warning: SG stopped or paused\n");
- return 0;
- }
- if (tmp & VIA_SGD_ACTIVE)
- return 1;
- return 0;
-}
-
-static int via_sg_offset(struct via_channel *chan)
-{
- return inl (chan->iobase + VIA_PCM_BLOCK_COUNT) & 0x00FFFFFF;
-}
-
-/****************************************************************
- *
- * Miscellaneous debris
- *
- *
- */
-
-
-/**
- * via_syscall_down - down the card-specific syscell semaphore
- * @card: Private info for specified board
- * @nonblock: boolean, non-zero if O_NONBLOCK is set
- *
- * Encapsulates standard method of acquiring the syscall sem.
- *
- * Returns negative errno on error, or zero for success.
- */
-
-static inline int via_syscall_down (struct via_info *card, int nonblock)
-{
- /* Thomas Sailer:
- * EAGAIN is supposed to be used if IO is pending,
- * not if there is contention on some internal
- * synchronization primitive which should be
- * held only for a short time anyway
- */
- nonblock = 0;
-
- if (nonblock) {
- if (!mutex_trylock(&card->syscall_mutex))
- return -EAGAIN;
- } else {
- if (mutex_lock_interruptible(&card->syscall_mutex))
- return -ERESTARTSYS;
- }
-
- return 0;
-}
-
-
-/**
- * via_stop_everything - Stop all audio operations
- * @card: Private info for specified board
- *
- * Stops all DMA operations and interrupts, and clear
- * any pending status bits resulting from those operations.
- */
-
-static void via_stop_everything (struct via_info *card)
-{
- u8 tmp, new_tmp;
-
- DPRINTK ("ENTER\n");
-
- assert (card != NULL);
-
- /*
- * terminate any existing operations on audio read/write channels
- */
- via_chan_stop (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN);
- via_chan_stop (card->baseaddr + VIA_BASE0_PCM_IN_CHAN);
- via_chan_stop (card->baseaddr + VIA_BASE0_FM_OUT_CHAN);
- if(card->sixchannel)
- via_chan_stop (card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN);
-
- /*
- * clear any existing stops / flags (sanity check mainly)
- */
- via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN);
- via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_IN_CHAN);
- via_chan_status_clear (card->baseaddr + VIA_BASE0_FM_OUT_CHAN);
- if(card->sixchannel)
- via_chan_status_clear (card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN);
-
- /*
- * clear any enabled interrupt bits
- */
- tmp = inb (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE);
- new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL);
- if (tmp != new_tmp)
- outb (0, card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE);
-
- tmp = inb (card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE);
- new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL);
- if (tmp != new_tmp)
- outb (0, card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE);
-
- tmp = inb (card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE);
- new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL);
- if (tmp != new_tmp)
- outb (0, card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE);
-
- if(card->sixchannel)
- {
- tmp = inb (card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN_TYPE);
- new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL);
- if (tmp != new_tmp)
- outb (0, card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN_TYPE);
- }
-
- udelay(10);
-
- /*
- * clear any existing flags
- */
- via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN);
- via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_IN_CHAN);
- via_chan_status_clear (card->baseaddr + VIA_BASE0_FM_OUT_CHAN);
-
- DPRINTK ("EXIT\n");
-}
-
-
-/**
- * via_set_rate - Set PCM rate for given channel
- * @ac97: Pointer to generic codec info struct
- * @chan: Private info for specified channel
- * @rate: Desired PCM sample rate, in Khz
- *
- * Sets the PCM sample rate for a channel.
- *
- * Values for @rate are clamped to a range of 4000 Khz through 48000 Khz,
- * due to hardware constraints.
- */
-
-static int via_set_rate (struct ac97_codec *ac97,
- struct via_channel *chan, unsigned rate)
-{
- struct via_info *card = ac97->private_data;
- int rate_reg;
- u32 dacp;
- u32 mast_vol, phone_vol, mono_vol, pcm_vol;
- u32 mute_vol = 0x8000; /* The mute volume? -- Seems to work! */
-
- DPRINTK ("ENTER, rate = %d\n", rate);
-
- if (chan->rate == rate)
- goto out;
- if (card->locked_rate) {
- chan->rate = 48000;
- goto out;
- }
-
- if (rate > 48000) rate = 48000;
- if (rate < 4000) rate = 4000;
-
- rate_reg = chan->is_record ? AC97_PCM_LR_ADC_RATE :
- AC97_PCM_FRONT_DAC_RATE;
-
- /* Save current state */
- dacp=via_ac97_read_reg(ac97, AC97_POWER_CONTROL);
- mast_vol = via_ac97_read_reg(ac97, AC97_MASTER_VOL_STEREO);
- mono_vol = via_ac97_read_reg(ac97, AC97_MASTER_VOL_MONO);
- phone_vol = via_ac97_read_reg(ac97, AC97_HEADPHONE_VOL);
- pcm_vol = via_ac97_read_reg(ac97, AC97_PCMOUT_VOL);
- /* Mute - largely reduces popping */
- via_ac97_write_reg(ac97, AC97_MASTER_VOL_STEREO, mute_vol);
- via_ac97_write_reg(ac97, AC97_MASTER_VOL_MONO, mute_vol);
- via_ac97_write_reg(ac97, AC97_HEADPHONE_VOL, mute_vol);
- via_ac97_write_reg(ac97, AC97_PCMOUT_VOL, mute_vol);
- /* Power down the DAC */
- via_ac97_write_reg(ac97, AC97_POWER_CONTROL, dacp|0x0200);
-
- /* Set new rate */
- via_ac97_write_reg (ac97, rate_reg, rate);
-
- /* Power DAC back up */
- via_ac97_write_reg(ac97, AC97_POWER_CONTROL, dacp);
- udelay (200); /* reduces popping */
-
- /* Restore volumes */
- via_ac97_write_reg(ac97, AC97_MASTER_VOL_STEREO, mast_vol);
- via_ac97_write_reg(ac97, AC97_MASTER_VOL_MONO, mono_vol);
- via_ac97_write_reg(ac97, AC97_HEADPHONE_VOL, phone_vol);
- via_ac97_write_reg(ac97, AC97_PCMOUT_VOL, pcm_vol);
-
- /* the hardware might return a value different than what we
- * passed to it, so read the rate value back from hardware
- * to see what we came up with
- */
- chan->rate = via_ac97_read_reg (ac97, rate_reg);
-
- if (chan->rate == 0) {
- card->locked_rate = 1;
- chan->rate = 48000;
- printk (KERN_WARNING PFX "Codec rate locked at 48Khz\n");
- }
-
-out:
- DPRINTK ("EXIT, returning rate %d Hz\n", chan->rate);
- return chan->rate;
-}
-
-
-/****************************************************************
- *
- * Channel-specific operations
- *
- *
- */
-
-
-/**
- * via_chan_init_defaults - Initialize a struct via_channel
- * @card: Private audio chip info
- * @chan: Channel to be initialized
- *
- * Zero @chan, and then set all static defaults for the structure.
- */
-
-static void via_chan_init_defaults (struct via_info *card, struct via_channel *chan)
-{
- memset (chan, 0, sizeof (*chan));
-
- if(card->intmask)
- chan->intmask = 0x23; /* Turn on the IRQ bits */
-
- if (chan == &card->ch_out) {
- chan->name = "PCM-OUT";
- if(card->sixchannel)
- {
- chan->iobase = card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN;
- chan->is_multi = 1;
- DPRINTK("Using multichannel for pcm out\n");
- }
- else
- chan->iobase = card->baseaddr + VIA_BASE0_PCM_OUT_CHAN;
- } else if (chan == &card->ch_in) {
- chan->name = "PCM-IN";
- chan->iobase = card->baseaddr + VIA_BASE0_PCM_IN_CHAN;
- chan->is_record = 1;
- } else if (chan == &card->ch_fm) {
- chan->name = "PCM-OUT-FM";
- chan->iobase = card->baseaddr + VIA_BASE0_FM_OUT_CHAN;
- } else {
- BUG();
- }
-
- init_waitqueue_head (&chan->wait);
-
- chan->pcm_fmt = VIA_PCM_FMT_MASK;
- chan->is_enabled = 1;
-
- chan->frag_number = 0;
- chan->frag_size = 0;
- atomic_set(&chan->n_frags, 0);
- atomic_set (&chan->hw_ptr, 0);
-}
-
-/**
- * via_chan_init - Initialize PCM channel
- * @card: Private audio chip info
- * @chan: Channel to be initialized
- *
- * Performs some of the preparations necessary to begin
- * using a PCM channel.
- *
- * Currently the preparations consist of
- * setting the PCM channel to a known state.
- */
-
-
-static void via_chan_init (struct via_info *card, struct via_channel *chan)
-{
-
- DPRINTK ("ENTER\n");
-
- /* bzero channel structure, and init members to defaults */
- via_chan_init_defaults (card, chan);
-
- /* stop any existing channel output */
- via_chan_clear (card, chan);
- via_chan_status_clear (chan->iobase);
- via_chan_pcm_fmt (chan, 1);
-
- DPRINTK ("EXIT\n");
-}
-
-/**
- * via_chan_buffer_init - Initialize PCM channel buffer
- * @card: Private audio chip info
- * @chan: Channel to be initialized
- *
- * Performs some of the preparations necessary to begin
- * using a PCM channel.
- *
- * Currently the preparations include allocating the
- * scatter-gather DMA table and buffers,
- * and passing the
- * address of the DMA table to the hardware.
- *
- * Note that special care is taken when passing the
- * DMA table address to hardware, because it was found
- * during driver development that the hardware did not
- * always "take" the address.
- */
-
-static int via_chan_buffer_init (struct via_info *card, struct via_channel *chan)
-{
- int page, offset;
- int i;
-
- DPRINTK ("ENTER\n");
-
-
- chan->intmask = 0;
- if(card->intmask)
- chan->intmask = 0x23; /* Turn on the IRQ bits */
-
- if (chan->sgtable != NULL) {
- DPRINTK ("EXIT\n");
- return 0;
- }
-
- /* alloc DMA-able memory for scatter-gather table */
- chan->sgtable = pci_alloc_consistent (card->pdev,
- (sizeof (struct via_sgd_table) * chan->frag_number),
- &chan->sgt_handle);
- if (!chan->sgtable) {
- printk (KERN_ERR PFX "DMA table alloc fail, aborting\n");
- DPRINTK ("EXIT\n");
- return -ENOMEM;
- }
-
- memset ((void*)chan->sgtable, 0,
- (sizeof (struct via_sgd_table) * chan->frag_number));
-
- /* alloc DMA-able memory for scatter-gather buffers */
-
- chan->page_number = (chan->frag_number * chan->frag_size) / PAGE_SIZE +
- (((chan->frag_number * chan->frag_size) % PAGE_SIZE) ? 1 : 0);
-
- for (i = 0; i < chan->page_number; i++) {
- chan->pgtbl[i].cpuaddr = pci_alloc_consistent (card->pdev, PAGE_SIZE,
- &chan->pgtbl[i].handle);
-
- if (!chan->pgtbl[i].cpuaddr) {
- chan->page_number = i;
- goto err_out_nomem;
- }
-
-#ifndef VIA_NDEBUG
- memset (chan->pgtbl[i].cpuaddr, 0xBC, chan->frag_size);
-#endif
-
-#if 1
- DPRINTK ("dmabuf_pg #%d (h=%lx, v2p=%lx, a=%p)\n",
- i, (long)chan->pgtbl[i].handle,
- virt_to_phys(chan->pgtbl[i].cpuaddr),
- chan->pgtbl[i].cpuaddr);
-#endif
- }
-
- for (i = 0; i < chan->frag_number; i++) {
-
- page = i / (PAGE_SIZE / chan->frag_size);
- offset = (i % (PAGE_SIZE / chan->frag_size)) * chan->frag_size;
-
- chan->sgtable[i].count = cpu_to_le32 (chan->frag_size | VIA_FLAG);
- chan->sgtable[i].addr = cpu_to_le32 (chan->pgtbl[page].handle + offset);
-
-#if 1
- DPRINTK ("dmabuf #%d (32(h)=%lx)\n",
- i,
- (long)chan->sgtable[i].addr);
-#endif
- }
-
- /* overwrite the last buffer information */
- chan->sgtable[chan->frag_number - 1].count = cpu_to_le32 (chan->frag_size | VIA_EOL);
-
- /* set location of DMA-able scatter-gather info table */
- DPRINTK ("outl (0x%X, 0x%04lX)\n",
- chan->sgt_handle, chan->iobase + VIA_PCM_TABLE_ADDR);
-
- via_ac97_wait_idle (card);
- outl (chan->sgt_handle, chan->iobase + VIA_PCM_TABLE_ADDR);
- udelay (20);
- via_ac97_wait_idle (card);
- /* load no rate adaption, stereo 16bit, set up ring slots */
- if(card->sixchannel)
- {
- if(!chan->is_multi)
- {
- outl (0xFFFFF | (0x3 << 20) | (chan->frag_number << 24), chan->iobase + VIA_PCM_STOPRATE);
- udelay (20);
- via_ac97_wait_idle (card);
- }
- }
-
- DPRINTK ("inl (0x%lX) = %x\n",
- chan->iobase + VIA_PCM_TABLE_ADDR,
- inl(chan->iobase + VIA_PCM_TABLE_ADDR));
-
- DPRINTK ("EXIT\n");
- return 0;
-
-err_out_nomem:
- printk (KERN_ERR PFX "DMA buffer alloc fail, aborting\n");
- via_chan_buffer_free (card, chan);
- DPRINTK ("EXIT\n");
- return -ENOMEM;
-}
-
-
-/**
- * via_chan_free - Release a PCM channel
- * @card: Private audio chip info
- * @chan: Channel to be released
- *
- * Performs all the functions necessary to clean up
- * an initialized channel.
- *
- * Currently these functions include disabled any
- * active DMA operations, setting the PCM channel
- * back to a known state, and releasing any allocated
- * sound buffers.
- */
-
-static void via_chan_free (struct via_info *card, struct via_channel *chan)
-{
- DPRINTK ("ENTER\n");
-
- spin_lock_irq (&card->lock);
-
- /* stop any existing channel output */
- via_chan_status_clear (chan->iobase);
- via_chan_stop (chan->iobase);
- via_chan_status_clear (chan->iobase);
-
- spin_unlock_irq (&card->lock);
-
- synchronize_irq(card->pdev->irq);
-
- DPRINTK ("EXIT\n");
-}
-
-static void via_chan_buffer_free (struct via_info *card, struct via_channel *chan)
-{
- int i;
-
- DPRINTK ("ENTER\n");
-
- /* zero location of DMA-able scatter-gather info table */
- via_ac97_wait_idle(card);
- outl (0, chan->iobase + VIA_PCM_TABLE_ADDR);
-
- for (i = 0; i < chan->page_number; i++)
- if (chan->pgtbl[i].cpuaddr) {
- pci_free_consistent (card->pdev, PAGE_SIZE,
- chan->pgtbl[i].cpuaddr,
- chan->pgtbl[i].handle);
- chan->pgtbl[i].cpuaddr = NULL;
- chan->pgtbl[i].handle = 0;
- }
-
- chan->page_number = 0;
-
- if (chan->sgtable) {
- pci_free_consistent (card->pdev,
- (sizeof (struct via_sgd_table) * chan->frag_number),
- (void*)chan->sgtable, chan->sgt_handle);
- chan->sgtable = NULL;
- }
-
- DPRINTK ("EXIT\n");
-}
-
-
-/**
- * via_chan_pcm_fmt - Update PCM channel settings
- * @chan: Channel to be updated
- * @reset: Boolean. If non-zero, channel will be reset
- * to 8-bit mono mode.
- *
- * Stores the settings of the current PCM format,
- * 8-bit or 16-bit, and mono/stereo, into the
- * hardware settings for the specified channel.
- * If @reset is non-zero, the channel is reset
- * to 8-bit mono mode. Otherwise, the channel
- * is set to the values stored in the channel
- * information struct @chan.
- */
-
-static void via_chan_pcm_fmt (struct via_channel *chan, int reset)
-{
- DPRINTK ("ENTER, pcm_fmt=0x%02X, reset=%s\n",
- chan->pcm_fmt, reset ? "yes" : "no");
-
- assert (chan != NULL);
-
- if (reset)
- {
- /* reset to 8-bit mono mode */
- chan->pcm_fmt = 0;
- chan->channels = 1;
- }
-
- /* enable interrupts on FLAG and EOL */
- chan->pcm_fmt |= VIA_CHAN_TYPE_MASK;
-
- /* if we are recording, enable recording fifo bit */
- if (chan->is_record)
- chan->pcm_fmt |= VIA_PCM_REC_FIFO;
- /* set interrupt select bits where applicable (PCM in & out channels) */
- if (!chan->is_record)
- chan->pcm_fmt |= VIA_CHAN_TYPE_INT_SELECT;
-
- DPRINTK("SET FMT - %02x %02x\n", chan->intmask , chan->is_multi);
-
- if(chan->intmask)
- {
- u32 m;
-
- /*
- * Channel 0x4 is up to 6 x 16bit and has to be
- * programmed differently
- */
-
- if(chan->is_multi)
- {
- u8 c = 0;
-
- /*
- * Load the type bit for num channels
- * and 8/16bit
- */
-
- if(chan->pcm_fmt & VIA_PCM_FMT_16BIT)
- c = 1 << 7;
- if(chan->pcm_fmt & VIA_PCM_FMT_STEREO)
- c |= (2<<4);
- else
- c |= (1<<4);
-
- outb(c, chan->iobase + VIA_PCM_TYPE);
-
- /*
- * Set the channel steering
- * Mono
- * Channel 0 to slot 3
- * Channel 0 to slot 4
- * Stereo
- * Channel 0 to slot 3
- * Channel 1 to slot 4
- */
-
- switch(chan->channels)
- {
- case 1:
- outl(0xFF000000 | (1<<0) | (1<<4) , chan->iobase + VIA_PCM_STOPRATE);
- break;
- case 2:
- outl(0xFF000000 | (1<<0) | (2<<4) , chan->iobase + VIA_PCM_STOPRATE);
- break;
- case 4:
- outl(0xFF000000 | (1<<0) | (2<<4) | (3<<8) | (4<<12), chan->iobase + VIA_PCM_STOPRATE);
- break;
- case 6:
- outl(0xFF000000 | (1<<0) | (2<<4) | (5<<8) | (6<<12) | (3<<16) | (4<<20), chan->iobase + VIA_PCM_STOPRATE);
- break;
- }
- }
- else
- {
- /*
- * New style, turn off channel volume
- * control, set bits in the right register
- */
- outb(0x0, chan->iobase + VIA_PCM_LEFTVOL);
- outb(0x0, chan->iobase + VIA_PCM_RIGHTVOL);
-
- m = inl(chan->iobase + VIA_PCM_STOPRATE);
- m &= ~(3<<20);
- if(chan->pcm_fmt & VIA_PCM_FMT_STEREO)
- m |= (1 << 20);
- if(chan->pcm_fmt & VIA_PCM_FMT_16BIT)
- m |= (1 << 21);
- outl(m, chan->iobase + VIA_PCM_STOPRATE);
- }
- }
- else
- outb (chan->pcm_fmt, chan->iobase + VIA_PCM_TYPE);
-
-
- DPRINTK ("EXIT, pcm_fmt = 0x%02X, reg = 0x%02X\n",
- chan->pcm_fmt,
- inb (chan->iobase + VIA_PCM_TYPE));
-}
-
-
-/**
- * via_chan_clear - Stop DMA channel operation, and reset pointers
- * @card: the chip to accessed
- * @chan: Channel to be cleared
- *
- * Call via_chan_stop to halt DMA operations, and then resets
- * all software pointers which track DMA operation.
- */
-
-static void via_chan_clear (struct via_info *card, struct via_channel *chan)
-{
- DPRINTK ("ENTER\n");
- via_chan_stop (chan->iobase);
- via_chan_buffer_free(card, chan);
- chan->is_active = 0;
- chan->is_mapped = 0;
- chan->is_enabled = 1;
- chan->slop_len = 0;
- chan->sw_ptr = 0;
- chan->n_irqs = 0;
- atomic_set (&chan->hw_ptr, 0);
- DPRINTK ("EXIT\n");
-}
-
-
-/**
- * via_chan_set_speed - Set PCM sample rate for given channel
- * @card: Private info for specified board
- * @chan: Channel whose sample rate will be adjusted
- * @val: New sample rate, in Khz
- *
- * Helper function for the %SNDCTL_DSP_SPEED ioctl. OSS semantics
- * demand that all audio operations halt (if they are not already
- * halted) when the %SNDCTL_DSP_SPEED is given.
- *
- * This function halts all audio operations for the given channel
- * @chan, and then calls via_set_rate to set the audio hardware
- * to the new rate.
- */
-
-static int via_chan_set_speed (struct via_info *card,
- struct via_channel *chan, int val)
-{
- DPRINTK ("ENTER, requested rate = %d\n", val);
-
- via_chan_clear (card, chan);
-
- val = via_set_rate (card->ac97, chan, val);
-
- DPRINTK ("EXIT, returning %d\n", val);
- return val;
-}
-
-
-/**
- * via_chan_set_fmt - Set PCM sample size for given channel
- * @card: Private info for specified board
- * @chan: Channel whose sample size will be adjusted
- * @val: New sample size, use the %AFMT_xxx constants
- *
- * Helper function for the %SNDCTL_DSP_SETFMT ioctl. OSS semantics
- * demand that all audio operations halt (if they are not already
- * halted) when the %SNDCTL_DSP_SETFMT is given.
- *
- * This function halts all audio operations for the given channel
- * @chan, and then calls via_chan_pcm_fmt to set the audio hardware
- * to the new sample size, either 8-bit or 16-bit.
- */
-
-static int via_chan_set_fmt (struct via_info *card,
- struct via_channel *chan, int val)
-{
- DPRINTK ("ENTER, val=%s\n",
- val == AFMT_U8 ? "AFMT_U8" :
- val == AFMT_S16_LE ? "AFMT_S16_LE" :
- "unknown");
-
- via_chan_clear (card, chan);
-
- assert (val != AFMT_QUERY); /* this case is handled elsewhere */
-
- switch (val) {
- case AFMT_S16_LE:
- if ((chan->pcm_fmt & VIA_PCM_FMT_16BIT) == 0) {
- chan->pcm_fmt |= VIA_PCM_FMT_16BIT;
- via_chan_pcm_fmt (chan, 0);
- }
- break;
-
- case AFMT_U8:
- if (chan->pcm_fmt & VIA_PCM_FMT_16BIT) {
- chan->pcm_fmt &= ~VIA_PCM_FMT_16BIT;
- via_chan_pcm_fmt (chan, 0);
- }
- break;
-
- default:
- DPRINTK ("unknown AFMT: 0x%X\n", val);
- val = AFMT_S16_LE;
- }
-
- DPRINTK ("EXIT\n");
- return val;
-}
-
-
-/**
- * via_chan_set_stereo - Enable or disable stereo for a DMA channel
- * @card: Private info for specified board
- * @chan: Channel whose stereo setting will be adjusted
- * @val: New sample size, use the %AFMT_xxx constants
- *
- * Helper function for the %SNDCTL_DSP_CHANNELS and %SNDCTL_DSP_STEREO ioctls. OSS semantics
- * demand that all audio operations halt (if they are not already
- * halted) when %SNDCTL_DSP_CHANNELS or SNDCTL_DSP_STEREO is given.
- *
- * This function halts all audio operations for the given channel
- * @chan, and then calls via_chan_pcm_fmt to set the audio hardware
- * to enable or disable stereo.
- */
-
-static int via_chan_set_stereo (struct via_info *card,
- struct via_channel *chan, int val)
-{
- DPRINTK ("ENTER, channels = %d\n", val);
-
- via_chan_clear (card, chan);
-
- switch (val) {
-
- /* mono */
- case 1:
- chan->pcm_fmt &= ~VIA_PCM_FMT_STEREO;
- chan->channels = 1;
- via_chan_pcm_fmt (chan, 0);
- break;
-
- /* stereo */
- case 2:
- chan->pcm_fmt |= VIA_PCM_FMT_STEREO;
- chan->channels = 2;
- via_chan_pcm_fmt (chan, 0);
- break;
-
- case 4:
- case 6:
- if(chan->is_multi)
- {
- chan->pcm_fmt |= VIA_PCM_FMT_STEREO;
- chan->channels = val;
- break;
- }
- /* unknown */
- default:
- val = -EINVAL;
- break;
- }
-
- DPRINTK ("EXIT, returning %d\n", val);
- return val;
-}
-
-static int via_chan_set_buffering (struct via_info *card,
- struct via_channel *chan, int val)
-{
- int shift;
-
- DPRINTK ("ENTER\n");
-
- /* in both cases the buffer cannot be changed */
- if (chan->is_active || chan->is_mapped) {
- DPRINTK ("EXIT\n");
- return -EINVAL;
- }
-
- /* called outside SETFRAGMENT */
- /* set defaults or do nothing */
- if (val < 0) {
-
- if (chan->frag_size && chan->frag_number)
- goto out;
-
- DPRINTK ("\n");
-
- chan->frag_size = (VIA_DEFAULT_FRAG_TIME * chan->rate * chan->channels
- * ((chan->pcm_fmt & VIA_PCM_FMT_16BIT) ? 2 : 1)) / 1000 - 1;
-
- shift = 0;
- while (chan->frag_size) {
- chan->frag_size >>= 1;
- shift++;
- }
- chan->frag_size = 1 << shift;
-
- chan->frag_number = (VIA_DEFAULT_BUFFER_TIME / VIA_DEFAULT_FRAG_TIME);
-
- DPRINTK ("setting default values %d %d\n", chan->frag_size, chan->frag_number);
- } else {
- chan->frag_size = 1 << (val & 0xFFFF);
- chan->frag_number = (val >> 16) & 0xFFFF;
-
- DPRINTK ("using user values %d %d\n", chan->frag_size, chan->frag_number);
- }
-
- /* quake3 wants frag_number to be a power of two */
- shift = 0;
- while (chan->frag_number) {
- chan->frag_number >>= 1;
- shift++;
- }
- chan->frag_number = 1 << shift;
-
- if (chan->frag_size > VIA_MAX_FRAG_SIZE)
- chan->frag_size = VIA_MAX_FRAG_SIZE;
- else if (chan->frag_size < VIA_MIN_FRAG_SIZE)
- chan->frag_size = VIA_MIN_FRAG_SIZE;
-
- if (chan->frag_number < VIA_MIN_FRAG_NUMBER)
- chan->frag_number = VIA_MIN_FRAG_NUMBER;
- if (chan->frag_number > VIA_MAX_FRAG_NUMBER)
- chan->frag_number = VIA_MAX_FRAG_NUMBER;
-
- if ((chan->frag_number * chan->frag_size) / PAGE_SIZE > VIA_MAX_BUFFER_DMA_PAGES)
- chan->frag_number = (VIA_MAX_BUFFER_DMA_PAGES * PAGE_SIZE) / chan->frag_size;
-
-out:
- if (chan->is_record)
- atomic_set (&chan->n_frags, 0);
- else
- atomic_set (&chan->n_frags, chan->frag_number);
-
- DPRINTK ("EXIT\n");
-
- return 0;
-}
-
-#ifdef VIA_CHAN_DUMP_BUFS
-/**
- * via_chan_dump_bufs - Display DMA table contents
- * @chan: Channel whose DMA table will be displayed
- *
- * Debugging function which displays the contents of the
- * scatter-gather DMA table for the given channel @chan.
- */
-
-static void via_chan_dump_bufs (struct via_channel *chan)
-{
- int i;
-
- for (i = 0; i < chan->frag_number; i++) {
- DPRINTK ("#%02d: addr=%x, count=%u, flag=%d, eol=%d\n",
- i, chan->sgtable[i].addr,
- chan->sgtable[i].count & 0x00FFFFFF,
- chan->sgtable[i].count & VIA_FLAG ? 1 : 0,
- chan->sgtable[i].count & VIA_EOL ? 1 : 0);
- }
- DPRINTK ("buf_in_use = %d, nextbuf = %d\n",
- atomic_read (&chan->buf_in_use),
- atomic_read (&chan->sw_ptr));
-}
-#endif /* VIA_CHAN_DUMP_BUFS */
-
-
-/**
- * via_chan_flush_frag - Flush partially-full playback buffer to hardware
- * @chan: Channel whose DMA table will be flushed
- *
- * Flushes partially-full playback buffer to hardware.
- */
-
-static void via_chan_flush_frag (struct via_channel *chan)
-{
- DPRINTK ("ENTER\n");
-
- assert (chan->slop_len > 0);
-
- if (chan->sw_ptr == (chan->frag_number - 1))
- chan->sw_ptr = 0;
- else
- chan->sw_ptr++;
-
- chan->slop_len = 0;
-
- assert (atomic_read (&chan->n_frags) > 0);
- atomic_dec (&chan->n_frags);
-
- DPRINTK ("EXIT\n");
-}
-
-
-
-/**
- * via_chan_maybe_start - Initiate audio hardware DMA operation
- * @chan: Channel whose DMA is to be started
- *
- * Initiate DMA operation, if the DMA engine for the given
- * channel @chan is not already active.
- */
-
-static inline void via_chan_maybe_start (struct via_channel *chan)
-{
- assert (chan->is_active == sg_active(chan->iobase));
-
- DPRINTK ("MAYBE START %s\n", chan->name);
- if (!chan->is_active && chan->is_enabled) {
- chan->is_active = 1;
- sg_begin (chan);
- DPRINTK ("starting channel %s\n", chan->name);
- }
-}
-
-
-/****************************************************************
- *
- * Interface to ac97-codec module
- *
- *
- */
-
-/**
- * via_ac97_wait_idle - Wait until AC97 codec is not busy
- * @card: Private info for specified board
- *
- * Sleep until the AC97 codec is no longer busy.
- * Returns the final value read from the SGD
- * register being polled.
- */
-
-static u8 via_ac97_wait_idle (struct via_info *card)
-{
- u8 tmp8;
- int counter = VIA_COUNTER_LIMIT;
-
- DPRINTK ("ENTER/EXIT\n");
-
- assert (card != NULL);
- assert (card->pdev != NULL);
-
- do {
- udelay (15);
-
- tmp8 = inb (card->baseaddr + 0x83);
- } while ((tmp8 & VIA_CR83_BUSY) && (counter-- > 0));
-
- if (tmp8 & VIA_CR83_BUSY)
- printk (KERN_WARNING PFX "timeout waiting on AC97 codec\n");
- return tmp8;
-}
-
-
-/**
- * via_ac97_read_reg - Read AC97 standard register
- * @codec: Pointer to generic AC97 codec info
- * @reg: Index of AC97 register to be read
- *
- * Read the value of a single AC97 codec register,
- * as defined by the Intel AC97 specification.
- *
- * Defines the standard AC97 read-register operation
- * required by the kernel's ac97_codec interface.
- *
- * Returns the 16-bit value stored in the specified
- * register.
- */
-
-static u16 via_ac97_read_reg (struct ac97_codec *codec, u8 reg)
-{
- unsigned long data;
- struct via_info *card;
- int counter;
-
- DPRINTK ("ENTER\n");
-
- assert (codec != NULL);
- assert (codec->private_data != NULL);
-
- card = codec->private_data;
-
- spin_lock(&card->ac97_lock);
-
- /* Every time we write to register 80 we cause a transaction.
- The only safe way to clear the valid bit is to write it at
- the same time as the command */
- data = (reg << 16) | VIA_CR80_READ | VIA_CR80_VALID;
-
- outl (data, card->baseaddr + VIA_BASE0_AC97_CTRL);
- udelay (20);
-
- for (counter = VIA_COUNTER_LIMIT; counter > 0; counter--) {
- udelay (1);
- if ((((data = inl(card->baseaddr + VIA_BASE0_AC97_CTRL)) &
- (VIA_CR80_VALID|VIA_CR80_BUSY)) == VIA_CR80_VALID))
- goto out;
- }
-
- printk (KERN_WARNING PFX "timeout while reading AC97 codec (0x%lX)\n", data);
- goto err_out;
-
-out:
- /* Once the valid bit has become set, we must wait a complete AC97
- frame before the data has settled. */
- udelay(25);
- data = (unsigned long) inl (card->baseaddr + VIA_BASE0_AC97_CTRL);
-
- outb (0x02, card->baseaddr + 0x83);
-
- if (((data & 0x007F0000) >> 16) == reg) {
- DPRINTK ("EXIT, success, data=0x%lx, retval=0x%lx\n",
- data, data & 0x0000FFFF);
- spin_unlock(&card->ac97_lock);
- return data & 0x0000FFFF;
- }
-
- printk (KERN_WARNING "via82cxxx_audio: not our index: reg=0x%x, newreg=0x%lx\n",
- reg, ((data & 0x007F0000) >> 16));
-
-err_out:
- spin_unlock(&card->ac97_lock);
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-}
-
-
-/**
- * via_ac97_write_reg - Write AC97 standard register
- * @codec: Pointer to generic AC97 codec info
- * @reg: Index of AC97 register to be written
- * @value: Value to be written to AC97 register
- *
- * Write the value of a single AC97 codec register,
- * as defined by the Intel AC97 specification.
- *
- * Defines the standard AC97 write-register operation
- * required by the kernel's ac97_codec interface.
- */
-
-static void via_ac97_write_reg (struct ac97_codec *codec, u8 reg, u16 value)
-{
- u32 data;
- struct via_info *card;
- int counter;
-
- DPRINTK ("ENTER\n");
-
- assert (codec != NULL);
- assert (codec->private_data != NULL);
-
- card = codec->private_data;
-
- spin_lock(&card->ac97_lock);
-
- data = (reg << 16) + value;
- outl (data, card->baseaddr + VIA_BASE0_AC97_CTRL);
- udelay (10);
-
- for (counter = VIA_COUNTER_LIMIT; counter > 0; counter--) {
- if ((inb (card->baseaddr + 0x83) & VIA_CR83_BUSY) == 0)
- goto out;
-
- udelay (15);
- }
-
- printk (KERN_WARNING PFX "timeout after AC97 codec write (0x%X, 0x%X)\n", reg, value);
-
-out:
- spin_unlock(&card->ac97_lock);
- DPRINTK ("EXIT\n");
-}
-
-
-static int via_mixer_open (struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct via_info *card;
- struct pci_dev *pdev = NULL;
- struct pci_driver *drvr;
-
- DPRINTK ("ENTER\n");
-
- while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
- drvr = pci_dev_driver (pdev);
- if (drvr == &via_driver) {
- assert (pci_get_drvdata (pdev) != NULL);
-
- card = pci_get_drvdata (pdev);
- if (card->ac97->dev_mixer == minor)
- goto match;
- }
- }
-
- DPRINTK ("EXIT, returning -ENODEV\n");
- return -ENODEV;
-
-match:
- pci_dev_put(pdev);
- file->private_data = card->ac97;
-
- DPRINTK ("EXIT, returning 0\n");
- return nonseekable_open(inode, file);
-}
-
-static int via_mixer_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct ac97_codec *codec = file->private_data;
- struct via_info *card;
- int nonblock = (file->f_flags & O_NONBLOCK);
- int rc;
-
- DPRINTK ("ENTER\n");
-
- assert (codec != NULL);
- card = codec->private_data;
- assert (card != NULL);
-
- rc = via_syscall_down (card, nonblock);
- if (rc) goto out;
-
-#if 0
- /*
- * Intercept volume control on 8233 and 8235
- */
- if(card->volume)
- {
- switch(cmd)
- {
- case SOUND_MIXER_READ_VOLUME:
- return card->mixer_vol;
- case SOUND_MIXER_WRITE_VOLUME:
- {
- int v;
- if(get_user(v, (int *)arg))
- {
- rc = -EFAULT;
- goto out;
- }
- card->mixer_vol = v;
- }
- }
- }
-#endif
- rc = codec->mixer_ioctl(codec, cmd, arg);
-
- mutex_unlock(&card->syscall_mutex);
-
-out:
- DPRINTK ("EXIT, returning %d\n", rc);
- return rc;
-}
-
-
-static const struct file_operations via_mixer_fops = {
- .owner = THIS_MODULE,
- .open = via_mixer_open,
- .llseek = no_llseek,
- .ioctl = via_mixer_ioctl,
-};
-
-
-static int __devinit via_ac97_reset (struct via_info *card)
-{
- struct pci_dev *pdev = card->pdev;
- u8 tmp8;
- u16 tmp16;
-
- DPRINTK ("ENTER\n");
-
- assert (pdev != NULL);
-
-#ifndef NDEBUG
- {
- u8 r40,r41,r42,r43,r44,r48;
- pci_read_config_byte (card->pdev, 0x40, &r40);
- pci_read_config_byte (card->pdev, 0x41, &r41);
- pci_read_config_byte (card->pdev, 0x42, &r42);
- pci_read_config_byte (card->pdev, 0x43, &r43);
- pci_read_config_byte (card->pdev, 0x44, &r44);
- pci_read_config_byte (card->pdev, 0x48, &r48);
- DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n",
- r40,r41,r42,r43,r44,r48);
-
- spin_lock_irq (&card->lock);
- DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
- inb (card->baseaddr + 0x00),
- inb (card->baseaddr + 0x01),
- inb (card->baseaddr + 0x02),
- inl (card->baseaddr + 0x04),
- inl (card->baseaddr + 0x0C),
- inl (card->baseaddr + 0x80),
- inl (card->baseaddr + 0x84));
- spin_unlock_irq (&card->lock);
-
- }
-#endif
-
- /*
- * Reset AC97 controller: enable, disable, enable,
- * pausing after each command for good luck. Only
- * do this if the codec is not ready, because it causes
- * loud pops and such due to such a hard codec reset.
- */
- pci_read_config_byte (pdev, VIA_ACLINK_STATUS, &tmp8);
- if ((tmp8 & VIA_CR40_AC97_READY) == 0) {
- pci_write_config_byte (pdev, VIA_ACLINK_CTRL,
- VIA_CR41_AC97_ENABLE |
- VIA_CR41_AC97_RESET |
- VIA_CR41_AC97_WAKEUP);
- udelay (100);
-
- pci_write_config_byte (pdev, VIA_ACLINK_CTRL, 0);
- udelay (100);
-
- pci_write_config_byte (pdev, VIA_ACLINK_CTRL,
- VIA_CR41_AC97_ENABLE |
- VIA_CR41_PCM_ENABLE |
- VIA_CR41_VRA | VIA_CR41_AC97_RESET);
- udelay (100);
- }
-
- /* Make sure VRA is enabled, in case we didn't do a
- * complete codec reset, above
- */
- pci_read_config_byte (pdev, VIA_ACLINK_CTRL, &tmp8);
- if (((tmp8 & VIA_CR41_VRA) == 0) ||
- ((tmp8 & VIA_CR41_AC97_ENABLE) == 0) ||
- ((tmp8 & VIA_CR41_PCM_ENABLE) == 0) ||
- ((tmp8 & VIA_CR41_AC97_RESET) == 0)) {
- pci_write_config_byte (pdev, VIA_ACLINK_CTRL,
- VIA_CR41_AC97_ENABLE |
- VIA_CR41_PCM_ENABLE |
- VIA_CR41_VRA | VIA_CR41_AC97_RESET);
- udelay (100);
- }
-
- if(card->legacy)
- {
-#if 0 /* this breaks on K7M */
- /* disable legacy stuff */
- pci_write_config_byte (pdev, 0x42, 0x00);
- udelay(10);
-#endif
-
- /* route FM trap to IRQ, disable FM trap */
- pci_write_config_byte (pdev, 0x48, 0x05);
- udelay(10);
- }
-
- /* disable all codec GPI interrupts */
- outl (0, pci_resource_start (pdev, 0) + 0x8C);
-
- /* WARNING: this line is magic. Remove this
- * and things break. */
- /* enable variable rate */
- tmp16 = via_ac97_read_reg (card->ac97, AC97_EXTENDED_STATUS);
- if ((tmp16 & 1) == 0)
- via_ac97_write_reg (card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1);
-
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-}
-
-
-static void via_ac97_codec_wait (struct ac97_codec *codec)
-{
- assert (codec->private_data != NULL);
- via_ac97_wait_idle (codec->private_data);
-}
-
-
-static int __devinit via_ac97_init (struct via_info *card)
-{
- int rc;
- u16 tmp16;
-
- DPRINTK ("ENTER\n");
-
- assert (card != NULL);
-
- card->ac97 = ac97_alloc_codec();
- if(card->ac97 == NULL)
- return -ENOMEM;
-
- card->ac97->private_data = card;
- card->ac97->codec_read = via_ac97_read_reg;
- card->ac97->codec_write = via_ac97_write_reg;
- card->ac97->codec_wait = via_ac97_codec_wait;
-
- card->ac97->dev_mixer = register_sound_mixer (&via_mixer_fops, -1);
- if (card->ac97->dev_mixer < 0) {
- printk (KERN_ERR PFX "unable to register AC97 mixer, aborting\n");
- DPRINTK ("EXIT, returning -EIO\n");
- ac97_release_codec(card->ac97);
- return -EIO;
- }
-
- rc = via_ac97_reset (card);
- if (rc) {
- printk (KERN_ERR PFX "unable to reset AC97 codec, aborting\n");
- goto err_out;
- }
-
- mdelay(10);
-
- if (ac97_probe_codec (card->ac97) == 0) {
- printk (KERN_ERR PFX "unable to probe AC97 codec, aborting\n");
- rc = -EIO;
- goto err_out;
- }
-
- /* enable variable rate */
- tmp16 = via_ac97_read_reg (card->ac97, AC97_EXTENDED_STATUS);
- via_ac97_write_reg (card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1);
-
- /*
- * If we cannot enable VRA, we have a locked-rate codec.
- * We try again to enable VRA before assuming so, however.
- */
- tmp16 = via_ac97_read_reg (card->ac97, AC97_EXTENDED_STATUS);
- if ((tmp16 & 1) == 0) {
- via_ac97_write_reg (card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1);
- tmp16 = via_ac97_read_reg (card->ac97, AC97_EXTENDED_STATUS);
- if ((tmp16 & 1) == 0) {
- card->locked_rate = 1;
- printk (KERN_WARNING PFX "Codec rate locked at 48Khz\n");
- }
- }
-
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-
-err_out:
- unregister_sound_mixer (card->ac97->dev_mixer);
- DPRINTK ("EXIT, returning %d\n", rc);
- ac97_release_codec(card->ac97);
- return rc;
-}
-
-
-static void via_ac97_cleanup (struct via_info *card)
-{
- DPRINTK ("ENTER\n");
-
- assert (card != NULL);
- assert (card->ac97->dev_mixer >= 0);
-
- unregister_sound_mixer (card->ac97->dev_mixer);
- ac97_release_codec(card->ac97);
-
- DPRINTK ("EXIT\n");
-}
-
-
-
-/****************************************************************
- *
- * Interrupt-related code
- *
- */
-
-/**
- * via_intr_channel - handle an interrupt for a single channel
- * @card: unused
- * @chan: handle interrupt for this channel
- *
- * This is the "meat" of the interrupt handler,
- * containing the actions taken each time an interrupt
- * occurs. All communication and coordination with
- * userspace takes place here.
- *
- * Locking: inside card->lock
- */
-
-static void via_intr_channel (struct via_info *card, struct via_channel *chan)
-{
- u8 status;
- int n;
-
- /* check pertinent bits of status register for action bits */
- status = inb (chan->iobase) & (VIA_SGD_FLAG | VIA_SGD_EOL | VIA_SGD_STOPPED);
- if (!status)
- return;
-
- /* acknowledge any flagged bits ASAP */
- outb (status, chan->iobase);
-
- if (!chan->sgtable) /* XXX: temporary solution */
- return;
-
- /* grab current h/w ptr value */
- n = atomic_read (&chan->hw_ptr);
-
- /* sanity check: make sure our h/w ptr doesn't have a weird value */
- assert (n >= 0);
- assert (n < chan->frag_number);
-
-
- /* reset SGD data structure in memory to reflect a full buffer,
- * and advance the h/w ptr, wrapping around to zero if needed
- */
- if (n == (chan->frag_number - 1)) {
- chan->sgtable[n].count = cpu_to_le32(chan->frag_size | VIA_EOL);
- atomic_set (&chan->hw_ptr, 0);
- } else {
- chan->sgtable[n].count = cpu_to_le32(chan->frag_size | VIA_FLAG);
- atomic_inc (&chan->hw_ptr);
- }
-
- /* accounting crap for SNDCTL_DSP_GETxPTR */
- chan->n_irqs++;
- chan->bytes += chan->frag_size;
- /* FIXME - signed overflow is undefined */
- if (chan->bytes < 0) /* handle overflow of 31-bit value */
- chan->bytes = chan->frag_size;
- /* all following checks only occur when not in mmap(2) mode */
- if (!chan->is_mapped)
- {
- /* If we are recording, then n_frags represents the number
- * of fragments waiting to be handled by userspace.
- * If we are playback, then n_frags represents the number
- * of fragments remaining to be filled by userspace.
- * We increment here. If we reach max number of fragments,
- * this indicates an underrun/overrun. For this case under OSS,
- * we stop the record/playback process.
- */
- if (atomic_read (&chan->n_frags) < chan->frag_number)
- atomic_inc (&chan->n_frags);
- assert (atomic_read (&chan->n_frags) <= chan->frag_number);
- if (atomic_read (&chan->n_frags) == chan->frag_number) {
- chan->is_active = 0;
- via_chan_stop (chan->iobase);
- }
- }
- /* wake up anyone listening to see when interrupts occur */
- wake_up_all (&chan->wait);
-
- DPRINTK ("%s intr, status=0x%02X, hwptr=0x%lX, chan->hw_ptr=%d\n",
- chan->name, status, (long) inl (chan->iobase + 0x04),
- atomic_read (&chan->hw_ptr));
-
- DPRINTK ("%s intr, channel n_frags == %d, missed %d\n", chan->name,
- atomic_read (&chan->n_frags), missed);
-}
-
-
-static irqreturn_t via_interrupt(int irq, void *dev_id)
-{
- struct via_info *card = dev_id;
- u32 status32;
-
- /* to minimize interrupt sharing costs, we use the SGD status
- * shadow register to check the status of all inputs and
- * outputs with a single 32-bit bus read. If no interrupt
- * conditions are flagged, we exit immediately
- */
- status32 = inl (card->baseaddr + VIA_BASE0_SGD_STATUS_SHADOW);
- if (!(status32 & VIA_INTR_MASK))
- {
-#ifdef CONFIG_MIDI_VIA82CXXX
- if (card->midi_devc)
- uart401intr(irq, card->midi_devc);
-#endif
- return IRQ_HANDLED;
- }
- DPRINTK ("intr, status32 == 0x%08X\n", status32);
-
- /* synchronize interrupt handling under SMP. this spinlock
- * goes away completely on UP
- */
- spin_lock (&card->lock);
-
- if (status32 & VIA_INTR_OUT)
- via_intr_channel (card, &card->ch_out);
- if (status32 & VIA_INTR_IN)
- via_intr_channel (card, &card->ch_in);
- if (status32 & VIA_INTR_FM)
- via_intr_channel (card, &card->ch_fm);
-
- spin_unlock (&card->lock);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t via_new_interrupt(int irq, void *dev_id)
-{
- struct via_info *card = dev_id;
- u32 status32;
-
- /* to minimize interrupt sharing costs, we use the SGD status
- * shadow register to check the status of all inputs and
- * outputs with a single 32-bit bus read. If no interrupt
- * conditions are flagged, we exit immediately
- */
- status32 = inl (card->baseaddr + VIA_BASE0_SGD_STATUS_SHADOW);
- if (!(status32 & VIA_NEW_INTR_MASK))
- return IRQ_NONE;
- /*
- * goes away completely on UP
- */
- spin_lock (&card->lock);
-
- via_intr_channel (card, &card->ch_out);
- via_intr_channel (card, &card->ch_in);
- via_intr_channel (card, &card->ch_fm);
-
- spin_unlock (&card->lock);
- return IRQ_HANDLED;
-}
-
-
-/**
- * via_interrupt_init - Initialize interrupt handling
- * @card: Private info for specified board
- *
- * Obtain and reserve IRQ for using in handling audio events.
- * Also, disable any IRQ-generating resources, to make sure
- * we don't get interrupts before we want them.
- */
-
-static int via_interrupt_init (struct via_info *card)
-{
- u8 tmp8;
-
- DPRINTK ("ENTER\n");
-
- assert (card != NULL);
- assert (card->pdev != NULL);
-
- /* check for sane IRQ number. can this ever happen? */
- if (card->pdev->irq < 2) {
- printk (KERN_ERR PFX "insane IRQ %d, aborting\n",
- card->pdev->irq);
- DPRINTK ("EXIT, returning -EIO\n");
- return -EIO;
- }
-
- /* VIA requires this is done */
- pci_write_config_byte(card->pdev, PCI_INTERRUPT_LINE, card->pdev->irq);
-
- if(card->legacy)
- {
- /* make sure FM irq is not routed to us */
- pci_read_config_byte (card->pdev, VIA_FM_NMI_CTRL, &tmp8);
- if ((tmp8 & VIA_CR48_FM_TRAP_TO_NMI) == 0) {
- tmp8 |= VIA_CR48_FM_TRAP_TO_NMI;
- pci_write_config_byte (card->pdev, VIA_FM_NMI_CTRL, tmp8);
- }
- if (request_irq (card->pdev->irq, via_interrupt, IRQF_SHARED, VIA_MODULE_NAME, card)) {
- printk (KERN_ERR PFX "unable to obtain IRQ %d, aborting\n",
- card->pdev->irq);
- DPRINTK ("EXIT, returning -EBUSY\n");
- return -EBUSY;
- }
- }
- else
- {
- if (request_irq (card->pdev->irq, via_new_interrupt, IRQF_SHARED, VIA_MODULE_NAME, card)) {
- printk (KERN_ERR PFX "unable to obtain IRQ %d, aborting\n",
- card->pdev->irq);
- DPRINTK ("EXIT, returning -EBUSY\n");
- return -EBUSY;
- }
- }
-
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-}
-
-
-/****************************************************************
- *
- * OSS DSP device
- *
- */
-
-static const struct file_operations via_dsp_fops = {
- .owner = THIS_MODULE,
- .open = via_dsp_open,
- .release = via_dsp_release,
- .read = via_dsp_read,
- .write = via_dsp_write,
- .poll = via_dsp_poll,
- .llseek = no_llseek,
- .ioctl = via_dsp_ioctl,
- .mmap = via_dsp_mmap,
-};
-
-
-static int __devinit via_dsp_init (struct via_info *card)
-{
- u8 tmp8;
-
- DPRINTK ("ENTER\n");
-
- assert (card != NULL);
-
- if(card->legacy)
- {
- /* turn off legacy features, if not already */
- pci_read_config_byte (card->pdev, VIA_FUNC_ENABLE, &tmp8);
- if (tmp8 & (VIA_CR42_SB_ENABLE | VIA_CR42_FM_ENABLE)) {
- tmp8 &= ~(VIA_CR42_SB_ENABLE | VIA_CR42_FM_ENABLE);
- pci_write_config_byte (card->pdev, VIA_FUNC_ENABLE, tmp8);
- }
- }
-
- via_stop_everything (card);
-
- card->dev_dsp = register_sound_dsp (&via_dsp_fops, -1);
- if (card->dev_dsp < 0) {
- DPRINTK ("EXIT, returning -ENODEV\n");
- return -ENODEV;
- }
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-}
-
-
-static void via_dsp_cleanup (struct via_info *card)
-{
- DPRINTK ("ENTER\n");
-
- assert (card != NULL);
- assert (card->dev_dsp >= 0);
-
- via_stop_everything (card);
-
- unregister_sound_dsp (card->dev_dsp);
-
- DPRINTK ("EXIT\n");
-}
-
-
-static struct page * via_mm_nopage (struct vm_area_struct * vma,
- unsigned long address, int *type)
-{
- struct via_info *card = vma->vm_private_data;
- struct via_channel *chan = &card->ch_out;
- struct page *dmapage;
- unsigned long pgoff;
- int rd, wr;
-
- DPRINTK ("ENTER, start %lXh, ofs %lXh, pgoff %ld, addr %lXh\n",
- vma->vm_start,
- address - vma->vm_start,
- (address - vma->vm_start) >> PAGE_SHIFT,
- address);
-
- if (address > vma->vm_end) {
- DPRINTK ("EXIT, returning NOPAGE_SIGBUS\n");
- return NOPAGE_SIGBUS; /* Disallow mremap */
- }
- if (!card) {
- DPRINTK ("EXIT, returning NOPAGE_SIGBUS\n");
- return NOPAGE_SIGBUS; /* Nothing allocated */
- }
-
- pgoff = vma->vm_pgoff + ((address - vma->vm_start) >> PAGE_SHIFT);
- rd = card->ch_in.is_mapped;
- wr = card->ch_out.is_mapped;
-
-#ifndef VIA_NDEBUG
- {
- unsigned long max_bufs = chan->frag_number;
- if (rd && wr) max_bufs *= 2;
- /* via_dsp_mmap() should ensure this */
- assert (pgoff < max_bufs);
- }
-#endif
-
- /* if full-duplex (read+write) and we have two sets of bufs,
- * then the playback buffers come first, sez soundcard.c */
- if (pgoff >= chan->page_number) {
- pgoff -= chan->page_number;
- chan = &card->ch_in;
- } else if (!wr)
- chan = &card->ch_in;
-
- assert ((((unsigned long)chan->pgtbl[pgoff].cpuaddr) % PAGE_SIZE) == 0);
-
- dmapage = virt_to_page (chan->pgtbl[pgoff].cpuaddr);
- DPRINTK ("EXIT, returning page %p for cpuaddr %lXh\n",
- dmapage, (unsigned long) chan->pgtbl[pgoff].cpuaddr);
- get_page (dmapage);
- if (type)
- *type = VM_FAULT_MINOR;
- return dmapage;
-}
-
-
-#ifndef VM_RESERVED
-static int via_mm_swapout (struct page *page, struct file *filp)
-{
- return 0;
-}
-#endif /* VM_RESERVED */
-
-
-static struct vm_operations_struct via_mm_ops = {
- .nopage = via_mm_nopage,
-
-#ifndef VM_RESERVED
- .swapout = via_mm_swapout,
-#endif
-};
-
-
-static int via_dsp_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct via_info *card;
- int nonblock = (file->f_flags & O_NONBLOCK);
- int rc = -EINVAL, rd=0, wr=0;
- unsigned long max_size, size, start, offset;
-
- assert (file != NULL);
- assert (vma != NULL);
- card = file->private_data;
- assert (card != NULL);
-
- DPRINTK ("ENTER, start %lXh, size %ld, pgoff %ld\n",
- vma->vm_start,
- vma->vm_end - vma->vm_start,
- vma->vm_pgoff);
-
- max_size = 0;
- if (vma->vm_flags & VM_READ) {
- rd = 1;
- via_chan_set_buffering(card, &card->ch_in, -1);
- via_chan_buffer_init (card, &card->ch_in);
- max_size += card->ch_in.page_number << PAGE_SHIFT;
- }
- if (vma->vm_flags & VM_WRITE) {
- wr = 1;
- via_chan_set_buffering(card, &card->ch_out, -1);
- via_chan_buffer_init (card, &card->ch_out);
- max_size += card->ch_out.page_number << PAGE_SHIFT;
- }
-
- start = vma->vm_start;
- offset = (vma->vm_pgoff << PAGE_SHIFT);
- size = vma->vm_end - vma->vm_start;
-
- /* some basic size/offset sanity checks */
- if (size > max_size)
- goto out;
- if (offset > max_size - size)
- goto out;
-
- rc = via_syscall_down (card, nonblock);
- if (rc) goto out;
-
- vma->vm_ops = &via_mm_ops;
- vma->vm_private_data = card;
-
-#ifdef VM_RESERVED
- vma->vm_flags |= VM_RESERVED;
-#endif
-
- if (rd)
- card->ch_in.is_mapped = 1;
- if (wr)
- card->ch_out.is_mapped = 1;
-
- mutex_unlock(&card->syscall_mutex);
- rc = 0;
-
-out:
- DPRINTK ("EXIT, returning %d\n", rc);
- return rc;
-}
-
-
-static ssize_t via_dsp_do_read (struct via_info *card,
- char __user *userbuf, size_t count,
- int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- const char __user *orig_userbuf = userbuf;
- struct via_channel *chan = &card->ch_in;
- size_t size;
- int n, tmp;
- ssize_t ret = 0;
-
- /* if SGD has not yet been started, start it */
- via_chan_maybe_start (chan);
-
-handle_one_block:
- /* just to be a nice neighbor */
- /* Thomas Sailer:
- * But also to ourselves, release semaphore if we do so */
- if (need_resched()) {
- mutex_unlock(&card->syscall_mutex);
- schedule ();
- ret = via_syscall_down (card, nonblock);
- if (ret)
- goto out;
- }
-
- /* grab current channel software pointer. In the case of
- * recording, this is pointing to the next buffer that
- * will receive data from the audio hardware.
- */
- n = chan->sw_ptr;
-
- /* n_frags represents the number of fragments waiting
- * to be copied to userland. sleep until at least
- * one buffer has been read from the audio hardware.
- */
- add_wait_queue(&chan->wait, &wait);
- for (;;) {
- __set_current_state(TASK_INTERRUPTIBLE);
- tmp = atomic_read (&chan->n_frags);
- assert (tmp >= 0);
- assert (tmp <= chan->frag_number);
- if (tmp)
- break;
- if (nonblock || !chan->is_active) {
- ret = -EAGAIN;
- break;
- }
-
- mutex_unlock(&card->syscall_mutex);
-
- DPRINTK ("Sleeping on block %d\n", n);
- schedule();
-
- ret = via_syscall_down (card, nonblock);
- if (ret)
- break;
-
- if (signal_pending (current)) {
- ret = -ERESTARTSYS;
- break;
- }
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&chan->wait, &wait);
- if (ret)
- goto out;
-
- /* Now that we have a buffer we can read from, send
- * as much as sample data possible to userspace.
- */
- while ((count > 0) && (chan->slop_len < chan->frag_size)) {
- size_t slop_left = chan->frag_size - chan->slop_len;
- void *base = chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr;
- unsigned ofs = (n % (PAGE_SIZE / chan->frag_size)) * chan->frag_size;
-
- size = (count < slop_left) ? count : slop_left;
- if (copy_to_user (userbuf,
- base + ofs + chan->slop_len,
- size)) {
- ret = -EFAULT;
- goto out;
- }
-
- count -= size;
- chan->slop_len += size;
- userbuf += size;
- }
-
- /* If we didn't copy the buffer completely to userspace,
- * stop now.
- */
- if (chan->slop_len < chan->frag_size)
- goto out;
-
- /*
- * If we get to this point, we copied one buffer completely
- * to userspace, give the buffer back to the hardware.
- */
-
- /* advance channel software pointer to point to
- * the next buffer from which we will copy
- */
- if (chan->sw_ptr == (chan->frag_number - 1))
- chan->sw_ptr = 0;
- else
- chan->sw_ptr++;
-
- /* mark one less buffer waiting to be processed */
- assert (atomic_read (&chan->n_frags) > 0);
- atomic_dec (&chan->n_frags);
-
- /* we are at a block boundary, there is no fragment data */
- chan->slop_len = 0;
-
- DPRINTK ("Flushed block %u, sw_ptr now %u, n_frags now %d\n",
- n, chan->sw_ptr, atomic_read (&chan->n_frags));
-
- DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
- inb (card->baseaddr + 0x00),
- inb (card->baseaddr + 0x01),
- inb (card->baseaddr + 0x02),
- inl (card->baseaddr + 0x04),
- inl (card->baseaddr + 0x0C),
- inl (card->baseaddr + 0x80),
- inl (card->baseaddr + 0x84));
-
- if (count > 0)
- goto handle_one_block;
-
-out:
- return (userbuf != orig_userbuf) ? (userbuf - orig_userbuf) : ret;
-}
-
-
-static ssize_t via_dsp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct via_info *card;
- int nonblock = (file->f_flags & O_NONBLOCK);
- int rc;
-
- DPRINTK ("ENTER, file=%p, buffer=%p, count=%u, ppos=%lu\n",
- file, buffer, count, ppos ? ((unsigned long)*ppos) : 0);
-
- assert (file != NULL);
- card = file->private_data;
- assert (card != NULL);
-
- rc = via_syscall_down (card, nonblock);
- if (rc) goto out;
-
- if (card->ch_in.is_mapped) {
- rc = -ENXIO;
- goto out_up;
- }
-
- via_chan_set_buffering(card, &card->ch_in, -1);
- rc = via_chan_buffer_init (card, &card->ch_in);
-
- if (rc)
- goto out_up;
-
- rc = via_dsp_do_read (card, buffer, count, nonblock);
-
-out_up:
- mutex_unlock(&card->syscall_mutex);
-out:
- DPRINTK ("EXIT, returning %ld\n",(long) rc);
- return rc;
-}
-
-
-static ssize_t via_dsp_do_write (struct via_info *card,
- const char __user *userbuf, size_t count,
- int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- const char __user *orig_userbuf = userbuf;
- struct via_channel *chan = &card->ch_out;
- volatile struct via_sgd_table *sgtable = chan->sgtable;
- size_t size;
- int n, tmp;
- ssize_t ret = 0;
-
-handle_one_block:
- /* just to be a nice neighbor */
- /* Thomas Sailer:
- * But also to ourselves, release semaphore if we do so */
- if (need_resched()) {
- mutex_unlock(&card->syscall_mutex);
- schedule ();
- ret = via_syscall_down (card, nonblock);
- if (ret)
- goto out;
- }
-
- /* grab current channel fragment pointer. In the case of
- * playback, this is pointing to the next fragment that
- * should receive data from userland.
- */
- n = chan->sw_ptr;
-
- /* n_frags represents the number of fragments remaining
- * to be filled by userspace. Sleep until
- * at least one fragment is available for our use.
- */
- add_wait_queue(&chan->wait, &wait);
- for (;;) {
- __set_current_state(TASK_INTERRUPTIBLE);
- tmp = atomic_read (&chan->n_frags);
- assert (tmp >= 0);
- assert (tmp <= chan->frag_number);
- if (tmp)
- break;
- if (nonblock || !chan->is_active) {
- ret = -EAGAIN;
- break;
- }
-
- mutex_unlock(&card->syscall_mutex);
-
- DPRINTK ("Sleeping on page %d, tmp==%d, ir==%d\n", n, tmp, chan->is_record);
- schedule();
-
- ret = via_syscall_down (card, nonblock);
- if (ret)
- break;
-
- if (signal_pending (current)) {
- ret = -ERESTARTSYS;
- break;
- }
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&chan->wait, &wait);
- if (ret)
- goto out;
-
- /* Now that we have at least one fragment we can write to, fill the buffer
- * as much as possible with data from userspace.
- */
- while ((count > 0) && (chan->slop_len < chan->frag_size)) {
- size_t slop_left = chan->frag_size - chan->slop_len;
-
- size = (count < slop_left) ? count : slop_left;
- if (copy_from_user (chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr + (n % (PAGE_SIZE / chan->frag_size)) * chan->frag_size + chan->slop_len,
- userbuf, size)) {
- ret = -EFAULT;
- goto out;
- }
-
- count -= size;
- chan->slop_len += size;
- userbuf += size;
- }
-
- /* If we didn't fill up the buffer with data, stop now.
- * Put a 'stop' marker in the DMA table too, to tell the
- * audio hardware to stop if it gets here.
- */
- if (chan->slop_len < chan->frag_size) {
- sgtable[n].count = cpu_to_le32 (chan->slop_len | VIA_EOL | VIA_STOP);
- goto out;
- }
-
- /*
- * If we get to this point, we have filled a buffer with
- * audio data, flush the buffer to audio hardware.
- */
-
- /* Record the true size for the audio hardware to notice */
- if (n == (chan->frag_number - 1))
- sgtable[n].count = cpu_to_le32 (chan->frag_size | VIA_EOL);
- else
- sgtable[n].count = cpu_to_le32 (chan->frag_size | VIA_FLAG);
-
- /* advance channel software pointer to point to
- * the next buffer we will fill with data
- */
- if (chan->sw_ptr == (chan->frag_number - 1))
- chan->sw_ptr = 0;
- else
- chan->sw_ptr++;
-
- /* mark one less buffer as being available for userspace consumption */
- assert (atomic_read (&chan->n_frags) > 0);
- atomic_dec (&chan->n_frags);
-
- /* we are at a block boundary, there is no fragment data */
- chan->slop_len = 0;
-
- /* if SGD has not yet been started, start it */
- via_chan_maybe_start (chan);
-
- DPRINTK ("Flushed block %u, sw_ptr now %u, n_frags now %d\n",
- n, chan->sw_ptr, atomic_read (&chan->n_frags));
-
- DPRINTK ("regs==S=%02X C=%02X TP=%02X BP=%08X RT=%08X SG=%08X CC=%08X SS=%08X\n",
- inb (card->baseaddr + 0x00),
- inb (card->baseaddr + 0x01),
- inb (card->baseaddr + 0x02),
- inl (card->baseaddr + 0x04),
- inl (card->baseaddr + 0x08),
- inl (card->baseaddr + 0x0C),
- inl (card->baseaddr + 0x80),
- inl (card->baseaddr + 0x84));
-
- if (count > 0)
- goto handle_one_block;
-
-out:
- if (userbuf - orig_userbuf)
- return userbuf - orig_userbuf;
- else
- return ret;
-}
-
-
-static ssize_t via_dsp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct via_info *card;
- ssize_t rc;
- int nonblock = (file->f_flags & O_NONBLOCK);
-
- DPRINTK ("ENTER, file=%p, buffer=%p, count=%u, ppos=%lu\n",
- file, buffer, count, ppos ? ((unsigned long)*ppos) : 0);
-
- assert (file != NULL);
- card = file->private_data;
- assert (card != NULL);
-
- rc = via_syscall_down (card, nonblock);
- if (rc) goto out;
-
- if (card->ch_out.is_mapped) {
- rc = -ENXIO;
- goto out_up;
- }
-
- via_chan_set_buffering(card, &card->ch_out, -1);
- rc = via_chan_buffer_init (card, &card->ch_out);
-
- if (rc)
- goto out_up;
-
- rc = via_dsp_do_write (card, buffer, count, nonblock);
-
-out_up:
- mutex_unlock(&card->syscall_mutex);
-out:
- DPRINTK ("EXIT, returning %ld\n",(long) rc);
- return rc;
-}
-
-
-static unsigned int via_dsp_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct via_info *card;
- struct via_channel *chan;
- unsigned int mask = 0;
-
- DPRINTK ("ENTER\n");
-
- assert (file != NULL);
- card = file->private_data;
- assert (card != NULL);
-
- if (file->f_mode & FMODE_READ) {
- chan = &card->ch_in;
- if (sg_active (chan->iobase))
- poll_wait(file, &chan->wait, wait);
- if (atomic_read (&chan->n_frags) > 0)
- mask |= POLLIN | POLLRDNORM;
- }
-
- if (file->f_mode & FMODE_WRITE) {
- chan = &card->ch_out;
- if (sg_active (chan->iobase))
- poll_wait(file, &chan->wait, wait);
- if (atomic_read (&chan->n_frags) > 0)
- mask |= POLLOUT | POLLWRNORM;
- }
-
- DPRINTK ("EXIT, returning %u\n", mask);
- return mask;
-}
-
-
-/**
- * via_dsp_drain_playback - sleep until all playback samples are flushed
- * @card: Private info for specified board
- * @chan: Channel to drain
- * @nonblock: boolean, non-zero if O_NONBLOCK is set
- *
- * Sleeps until all playback has been flushed to the audio
- * hardware.
- *
- * Locking: inside card->syscall_mutex
- */
-
-static int via_dsp_drain_playback (struct via_info *card,
- struct via_channel *chan, int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- int ret = 0;
-
- DPRINTK ("ENTER, nonblock = %d\n", nonblock);
-
- if (chan->slop_len > 0)
- via_chan_flush_frag (chan);
-
- if (atomic_read (&chan->n_frags) == chan->frag_number)
- goto out;
-
- via_chan_maybe_start (chan);
-
- add_wait_queue(&chan->wait, &wait);
- for (;;) {
- DPRINTK ("FRAGS %d FRAGNUM %d\n", atomic_read(&chan->n_frags), chan->frag_number);
- __set_current_state(TASK_INTERRUPTIBLE);
- if (atomic_read (&chan->n_frags) >= chan->frag_number)
- break;
-
- if (nonblock) {
- DPRINTK ("EXIT, returning -EAGAIN\n");
- ret = -EAGAIN;
- break;
- }
-
-#ifdef VIA_DEBUG
- {
- u8 r40,r41,r42,r43,r44,r48;
- pci_read_config_byte (card->pdev, 0x40, &r40);
- pci_read_config_byte (card->pdev, 0x41, &r41);
- pci_read_config_byte (card->pdev, 0x42, &r42);
- pci_read_config_byte (card->pdev, 0x43, &r43);
- pci_read_config_byte (card->pdev, 0x44, &r44);
- pci_read_config_byte (card->pdev, 0x48, &r48);
- DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n",
- r40,r41,r42,r43,r44,r48);
-
- DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
- inb (card->baseaddr + 0x00),
- inb (card->baseaddr + 0x01),
- inb (card->baseaddr + 0x02),
- inl (card->baseaddr + 0x04),
- inl (card->baseaddr + 0x0C),
- inl (card->baseaddr + 0x80),
- inl (card->baseaddr + 0x84));
- }
-
- if (!chan->is_active)
- printk (KERN_ERR "sleeping but not active\n");
-#endif
-
- mutex_unlock(&card->syscall_mutex);
-
- DPRINTK ("sleeping, nbufs=%d\n", atomic_read (&chan->n_frags));
- schedule();
-
- if ((ret = via_syscall_down (card, nonblock)))
- break;
-
- if (signal_pending (current)) {
- DPRINTK ("EXIT, returning -ERESTARTSYS\n");
- ret = -ERESTARTSYS;
- break;
- }
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&chan->wait, &wait);
-
-#ifdef VIA_DEBUG
- {
- u8 r40,r41,r42,r43,r44,r48;
- pci_read_config_byte (card->pdev, 0x40, &r40);
- pci_read_config_byte (card->pdev, 0x41, &r41);
- pci_read_config_byte (card->pdev, 0x42, &r42);
- pci_read_config_byte (card->pdev, 0x43, &r43);
- pci_read_config_byte (card->pdev, 0x44, &r44);
- pci_read_config_byte (card->pdev, 0x48, &r48);
- DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n",
- r40,r41,r42,r43,r44,r48);
-
- DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
- inb (card->baseaddr + 0x00),
- inb (card->baseaddr + 0x01),
- inb (card->baseaddr + 0x02),
- inl (card->baseaddr + 0x04),
- inl (card->baseaddr + 0x0C),
- inl (card->baseaddr + 0x80),
- inl (card->baseaddr + 0x84));
-
- DPRINTK ("final nbufs=%d\n", atomic_read (&chan->n_frags));
- }
-#endif
-
-out:
- DPRINTK ("EXIT, returning %d\n", ret);
- return ret;
-}
-
-
-/**
- * via_dsp_ioctl_space - get information about channel buffering
- * @card: Private info for specified board
- * @chan: pointer to channel-specific info
- * @arg: user buffer for returned information
- *
- * Handles SNDCTL_DSP_GETISPACE and SNDCTL_DSP_GETOSPACE.
- *
- * Locking: inside card->syscall_mutex
- */
-
-static int via_dsp_ioctl_space (struct via_info *card,
- struct via_channel *chan,
- void __user *arg)
-{
- audio_buf_info info;
-
- via_chan_set_buffering(card, chan, -1);
-
- info.fragstotal = chan->frag_number;
- info.fragsize = chan->frag_size;
-
- /* number of full fragments we can read/write without blocking */
- info.fragments = atomic_read (&chan->n_frags);
-
- if ((chan->slop_len % chan->frag_size > 0) && (info.fragments > 0))
- info.fragments--;
-
- /* number of bytes that can be read or written immediately
- * without blocking.
- */
- info.bytes = (info.fragments * chan->frag_size);
- if (chan->slop_len % chan->frag_size > 0)
- info.bytes += chan->frag_size - (chan->slop_len % chan->frag_size);
-
- DPRINTK ("EXIT, returning fragstotal=%d, fragsize=%d, fragments=%d, bytes=%d\n",
- info.fragstotal,
- info.fragsize,
- info.fragments,
- info.bytes);
-
- return copy_to_user (arg, &info, sizeof (info))?-EFAULT:0;
-}
-
-
-/**
- * via_dsp_ioctl_ptr - get information about hardware buffer ptr
- * @card: Private info for specified board
- * @chan: pointer to channel-specific info
- * @arg: user buffer for returned information
- *
- * Handles SNDCTL_DSP_GETIPTR and SNDCTL_DSP_GETOPTR.
- *
- * Locking: inside card->syscall_mutex
- */
-
-static int via_dsp_ioctl_ptr (struct via_info *card,
- struct via_channel *chan,
- void __user *arg)
-{
- count_info info;
-
- spin_lock_irq (&card->lock);
-
- info.bytes = chan->bytes;
- info.blocks = chan->n_irqs;
- chan->n_irqs = 0;
-
- spin_unlock_irq (&card->lock);
-
- if (chan->is_active) {
- unsigned long extra;
- info.ptr = atomic_read (&chan->hw_ptr) * chan->frag_size;
- extra = chan->frag_size - via_sg_offset(chan);
- info.ptr += extra;
- info.bytes += extra;
- } else {
- info.ptr = 0;
- }
-
- DPRINTK ("EXIT, returning bytes=%d, blocks=%d, ptr=%d\n",
- info.bytes,
- info.blocks,
- info.ptr);
-
- return copy_to_user (arg, &info, sizeof (info))?-EFAULT:0;
-}
-
-
-static int via_dsp_ioctl_trigger (struct via_channel *chan, int val)
-{
- int enable, do_something;
-
- if (chan->is_record)
- enable = (val & PCM_ENABLE_INPUT);
- else
- enable = (val & PCM_ENABLE_OUTPUT);
-
- if (!chan->is_enabled && enable) {
- do_something = 1;
- } else if (chan->is_enabled && !enable) {
- do_something = -1;
- } else {
- do_something = 0;
- }
-
- DPRINTK ("enable=%d, do_something=%d\n",
- enable, do_something);
-
- if (chan->is_active && do_something)
- return -EINVAL;
-
- if (do_something == 1) {
- chan->is_enabled = 1;
- via_chan_maybe_start (chan);
- DPRINTK ("Triggering input\n");
- }
-
- else if (do_something == -1) {
- chan->is_enabled = 0;
- DPRINTK ("Setup input trigger\n");
- }
-
- return 0;
-}
-
-
-static int via_dsp_ioctl (struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int rc, rd=0, wr=0, val=0;
- struct via_info *card;
- struct via_channel *chan;
- int nonblock = (file->f_flags & O_NONBLOCK);
- int __user *ip = (int __user *)arg;
- void __user *p = (void __user *)arg;
-
- assert (file != NULL);
- card = file->private_data;
- assert (card != NULL);
-
- if (file->f_mode & FMODE_WRITE)
- wr = 1;
- if (file->f_mode & FMODE_READ)
- rd = 1;
-
- rc = via_syscall_down (card, nonblock);
- if (rc)
- return rc;
- rc = -EINVAL;
-
- switch (cmd) {
-
- /* OSS API version. XXX unverified */
- case OSS_GETVERSION:
- DPRINTK ("ioctl OSS_GETVERSION, EXIT, returning SOUND_VERSION\n");
- rc = put_user (SOUND_VERSION, ip);
- break;
-
- /* list of supported PCM data formats */
- case SNDCTL_DSP_GETFMTS:
- DPRINTK ("DSP_GETFMTS, EXIT, returning AFMT U8|S16_LE\n");
- rc = put_user (AFMT_U8 | AFMT_S16_LE, ip);
- break;
-
- /* query or set current channel's PCM data format */
- case SNDCTL_DSP_SETFMT:
- if (get_user(val, ip)) {
- rc = -EFAULT;
- break;
- }
- DPRINTK ("DSP_SETFMT, val==%d\n", val);
- if (val != AFMT_QUERY) {
- rc = 0;
-
- if (rd)
- rc = via_chan_set_fmt (card, &card->ch_in, val);
-
- if (rc >= 0 && wr)
- rc = via_chan_set_fmt (card, &card->ch_out, val);
-
- if (rc < 0)
- break;
-
- val = rc;
- } else {
- if ((rd && (card->ch_in.pcm_fmt & VIA_PCM_FMT_16BIT)) ||
- (wr && (card->ch_out.pcm_fmt & VIA_PCM_FMT_16BIT)))
- val = AFMT_S16_LE;
- else
- val = AFMT_U8;
- }
- DPRINTK ("SETFMT EXIT, returning %d\n", val);
- rc = put_user (val, ip);
- break;
-
- /* query or set number of channels (1=mono, 2=stereo, 4/6 for multichannel) */
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, ip)) {
- rc = -EFAULT;
- break;
- }
- DPRINTK ("DSP_CHANNELS, val==%d\n", val);
- if (val != 0) {
- rc = 0;
-
- if (rd)
- rc = via_chan_set_stereo (card, &card->ch_in, val);
-
- if (rc >= 0 && wr)
- rc = via_chan_set_stereo (card, &card->ch_out, val);
-
- if (rc < 0)
- break;
-
- val = rc;
- } else {
- if (rd)
- val = card->ch_in.channels;
- else
- val = card->ch_out.channels;
- }
- DPRINTK ("CHANNELS EXIT, returning %d\n", val);
- rc = put_user (val, ip);
- break;
-
- /* enable (val is not zero) or disable (val == 0) stereo */
- case SNDCTL_DSP_STEREO:
- if (get_user(val, ip)) {
- rc = -EFAULT;
- break;
- }
- DPRINTK ("DSP_STEREO, val==%d\n", val);
- rc = 0;
-
- if (rd)
- rc = via_chan_set_stereo (card, &card->ch_in, val ? 2 : 1);
- if (rc >= 0 && wr)
- rc = via_chan_set_stereo (card, &card->ch_out, val ? 2 : 1);
-
- if (rc < 0)
- break;
-
- val = rc - 1;
-
- DPRINTK ("STEREO EXIT, returning %d\n", val);
- rc = put_user(val, ip);
- break;
-
- /* query or set sampling rate */
- case SNDCTL_DSP_SPEED:
- if (get_user(val, ip)) {
- rc = -EFAULT;
- break;
- }
- DPRINTK ("DSP_SPEED, val==%d\n", val);
- if (val < 0) {
- rc = -EINVAL;
- break;
- }
- if (val > 0) {
- rc = 0;
-
- if (rd)
- rc = via_chan_set_speed (card, &card->ch_in, val);
- if (rc >= 0 && wr)
- rc = via_chan_set_speed (card, &card->ch_out, val);
-
- if (rc < 0)
- break;
-
- val = rc;
- } else {
- if (rd)
- val = card->ch_in.rate;
- else if (wr)
- val = card->ch_out.rate;
- else
- val = 0;
- }
- DPRINTK ("SPEED EXIT, returning %d\n", val);
- rc = put_user (val, ip);
- break;
-
- /* wait until all buffers have been played, and then stop device */
- case SNDCTL_DSP_SYNC:
- DPRINTK ("DSP_SYNC\n");
- rc = 0;
- if (wr) {
- DPRINTK ("SYNC EXIT (after calling via_dsp_drain_playback)\n");
- rc = via_dsp_drain_playback (card, &card->ch_out, nonblock);
- }
- break;
-
- /* stop recording/playback immediately */
- case SNDCTL_DSP_RESET:
- DPRINTK ("DSP_RESET\n");
- if (rd) {
- via_chan_clear (card, &card->ch_in);
- card->ch_in.frag_number = 0;
- card->ch_in.frag_size = 0;
- atomic_set(&card->ch_in.n_frags, 0);
- }
-
- if (wr) {
- via_chan_clear (card, &card->ch_out);
- card->ch_out.frag_number = 0;
- card->ch_out.frag_size = 0;
- atomic_set(&card->ch_out.n_frags, 0);
- }
-
- rc = 0;
- break;
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- rc = 0;
- break;
-
- /* obtain bitmask of device capabilities, such as mmap, full duplex, etc. */
- case SNDCTL_DSP_GETCAPS:
- DPRINTK ("DSP_GETCAPS\n");
- rc = put_user(VIA_DSP_CAP, ip);
- break;
-
- /* obtain buffer fragment size */
- case SNDCTL_DSP_GETBLKSIZE:
- DPRINTK ("DSP_GETBLKSIZE\n");
-
- if (rd) {
- via_chan_set_buffering(card, &card->ch_in, -1);
- rc = put_user(card->ch_in.frag_size, ip);
- } else if (wr) {
- via_chan_set_buffering(card, &card->ch_out, -1);
- rc = put_user(card->ch_out.frag_size, ip);
- }
- break;
-
- /* obtain information about input buffering */
- case SNDCTL_DSP_GETISPACE:
- DPRINTK ("DSP_GETISPACE\n");
- if (rd)
- rc = via_dsp_ioctl_space (card, &card->ch_in, p);
- break;
-
- /* obtain information about output buffering */
- case SNDCTL_DSP_GETOSPACE:
- DPRINTK ("DSP_GETOSPACE\n");
- if (wr)
- rc = via_dsp_ioctl_space (card, &card->ch_out, p);
- break;
-
- /* obtain information about input hardware pointer */
- case SNDCTL_DSP_GETIPTR:
- DPRINTK ("DSP_GETIPTR\n");
- if (rd)
- rc = via_dsp_ioctl_ptr (card, &card->ch_in, p);
- break;
-
- /* obtain information about output hardware pointer */
- case SNDCTL_DSP_GETOPTR:
- DPRINTK ("DSP_GETOPTR\n");
- if (wr)
- rc = via_dsp_ioctl_ptr (card, &card->ch_out, p);
- break;
-
- /* return number of bytes remaining to be played by DMA engine */
- case SNDCTL_DSP_GETODELAY:
- {
- DPRINTK ("DSP_GETODELAY\n");
-
- chan = &card->ch_out;
-
- if (!wr)
- break;
-
- if (chan->is_active) {
-
- val = chan->frag_number - atomic_read (&chan->n_frags);
-
- assert(val >= 0);
-
- if (val > 0) {
- val *= chan->frag_size;
- val -= chan->frag_size - via_sg_offset(chan);
- }
- val += chan->slop_len % chan->frag_size;
- } else
- val = 0;
-
- assert (val <= (chan->frag_size * chan->frag_number));
-
- DPRINTK ("GETODELAY EXIT, val = %d bytes\n", val);
- rc = put_user (val, ip);
- break;
- }
-
- /* handle the quick-start of a channel,
- * or the notification that a quick-start will
- * occur in the future
- */
- case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, ip)) {
- rc = -EFAULT;
- break;
- }
- DPRINTK ("DSP_SETTRIGGER, rd=%d, wr=%d, act=%d/%d, en=%d/%d\n",
- rd, wr, card->ch_in.is_active, card->ch_out.is_active,
- card->ch_in.is_enabled, card->ch_out.is_enabled);
-
- rc = 0;
-
- if (rd)
- rc = via_dsp_ioctl_trigger (&card->ch_in, val);
-
- if (!rc && wr)
- rc = via_dsp_ioctl_trigger (&card->ch_out, val);
-
- break;
-
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
- if ((file->f_mode & FMODE_READ) && card->ch_in.is_enabled)
- val |= PCM_ENABLE_INPUT;
- if ((file->f_mode & FMODE_WRITE) && card->ch_out.is_enabled)
- val |= PCM_ENABLE_OUTPUT;
- rc = put_user(val, ip);
- break;
-
- /* Enable full duplex. Since we do this as soon as we are opened
- * with O_RDWR, this is mainly a no-op that always returns success.
- */
- case SNDCTL_DSP_SETDUPLEX:
- DPRINTK ("DSP_SETDUPLEX\n");
- if (!rd || !wr)
- break;
- rc = 0;
- break;
-
- /* set fragment size. implemented as a successful no-op for now */
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, ip)) {
- rc = -EFAULT;
- break;
- }
- DPRINTK ("DSP_SETFRAGMENT, val==%d\n", val);
-
- if (rd)
- rc = via_chan_set_buffering(card, &card->ch_in, val);
-
- if (wr)
- rc = via_chan_set_buffering(card, &card->ch_out, val);
-
- DPRINTK ("SNDCTL_DSP_SETFRAGMENT (fragshift==0x%04X (%d), maxfrags==0x%04X (%d))\n",
- val & 0xFFFF,
- val & 0xFFFF,
- (val >> 16) & 0xFFFF,
- (val >> 16) & 0xFFFF);
-
- rc = 0;
- break;
-
- /* inform device of an upcoming pause in input (or output). */
- case SNDCTL_DSP_POST:
- DPRINTK ("DSP_POST\n");
- if (wr) {
- if (card->ch_out.slop_len > 0)
- via_chan_flush_frag (&card->ch_out);
- via_chan_maybe_start (&card->ch_out);
- }
-
- rc = 0;
- break;
-
- /* not implemented */
- default:
- DPRINTK ("unhandled ioctl, cmd==%u, arg==%p\n",
- cmd, p);
- break;
- }
-
- mutex_unlock(&card->syscall_mutex);
- DPRINTK ("EXIT, returning %d\n", rc);
- return rc;
-}
-
-
-static int via_dsp_open (struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct via_info *card;
- struct pci_dev *pdev = NULL;
- struct via_channel *chan;
- struct pci_driver *drvr;
- int nonblock = (file->f_flags & O_NONBLOCK);
-
- DPRINTK ("ENTER, minor=%d, file->f_mode=0x%x\n", minor, file->f_mode);
-
- if (!(file->f_mode & (FMODE_READ | FMODE_WRITE))) {
- DPRINTK ("EXIT, returning -EINVAL\n");
- return -EINVAL;
- }
-
- card = NULL;
- while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
- drvr = pci_dev_driver (pdev);
- if (drvr == &via_driver) {
- assert (pci_get_drvdata (pdev) != NULL);
-
- card = pci_get_drvdata (pdev);
- DPRINTK ("dev_dsp = %d, minor = %d, assn = %d\n",
- card->dev_dsp, minor,
- (card->dev_dsp ^ minor) & ~0xf);
-
- if (((card->dev_dsp ^ minor) & ~0xf) == 0)
- goto match;
- }
- }
-
- DPRINTK ("no matching %s found\n", card ? "minor" : "driver");
- return -ENODEV;
-
-match:
- pci_dev_put(pdev);
- if (nonblock) {
- if (!mutex_trylock(&card->open_mutex)) {
- DPRINTK ("EXIT, returning -EAGAIN\n");
- return -EAGAIN;
- }
- } else {
- if (mutex_lock_interruptible(&card->open_mutex)) {
- DPRINTK ("EXIT, returning -ERESTARTSYS\n");
- return -ERESTARTSYS;
- }
- }
-
- file->private_data = card;
- DPRINTK ("file->f_mode == 0x%x\n", file->f_mode);
-
- /* handle input from analog source */
- if (file->f_mode & FMODE_READ) {
- chan = &card->ch_in;
-
- via_chan_init (card, chan);
-
- /* why is this forced to 16-bit stereo in all drivers? */
- chan->pcm_fmt = VIA_PCM_FMT_16BIT | VIA_PCM_FMT_STEREO;
- chan->channels = 2;
-
- // TO DO - use FIFO: via_capture_fifo(card, 1);
- via_chan_pcm_fmt (chan, 0);
- via_set_rate (card->ac97, chan, 44100);
- }
-
- /* handle output to analog source */
- if (file->f_mode & FMODE_WRITE) {
- chan = &card->ch_out;
-
- via_chan_init (card, chan);
-
- if (file->f_mode & FMODE_READ) {
- /* if in duplex mode make the recording and playback channels
- have the same settings */
- chan->pcm_fmt = VIA_PCM_FMT_16BIT | VIA_PCM_FMT_STEREO;
- chan->channels = 2;
- via_chan_pcm_fmt (chan, 0);
- via_set_rate (card->ac97, chan, 44100);
- } else {
- if ((minor & 0xf) == SND_DEV_DSP16) {
- chan->pcm_fmt = VIA_PCM_FMT_16BIT;
- via_chan_pcm_fmt (chan, 0);
- via_set_rate (card->ac97, chan, 44100);
- } else {
- via_chan_pcm_fmt (chan, 1);
- via_set_rate (card->ac97, chan, 8000);
- }
- }
- }
-
- DPRINTK ("EXIT, returning 0\n");
- return nonseekable_open(inode, file);
-}
-
-
-static int via_dsp_release(struct inode *inode, struct file *file)
-{
- struct via_info *card;
- int nonblock = (file->f_flags & O_NONBLOCK);
- int rc;
-
- DPRINTK ("ENTER\n");
-
- assert (file != NULL);
- card = file->private_data;
- assert (card != NULL);
-
- rc = via_syscall_down (card, nonblock);
- if (rc) {
- DPRINTK ("EXIT (syscall_down error), rc=%d\n", rc);
- return rc;
- }
-
- if (file->f_mode & FMODE_WRITE) {
- rc = via_dsp_drain_playback (card, &card->ch_out, nonblock);
- if (rc && rc != -ERESTARTSYS) /* Nobody needs to know about ^C */
- printk (KERN_DEBUG "via_audio: ignoring drain playback error %d\n", rc);
-
- via_chan_free (card, &card->ch_out);
- via_chan_buffer_free(card, &card->ch_out);
- }
-
- if (file->f_mode & FMODE_READ) {
- via_chan_free (card, &card->ch_in);
- via_chan_buffer_free (card, &card->ch_in);
- }
-
- mutex_unlock(&card->syscall_mutex);
- mutex_unlock(&card->open_mutex);
-
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-}
-
-
-/****************************************************************
- *
- * Chip setup and kernel registration
- *
- *
- */
-
-static int __devinit via_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
-{
-#ifdef CONFIG_MIDI_VIA82CXXX
- u8 r42;
-#endif
- int rc;
- struct via_info *card;
- static int printed_version;
-
- DPRINTK ("ENTER\n");
-
- if (printed_version++ == 0)
- printk (KERN_INFO "Via 686a/8233/8235 audio driver " VIA_VERSION "\n");
-
- rc = pci_enable_device (pdev);
- if (rc)
- goto err_out;
-
- rc = pci_request_regions (pdev, "via82cxxx_audio");
- if (rc)
- goto err_out_disable;
-
- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
- if (rc)
- goto err_out_res;
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
- if (rc)
- goto err_out_res;
-
- card = kmalloc (sizeof (*card), GFP_KERNEL);
- if (!card) {
- printk (KERN_ERR PFX "out of memory, aborting\n");
- rc = -ENOMEM;
- goto err_out_res;
- }
-
- pci_set_drvdata (pdev, card);
-
- memset (card, 0, sizeof (*card));
- card->pdev = pdev;
- card->baseaddr = pci_resource_start (pdev, 0);
- card->card_num = via_num_cards++;
- spin_lock_init (&card->lock);
- spin_lock_init (&card->ac97_lock);
- mutex_init(&card->syscall_mutex);
- mutex_init(&card->open_mutex);
-
- /* we must init these now, in case the intr handler needs them */
- via_chan_init_defaults (card, &card->ch_out);
- via_chan_init_defaults (card, &card->ch_in);
- via_chan_init_defaults (card, &card->ch_fm);
-
- /* if BAR 2 is present, chip is Rev H or later,
- * which means it has a few extra features */
- if (pci_resource_start (pdev, 2) > 0)
- card->rev_h = 1;
-
- /* Overkill for now, but more flexible done right */
-
- card->intmask = id->driver_data;
- card->legacy = !card->intmask;
- card->sixchannel = id->driver_data;
-
- if(card->sixchannel)
- printk(KERN_INFO PFX "Six channel audio available\n");
- if (pdev->irq < 1) {
- printk (KERN_ERR PFX "invalid PCI IRQ %d, aborting\n", pdev->irq);
- rc = -ENODEV;
- goto err_out_kfree;
- }
-
- if (!(pci_resource_flags (pdev, 0) & IORESOURCE_IO)) {
- printk (KERN_ERR PFX "unable to locate I/O resources, aborting\n");
- rc = -ENODEV;
- goto err_out_kfree;
- }
-
- pci_set_master(pdev);
-
- /*
- * init AC97 mixer and codec
- */
- rc = via_ac97_init (card);
- if (rc) {
- printk (KERN_ERR PFX "AC97 init failed, aborting\n");
- goto err_out_kfree;
- }
-
- /*
- * init DSP device
- */
- rc = via_dsp_init (card);
- if (rc) {
- printk (KERN_ERR PFX "DSP device init failed, aborting\n");
- goto err_out_have_mixer;
- }
-
- /*
- * init and turn on interrupts, as the last thing we do
- */
- rc = via_interrupt_init (card);
- if (rc) {
- printk (KERN_ERR PFX "interrupt init failed, aborting\n");
- goto err_out_have_dsp;
- }
-
- printk (KERN_INFO PFX "board #%d at 0x%04lX, IRQ %d\n",
- card->card_num + 1, card->baseaddr, pdev->irq);
-
-#ifdef CONFIG_MIDI_VIA82CXXX
- /* Disable by default */
- card->midi_info.io_base = 0;
-
- if(card->legacy)
- {
- pci_read_config_byte (pdev, 0x42, &r42);
- /* Disable MIDI interrupt */
- pci_write_config_byte (pdev, 0x42, r42 | VIA_CR42_MIDI_IRQMASK);
- if (r42 & VIA_CR42_MIDI_ENABLE)
- {
- if (r42 & VIA_CR42_MIDI_PNP) /* Address selected by iobase 2 - not tested */
- card->midi_info.io_base = pci_resource_start (pdev, 2);
- else /* Address selected by byte 0x43 */
- {
- u8 r43;
- pci_read_config_byte (pdev, 0x43, &r43);
- card->midi_info.io_base = 0x300 + ((r43 & 0x0c) << 2);
- }
-
- card->midi_info.irq = -pdev->irq;
- if (probe_uart401(& card->midi_info, THIS_MODULE))
- {
- card->midi_devc=midi_devs[card->midi_info.slots[4]]->devc;
- pci_write_config_byte(pdev, 0x42, r42 & ~VIA_CR42_MIDI_IRQMASK);
- printk("Enabled Via MIDI\n");
- }
- }
- }
-#endif
-
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-
-err_out_have_dsp:
- via_dsp_cleanup (card);
-
-err_out_have_mixer:
- via_ac97_cleanup (card);
-
-err_out_kfree:
-#ifndef VIA_NDEBUG
- memset (card, OSS_POISON_FREE, sizeof (*card)); /* poison memory */
-#endif
- kfree (card);
-
-err_out_res:
- pci_release_regions (pdev);
-
-err_out_disable:
- pci_disable_device (pdev);
-
-err_out:
- pci_set_drvdata (pdev, NULL);
- DPRINTK ("EXIT - returning %d\n", rc);
- return rc;
-}
-
-
-static void __devexit via_remove_one (struct pci_dev *pdev)
-{
- struct via_info *card;
-
- DPRINTK ("ENTER\n");
-
- assert (pdev != NULL);
- card = pci_get_drvdata (pdev);
- assert (card != NULL);
-
-#ifdef CONFIG_MIDI_VIA82CXXX
- if (card->midi_info.io_base)
- unload_uart401(&card->midi_info);
-#endif
-
- free_irq (card->pdev->irq, card);
- via_dsp_cleanup (card);
- via_ac97_cleanup (card);
-
-#ifndef VIA_NDEBUG
- memset (card, OSS_POISON_FREE, sizeof (*card)); /* poison memory */
-#endif
- kfree (card);
-
- pci_set_drvdata (pdev, NULL);
-
- pci_release_regions (pdev);
- pci_disable_device (pdev);
- pci_set_power_state (pdev, 3); /* ...zzzzzz */
-
- DPRINTK ("EXIT\n");
- return;
-}
-
-
-/****************************************************************
- *
- * Driver initialization and cleanup
- *
- *
- */
-
-static int __init init_via82cxxx_audio(void)
-{
- int rc;
-
- DPRINTK ("ENTER\n");
-
- rc = pci_register_driver (&via_driver);
- if (rc) {
- DPRINTK ("EXIT, returning %d\n", rc);
- return rc;
- }
-
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-}
-
-
-static void __exit cleanup_via82cxxx_audio(void)
-{
- DPRINTK ("ENTER\n");
-
- pci_unregister_driver (&via_driver);
-
- DPRINTK ("EXIT\n");
-}
-
-
-module_init(init_via82cxxx_audio);
-module_exit(cleanup_via82cxxx_audio);
-
-MODULE_AUTHOR("Jeff Garzik");
-MODULE_DESCRIPTION("DSP audio and mixer driver for Via 82Cxxx audio devices");
-MODULE_LICENSE("GPL");
-
diff --git a/sound/oss/vidc.c b/sound/oss/vidc.c
index bb4a0969f46..92ca5bee186 100644
--- a/sound/oss/vidc.c
+++ b/sound/oss/vidc.c
@@ -17,17 +17,17 @@
* We currently support a mixer device, but it is currently non-functional.
*/
+#include <linux/gfp.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
-#include <asm/hardware.h>
+#include <mach/hardware.h>
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/hardware/iomd.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include "sound_config.h"
#include "vidc.h"
@@ -226,7 +226,7 @@ static int vidc_audio_set_speed(int dev, int rate)
} else {
/*printk("VIDC: internal %d %d %d\n", rate, rate_int, hwrate);*/
hwctrl=0x00000003;
- /* Allow rougly 0.4% tolerance */
+ /* Allow roughly 0.4% tolerance */
if (diff_int > (rate/256))
rate=rate_int;
}
@@ -363,13 +363,13 @@ static void vidc_audio_trigger(int dev, int enable_bits)
struct audio_operations *adev = audio_devs[dev];
if (enable_bits & PCM_ENABLE_OUTPUT) {
- if (!(adev->flags & DMA_ACTIVE)) {
+ if (!(adev->dmap_out->flags & DMA_ACTIVE)) {
unsigned long flags;
local_irq_save(flags);
/* prevent recusion */
- adev->flags |= DMA_ACTIVE;
+ adev->dmap_out->flags |= DMA_ACTIVE;
dma_interrupt = vidc_audio_dma_interrupt;
vidc_sound_dma_irq(0, NULL);
@@ -490,9 +490,6 @@ static void __init attach_vidc(struct address_info *hw_config)
vidc_adev = adev;
vidc_mixer_set(SOUND_MIXER_VOLUME, (85 | 85 << 8));
-#if defined(CONFIG_SOUND_SOFTOSS) || defined(CONFIG_SOUND_SOFTOSS_MODULE)
- softoss_dev = adev;
-#endif
return;
irq_failed:
diff --git a/sound/oss/vidc_fill.S b/sound/oss/vidc_fill.S
index 01ccc074cc1..bed34921d17 100644
--- a/sound/oss/vidc_fill.S
+++ b/sound/oss/vidc_fill.S
@@ -11,7 +11,7 @@
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
-#include <asm/hardware.h>
+#include <mach/hardware.h>
#include <asm/hardware/iomd.h>
.text
diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c
deleted file mode 100644
index d25249a932b..00000000000
--- a/sound/oss/vwsnd.c
+++ /dev/null
@@ -1,3485 +0,0 @@
-/*
- * Sound driver for Silicon Graphics 320 and 540 Visual Workstations'
- * onboard audio. See notes in Documentation/sound/oss/vwsnd .
- *
- * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#undef VWSND_DEBUG /* define for debugging */
-
-/*
- * XXX to do -
- *
- * External sync.
- * Rename swbuf, hwbuf, u&i, hwptr&swptr to something rational.
- * Bug - if select() called before read(), pcm_setup() not called.
- * Bug - output doesn't stop soon enough if process killed.
- */
-
-/*
- * Things to test -
- *
- * Will readv/writev work? Write a test.
- *
- * insmod/rmmod 100 million times.
- *
- * Run I/O until int ptrs wrap around (roughly 6.2 hours @ DAT
- * rate).
- *
- * Concurrent threads banging on mixer simultaneously, both UP
- * and SMP kernels. Especially, watch for thread A changing
- * OUTSRC while thread B changes gain -- both write to the same
- * ad1843 register.
- *
- * What happens if a client opens /dev/audio then forks?
- * Do two procs have /dev/audio open? Test.
- *
- * Pump audio through the CD, MIC and line inputs and verify that
- * they mix/mute into the output.
- *
- * Apps:
- * amp
- * mpg123
- * x11amp
- * mxv
- * kmedia
- * esound
- * need more input apps
- *
- * Run tests while bombarding with signals. setitimer(2) will do it... */
-
-/*
- * This driver is organized in nine sections.
- * The nine sections are:
- *
- * debug stuff
- * low level lithium access
- * high level lithium access
- * AD1843 access
- * PCM I/O
- * audio driver
- * mixer driver
- * probe/attach/unload
- * initialization and loadable kernel module interface
- *
- * That is roughly the order of increasing abstraction, so forward
- * dependencies are minimal.
- */
-
-/*
- * Locking Notes
- *
- * INC_USE_COUNT and DEC_USE_COUNT keep track of the number of
- * open descriptors to this driver. They store it in vwsnd_use_count.
- * The global device list, vwsnd_dev_list, is immutable when the IN_USE
- * is true.
- *
- * devc->open_lock is a semaphore that is used to enforce the
- * single reader/single writer rule for /dev/audio. The rule is
- * that each device may have at most one reader and one writer.
- * Open will block until the previous client has closed the
- * device, unless O_NONBLOCK is specified.
- *
- * The semaphore devc->io_mutex serializes PCM I/O syscalls. This
- * is unnecessary in Linux 2.2, because the kernel lock
- * serializes read, write, and ioctl globally, but it's there,
- * ready for the brave, new post-kernel-lock world.
- *
- * Locking between interrupt and baselevel is handled by the
- * "lock" spinlock in vwsnd_port (one lock each for read and
- * write). Each half holds the lock just long enough to see what
- * area it owns and update its pointers. See pcm_output() and
- * pcm_input() for most of the gory stuff.
- *
- * devc->mix_mutex serializes all mixer ioctls. This is also
- * redundant because of the kernel lock.
- *
- * The lowest level lock is lith->lithium_lock. It is a
- * spinlock which is held during the two-register tango of
- * reading/writing an AD1843 register. See
- * li_{read,write}_ad1843_reg().
- */
-
-/*
- * Sample Format Notes
- *
- * Lithium's DMA engine has two formats: 16-bit 2's complement
- * and 8-bit unsigned . 16-bit transfers the data unmodified, 2
- * bytes per sample. 8-bit unsigned transfers 1 byte per sample
- * and XORs each byte with 0x80. Lithium can input or output
- * either mono or stereo in either format.
- *
- * The AD1843 has four formats: 16-bit 2's complement, 8-bit
- * unsigned, 8-bit mu-Law and 8-bit A-Law.
- *
- * This driver supports five formats: AFMT_S8, AFMT_U8,
- * AFMT_MU_LAW, AFMT_A_LAW, and AFMT_S16_LE.
- *
- * For AFMT_U8 output, we keep the AD1843 in 16-bit mode, and
- * rely on Lithium's XOR to translate between U8 and S8.
- *
- * For AFMT_S8, AFMT_MU_LAW and AFMT_A_LAW output, we have to XOR
- * the 0x80 bit in software to compensate for Lithium's XOR.
- * This happens in pcm_copy_{in,out}().
- *
- * Changes:
- * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
- * Added some __init/__exit
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/wait.h>
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
-
-#include <asm/mach-visws/cobalt.h>
-
-#include "sound_config.h"
-
-/*****************************************************************************/
-/* debug stuff */
-
-#ifdef VWSND_DEBUG
-
-static int shut_up = 1;
-
-/*
- * dbgassert - called when an assertion fails.
- */
-
-static void dbgassert(const char *fcn, int line, const char *expr)
-{
- if (in_interrupt())
- panic("ASSERTION FAILED IN INTERRUPT, %s:%s:%d %s\n",
- __FILE__, fcn, line, expr);
- else {
- int x;
- printk(KERN_ERR "ASSERTION FAILED, %s:%s:%d %s\n",
- __FILE__, fcn, line, expr);
- x = * (volatile int *) 0; /* force proc to exit */
- }
-}
-
-/*
- * Bunch of useful debug macros:
- *
- * ASSERT - print unless e nonzero (panic if in interrupt)
- * DBGDO - include arbitrary code if debugging
- * DBGX - debug print raw (w/o function name)
- * DBGP - debug print w/ function name
- * DBGE - debug print function entry
- * DBGC - debug print function call
- * DBGR - debug print function return
- * DBGXV - debug print raw when verbose
- * DBGPV - debug print when verbose
- * DBGEV - debug print function entry when verbose
- * DBGRV - debug print function return when verbose
- */
-
-#define ASSERT(e) ((e) ? (void) 0 : dbgassert(__FUNCTION__, __LINE__, #e))
-#define DBGDO(x) x
-#define DBGX(fmt, args...) (in_interrupt() ? 0 : printk(KERN_ERR fmt, ##args))
-#define DBGP(fmt, args...) (DBGX("%s: " fmt, __FUNCTION__ , ##args))
-#define DBGE(fmt, args...) (DBGX("%s" fmt, __FUNCTION__ , ##args))
-#define DBGC(rtn) (DBGP("calling %s\n", rtn))
-#define DBGR() (DBGP("returning\n"))
-#define DBGXV(fmt, args...) (shut_up ? 0 : DBGX(fmt, ##args))
-#define DBGPV(fmt, args...) (shut_up ? 0 : DBGP(fmt, ##args))
-#define DBGEV(fmt, args...) (shut_up ? 0 : DBGE(fmt, ##args))
-#define DBGCV(rtn) (shut_up ? 0 : DBGC(rtn))
-#define DBGRV() (shut_up ? 0 : DBGR())
-
-#else /* !VWSND_DEBUG */
-
-#define ASSERT(e) ((void) 0)
-#define DBGDO(x) /* don't */
-#define DBGX(fmt, args...) ((void) 0)
-#define DBGP(fmt, args...) ((void) 0)
-#define DBGE(fmt, args...) ((void) 0)
-#define DBGC(rtn) ((void) 0)
-#define DBGR() ((void) 0)
-#define DBGPV(fmt, args...) ((void) 0)
-#define DBGXV(fmt, args...) ((void) 0)
-#define DBGEV(fmt, args...) ((void) 0)
-#define DBGCV(rtn) ((void) 0)
-#define DBGRV() ((void) 0)
-
-#endif /* !VWSND_DEBUG */
-
-/*****************************************************************************/
-/* low level lithium access */
-
-/*
- * We need to talk to Lithium registers on three pages. Here are
- * the pages' offsets from the base address (0xFF001000).
- */
-
-enum {
- LI_PAGE0_OFFSET = 0x01000 - 0x1000, /* FF001000 */
- LI_PAGE1_OFFSET = 0x0F000 - 0x1000, /* FF00F000 */
- LI_PAGE2_OFFSET = 0x10000 - 0x1000, /* FF010000 */
-};
-
-/* low-level lithium data */
-
-typedef struct lithium {
- void * page0; /* virtual addresses */
- void * page1;
- void * page2;
- spinlock_t lock; /* protects codec and UST/MSC access */
-} lithium_t;
-
-/*
- * li_destroy destroys the lithium_t structure and vm mappings.
- */
-
-static void li_destroy(lithium_t *lith)
-{
- if (lith->page0) {
- iounmap(lith->page0);
- lith->page0 = NULL;
- }
- if (lith->page1) {
- iounmap(lith->page1);
- lith->page1 = NULL;
- }
- if (lith->page2) {
- iounmap(lith->page2);
- lith->page2 = NULL;
- }
-}
-
-/*
- * li_create initializes the lithium_t structure and sets up vm mappings
- * to access the registers.
- * Returns 0 on success, -errno on failure.
- */
-
-static int __init li_create(lithium_t *lith, unsigned long baseaddr)
-{
- spin_lock_init(&lith->lock);
- lith->page0 = ioremap_nocache(baseaddr + LI_PAGE0_OFFSET, PAGE_SIZE);
- lith->page1 = ioremap_nocache(baseaddr + LI_PAGE1_OFFSET, PAGE_SIZE);
- lith->page2 = ioremap_nocache(baseaddr + LI_PAGE2_OFFSET, PAGE_SIZE);
- if (!lith->page0 || !lith->page1 || !lith->page2) {
- li_destroy(lith);
- return -ENOMEM;
- }
- return 0;
-}
-
-/*
- * basic register accessors - read/write long/byte
- */
-
-static __inline__ unsigned long li_readl(lithium_t *lith, int off)
-{
- return * (volatile unsigned long *) (lith->page0 + off);
-}
-
-static __inline__ unsigned char li_readb(lithium_t *lith, int off)
-{
- return * (volatile unsigned char *) (lith->page0 + off);
-}
-
-static __inline__ void li_writel(lithium_t *lith, int off, unsigned long val)
-{
- * (volatile unsigned long *) (lith->page0 + off) = val;
-}
-
-static __inline__ void li_writeb(lithium_t *lith, int off, unsigned char val)
-{
- * (volatile unsigned char *) (lith->page0 + off) = val;
-}
-
-/*****************************************************************************/
-/* High Level Lithium Access */
-
-/*
- * Lithium DMA Notes
- *
- * Lithium has two dedicated DMA channels for audio. They are known
- * as comm1 and comm2 (communication areas 1 and 2). Comm1 is for
- * input, and comm2 is for output. Each is controlled by three
- * registers: BASE (base address), CFG (config) and CCTL
- * (config/control).
- *
- * Each DMA channel points to a physically contiguous ring buffer in
- * main memory of up to 8 Kbytes. (This driver always uses 8 Kb.)
- * There are three pointers into the ring buffer: read, write, and
- * trigger. The pointers are 8 bits each. Each pointer points to
- * 32-byte "chunks" of data. The DMA engine moves 32 bytes at a time,
- * so there is no finer-granularity control.
- *
- * In comm1, the hardware updates the write ptr, and software updates
- * the read ptr. In comm2, it's the opposite: hardware updates the
- * read ptr, and software updates the write ptr. I designate the
- * hardware-updated ptr as the hwptr, and the software-updated ptr as
- * the swptr.
- *
- * The trigger ptr and trigger mask are used to trigger interrupts.
- * From the Lithium spec, section 5.6.8, revision of 12/15/1998:
- *
- * Trigger Mask Value
- *
- * A three bit wide field that represents a power of two mask
- * that is used whenever the trigger pointer is compared to its
- * respective read or write pointer. A value of zero here
- * implies a mask of 0xFF and a value of seven implies a mask
- * 0x01. This value can be used to sub-divide the ring buffer
- * into pie sections so that interrupts monitor the progress of
- * hardware from section to section.
- *
- * My interpretation of that is, whenever the hw ptr is updated, it is
- * compared with the trigger ptr, and the result is masked by the
- * trigger mask. (Actually, by the complement of the trigger mask.)
- * If the result is zero, an interrupt is triggered. I.e., interrupt
- * if ((hwptr & ~mask) == (trptr & ~mask)). The mask is formed from
- * the trigger register value as mask = (1 << (8 - tmreg)) - 1.
- *
- * In yet different words, setting tmreg to 0 causes an interrupt after
- * every 256 DMA chunks (8192 bytes) or once per traversal of the
- * ring buffer. Setting it to 7 caues an interrupt every 2 DMA chunks
- * (64 bytes) or 128 times per traversal of the ring buffer.
- */
-
-/* Lithium register offsets and bit definitions */
-
-#define LI_HOST_CONTROLLER 0x000
-# define LI_HC_RESET 0x00008000
-# define LI_HC_LINK_ENABLE 0x00004000
-# define LI_HC_LINK_FAILURE 0x00000004
-# define LI_HC_LINK_CODEC 0x00000002
-# define LI_HC_LINK_READY 0x00000001
-
-#define LI_INTR_STATUS 0x010
-#define LI_INTR_MASK 0x014
-# define LI_INTR_LINK_ERR 0x00008000
-# define LI_INTR_COMM2_TRIG 0x00000008
-# define LI_INTR_COMM2_UNDERFLOW 0x00000004
-# define LI_INTR_COMM1_TRIG 0x00000002
-# define LI_INTR_COMM1_OVERFLOW 0x00000001
-
-#define LI_CODEC_COMMAND 0x018
-# define LI_CC_BUSY 0x00008000
-# define LI_CC_DIR 0x00000080
-# define LI_CC_DIR_RD LI_CC_DIR
-# define LI_CC_DIR_WR (!LI_CC_DIR)
-# define LI_CC_ADDR_MASK 0x0000007F
-
-#define LI_CODEC_DATA 0x01C
-
-#define LI_COMM1_BASE 0x100
-#define LI_COMM1_CTL 0x104
-# define LI_CCTL_RESET 0x80000000
-# define LI_CCTL_SIZE 0x70000000
-# define LI_CCTL_DMA_ENABLE 0x08000000
-# define LI_CCTL_TMASK 0x07000000 /* trigger mask */
-# define LI_CCTL_TPTR 0x00FF0000 /* trigger pointer */
-# define LI_CCTL_RPTR 0x0000FF00
-# define LI_CCTL_WPTR 0x000000FF
-#define LI_COMM1_CFG 0x108
-# define LI_CCFG_LOCK 0x00008000
-# define LI_CCFG_SLOT 0x00000070
-# define LI_CCFG_DIRECTION 0x00000008
-# define LI_CCFG_DIR_IN (!LI_CCFG_DIRECTION)
-# define LI_CCFG_DIR_OUT LI_CCFG_DIRECTION
-# define LI_CCFG_MODE 0x00000004
-# define LI_CCFG_MODE_MONO (!LI_CCFG_MODE)
-# define LI_CCFG_MODE_STEREO LI_CCFG_MODE
-# define LI_CCFG_FORMAT 0x00000003
-# define LI_CCFG_FMT_8BIT 0x00000000
-# define LI_CCFG_FMT_16BIT 0x00000001
-#define LI_COMM2_BASE 0x10C
-#define LI_COMM2_CTL 0x110
- /* bit definitions are the same as LI_COMM1_CTL */
-#define LI_COMM2_CFG 0x114
- /* bit definitions are the same as LI_COMM1_CFG */
-
-#define LI_UST_LOW 0x200 /* 64-bit Unadjusted System Time is */
-#define LI_UST_HIGH 0x204 /* microseconds since boot */
-
-#define LI_AUDIO1_UST 0x300 /* UST-MSC pairs */
-#define LI_AUDIO1_MSC 0x304 /* MSC (Media Stream Counter) */
-#define LI_AUDIO2_UST 0x308 /* counts samples actually */
-#define LI_AUDIO2_MSC 0x30C /* processed as of time UST */
-
-/*
- * Lithium's DMA engine operates on chunks of 32 bytes. We call that
- * a DMACHUNK.
- */
-
-#define DMACHUNK_SHIFT 5
-#define DMACHUNK_SIZE (1 << DMACHUNK_SHIFT)
-#define BYTES_TO_CHUNKS(bytes) ((bytes) >> DMACHUNK_SHIFT)
-#define CHUNKS_TO_BYTES(chunks) ((chunks) << DMACHUNK_SHIFT)
-
-/*
- * Two convenient macros to shift bitfields into/out of position.
- *
- * Observe that (mask & -mask) is (1 << low_set_bit_of(mask)).
- * As long as mask is constant, we trust the compiler will change the
- * multipy and divide into shifts.
- */
-
-#define SHIFT_FIELD(val, mask) (((val) * ((mask) & -(mask))) & (mask))
-#define UNSHIFT_FIELD(val, mask) (((val) & (mask)) / ((mask) & -(mask)))
-
-/*
- * dma_chan_desc is invariant information about a Lithium
- * DMA channel. There are two instances, li_comm1 and li_comm2.
- *
- * Note that the CCTL register fields are write ptr and read ptr, but what
- * we care about are which pointer is updated by software and which by
- * hardware.
- */
-
-typedef struct dma_chan_desc {
- int basereg;
- int cfgreg;
- int ctlreg;
- int hwptrreg;
- int swptrreg;
- int ustreg;
- int mscreg;
- unsigned long swptrmask;
- int ad1843_slot;
- int direction; /* LI_CCTL_DIR_IN/OUT */
-} dma_chan_desc_t;
-
-static const dma_chan_desc_t li_comm1 = {
- LI_COMM1_BASE, /* base register offset */
- LI_COMM1_CFG, /* config register offset */
- LI_COMM1_CTL, /* control register offset */
- LI_COMM1_CTL + 0, /* hw ptr reg offset (write ptr) */
- LI_COMM1_CTL + 1, /* sw ptr reg offset (read ptr) */
- LI_AUDIO1_UST, /* ust reg offset */
- LI_AUDIO1_MSC, /* msc reg offset */
- LI_CCTL_RPTR, /* sw ptr bitmask in ctlval */
- 2, /* ad1843 serial slot */
- LI_CCFG_DIR_IN /* direction */
-};
-
-static const dma_chan_desc_t li_comm2 = {
- LI_COMM2_BASE, /* base register offset */
- LI_COMM2_CFG, /* config register offset */
- LI_COMM2_CTL, /* control register offset */
- LI_COMM2_CTL + 1, /* hw ptr reg offset (read ptr) */
- LI_COMM2_CTL + 0, /* sw ptr reg offset (writr ptr) */
- LI_AUDIO2_UST, /* ust reg offset */
- LI_AUDIO2_MSC, /* msc reg offset */
- LI_CCTL_WPTR, /* sw ptr bitmask in ctlval */
- 2, /* ad1843 serial slot */
- LI_CCFG_DIR_OUT /* direction */
-};
-
-/*
- * dma_chan is variable information about a Lithium DMA channel.
- *
- * The desc field points to invariant information.
- * The lith field points to a lithium_t which is passed
- * to li_read* and li_write* to access the registers.
- * The *val fields shadow the lithium registers' contents.
- */
-
-typedef struct dma_chan {
- const dma_chan_desc_t *desc;
- lithium_t *lith;
- unsigned long baseval;
- unsigned long cfgval;
- unsigned long ctlval;
-} dma_chan_t;
-
-/*
- * ustmsc is a UST/MSC pair (Unadjusted System Time/Media Stream Counter).
- * UST is time in microseconds since the system booted, and MSC is a
- * counter that increments with every audio sample.
- */
-
-typedef struct ustmsc {
- unsigned long long ust;
- unsigned long msc;
-} ustmsc_t;
-
-/*
- * li_ad1843_wait waits until lithium says the AD1843 register
- * exchange is not busy. Returns 0 on success, -EBUSY on timeout.
- *
- * Locking: must be called with lithium_lock held.
- */
-
-static int li_ad1843_wait(lithium_t *lith)
-{
- unsigned long later = jiffies + 2;
- while (li_readl(lith, LI_CODEC_COMMAND) & LI_CC_BUSY)
- if (time_after_eq(jiffies, later))
- return -EBUSY;
- return 0;
-}
-
-/*
- * li_read_ad1843_reg returns the current contents of a 16 bit AD1843 register.
- *
- * Returns unsigned register value on success, -errno on failure.
- */
-
-static int li_read_ad1843_reg(lithium_t *lith, int reg)
-{
- int val;
-
- ASSERT(!in_interrupt());
- spin_lock(&lith->lock);
- {
- val = li_ad1843_wait(lith);
- if (val == 0) {
- li_writel(lith, LI_CODEC_COMMAND, LI_CC_DIR_RD | reg);
- val = li_ad1843_wait(lith);
- }
- if (val == 0)
- val = li_readl(lith, LI_CODEC_DATA);
- }
- spin_unlock(&lith->lock);
-
- DBGXV("li_read_ad1843_reg(lith=0x%p, reg=%d) returns 0x%04x\n",
- lith, reg, val);
-
- return val;
-}
-
-/*
- * li_write_ad1843_reg writes the specified value to a 16 bit AD1843 register.
- */
-
-static void li_write_ad1843_reg(lithium_t *lith, int reg, int newval)
-{
- spin_lock(&lith->lock);
- {
- if (li_ad1843_wait(lith) == 0) {
- li_writel(lith, LI_CODEC_DATA, newval);
- li_writel(lith, LI_CODEC_COMMAND, LI_CC_DIR_WR | reg);
- }
- }
- spin_unlock(&lith->lock);
-}
-
-/*
- * li_setup_dma calculates all the register settings for DMA in a particular
- * mode. It takes too many arguments.
- */
-
-static void li_setup_dma(dma_chan_t *chan,
- const dma_chan_desc_t *desc,
- lithium_t *lith,
- unsigned long buffer_paddr,
- int bufshift,
- int fragshift,
- int channels,
- int sampsize)
-{
- unsigned long mode, format;
- unsigned long size, tmask;
-
- DBGEV("(chan=0x%p, desc=0x%p, lith=0x%p, buffer_paddr=0x%lx, "
- "bufshift=%d, fragshift=%d, channels=%d, sampsize=%d)\n",
- chan, desc, lith, buffer_paddr,
- bufshift, fragshift, channels, sampsize);
-
- /* Reset the channel first. */
-
- li_writel(lith, desc->ctlreg, LI_CCTL_RESET);
-
- ASSERT(channels == 1 || channels == 2);
- if (channels == 2)
- mode = LI_CCFG_MODE_STEREO;
- else
- mode = LI_CCFG_MODE_MONO;
- ASSERT(sampsize == 1 || sampsize == 2);
- if (sampsize == 2)
- format = LI_CCFG_FMT_16BIT;
- else
- format = LI_CCFG_FMT_8BIT;
- chan->desc = desc;
- chan->lith = lith;
-
- /*
- * Lithium DMA address register takes a 40-bit physical
- * address, right-shifted by 8 so it fits in 32 bits. Bit 37
- * must be set -- it enables cache coherence.
- */
-
- ASSERT(!(buffer_paddr & 0xFF));
- chan->baseval = (buffer_paddr >> 8) | 1 << (37 - 8);
-
- chan->cfgval = (!LI_CCFG_LOCK |
- SHIFT_FIELD(desc->ad1843_slot, LI_CCFG_SLOT) |
- desc->direction |
- mode |
- format);
-
- size = bufshift - 6;
- tmask = 13 - fragshift; /* See Lithium DMA Notes above. */
- ASSERT(size >= 2 && size <= 7);
- ASSERT(tmask >= 1 && tmask <= 7);
- chan->ctlval = (!LI_CCTL_RESET |
- SHIFT_FIELD(size, LI_CCTL_SIZE) |
- !LI_CCTL_DMA_ENABLE |
- SHIFT_FIELD(tmask, LI_CCTL_TMASK) |
- SHIFT_FIELD(0, LI_CCTL_TPTR));
-
- DBGPV("basereg 0x%x = 0x%lx\n", desc->basereg, chan->baseval);
- DBGPV("cfgreg 0x%x = 0x%lx\n", desc->cfgreg, chan->cfgval);
- DBGPV("ctlreg 0x%x = 0x%lx\n", desc->ctlreg, chan->ctlval);
-
- li_writel(lith, desc->basereg, chan->baseval);
- li_writel(lith, desc->cfgreg, chan->cfgval);
- li_writel(lith, desc->ctlreg, chan->ctlval);
-
- DBGRV();
-}
-
-static void li_shutdown_dma(dma_chan_t *chan)
-{
- lithium_t *lith = chan->lith;
- void * lith1 = lith->page1;
-
- DBGEV("(chan=0x%p)\n", chan);
-
- chan->ctlval &= ~LI_CCTL_DMA_ENABLE;
- DBGPV("ctlreg 0x%x = 0x%lx\n", chan->desc->ctlreg, chan->ctlval);
- li_writel(lith, chan->desc->ctlreg, chan->ctlval);
-
- /*
- * Offset 0x500 on Lithium page 1 is an undocumented,
- * unsupported register that holds the zero sample value.
- * Lithium is supposed to output zero samples when DMA is
- * inactive, and repeat the last sample when DMA underflows.
- * But it has a bug, where, after underflow occurs, the zero
- * sample is not reset.
- *
- * I expect this to break in a future rev of Lithium.
- */
-
- if (lith1 && chan->desc->direction == LI_CCFG_DIR_OUT)
- * (volatile unsigned long *) (lith1 + 0x500) = 0;
-}
-
-/*
- * li_activate_dma always starts dma at the beginning of the buffer.
- *
- * N.B., these may be called from interrupt.
- */
-
-static __inline__ void li_activate_dma(dma_chan_t *chan)
-{
- chan->ctlval |= LI_CCTL_DMA_ENABLE;
- DBGPV("ctlval = 0x%lx\n", chan->ctlval);
- li_writel(chan->lith, chan->desc->ctlreg, chan->ctlval);
-}
-
-static void li_deactivate_dma(dma_chan_t *chan)
-{
- lithium_t *lith = chan->lith;
- void * lith2 = lith->page2;
-
- chan->ctlval &= ~(LI_CCTL_DMA_ENABLE | LI_CCTL_RPTR | LI_CCTL_WPTR);
- DBGPV("ctlval = 0x%lx\n", chan->ctlval);
- DBGPV("ctlreg 0x%x = 0x%lx\n", chan->desc->ctlreg, chan->ctlval);
- li_writel(lith, chan->desc->ctlreg, chan->ctlval);
-
- /*
- * Offsets 0x98 and 0x9C on Lithium page 2 are undocumented,
- * unsupported registers that are internal copies of the DMA
- * read and write pointers. Because of a Lithium bug, these
- * registers aren't zeroed correctly when DMA is shut off. So
- * we whack them directly.
- *
- * I expect this to break in a future rev of Lithium.
- */
-
- if (lith2 && chan->desc->direction == LI_CCFG_DIR_OUT) {
- * (volatile unsigned long *) (lith2 + 0x98) = 0;
- * (volatile unsigned long *) (lith2 + 0x9C) = 0;
- }
-}
-
-/*
- * read/write the ring buffer pointers. These routines' arguments and results
- * are byte offsets from the beginning of the ring buffer.
- */
-
-static __inline__ int li_read_swptr(dma_chan_t *chan)
-{
- const unsigned long mask = chan->desc->swptrmask;
-
- return CHUNKS_TO_BYTES(UNSHIFT_FIELD(chan->ctlval, mask));
-}
-
-static __inline__ int li_read_hwptr(dma_chan_t *chan)
-{
- return CHUNKS_TO_BYTES(li_readb(chan->lith, chan->desc->hwptrreg));
-}
-
-static __inline__ void li_write_swptr(dma_chan_t *chan, int val)
-{
- const unsigned long mask = chan->desc->swptrmask;
-
- ASSERT(!(val & ~CHUNKS_TO_BYTES(0xFF)));
- val = BYTES_TO_CHUNKS(val);
- chan->ctlval = (chan->ctlval & ~mask) | SHIFT_FIELD(val, mask);
- li_writeb(chan->lith, chan->desc->swptrreg, val);
-}
-
-/* li_read_USTMSC() returns a UST/MSC pair for the given channel. */
-
-static void li_read_USTMSC(dma_chan_t *chan, ustmsc_t *ustmsc)
-{
- lithium_t *lith = chan->lith;
- const dma_chan_desc_t *desc = chan->desc;
- unsigned long now_low, now_high0, now_high1, chan_ust;
-
- spin_lock(&lith->lock);
- {
- /*
- * retry until we do all five reads without the
- * high word changing. (High word increments
- * every 2^32 microseconds, i.e., not often)
- */
- do {
- now_high0 = li_readl(lith, LI_UST_HIGH);
- now_low = li_readl(lith, LI_UST_LOW);
-
- /*
- * Lithium guarantees these two reads will be
- * atomic -- ust will not increment after msc
- * is read.
- */
-
- ustmsc->msc = li_readl(lith, desc->mscreg);
- chan_ust = li_readl(lith, desc->ustreg);
-
- now_high1 = li_readl(lith, LI_UST_HIGH);
- } while (now_high0 != now_high1);
- }
- spin_unlock(&lith->lock);
- ustmsc->ust = ((unsigned long long) now_high0 << 32 | chan_ust);
-}
-
-static void li_enable_interrupts(lithium_t *lith, unsigned int mask)
-{
- DBGEV("(lith=0x%p, mask=0x%x)\n", lith, mask);
-
- /* clear any already-pending interrupts. */
-
- li_writel(lith, LI_INTR_STATUS, mask);
-
- /* enable the interrupts. */
-
- mask |= li_readl(lith, LI_INTR_MASK);
- li_writel(lith, LI_INTR_MASK, mask);
-}
-
-static void li_disable_interrupts(lithium_t *lith, unsigned int mask)
-{
- unsigned int keepmask;
-
- DBGEV("(lith=0x%p, mask=0x%x)\n", lith, mask);
-
- /* disable the interrupts */
-
- keepmask = li_readl(lith, LI_INTR_MASK) & ~mask;
- li_writel(lith, LI_INTR_MASK, keepmask);
-
- /* clear any pending interrupts. */
-
- li_writel(lith, LI_INTR_STATUS, mask);
-}
-
-/* Get the interrupt status and clear all pending interrupts. */
-
-static unsigned int li_get_clear_intr_status(lithium_t *lith)
-{
- unsigned int status;
-
- status = li_readl(lith, LI_INTR_STATUS);
- li_writel(lith, LI_INTR_STATUS, ~0);
- return status & li_readl(lith, LI_INTR_MASK);
-}
-
-static int li_init(lithium_t *lith)
-{
- /* 1. System power supplies stabilize. */
-
- /* 2. Assert the ~RESET signal. */
-
- li_writel(lith, LI_HOST_CONTROLLER, LI_HC_RESET);
- udelay(1);
-
- /* 3. Deassert the ~RESET signal and enter a wait period to allow
- the AD1843 internal clocks and the external crystal oscillator
- to stabilize. */
-
- li_writel(lith, LI_HOST_CONTROLLER, LI_HC_LINK_ENABLE);
- udelay(1);
-
- return 0;
-}
-
-/*****************************************************************************/
-/* AD1843 access */
-
-/*
- * AD1843 bitfield definitions. All are named as in the AD1843 data
- * sheet, with ad1843_ prepended and individual bit numbers removed.
- *
- * E.g., bits LSS0 through LSS2 become ad1843_LSS.
- *
- * Only the bitfields we need are defined.
- */
-
-typedef struct ad1843_bitfield {
- char reg;
- char lo_bit;
- char nbits;
-} ad1843_bitfield_t;
-
-static const ad1843_bitfield_t
- ad1843_PDNO = { 0, 14, 1 }, /* Converter Power-Down Flag */
- ad1843_INIT = { 0, 15, 1 }, /* Clock Initialization Flag */
- ad1843_RIG = { 2, 0, 4 }, /* Right ADC Input Gain */
- ad1843_RMGE = { 2, 4, 1 }, /* Right ADC Mic Gain Enable */
- ad1843_RSS = { 2, 5, 3 }, /* Right ADC Source Select */
- ad1843_LIG = { 2, 8, 4 }, /* Left ADC Input Gain */
- ad1843_LMGE = { 2, 12, 1 }, /* Left ADC Mic Gain Enable */
- ad1843_LSS = { 2, 13, 3 }, /* Left ADC Source Select */
- ad1843_RX1M = { 4, 0, 5 }, /* Right Aux 1 Mix Gain/Atten */
- ad1843_RX1MM = { 4, 7, 1 }, /* Right Aux 1 Mix Mute */
- ad1843_LX1M = { 4, 8, 5 }, /* Left Aux 1 Mix Gain/Atten */
- ad1843_LX1MM = { 4, 15, 1 }, /* Left Aux 1 Mix Mute */
- ad1843_RX2M = { 5, 0, 5 }, /* Right Aux 2 Mix Gain/Atten */
- ad1843_RX2MM = { 5, 7, 1 }, /* Right Aux 2 Mix Mute */
- ad1843_LX2M = { 5, 8, 5 }, /* Left Aux 2 Mix Gain/Atten */
- ad1843_LX2MM = { 5, 15, 1 }, /* Left Aux 2 Mix Mute */
- ad1843_RMCM = { 7, 0, 5 }, /* Right Mic Mix Gain/Atten */
- ad1843_RMCMM = { 7, 7, 1 }, /* Right Mic Mix Mute */
- ad1843_LMCM = { 7, 8, 5 }, /* Left Mic Mix Gain/Atten */
- ad1843_LMCMM = { 7, 15, 1 }, /* Left Mic Mix Mute */
- ad1843_HPOS = { 8, 4, 1 }, /* Headphone Output Voltage Swing */
- ad1843_HPOM = { 8, 5, 1 }, /* Headphone Output Mute */
- ad1843_RDA1G = { 9, 0, 6 }, /* Right DAC1 Analog/Digital Gain */
- ad1843_RDA1GM = { 9, 7, 1 }, /* Right DAC1 Analog Mute */
- ad1843_LDA1G = { 9, 8, 6 }, /* Left DAC1 Analog/Digital Gain */
- ad1843_LDA1GM = { 9, 15, 1 }, /* Left DAC1 Analog Mute */
- ad1843_RDA1AM = { 11, 7, 1 }, /* Right DAC1 Digital Mute */
- ad1843_LDA1AM = { 11, 15, 1 }, /* Left DAC1 Digital Mute */
- ad1843_ADLC = { 15, 0, 2 }, /* ADC Left Sample Rate Source */
- ad1843_ADRC = { 15, 2, 2 }, /* ADC Right Sample Rate Source */
- ad1843_DA1C = { 15, 8, 2 }, /* DAC1 Sample Rate Source */
- ad1843_C1C = { 17, 0, 16 }, /* Clock 1 Sample Rate Select */
- ad1843_C2C = { 20, 0, 16 }, /* Clock 1 Sample Rate Select */
- ad1843_DAADL = { 25, 4, 2 }, /* Digital ADC Left Source Select */
- ad1843_DAADR = { 25, 6, 2 }, /* Digital ADC Right Source Select */
- ad1843_DRSFLT = { 25, 15, 1 }, /* Digital Reampler Filter Mode */
- ad1843_ADLF = { 26, 0, 2 }, /* ADC Left Channel Data Format */
- ad1843_ADRF = { 26, 2, 2 }, /* ADC Right Channel Data Format */
- ad1843_ADTLK = { 26, 4, 1 }, /* ADC Transmit Lock Mode Select */
- ad1843_SCF = { 26, 7, 1 }, /* SCLK Frequency Select */
- ad1843_DA1F = { 26, 8, 2 }, /* DAC1 Data Format Select */
- ad1843_DA1SM = { 26, 14, 1 }, /* DAC1 Stereo/Mono Mode Select */
- ad1843_ADLEN = { 27, 0, 1 }, /* ADC Left Channel Enable */
- ad1843_ADREN = { 27, 1, 1 }, /* ADC Right Channel Enable */
- ad1843_AAMEN = { 27, 4, 1 }, /* Analog to Analog Mix Enable */
- ad1843_ANAEN = { 27, 7, 1 }, /* Analog Channel Enable */
- ad1843_DA1EN = { 27, 8, 1 }, /* DAC1 Enable */
- ad1843_DA2EN = { 27, 9, 1 }, /* DAC2 Enable */
- ad1843_C1EN = { 28, 11, 1 }, /* Clock Generator 1 Enable */
- ad1843_C2EN = { 28, 12, 1 }, /* Clock Generator 2 Enable */
- ad1843_PDNI = { 28, 15, 1 }; /* Converter Power Down */
-
-/*
- * The various registers of the AD1843 use three different formats for
- * specifying gain. The ad1843_gain structure parameterizes the
- * formats.
- */
-
-typedef struct ad1843_gain {
-
- int negative; /* nonzero if gain is negative. */
- const ad1843_bitfield_t *lfield;
- const ad1843_bitfield_t *rfield;
-
-} ad1843_gain_t;
-
-static const ad1843_gain_t ad1843_gain_RECLEV
- = { 0, &ad1843_LIG, &ad1843_RIG };
-static const ad1843_gain_t ad1843_gain_LINE
- = { 1, &ad1843_LX1M, &ad1843_RX1M };
-static const ad1843_gain_t ad1843_gain_CD
- = { 1, &ad1843_LX2M, &ad1843_RX2M };
-static const ad1843_gain_t ad1843_gain_MIC
- = { 1, &ad1843_LMCM, &ad1843_RMCM };
-static const ad1843_gain_t ad1843_gain_PCM
- = { 1, &ad1843_LDA1G, &ad1843_RDA1G };
-
-/* read the current value of an AD1843 bitfield. */
-
-static int ad1843_read_bits(lithium_t *lith, const ad1843_bitfield_t *field)
-{
- int w = li_read_ad1843_reg(lith, field->reg);
- int val = w >> field->lo_bit & ((1 << field->nbits) - 1);
-
- DBGXV("ad1843_read_bits(lith=0x%p, field->{%d %d %d}) returns 0x%x\n",
- lith, field->reg, field->lo_bit, field->nbits, val);
-
- return val;
-}
-
-/*
- * write a new value to an AD1843 bitfield and return the old value.
- */
-
-static int ad1843_write_bits(lithium_t *lith,
- const ad1843_bitfield_t *field,
- int newval)
-{
- int w = li_read_ad1843_reg(lith, field->reg);
- int mask = ((1 << field->nbits) - 1) << field->lo_bit;
- int oldval = (w & mask) >> field->lo_bit;
- int newbits = (newval << field->lo_bit) & mask;
- w = (w & ~mask) | newbits;
- (void) li_write_ad1843_reg(lith, field->reg, w);
-
- DBGXV("ad1843_write_bits(lith=0x%p, field->{%d %d %d}, val=0x%x) "
- "returns 0x%x\n",
- lith, field->reg, field->lo_bit, field->nbits, newval,
- oldval);
-
- return oldval;
-}
-
-/*
- * ad1843_read_multi reads multiple bitfields from the same AD1843
- * register. It uses a single read cycle to do it. (Reading the
- * ad1843 requires 256 bit times at 12.288 MHz, or nearly 20
- * microseconds.)
- *
- * Called ike this.
- *
- * ad1843_read_multi(lith, nfields,
- * &ad1843_FIELD1, &val1,
- * &ad1843_FIELD2, &val2, ...);
- */
-
-static void ad1843_read_multi(lithium_t *lith, int argcount, ...)
-{
- va_list ap;
- const ad1843_bitfield_t *fp;
- int w = 0, mask, *value, reg = -1;
-
- va_start(ap, argcount);
- while (--argcount >= 0) {
- fp = va_arg(ap, const ad1843_bitfield_t *);
- value = va_arg(ap, int *);
- if (reg == -1) {
- reg = fp->reg;
- w = li_read_ad1843_reg(lith, reg);
- }
- ASSERT(reg == fp->reg);
- mask = (1 << fp->nbits) - 1;
- *value = w >> fp->lo_bit & mask;
- }
- va_end(ap);
-}
-
-/*
- * ad1843_write_multi stores multiple bitfields into the same AD1843
- * register. It uses one read and one write cycle to do it.
- *
- * Called like this.
- *
- * ad1843_write_multi(lith, nfields,
- * &ad1843_FIELD1, val1,
- * &ad1843_FIELF2, val2, ...);
- */
-
-static void ad1843_write_multi(lithium_t *lith, int argcount, ...)
-{
- va_list ap;
- int reg;
- const ad1843_bitfield_t *fp;
- int value;
- int w, m, mask, bits;
-
- mask = 0;
- bits = 0;
- reg = -1;
-
- va_start(ap, argcount);
- while (--argcount >= 0) {
- fp = va_arg(ap, const ad1843_bitfield_t *);
- value = va_arg(ap, int);
- if (reg == -1)
- reg = fp->reg;
- ASSERT(fp->reg == reg);
- m = ((1 << fp->nbits) - 1) << fp->lo_bit;
- mask |= m;
- bits |= (value << fp->lo_bit) & m;
- }
- va_end(ap);
- ASSERT(!(bits & ~mask));
- if (~mask & 0xFFFF)
- w = li_read_ad1843_reg(lith, reg);
- else
- w = 0;
- w = (w & ~mask) | bits;
- (void) li_write_ad1843_reg(lith, reg, w);
-}
-
-/*
- * ad1843_get_gain reads the specified register and extracts the gain value
- * using the supplied gain type. It returns the gain in OSS format.
- */
-
-static int ad1843_get_gain(lithium_t *lith, const ad1843_gain_t *gp)
-{
- int lg, rg;
- unsigned short mask = (1 << gp->lfield->nbits) - 1;
-
- ad1843_read_multi(lith, 2, gp->lfield, &lg, gp->rfield, &rg);
- if (gp->negative) {
- lg = mask - lg;
- rg = mask - rg;
- }
- lg = (lg * 100 + (mask >> 1)) / mask;
- rg = (rg * 100 + (mask >> 1)) / mask;
- return lg << 0 | rg << 8;
-}
-
-/*
- * Set an audio channel's gain. Converts from OSS format to AD1843's
- * format.
- *
- * Returns the new gain, which may be lower than the old gain.
- */
-
-static int ad1843_set_gain(lithium_t *lith,
- const ad1843_gain_t *gp,
- int newval)
-{
- unsigned short mask = (1 << gp->lfield->nbits) - 1;
-
- int lg = newval >> 0 & 0xFF;
- int rg = newval >> 8;
- if (lg < 0 || lg > 100 || rg < 0 || rg > 100)
- return -EINVAL;
- lg = (lg * mask + (mask >> 1)) / 100;
- rg = (rg * mask + (mask >> 1)) / 100;
- if (gp->negative) {
- lg = mask - lg;
- rg = mask - rg;
- }
- ad1843_write_multi(lith, 2, gp->lfield, lg, gp->rfield, rg);
- return ad1843_get_gain(lith, gp);
-}
-
-/* Returns the current recording source, in OSS format. */
-
-static int ad1843_get_recsrc(lithium_t *lith)
-{
- int ls = ad1843_read_bits(lith, &ad1843_LSS);
-
- switch (ls) {
- case 1:
- return SOUND_MASK_MIC;
- case 2:
- return SOUND_MASK_LINE;
- case 3:
- return SOUND_MASK_CD;
- case 6:
- return SOUND_MASK_PCM;
- default:
- ASSERT(0);
- return -1;
- }
-}
-
-/*
- * Enable/disable digital resample mode in the AD1843.
- *
- * The AD1843 requires that ADL, ADR, DA1 and DA2 be powered down
- * while switching modes. So we save DA1's state (DA2's state is not
- * interesting), power them down, switch into/out of resample mode,
- * power them up, and restore state.
- *
- * This will cause audible glitches if D/A or A/D is going on, so the
- * driver disallows that (in mixer_write_ioctl()).
- *
- * The open question is, is this worth doing? I'm leaving it in,
- * because it's written, but...
- */
-
-static void ad1843_set_resample_mode(lithium_t *lith, int onoff)
-{
- /* Save DA1 mute and gain (addr 9 is DA1 analog gain/attenuation) */
- int save_da1 = li_read_ad1843_reg(lith, 9);
-
- /* Power down A/D and D/A. */
- ad1843_write_multi(lith, 4,
- &ad1843_DA1EN, 0,
- &ad1843_DA2EN, 0,
- &ad1843_ADLEN, 0,
- &ad1843_ADREN, 0);
-
- /* Switch mode */
- ASSERT(onoff == 0 || onoff == 1);
- ad1843_write_bits(lith, &ad1843_DRSFLT, onoff);
-
- /* Power up A/D and D/A. */
- ad1843_write_multi(lith, 3,
- &ad1843_DA1EN, 1,
- &ad1843_ADLEN, 1,
- &ad1843_ADREN, 1);
-
- /* Restore DA1 mute and gain. */
- li_write_ad1843_reg(lith, 9, save_da1);
-}
-
-/*
- * Set recording source. Arg newsrc specifies an OSS channel mask.
- *
- * The complication is that when we switch into/out of loopback mode
- * (i.e., src = SOUND_MASK_PCM), we change the AD1843 into/out of
- * digital resampling mode.
- *
- * Returns newsrc on success, -errno on failure.
- */
-
-static int ad1843_set_recsrc(lithium_t *lith, int newsrc)
-{
- int bits;
- int oldbits;
-
- switch (newsrc) {
- case SOUND_MASK_PCM:
- bits = 6;
- break;
-
- case SOUND_MASK_MIC:
- bits = 1;
- break;
-
- case SOUND_MASK_LINE:
- bits = 2;
- break;
-
- case SOUND_MASK_CD:
- bits = 3;
- break;
-
- default:
- return -EINVAL;
- }
- oldbits = ad1843_read_bits(lith, &ad1843_LSS);
- if (newsrc == SOUND_MASK_PCM && oldbits != 6) {
- DBGP("enabling digital resample mode\n");
- ad1843_set_resample_mode(lith, 1);
- ad1843_write_multi(lith, 2,
- &ad1843_DAADL, 2,
- &ad1843_DAADR, 2);
- } else if (newsrc != SOUND_MASK_PCM && oldbits == 6) {
- DBGP("disabling digital resample mode\n");
- ad1843_set_resample_mode(lith, 0);
- ad1843_write_multi(lith, 2,
- &ad1843_DAADL, 0,
- &ad1843_DAADR, 0);
- }
- ad1843_write_multi(lith, 2, &ad1843_LSS, bits, &ad1843_RSS, bits);
- return newsrc;
-}
-
-/*
- * Return current output sources, in OSS format.
- */
-
-static int ad1843_get_outsrc(lithium_t *lith)
-{
- int pcm, line, mic, cd;
-
- pcm = ad1843_read_bits(lith, &ad1843_LDA1GM) ? 0 : SOUND_MASK_PCM;
- line = ad1843_read_bits(lith, &ad1843_LX1MM) ? 0 : SOUND_MASK_LINE;
- cd = ad1843_read_bits(lith, &ad1843_LX2MM) ? 0 : SOUND_MASK_CD;
- mic = ad1843_read_bits(lith, &ad1843_LMCMM) ? 0 : SOUND_MASK_MIC;
-
- return pcm | line | cd | mic;
-}
-
-/*
- * Set output sources. Arg is a mask of active sources in OSS format.
- *
- * Returns source mask on success, -errno on failure.
- */
-
-static int ad1843_set_outsrc(lithium_t *lith, int mask)
-{
- int pcm, line, mic, cd;
-
- if (mask & ~(SOUND_MASK_PCM | SOUND_MASK_LINE |
- SOUND_MASK_CD | SOUND_MASK_MIC))
- return -EINVAL;
- pcm = (mask & SOUND_MASK_PCM) ? 0 : 1;
- line = (mask & SOUND_MASK_LINE) ? 0 : 1;
- mic = (mask & SOUND_MASK_MIC) ? 0 : 1;
- cd = (mask & SOUND_MASK_CD) ? 0 : 1;
-
- ad1843_write_multi(lith, 2, &ad1843_LDA1GM, pcm, &ad1843_RDA1GM, pcm);
- ad1843_write_multi(lith, 2, &ad1843_LX1MM, line, &ad1843_RX1MM, line);
- ad1843_write_multi(lith, 2, &ad1843_LX2MM, cd, &ad1843_RX2MM, cd);
- ad1843_write_multi(lith, 2, &ad1843_LMCMM, mic, &ad1843_RMCMM, mic);
-
- return mask;
-}
-
-/* Setup ad1843 for D/A conversion. */
-
-static void ad1843_setup_dac(lithium_t *lith,
- int framerate,
- int fmt,
- int channels)
-{
- int ad_fmt = 0, ad_mode = 0;
-
- DBGEV("(lith=0x%p, framerate=%d, fmt=%d, channels=%d)\n",
- lith, framerate, fmt, channels);
-
- switch (fmt) {
- case AFMT_S8: ad_fmt = 1; break;
- case AFMT_U8: ad_fmt = 1; break;
- case AFMT_S16_LE: ad_fmt = 1; break;
- case AFMT_MU_LAW: ad_fmt = 2; break;
- case AFMT_A_LAW: ad_fmt = 3; break;
- default: ASSERT(0);
- }
-
- switch (channels) {
- case 2: ad_mode = 0; break;
- case 1: ad_mode = 1; break;
- default: ASSERT(0);
- }
-
- DBGPV("ad_mode = %d, ad_fmt = %d\n", ad_mode, ad_fmt);
- ASSERT(framerate >= 4000 && framerate <= 49000);
- ad1843_write_bits(lith, &ad1843_C1C, framerate);
- ad1843_write_multi(lith, 2,
- &ad1843_DA1SM, ad_mode, &ad1843_DA1F, ad_fmt);
-}
-
-static void ad1843_shutdown_dac(lithium_t *lith)
-{
- ad1843_write_bits(lith, &ad1843_DA1F, 1);
-}
-
-static void ad1843_setup_adc(lithium_t *lith, int framerate, int fmt, int channels)
-{
- int da_fmt = 0;
-
- DBGEV("(lith=0x%p, framerate=%d, fmt=%d, channels=%d)\n",
- lith, framerate, fmt, channels);
-
- switch (fmt) {
- case AFMT_S8: da_fmt = 1; break;
- case AFMT_U8: da_fmt = 1; break;
- case AFMT_S16_LE: da_fmt = 1; break;
- case AFMT_MU_LAW: da_fmt = 2; break;
- case AFMT_A_LAW: da_fmt = 3; break;
- default: ASSERT(0);
- }
-
- DBGPV("da_fmt = %d\n", da_fmt);
- ASSERT(framerate >= 4000 && framerate <= 49000);
- ad1843_write_bits(lith, &ad1843_C2C, framerate);
- ad1843_write_multi(lith, 2,
- &ad1843_ADLF, da_fmt, &ad1843_ADRF, da_fmt);
-}
-
-static void ad1843_shutdown_adc(lithium_t *lith)
-{
- /* nothing to do */
-}
-
-/*
- * Fully initialize the ad1843. As described in the AD1843 data
- * sheet, section "START-UP SEQUENCE". The numbered comments are
- * subsection headings from the data sheet. See the data sheet, pages
- * 52-54, for more info.
- *
- * return 0 on success, -errno on failure. */
-
-static int __init ad1843_init(lithium_t *lith)
-{
- unsigned long later;
- int err;
-
- err = li_init(lith);
- if (err)
- return err;
-
- if (ad1843_read_bits(lith, &ad1843_INIT) != 0) {
- printk(KERN_ERR "vwsnd sound: AD1843 won't initialize\n");
- return -EIO;
- }
-
- ad1843_write_bits(lith, &ad1843_SCF, 1);
-
- /* 4. Put the conversion resources into standby. */
-
- ad1843_write_bits(lith, &ad1843_PDNI, 0);
- later = jiffies + HZ / 2; /* roughly half a second */
- DBGDO(shut_up++);
- while (ad1843_read_bits(lith, &ad1843_PDNO)) {
- if (time_after(jiffies, later)) {
- printk(KERN_ERR
- "vwsnd audio: AD1843 won't power up\n");
- return -EIO;
- }
- schedule();
- }
- DBGDO(shut_up--);
-
- /* 5. Power up the clock generators and enable clock output pins. */
-
- ad1843_write_multi(lith, 2, &ad1843_C1EN, 1, &ad1843_C2EN, 1);
-
- /* 6. Configure conversion resources while they are in standby. */
-
- /* DAC1 uses clock 1 as source, ADC uses clock 2. Always. */
-
- ad1843_write_multi(lith, 3,
- &ad1843_DA1C, 1,
- &ad1843_ADLC, 2,
- &ad1843_ADRC, 2);
-
- /* 7. Enable conversion resources. */
-
- ad1843_write_bits(lith, &ad1843_ADTLK, 1);
- ad1843_write_multi(lith, 5,
- &ad1843_ANAEN, 1,
- &ad1843_AAMEN, 1,
- &ad1843_DA1EN, 1,
- &ad1843_ADLEN, 1,
- &ad1843_ADREN, 1);
-
- /* 8. Configure conversion resources while they are enabled. */
-
- ad1843_write_bits(lith, &ad1843_DA1C, 1);
-
- /* Unmute all channels. */
-
- ad1843_set_outsrc(lith,
- (SOUND_MASK_PCM | SOUND_MASK_LINE |
- SOUND_MASK_MIC | SOUND_MASK_CD));
- ad1843_write_multi(lith, 2, &ad1843_LDA1AM, 0, &ad1843_RDA1AM, 0);
-
- /* Set default recording source to Line In and set
- * mic gain to +20 dB.
- */
-
- ad1843_set_recsrc(lith, SOUND_MASK_LINE);
- ad1843_write_multi(lith, 2, &ad1843_LMGE, 1, &ad1843_RMGE, 1);
-
- /* Set Speaker Out level to +/- 4V and unmute it. */
-
- ad1843_write_multi(lith, 2, &ad1843_HPOS, 1, &ad1843_HPOM, 0);
-
- return 0;
-}
-
-/*****************************************************************************/
-/* PCM I/O */
-
-#define READ_INTR_MASK (LI_INTR_COMM1_TRIG | LI_INTR_COMM1_OVERFLOW)
-#define WRITE_INTR_MASK (LI_INTR_COMM2_TRIG | LI_INTR_COMM2_UNDERFLOW)
-
-typedef enum vwsnd_port_swstate { /* software state */
- SW_OFF,
- SW_INITIAL,
- SW_RUN,
- SW_DRAIN,
-} vwsnd_port_swstate_t;
-
-typedef enum vwsnd_port_hwstate { /* hardware state */
- HW_STOPPED,
- HW_RUNNING,
-} vwsnd_port_hwstate_t;
-
-/*
- * These flags are read by ISR, but only written at baseline.
- */
-
-typedef enum vwsnd_port_flags {
- DISABLED = 1 << 0,
- ERFLOWN = 1 << 1, /* overflown or underflown */
- HW_BUSY = 1 << 2,
-} vwsnd_port_flags_t;
-
-/*
- * vwsnd_port is the per-port data structure. Each device has two
- * ports, one for input and one for output.
- *
- * Locking:
- *
- * port->lock protects: hwstate, flags, swb_[iu]_avail.
- *
- * devc->io_mutex protects: swstate, sw_*, swb_[iu]_idx.
- *
- * everything else is only written by open/release or
- * pcm_{setup,shutdown}(), which are serialized by a
- * combination of devc->open_mutex and devc->io_mutex.
- */
-
-typedef struct vwsnd_port {
-
- spinlock_t lock;
- wait_queue_head_t queue;
- vwsnd_port_swstate_t swstate;
- vwsnd_port_hwstate_t hwstate;
- vwsnd_port_flags_t flags;
-
- int sw_channels;
- int sw_samplefmt;
- int sw_framerate;
- int sample_size;
- int frame_size;
- unsigned int zero_word; /* zero for the sample format */
-
- int sw_fragshift;
- int sw_fragcount;
- int sw_subdivshift;
-
- unsigned int hw_fragshift;
- unsigned int hw_fragsize;
- unsigned int hw_fragcount;
-
- int hwbuf_size;
- unsigned long hwbuf_paddr;
- unsigned long hwbuf_vaddr;
- void * hwbuf; /* hwbuf == hwbuf_vaddr */
- int hwbuf_max; /* max bytes to preload */
-
- void * swbuf;
- unsigned int swbuf_size; /* size in bytes */
- unsigned int swb_u_idx; /* index of next user byte */
- unsigned int swb_i_idx; /* index of next intr byte */
- unsigned int swb_u_avail; /* # bytes avail to user */
- unsigned int swb_i_avail; /* # bytes avail to intr */
-
- dma_chan_t chan;
-
- /* Accounting */
-
- int byte_count;
- int frag_count;
- int MSC_offset;
-
-} vwsnd_port_t;
-
-/* vwsnd_dev is the per-device data structure. */
-
-typedef struct vwsnd_dev {
- struct vwsnd_dev *next_dev;
- int audio_minor; /* minor number of audio device */
- int mixer_minor; /* minor number of mixer device */
-
- struct mutex open_mutex;
- struct mutex io_mutex;
- struct mutex mix_mutex;
- mode_t open_mode;
- wait_queue_head_t open_wait;
-
- lithium_t lith;
-
- vwsnd_port_t rport;
- vwsnd_port_t wport;
-} vwsnd_dev_t;
-
-static vwsnd_dev_t *vwsnd_dev_list; /* linked list of all devices */
-
-static atomic_t vwsnd_use_count = ATOMIC_INIT(0);
-
-# define INC_USE_COUNT (atomic_inc(&vwsnd_use_count))
-# define DEC_USE_COUNT (atomic_dec(&vwsnd_use_count))
-# define IN_USE (atomic_read(&vwsnd_use_count) != 0)
-
-/*
- * Lithium can only DMA multiples of 32 bytes. Its DMA buffer may
- * be up to 8 Kb. This driver always uses 8 Kb.
- *
- * Memory bug workaround -- I'm not sure what's going on here, but
- * somehow pcm_copy_out() was triggering segv's going on to the next
- * page of the hw buffer. So, I make the hw buffer one size bigger
- * than we actually use. That way, the following page is allocated
- * and mapped, and no error. I suspect that something is broken
- * in Cobalt, but haven't really investigated. HBO is the actual
- * size of the buffer, and HWBUF_ORDER is what we allocate.
- */
-
-#define HWBUF_SHIFT 13
-#define HWBUF_SIZE (1 << HWBUF_SHIFT)
-# define HBO (HWBUF_SHIFT > PAGE_SHIFT ? HWBUF_SHIFT - PAGE_SHIFT : 0)
-# define HWBUF_ORDER (HBO + 1) /* next size bigger */
-#define MIN_SPEED 4000
-#define MAX_SPEED 49000
-
-#define MIN_FRAGSHIFT (DMACHUNK_SHIFT + 1)
-#define MAX_FRAGSHIFT (PAGE_SHIFT)
-#define MIN_FRAGSIZE (1 << MIN_FRAGSHIFT)
-#define MAX_FRAGSIZE (1 << MAX_FRAGSHIFT)
-#define MIN_FRAGCOUNT(fragsize) 3
-#define MAX_FRAGCOUNT(fragsize) (32 * PAGE_SIZE / (fragsize))
-#define DEFAULT_FRAGSHIFT 12
-#define DEFAULT_FRAGCOUNT 16
-#define DEFAULT_SUBDIVSHIFT 0
-
-/*
- * The software buffer (swbuf) is a ring buffer shared between user
- * level and interrupt level. Each level owns some of the bytes in
- * the buffer, and may give bytes away by calling swb_inc_{u,i}().
- * User level calls _u for user, and interrupt level calls _i for
- * interrupt.
- *
- * port->swb_{u,i}_avail is the number of bytes available to that level.
- *
- * port->swb_{u,i}_idx is the index of the first available byte in the
- * buffer.
- *
- * Each level calls swb_inc_{u,i}() to atomically increment its index,
- * recalculate the number of bytes available for both sides, and
- * return the number of bytes available. Since each side can only
- * give away bytes, the other side can only increase the number of
- * bytes available to this side. Each side updates its own index
- * variable, swb_{u,i}_idx, so no lock is needed to read it.
- *
- * To query the number of bytes available, call swb_inc_{u,i} with an
- * increment of zero.
- */
-
-static __inline__ unsigned int __swb_inc_u(vwsnd_port_t *port, int inc)
-{
- if (inc) {
- port->swb_u_idx += inc;
- port->swb_u_idx %= port->swbuf_size;
- port->swb_u_avail -= inc;
- port->swb_i_avail += inc;
- }
- return port->swb_u_avail;
-}
-
-static __inline__ unsigned int swb_inc_u(vwsnd_port_t *port, int inc)
-{
- unsigned long flags;
- unsigned int ret;
-
- spin_lock_irqsave(&port->lock, flags);
- {
- ret = __swb_inc_u(port, inc);
- }
- spin_unlock_irqrestore(&port->lock, flags);
- return ret;
-}
-
-static __inline__ unsigned int __swb_inc_i(vwsnd_port_t *port, int inc)
-{
- if (inc) {
- port->swb_i_idx += inc;
- port->swb_i_idx %= port->swbuf_size;
- port->swb_i_avail -= inc;
- port->swb_u_avail += inc;
- }
- return port->swb_i_avail;
-}
-
-static __inline__ unsigned int swb_inc_i(vwsnd_port_t *port, int inc)
-{
- unsigned long flags;
- unsigned int ret;
-
- spin_lock_irqsave(&port->lock, flags);
- {
- ret = __swb_inc_i(port, inc);
- }
- spin_unlock_irqrestore(&port->lock, flags);
- return ret;
-}
-
-/*
- * pcm_setup - this routine initializes all port state after
- * mode-setting ioctls have been done, but before the first I/O is
- * done.
- *
- * Locking: called with devc->io_mutex held.
- *
- * Returns 0 on success, -errno on failure.
- */
-
-static int pcm_setup(vwsnd_dev_t *devc,
- vwsnd_port_t *rport,
- vwsnd_port_t *wport)
-{
- vwsnd_port_t *aport = rport ? rport : wport;
- int sample_size;
- unsigned int zero_word;
-
- DBGEV("(devc=0x%p, rport=0x%p, wport=0x%p)\n", devc, rport, wport);
-
- ASSERT(aport != NULL);
- if (aport->swbuf != NULL)
- return 0;
- switch (aport->sw_samplefmt) {
- case AFMT_MU_LAW:
- sample_size = 1;
- zero_word = 0xFFFFFFFF ^ 0x80808080;
- break;
-
- case AFMT_A_LAW:
- sample_size = 1;
- zero_word = 0xD5D5D5D5 ^ 0x80808080;
- break;
-
- case AFMT_U8:
- sample_size = 1;
- zero_word = 0x80808080;
- break;
-
- case AFMT_S8:
- sample_size = 1;
- zero_word = 0x00000000;
- break;
-
- case AFMT_S16_LE:
- sample_size = 2;
- zero_word = 0x00000000;
- break;
-
- default:
- sample_size = 0; /* prevent compiler warning */
- zero_word = 0;
- ASSERT(0);
- }
- aport->sample_size = sample_size;
- aport->zero_word = zero_word;
- aport->frame_size = aport->sw_channels * aport->sample_size;
- aport->hw_fragshift = aport->sw_fragshift - aport->sw_subdivshift;
- aport->hw_fragsize = 1 << aport->hw_fragshift;
- aport->hw_fragcount = aport->sw_fragcount << aport->sw_subdivshift;
- ASSERT(aport->hw_fragsize >= MIN_FRAGSIZE);
- ASSERT(aport->hw_fragsize <= MAX_FRAGSIZE);
- ASSERT(aport->hw_fragcount >= MIN_FRAGCOUNT(aport->hw_fragsize));
- ASSERT(aport->hw_fragcount <= MAX_FRAGCOUNT(aport->hw_fragsize));
- if (rport) {
- int hwfrags, swfrags;
- rport->hwbuf_max = aport->hwbuf_size - DMACHUNK_SIZE;
- hwfrags = rport->hwbuf_max >> aport->hw_fragshift;
- swfrags = aport->hw_fragcount - hwfrags;
- if (swfrags < 2)
- swfrags = 2;
- rport->swbuf_size = swfrags * aport->hw_fragsize;
- DBGPV("hwfrags = %d, swfrags = %d\n", hwfrags, swfrags);
- DBGPV("read hwbuf_max = %d, swbuf_size = %d\n",
- rport->hwbuf_max, rport->swbuf_size);
- }
- if (wport) {
- int hwfrags, swfrags;
- int total_bytes = aport->hw_fragcount * aport->hw_fragsize;
- wport->hwbuf_max = aport->hwbuf_size - DMACHUNK_SIZE;
- if (wport->hwbuf_max > total_bytes)
- wport->hwbuf_max = total_bytes;
- hwfrags = wport->hwbuf_max >> aport->hw_fragshift;
- DBGPV("hwfrags = %d\n", hwfrags);
- swfrags = aport->hw_fragcount - hwfrags;
- if (swfrags < 2)
- swfrags = 2;
- wport->swbuf_size = swfrags * aport->hw_fragsize;
- DBGPV("hwfrags = %d, swfrags = %d\n", hwfrags, swfrags);
- DBGPV("write hwbuf_max = %d, swbuf_size = %d\n",
- wport->hwbuf_max, wport->swbuf_size);
- }
-
- aport->swb_u_idx = 0;
- aport->swb_i_idx = 0;
- aport->byte_count = 0;
-
- /*
- * Is this a Cobalt bug? We need to make this buffer extend
- * one page further than we actually use -- somehow memcpy
- * causes an exceptoin otherwise. I suspect there's a bug in
- * Cobalt (or somewhere) where it's generating a fault on a
- * speculative load or something. Obviously, I haven't taken
- * the time to track it down.
- */
-
- aport->swbuf = vmalloc(aport->swbuf_size + PAGE_SIZE);
- if (!aport->swbuf)
- return -ENOMEM;
- if (rport && wport) {
- ASSERT(aport == rport);
- ASSERT(wport->swbuf == NULL);
- /* One extra page - see comment above. */
- wport->swbuf = vmalloc(aport->swbuf_size + PAGE_SIZE);
- if (!wport->swbuf) {
- vfree(aport->swbuf);
- aport->swbuf = NULL;
- return -ENOMEM;
- }
- wport->sample_size = rport->sample_size;
- wport->zero_word = rport->zero_word;
- wport->frame_size = rport->frame_size;
- wport->hw_fragshift = rport->hw_fragshift;
- wport->hw_fragsize = rport->hw_fragsize;
- wport->hw_fragcount = rport->hw_fragcount;
- wport->swbuf_size = rport->swbuf_size;
- wport->hwbuf_max = rport->hwbuf_max;
- wport->swb_u_idx = rport->swb_u_idx;
- wport->swb_i_idx = rport->swb_i_idx;
- wport->byte_count = rport->byte_count;
- }
- if (rport) {
- rport->swb_u_avail = 0;
- rport->swb_i_avail = rport->swbuf_size;
- rport->swstate = SW_RUN;
- li_setup_dma(&rport->chan,
- &li_comm1,
- &devc->lith,
- rport->hwbuf_paddr,
- HWBUF_SHIFT,
- rport->hw_fragshift,
- rport->sw_channels,
- rport->sample_size);
- ad1843_setup_adc(&devc->lith,
- rport->sw_framerate,
- rport->sw_samplefmt,
- rport->sw_channels);
- li_enable_interrupts(&devc->lith, READ_INTR_MASK);
- if (!(rport->flags & DISABLED)) {
- ustmsc_t ustmsc;
- rport->hwstate = HW_RUNNING;
- li_activate_dma(&rport->chan);
- li_read_USTMSC(&rport->chan, &ustmsc);
- rport->MSC_offset = ustmsc.msc;
- }
- }
- if (wport) {
- if (wport->hwbuf_max > wport->swbuf_size)
- wport->hwbuf_max = wport->swbuf_size;
- wport->flags &= ~ERFLOWN;
- wport->swb_u_avail = wport->swbuf_size;
- wport->swb_i_avail = 0;
- wport->swstate = SW_RUN;
- li_setup_dma(&wport->chan,
- &li_comm2,
- &devc->lith,
- wport->hwbuf_paddr,
- HWBUF_SHIFT,
- wport->hw_fragshift,
- wport->sw_channels,
- wport->sample_size);
- ad1843_setup_dac(&devc->lith,
- wport->sw_framerate,
- wport->sw_samplefmt,
- wport->sw_channels);
- li_enable_interrupts(&devc->lith, WRITE_INTR_MASK);
- }
- DBGRV();
- return 0;
-}
-
-/*
- * pcm_shutdown_port - shut down one port (direction) for PCM I/O.
- * Only called from pcm_shutdown.
- */
-
-static void pcm_shutdown_port(vwsnd_dev_t *devc,
- vwsnd_port_t *aport,
- unsigned int mask)
-{
- unsigned long flags;
- vwsnd_port_hwstate_t hwstate;
- DECLARE_WAITQUEUE(wait, current);
-
- aport->swstate = SW_INITIAL;
- add_wait_queue(&aport->queue, &wait);
- while (1) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- spin_lock_irqsave(&aport->lock, flags);
- {
- hwstate = aport->hwstate;
- }
- spin_unlock_irqrestore(&aport->lock, flags);
- if (hwstate == HW_STOPPED)
- break;
- schedule();
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&aport->queue, &wait);
- li_disable_interrupts(&devc->lith, mask);
- if (aport == &devc->rport)
- ad1843_shutdown_adc(&devc->lith);
- else /* aport == &devc->wport) */
- ad1843_shutdown_dac(&devc->lith);
- li_shutdown_dma(&aport->chan);
- vfree(aport->swbuf);
- aport->swbuf = NULL;
- aport->byte_count = 0;
-}
-
-/*
- * pcm_shutdown undoes what pcm_setup did.
- * Also sets the ports' swstate to newstate.
- */
-
-static void pcm_shutdown(vwsnd_dev_t *devc,
- vwsnd_port_t *rport,
- vwsnd_port_t *wport)
-{
- DBGEV("(devc=0x%p, rport=0x%p, wport=0x%p)\n", devc, rport, wport);
-
- if (rport && rport->swbuf) {
- DBGPV("shutting down rport\n");
- pcm_shutdown_port(devc, rport, READ_INTR_MASK);
- }
- if (wport && wport->swbuf) {
- DBGPV("shutting down wport\n");
- pcm_shutdown_port(devc, wport, WRITE_INTR_MASK);
- }
- DBGRV();
-}
-
-static void pcm_copy_in(vwsnd_port_t *rport, int swidx, int hwidx, int nb)
-{
- char *src = rport->hwbuf + hwidx;
- char *dst = rport->swbuf + swidx;
- int fmt = rport->sw_samplefmt;
-
- DBGPV("swidx = %d, hwidx = %d\n", swidx, hwidx);
- ASSERT(rport->hwbuf != NULL);
- ASSERT(rport->swbuf != NULL);
- ASSERT(nb > 0 && (nb % 32) == 0);
- ASSERT(swidx % 32 == 0 && hwidx % 32 == 0);
- ASSERT(swidx >= 0 && swidx + nb <= rport->swbuf_size);
- ASSERT(hwidx >= 0 && hwidx + nb <= rport->hwbuf_size);
-
- if (fmt == AFMT_MU_LAW || fmt == AFMT_A_LAW || fmt == AFMT_S8) {
-
- /* See Sample Format Notes above. */
-
- char *end = src + nb;
- while (src < end)
- *dst++ = *src++ ^ 0x80;
- } else
- memcpy(dst, src, nb);
-}
-
-static void pcm_copy_out(vwsnd_port_t *wport, int swidx, int hwidx, int nb)
-{
- char *src = wport->swbuf + swidx;
- char *dst = wport->hwbuf + hwidx;
- int fmt = wport->sw_samplefmt;
-
- ASSERT(nb > 0 && (nb % 32) == 0);
- ASSERT(wport->hwbuf != NULL);
- ASSERT(wport->swbuf != NULL);
- ASSERT(swidx % 32 == 0 && hwidx % 32 == 0);
- ASSERT(swidx >= 0 && swidx + nb <= wport->swbuf_size);
- ASSERT(hwidx >= 0 && hwidx + nb <= wport->hwbuf_size);
- if (fmt == AFMT_MU_LAW || fmt == AFMT_A_LAW || fmt == AFMT_S8) {
-
- /* See Sample Format Notes above. */
-
- char *end = src + nb;
- while (src < end)
- *dst++ = *src++ ^ 0x80;
- } else
- memcpy(dst, src, nb);
-}
-
-/*
- * pcm_output() is called both from baselevel and from interrupt level.
- * This is where audio frames are copied into the hardware-accessible
- * ring buffer.
- *
- * Locking note: The part of this routine that figures out what to do
- * holds wport->lock. The longer part releases wport->lock, but sets
- * wport->flags & HW_BUSY. Afterward, it reacquires wport->lock, and
- * checks for more work to do.
- *
- * If another thread calls pcm_output() while HW_BUSY is set, it
- * returns immediately, knowing that the thread that set HW_BUSY will
- * look for more work to do before returning.
- *
- * This has the advantage that port->lock is held for several short
- * periods instead of one long period. Also, when pcm_output is
- * called from base level, it reenables interrupts.
- */
-
-static void pcm_output(vwsnd_dev_t *devc, int erflown, int nb)
-{
- vwsnd_port_t *wport = &devc->wport;
- const int hwmax = wport->hwbuf_max;
- const int hwsize = wport->hwbuf_size;
- const int swsize = wport->swbuf_size;
- const int fragsize = wport->hw_fragsize;
- unsigned long iflags;
-
- DBGEV("(devc=0x%p, erflown=%d, nb=%d)\n", devc, erflown, nb);
- spin_lock_irqsave(&wport->lock, iflags);
- if (erflown)
- wport->flags |= ERFLOWN;
- (void) __swb_inc_u(wport, nb);
- if (wport->flags & HW_BUSY) {
- spin_unlock_irqrestore(&wport->lock, iflags);
- DBGPV("returning: HW BUSY\n");
- return;
- }
- if (wport->flags & DISABLED) {
- spin_unlock_irqrestore(&wport->lock, iflags);
- DBGPV("returning: DISABLED\n");
- return;
- }
- wport->flags |= HW_BUSY;
- while (1) {
- int swptr, hwptr, hw_avail, sw_avail, swidx;
- vwsnd_port_hwstate_t hwstate = wport->hwstate;
- vwsnd_port_swstate_t swstate = wport->swstate;
- int hw_unavail;
- ustmsc_t ustmsc;
-
- hwptr = li_read_hwptr(&wport->chan);
- swptr = li_read_swptr(&wport->chan);
- hw_unavail = (swptr - hwptr + hwsize) % hwsize;
- hw_avail = (hwmax - hw_unavail) & -fragsize;
- sw_avail = wport->swb_i_avail & -fragsize;
- if (sw_avail && swstate == SW_RUN) {
- if (wport->flags & ERFLOWN) {
- wport->flags &= ~ERFLOWN;
- }
- } else if (swstate == SW_INITIAL ||
- swstate == SW_OFF ||
- (swstate == SW_DRAIN &&
- !sw_avail &&
- (wport->flags & ERFLOWN))) {
- DBGP("stopping. hwstate = %d\n", hwstate);
- if (hwstate != HW_STOPPED) {
- li_deactivate_dma(&wport->chan);
- wport->hwstate = HW_STOPPED;
- }
- wake_up(&wport->queue);
- break;
- }
- if (!sw_avail || !hw_avail)
- break;
- spin_unlock_irqrestore(&wport->lock, iflags);
-
- /*
- * We gave up the port lock, but we have the HW_BUSY flag.
- * Proceed without accessing any nonlocal state.
- * Do not exit the loop -- must check for more work.
- */
-
- swidx = wport->swb_i_idx;
- nb = hw_avail;
- if (nb > sw_avail)
- nb = sw_avail;
- if (nb > hwsize - swptr)
- nb = hwsize - swptr; /* don't overflow hwbuf */
- if (nb > swsize - swidx)
- nb = swsize - swidx; /* don't overflow swbuf */
- ASSERT(nb > 0);
- if (nb % fragsize) {
- DBGP("nb = %d, fragsize = %d\n", nb, fragsize);
- DBGP("hw_avail = %d\n", hw_avail);
- DBGP("sw_avail = %d\n", sw_avail);
- DBGP("hwsize = %d, swptr = %d\n", hwsize, swptr);
- DBGP("swsize = %d, swidx = %d\n", swsize, swidx);
- }
- ASSERT(!(nb % fragsize));
- DBGPV("copying swb[%d..%d] to hwb[%d..%d]\n",
- swidx, swidx + nb, swptr, swptr + nb);
- pcm_copy_out(wport, swidx, swptr, nb);
- li_write_swptr(&wport->chan, (swptr + nb) % hwsize);
- spin_lock_irqsave(&wport->lock, iflags);
- if (hwstate == HW_STOPPED) {
- DBGPV("starting\n");
- li_activate_dma(&wport->chan);
- wport->hwstate = HW_RUNNING;
- li_read_USTMSC(&wport->chan, &ustmsc);
- ASSERT(wport->byte_count % wport->frame_size == 0);
- wport->MSC_offset = ustmsc.msc - wport->byte_count / wport->frame_size;
- }
- __swb_inc_i(wport, nb);
- wport->byte_count += nb;
- wport->frag_count += nb / fragsize;
- ASSERT(nb % fragsize == 0);
- wake_up(&wport->queue);
- }
- wport->flags &= ~HW_BUSY;
- spin_unlock_irqrestore(&wport->lock, iflags);
- DBGRV();
-}
-
-/*
- * pcm_input() is called both from baselevel and from interrupt level.
- * This is where audio frames are copied out of the hardware-accessible
- * ring buffer.
- *
- * Locking note: The part of this routine that figures out what to do
- * holds rport->lock. The longer part releases rport->lock, but sets
- * rport->flags & HW_BUSY. Afterward, it reacquires rport->lock, and
- * checks for more work to do.
- *
- * If another thread calls pcm_input() while HW_BUSY is set, it
- * returns immediately, knowing that the thread that set HW_BUSY will
- * look for more work to do before returning.
- *
- * This has the advantage that port->lock is held for several short
- * periods instead of one long period. Also, when pcm_input is
- * called from base level, it reenables interrupts.
- */
-
-static void pcm_input(vwsnd_dev_t *devc, int erflown, int nb)
-{
- vwsnd_port_t *rport = &devc->rport;
- const int hwmax = rport->hwbuf_max;
- const int hwsize = rport->hwbuf_size;
- const int swsize = rport->swbuf_size;
- const int fragsize = rport->hw_fragsize;
- unsigned long iflags;
-
- DBGEV("(devc=0x%p, erflown=%d, nb=%d)\n", devc, erflown, nb);
-
- spin_lock_irqsave(&rport->lock, iflags);
- if (erflown)
- rport->flags |= ERFLOWN;
- (void) __swb_inc_u(rport, nb);
- if (rport->flags & HW_BUSY || !rport->swbuf) {
- spin_unlock_irqrestore(&rport->lock, iflags);
- DBGPV("returning: HW BUSY or !swbuf\n");
- return;
- }
- if (rport->flags & DISABLED) {
- spin_unlock_irqrestore(&rport->lock, iflags);
- DBGPV("returning: DISABLED\n");
- return;
- }
- rport->flags |= HW_BUSY;
- while (1) {
- int swptr, hwptr, hw_avail, sw_avail, swidx;
- vwsnd_port_hwstate_t hwstate = rport->hwstate;
- vwsnd_port_swstate_t swstate = rport->swstate;
-
- hwptr = li_read_hwptr(&rport->chan);
- swptr = li_read_swptr(&rport->chan);
- hw_avail = (hwptr - swptr + hwsize) % hwsize & -fragsize;
- if (hw_avail > hwmax)
- hw_avail = hwmax;
- sw_avail = rport->swb_i_avail & -fragsize;
- if (swstate != SW_RUN) {
- DBGP("stopping. hwstate = %d\n", hwstate);
- if (hwstate != HW_STOPPED) {
- li_deactivate_dma(&rport->chan);
- rport->hwstate = HW_STOPPED;
- }
- wake_up(&rport->queue);
- break;
- }
- if (!sw_avail || !hw_avail)
- break;
- spin_unlock_irqrestore(&rport->lock, iflags);
-
- /*
- * We gave up the port lock, but we have the HW_BUSY flag.
- * Proceed without accessing any nonlocal state.
- * Do not exit the loop -- must check for more work.
- */
-
- swidx = rport->swb_i_idx;
- nb = hw_avail;
- if (nb > sw_avail)
- nb = sw_avail;
- if (nb > hwsize - swptr)
- nb = hwsize - swptr; /* don't overflow hwbuf */
- if (nb > swsize - swidx)
- nb = swsize - swidx; /* don't overflow swbuf */
- ASSERT(nb > 0);
- if (nb % fragsize) {
- DBGP("nb = %d, fragsize = %d\n", nb, fragsize);
- DBGP("hw_avail = %d\n", hw_avail);
- DBGP("sw_avail = %d\n", sw_avail);
- DBGP("hwsize = %d, swptr = %d\n", hwsize, swptr);
- DBGP("swsize = %d, swidx = %d\n", swsize, swidx);
- }
- ASSERT(!(nb % fragsize));
- DBGPV("copying hwb[%d..%d] to swb[%d..%d]\n",
- swptr, swptr + nb, swidx, swidx + nb);
- pcm_copy_in(rport, swidx, swptr, nb);
- li_write_swptr(&rport->chan, (swptr + nb) % hwsize);
- spin_lock_irqsave(&rport->lock, iflags);
- __swb_inc_i(rport, nb);
- rport->byte_count += nb;
- rport->frag_count += nb / fragsize;
- ASSERT(nb % fragsize == 0);
- wake_up(&rport->queue);
- }
- rport->flags &= ~HW_BUSY;
- spin_unlock_irqrestore(&rport->lock, iflags);
- DBGRV();
-}
-
-/*
- * pcm_flush_frag() writes zero samples to fill the current fragment,
- * then flushes it to the hardware.
- *
- * It is only meaningful to flush output, not input.
- */
-
-static void pcm_flush_frag(vwsnd_dev_t *devc)
-{
- vwsnd_port_t *wport = &devc->wport;
-
- DBGPV("swstate = %d\n", wport->swstate);
- if (wport->swstate == SW_RUN) {
- int idx = wport->swb_u_idx;
- int end = (idx + wport->hw_fragsize - 1)
- >> wport->hw_fragshift
- << wport->hw_fragshift;
- int nb = end - idx;
- DBGPV("clearing %d bytes\n", nb);
- if (nb)
- memset(wport->swbuf + idx,
- (char) wport->zero_word,
- nb);
- wport->swstate = SW_DRAIN;
- pcm_output(devc, 0, nb);
- }
- DBGRV();
-}
-
-/*
- * Wait for output to drain. This sleeps uninterruptibly because
- * there is nothing intelligent we can do if interrupted. This
- * means the process will be delayed in responding to the signal.
- */
-
-static void pcm_write_sync(vwsnd_dev_t *devc)
-{
- vwsnd_port_t *wport = &devc->wport;
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- vwsnd_port_hwstate_t hwstate;
-
- DBGEV("(devc=0x%p)\n", devc);
- add_wait_queue(&wport->queue, &wait);
- while (1) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- spin_lock_irqsave(&wport->lock, flags);
- {
- hwstate = wport->hwstate;
- }
- spin_unlock_irqrestore(&wport->lock, flags);
- if (hwstate == HW_STOPPED)
- break;
- schedule();
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&wport->queue, &wait);
- DBGPV("swstate = %d, hwstate = %d\n", wport->swstate, wport->hwstate);
- DBGRV();
-}
-
-/*****************************************************************************/
-/* audio driver */
-
-/*
- * seek on an audio device always fails.
- */
-
-static void vwsnd_audio_read_intr(vwsnd_dev_t *devc, unsigned int status)
-{
- int overflown = status & LI_INTR_COMM1_OVERFLOW;
-
- if (status & READ_INTR_MASK)
- pcm_input(devc, overflown, 0);
-}
-
-static void vwsnd_audio_write_intr(vwsnd_dev_t *devc, unsigned int status)
-{
- int underflown = status & LI_INTR_COMM2_UNDERFLOW;
-
- if (status & WRITE_INTR_MASK)
- pcm_output(devc, underflown, 0);
-}
-
-static irqreturn_t vwsnd_audio_intr(int irq, void *dev_id)
-{
- vwsnd_dev_t *devc = dev_id;
- unsigned int status;
-
- DBGEV("(irq=%d, dev_id=0x%p)\n", irq, dev_id);
-
- status = li_get_clear_intr_status(&devc->lith);
- vwsnd_audio_read_intr(devc, status);
- vwsnd_audio_write_intr(devc, status);
- return IRQ_HANDLED;
-}
-
-static ssize_t vwsnd_audio_do_read(struct file *file,
- char *buffer,
- size_t count,
- loff_t *ppos)
-{
- vwsnd_dev_t *devc = file->private_data;
- vwsnd_port_t *rport = ((file->f_mode & FMODE_READ) ?
- &devc->rport : NULL);
- int ret, nb;
-
- DBGEV("(file=0x%p, buffer=0x%p, count=%d, ppos=0x%p)\n",
- file, buffer, count, ppos);
-
- if (!rport)
- return -EINVAL;
-
- if (rport->swbuf == NULL) {
- vwsnd_port_t *wport = (file->f_mode & FMODE_WRITE) ?
- &devc->wport : NULL;
- ret = pcm_setup(devc, rport, wport);
- if (ret < 0)
- return ret;
- }
-
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- ret = 0;
- while (count) {
- DECLARE_WAITQUEUE(wait, current);
- add_wait_queue(&rport->queue, &wait);
- while ((nb = swb_inc_u(rport, 0)) == 0) {
- DBGPV("blocking\n");
- set_current_state(TASK_INTERRUPTIBLE);
- if (rport->flags & DISABLED ||
- file->f_flags & O_NONBLOCK) {
- current->state = TASK_RUNNING;
- remove_wait_queue(&rport->queue, &wait);
- return ret ? ret : -EAGAIN;
- }
- schedule();
- if (signal_pending(current)) {
- current->state = TASK_RUNNING;
- remove_wait_queue(&rport->queue, &wait);
- return ret ? ret : -ERESTARTSYS;
- }
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&rport->queue, &wait);
- pcm_input(devc, 0, 0);
- /* nb bytes are available in userbuf. */
- if (nb > count)
- nb = count;
- DBGPV("nb = %d\n", nb);
- if (copy_to_user(buffer, rport->swbuf + rport->swb_u_idx, nb))
- return -EFAULT;
- (void) swb_inc_u(rport, nb);
- buffer += nb;
- count -= nb;
- ret += nb;
- }
- DBGPV("returning %d\n", ret);
- return ret;
-}
-
-static ssize_t vwsnd_audio_read(struct file *file,
- char *buffer,
- size_t count,
- loff_t *ppos)
-{
- vwsnd_dev_t *devc = file->private_data;
- ssize_t ret;
-
- mutex_lock(&devc->io_mutex);
- ret = vwsnd_audio_do_read(file, buffer, count, ppos);
- mutex_unlock(&devc->io_mutex);
- return ret;
-}
-
-static ssize_t vwsnd_audio_do_write(struct file *file,
- const char *buffer,
- size_t count,
- loff_t *ppos)
-{
- vwsnd_dev_t *devc = file->private_data;
- vwsnd_port_t *wport = ((file->f_mode & FMODE_WRITE) ?
- &devc->wport : NULL);
- int ret, nb;
-
- DBGEV("(file=0x%p, buffer=0x%p, count=%d, ppos=0x%p)\n",
- file, buffer, count, ppos);
-
- if (!wport)
- return -EINVAL;
-
- if (wport->swbuf == NULL) {
- vwsnd_port_t *rport = (file->f_mode & FMODE_READ) ?
- &devc->rport : NULL;
- ret = pcm_setup(devc, rport, wport);
- if (ret < 0)
- return ret;
- }
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- ret = 0;
- while (count) {
- DECLARE_WAITQUEUE(wait, current);
- add_wait_queue(&wport->queue, &wait);
- while ((nb = swb_inc_u(wport, 0)) == 0) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (wport->flags & DISABLED ||
- file->f_flags & O_NONBLOCK) {
- current->state = TASK_RUNNING;
- remove_wait_queue(&wport->queue, &wait);
- return ret ? ret : -EAGAIN;
- }
- schedule();
- if (signal_pending(current)) {
- current->state = TASK_RUNNING;
- remove_wait_queue(&wport->queue, &wait);
- return ret ? ret : -ERESTARTSYS;
- }
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&wport->queue, &wait);
- /* nb bytes are available in userbuf. */
- if (nb > count)
- nb = count;
- DBGPV("nb = %d\n", nb);
- if (copy_from_user(wport->swbuf + wport->swb_u_idx, buffer, nb))
- return -EFAULT;
- pcm_output(devc, 0, nb);
- buffer += nb;
- count -= nb;
- ret += nb;
- }
- DBGPV("returning %d\n", ret);
- return ret;
-}
-
-static ssize_t vwsnd_audio_write(struct file *file,
- const char *buffer,
- size_t count,
- loff_t *ppos)
-{
- vwsnd_dev_t *devc = file->private_data;
- ssize_t ret;
-
- mutex_lock(&devc->io_mutex);
- ret = vwsnd_audio_do_write(file, buffer, count, ppos);
- mutex_unlock(&devc->io_mutex);
- return ret;
-}
-
-/* No kernel lock - fine */
-static unsigned int vwsnd_audio_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data;
- vwsnd_port_t *rport = (file->f_mode & FMODE_READ) ?
- &devc->rport : NULL;
- vwsnd_port_t *wport = (file->f_mode & FMODE_WRITE) ?
- &devc->wport : NULL;
- unsigned int mask = 0;
-
- DBGEV("(file=0x%p, wait=0x%p)\n", file, wait);
-
- ASSERT(rport || wport);
- if (rport) {
- poll_wait(file, &rport->queue, wait);
- if (swb_inc_u(rport, 0))
- mask |= (POLLIN | POLLRDNORM);
- }
- if (wport) {
- poll_wait(file, &wport->queue, wait);
- if (wport->swbuf == NULL || swb_inc_u(wport, 0))
- mask |= (POLLOUT | POLLWRNORM);
- }
-
- DBGPV("returning 0x%x\n", mask);
- return mask;
-}
-
-static int vwsnd_audio_do_ioctl(struct inode *inode,
- struct file *file,
- unsigned int cmd,
- unsigned long arg)
-{
- vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data;
- vwsnd_port_t *rport = (file->f_mode & FMODE_READ) ?
- &devc->rport : NULL;
- vwsnd_port_t *wport = (file->f_mode & FMODE_WRITE) ?
- &devc->wport : NULL;
- vwsnd_port_t *aport = rport ? rport : wport;
- struct audio_buf_info buf_info;
- struct count_info info;
- unsigned long flags;
- int ival;
-
-
- DBGEV("(inode=0x%p, file=0x%p, cmd=0x%x, arg=0x%lx)\n",
- inode, file, cmd, arg);
- switch (cmd) {
- case OSS_GETVERSION: /* _SIOR ('M', 118, int) */
- DBGX("OSS_GETVERSION\n");
- ival = SOUND_VERSION;
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_GETCAPS: /* _SIOR ('P',15, int) */
- DBGX("SNDCTL_DSP_GETCAPS\n");
- ival = DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER;
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_GETFMTS: /* _SIOR ('P',11, int) */
- DBGX("SNDCTL_DSP_GETFMTS\n");
- ival = (AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW |
- AFMT_U8 | AFMT_S8);
- return put_user(ival, (int *) arg);
- break;
-
- case SOUND_PCM_READ_RATE: /* _SIOR ('P', 2, int) */
- DBGX("SOUND_PCM_READ_RATE\n");
- ival = aport->sw_framerate;
- return put_user(ival, (int *) arg);
-
- case SOUND_PCM_READ_CHANNELS: /* _SIOR ('P', 6, int) */
- DBGX("SOUND_PCM_READ_CHANNELS\n");
- ival = aport->sw_channels;
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_SPEED: /* _SIOWR('P', 2, int) */
- if (get_user(ival, (int *) arg))
- return -EFAULT;
- DBGX("SNDCTL_DSP_SPEED %d\n", ival);
- if (ival) {
- if (aport->swstate != SW_INITIAL) {
- DBGX("SNDCTL_DSP_SPEED failed: swstate = %d\n",
- aport->swstate);
- return -EINVAL;
- }
- if (ival < MIN_SPEED)
- ival = MIN_SPEED;
- if (ival > MAX_SPEED)
- ival = MAX_SPEED;
- if (rport)
- rport->sw_framerate = ival;
- if (wport)
- wport->sw_framerate = ival;
- } else
- ival = aport->sw_framerate;
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_STEREO: /* _SIOWR('P', 3, int) */
- if (get_user(ival, (int *) arg))
- return -EFAULT;
- DBGX("SNDCTL_DSP_STEREO %d\n", ival);
- if (ival != 0 && ival != 1)
- return -EINVAL;
- if (aport->swstate != SW_INITIAL)
- return -EINVAL;
- if (rport)
- rport->sw_channels = ival + 1;
- if (wport)
- wport->sw_channels = ival + 1;
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_CHANNELS: /* _SIOWR('P', 6, int) */
- if (get_user(ival, (int *) arg))
- return -EFAULT;
- DBGX("SNDCTL_DSP_CHANNELS %d\n", ival);
- if (ival != 1 && ival != 2)
- return -EINVAL;
- if (aport->swstate != SW_INITIAL)
- return -EINVAL;
- if (rport)
- rport->sw_channels = ival;
- if (wport)
- wport->sw_channels = ival;
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_GETBLKSIZE: /* _SIOWR('P', 4, int) */
- ival = pcm_setup(devc, rport, wport);
- if (ival < 0) {
- DBGX("SNDCTL_DSP_GETBLKSIZE failed, errno %d\n", ival);
- return ival;
- }
- ival = 1 << aport->sw_fragshift;
- DBGX("SNDCTL_DSP_GETBLKSIZE returning %d\n", ival);
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_SETFRAGMENT: /* _SIOWR('P',10, int) */
- if (get_user(ival, (int *) arg))
- return -EFAULT;
- DBGX("SNDCTL_DSP_SETFRAGMENT %d:%d\n",
- ival >> 16, ival & 0xFFFF);
- if (aport->swstate != SW_INITIAL)
- return -EINVAL;
- {
- int sw_fragshift = ival & 0xFFFF;
- int sw_subdivshift = aport->sw_subdivshift;
- int hw_fragshift = sw_fragshift - sw_subdivshift;
- int sw_fragcount = (ival >> 16) & 0xFFFF;
- int hw_fragsize;
- if (hw_fragshift < MIN_FRAGSHIFT)
- hw_fragshift = MIN_FRAGSHIFT;
- if (hw_fragshift > MAX_FRAGSHIFT)
- hw_fragshift = MAX_FRAGSHIFT;
- sw_fragshift = hw_fragshift + aport->sw_subdivshift;
- hw_fragsize = 1 << hw_fragshift;
- if (sw_fragcount < MIN_FRAGCOUNT(hw_fragsize))
- sw_fragcount = MIN_FRAGCOUNT(hw_fragsize);
- if (sw_fragcount > MAX_FRAGCOUNT(hw_fragsize))
- sw_fragcount = MAX_FRAGCOUNT(hw_fragsize);
- DBGPV("sw_fragshift = %d\n", sw_fragshift);
- DBGPV("rport = 0x%p, wport = 0x%p\n", rport, wport);
- if (rport) {
- rport->sw_fragshift = sw_fragshift;
- rport->sw_fragcount = sw_fragcount;
- }
- if (wport) {
- wport->sw_fragshift = sw_fragshift;
- wport->sw_fragcount = sw_fragcount;
- }
- ival = sw_fragcount << 16 | sw_fragshift;
- }
- DBGX("SNDCTL_DSP_SETFRAGMENT returns %d:%d\n",
- ival >> 16, ival & 0xFFFF);
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_SUBDIVIDE: /* _SIOWR('P', 9, int) */
- if (get_user(ival, (int *) arg))
- return -EFAULT;
- DBGX("SNDCTL_DSP_SUBDIVIDE %d\n", ival);
- if (aport->swstate != SW_INITIAL)
- return -EINVAL;
- {
- int subdivshift;
- int hw_fragshift, hw_fragsize, hw_fragcount;
- switch (ival) {
- case 1: subdivshift = 0; break;
- case 2: subdivshift = 1; break;
- case 4: subdivshift = 2; break;
- default: return -EINVAL;
- }
- hw_fragshift = aport->sw_fragshift - subdivshift;
- if (hw_fragshift < MIN_FRAGSHIFT ||
- hw_fragshift > MAX_FRAGSHIFT)
- return -EINVAL;
- hw_fragsize = 1 << hw_fragshift;
- hw_fragcount = aport->sw_fragcount >> subdivshift;
- if (hw_fragcount < MIN_FRAGCOUNT(hw_fragsize) ||
- hw_fragcount > MAX_FRAGCOUNT(hw_fragsize))
- return -EINVAL;
- if (rport)
- rport->sw_subdivshift = subdivshift;
- if (wport)
- wport->sw_subdivshift = subdivshift;
- }
- return 0;
-
- case SNDCTL_DSP_SETFMT: /* _SIOWR('P',5, int) */
- if (get_user(ival, (int *) arg))
- return -EFAULT;
- DBGX("SNDCTL_DSP_SETFMT %d\n", ival);
- if (ival != AFMT_QUERY) {
- if (aport->swstate != SW_INITIAL) {
- DBGP("SETFMT failed, swstate = %d\n",
- aport->swstate);
- return -EINVAL;
- }
- switch (ival) {
- case AFMT_MU_LAW:
- case AFMT_A_LAW:
- case AFMT_U8:
- case AFMT_S8:
- case AFMT_S16_LE:
- if (rport)
- rport->sw_samplefmt = ival;
- if (wport)
- wport->sw_samplefmt = ival;
- break;
- default:
- return -EINVAL;
- }
- }
- ival = aport->sw_samplefmt;
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_GETOSPACE: /* _SIOR ('P',12, audio_buf_info) */
- DBGXV("SNDCTL_DSP_GETOSPACE\n");
- if (!wport)
- return -EINVAL;
- ival = pcm_setup(devc, rport, wport);
- if (ival < 0)
- return ival;
- ival = swb_inc_u(wport, 0);
- buf_info.fragments = ival >> wport->sw_fragshift;
- buf_info.fragstotal = wport->sw_fragcount;
- buf_info.fragsize = 1 << wport->sw_fragshift;
- buf_info.bytes = ival;
- DBGXV("SNDCTL_DSP_GETOSPACE returns { %d %d %d %d }\n",
- buf_info.fragments, buf_info.fragstotal,
- buf_info.fragsize, buf_info.bytes);
- if (copy_to_user((void *) arg, &buf_info, sizeof buf_info))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETISPACE: /* _SIOR ('P',13, audio_buf_info) */
- DBGX("SNDCTL_DSP_GETISPACE\n");
- if (!rport)
- return -EINVAL;
- ival = pcm_setup(devc, rport, wport);
- if (ival < 0)
- return ival;
- ival = swb_inc_u(rport, 0);
- buf_info.fragments = ival >> rport->sw_fragshift;
- buf_info.fragstotal = rport->sw_fragcount;
- buf_info.fragsize = 1 << rport->sw_fragshift;
- buf_info.bytes = ival;
- DBGX("SNDCTL_DSP_GETISPACE returns { %d %d %d %d }\n",
- buf_info.fragments, buf_info.fragstotal,
- buf_info.fragsize, buf_info.bytes);
- if (copy_to_user((void *) arg, &buf_info, sizeof buf_info))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_NONBLOCK: /* _SIO ('P',14) */
- DBGX("SNDCTL_DSP_NONBLOCK\n");
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_RESET: /* _SIO ('P', 0) */
- DBGX("SNDCTL_DSP_RESET\n");
- /*
- * Nothing special needs to be done for input. Input
- * samples sit in swbuf, but it will be reinitialized
- * to empty when pcm_setup() is called.
- */
- if (wport && wport->swbuf) {
- wport->swstate = SW_INITIAL;
- pcm_output(devc, 0, 0);
- pcm_write_sync(devc);
- }
- pcm_shutdown(devc, rport, wport);
- return 0;
-
- case SNDCTL_DSP_SYNC: /* _SIO ('P', 1) */
- DBGX("SNDCTL_DSP_SYNC\n");
- if (wport) {
- pcm_flush_frag(devc);
- pcm_write_sync(devc);
- }
- pcm_shutdown(devc, rport, wport);
- return 0;
-
- case SNDCTL_DSP_POST: /* _SIO ('P', 8) */
- DBGX("SNDCTL_DSP_POST\n");
- if (!wport)
- return -EINVAL;
- pcm_flush_frag(devc);
- return 0;
-
- case SNDCTL_DSP_GETIPTR: /* _SIOR ('P', 17, count_info) */
- DBGX("SNDCTL_DSP_GETIPTR\n");
- if (!rport)
- return -EINVAL;
- spin_lock_irqsave(&rport->lock, flags);
- {
- ustmsc_t ustmsc;
- if (rport->hwstate == HW_RUNNING) {
- ASSERT(rport->swstate == SW_RUN);
- li_read_USTMSC(&rport->chan, &ustmsc);
- info.bytes = ustmsc.msc - rport->MSC_offset;
- info.bytes *= rport->frame_size;
- } else {
- info.bytes = rport->byte_count;
- }
- info.blocks = rport->frag_count;
- info.ptr = 0; /* not implemented */
- rport->frag_count = 0;
- }
- spin_unlock_irqrestore(&rport->lock, flags);
- if (copy_to_user((void *) arg, &info, sizeof info))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETOPTR: /* _SIOR ('P',18, count_info) */
- DBGX("SNDCTL_DSP_GETOPTR\n");
- if (!wport)
- return -EINVAL;
- spin_lock_irqsave(&wport->lock, flags);
- {
- ustmsc_t ustmsc;
- if (wport->hwstate == HW_RUNNING) {
- ASSERT(wport->swstate == SW_RUN);
- li_read_USTMSC(&wport->chan, &ustmsc);
- info.bytes = ustmsc.msc - wport->MSC_offset;
- info.bytes *= wport->frame_size;
- } else {
- info.bytes = wport->byte_count;
- }
- info.blocks = wport->frag_count;
- info.ptr = 0; /* not implemented */
- wport->frag_count = 0;
- }
- spin_unlock_irqrestore(&wport->lock, flags);
- if (copy_to_user((void *) arg, &info, sizeof info))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETODELAY: /* _SIOR ('P', 23, int) */
- DBGX("SNDCTL_DSP_GETODELAY\n");
- if (!wport)
- return -EINVAL;
- spin_lock_irqsave(&wport->lock, flags);
- {
- int fsize = wport->frame_size;
- ival = wport->swb_i_avail / fsize;
- if (wport->hwstate == HW_RUNNING) {
- int swptr, hwptr, hwframes, hwbytes, hwsize;
- int totalhwbytes;
- ustmsc_t ustmsc;
-
- hwsize = wport->hwbuf_size;
- swptr = li_read_swptr(&wport->chan);
- li_read_USTMSC(&wport->chan, &ustmsc);
- hwframes = ustmsc.msc - wport->MSC_offset;
- totalhwbytes = hwframes * fsize;
- hwptr = totalhwbytes % hwsize;
- hwbytes = (swptr - hwptr + hwsize) % hwsize;
- ival += hwbytes / fsize;
- }
- }
- spin_unlock_irqrestore(&wport->lock, flags);
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_PROFILE: /* _SIOW ('P', 23, int) */
- DBGX("SNDCTL_DSP_PROFILE\n");
-
- /*
- * Thomas Sailer explains SNDCTL_DSP_PROFILE
- * (private email, March 24, 1999):
- *
- * This gives the sound driver a hint on what it
- * should do with partial fragments
- * (i.e. fragments partially filled with write).
- * This can direct the driver to zero them or
- * leave them alone. But don't ask me what this
- * is good for, my driver just zeroes the last
- * fragment before the receiver stops, no idea
- * what good for any other behaviour could
- * be. Implementing it as NOP seems safe.
- */
-
- break;
-
- case SNDCTL_DSP_GETTRIGGER: /* _SIOR ('P',16, int) */
- DBGX("SNDCTL_DSP_GETTRIGGER\n");
- ival = 0;
- if (rport) {
- spin_lock_irqsave(&rport->lock, flags);
- {
- if (!(rport->flags & DISABLED))
- ival |= PCM_ENABLE_INPUT;
- }
- spin_unlock_irqrestore(&rport->lock, flags);
- }
- if (wport) {
- spin_lock_irqsave(&wport->lock, flags);
- {
- if (!(wport->flags & DISABLED))
- ival |= PCM_ENABLE_OUTPUT;
- }
- spin_unlock_irqrestore(&wport->lock, flags);
- }
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_SETTRIGGER: /* _SIOW ('P',16, int) */
- if (get_user(ival, (int *) arg))
- return -EFAULT;
- DBGX("SNDCTL_DSP_SETTRIGGER %d\n", ival);
-
- /*
- * If user is disabling I/O and port is not in initial
- * state, fail with EINVAL.
- */
-
- if (((rport && !(ival & PCM_ENABLE_INPUT)) ||
- (wport && !(ival & PCM_ENABLE_OUTPUT))) &&
- aport->swstate != SW_INITIAL)
- return -EINVAL;
-
- if (rport) {
- vwsnd_port_hwstate_t hwstate;
- spin_lock_irqsave(&rport->lock, flags);
- {
- hwstate = rport->hwstate;
- if (ival & PCM_ENABLE_INPUT)
- rport->flags &= ~DISABLED;
- else
- rport->flags |= DISABLED;
- }
- spin_unlock_irqrestore(&rport->lock, flags);
- if (hwstate != HW_RUNNING && ival & PCM_ENABLE_INPUT) {
-
- if (rport->swstate == SW_INITIAL)
- pcm_setup(devc, rport, wport);
- else
- li_activate_dma(&rport->chan);
- }
- }
- if (wport) {
- vwsnd_port_flags_t pflags;
- spin_lock_irqsave(&wport->lock, flags);
- {
- pflags = wport->flags;
- if (ival & PCM_ENABLE_OUTPUT)
- wport->flags &= ~DISABLED;
- else
- wport->flags |= DISABLED;
- }
- spin_unlock_irqrestore(&wport->lock, flags);
- if (pflags & DISABLED && ival & PCM_ENABLE_OUTPUT) {
- if (wport->swstate == SW_RUN)
- pcm_output(devc, 0, 0);
- }
- }
- return 0;
-
- default:
- DBGP("unknown ioctl 0x%x\n", cmd);
- return -EINVAL;
- }
- DBGP("unimplemented ioctl 0x%x\n", cmd);
- return -EINVAL;
-}
-
-static int vwsnd_audio_ioctl(struct inode *inode,
- struct file *file,
- unsigned int cmd,
- unsigned long arg)
-{
- vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data;
- int ret;
-
- mutex_lock(&devc->io_mutex);
- ret = vwsnd_audio_do_ioctl(inode, file, cmd, arg);
- mutex_unlock(&devc->io_mutex);
- return ret;
-}
-
-/* No mmap. */
-
-static int vwsnd_audio_mmap(struct file *file, struct vm_area_struct *vma)
-{
- DBGE("(file=0x%p, vma=0x%p)\n", file, vma);
- return -ENODEV;
-}
-
-/*
- * Open the audio device for read and/or write.
- *
- * Returns 0 on success, -errno on failure.
- */
-
-static int vwsnd_audio_open(struct inode *inode, struct file *file)
-{
- vwsnd_dev_t *devc;
- int minor = iminor(inode);
- int sw_samplefmt;
-
- DBGE("(inode=0x%p, file=0x%p)\n", inode, file);
-
- INC_USE_COUNT;
- for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
- if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F))
- break;
-
- if (devc == NULL) {
- DEC_USE_COUNT;
- return -ENODEV;
- }
-
- mutex_lock(&devc->open_mutex);
- while (devc->open_mode & file->f_mode) {
- mutex_unlock(&devc->open_mutex);
- if (file->f_flags & O_NONBLOCK) {
- DEC_USE_COUNT;
- return -EBUSY;
- }
- interruptible_sleep_on(&devc->open_wait);
- if (signal_pending(current)) {
- DEC_USE_COUNT;
- return -ERESTARTSYS;
- }
- mutex_lock(&devc->open_mutex);
- }
- devc->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
- mutex_unlock(&devc->open_mutex);
-
- /* get default sample format from minor number. */
-
- sw_samplefmt = 0;
- if ((minor & 0xF) == SND_DEV_DSP)
- sw_samplefmt = AFMT_U8;
- else if ((minor & 0xF) == SND_DEV_AUDIO)
- sw_samplefmt = AFMT_MU_LAW;
- else if ((minor & 0xF) == SND_DEV_DSP16)
- sw_samplefmt = AFMT_S16_LE;
- else
- ASSERT(0);
-
- /* Initialize vwsnd_ports. */
-
- mutex_lock(&devc->io_mutex);
- {
- if (file->f_mode & FMODE_READ) {
- devc->rport.swstate = SW_INITIAL;
- devc->rport.flags = 0;
- devc->rport.sw_channels = 1;
- devc->rport.sw_samplefmt = sw_samplefmt;
- devc->rport.sw_framerate = 8000;
- devc->rport.sw_fragshift = DEFAULT_FRAGSHIFT;
- devc->rport.sw_fragcount = DEFAULT_FRAGCOUNT;
- devc->rport.sw_subdivshift = DEFAULT_SUBDIVSHIFT;
- devc->rport.byte_count = 0;
- devc->rport.frag_count = 0;
- }
- if (file->f_mode & FMODE_WRITE) {
- devc->wport.swstate = SW_INITIAL;
- devc->wport.flags = 0;
- devc->wport.sw_channels = 1;
- devc->wport.sw_samplefmt = sw_samplefmt;
- devc->wport.sw_framerate = 8000;
- devc->wport.sw_fragshift = DEFAULT_FRAGSHIFT;
- devc->wport.sw_fragcount = DEFAULT_FRAGCOUNT;
- devc->wport.sw_subdivshift = DEFAULT_SUBDIVSHIFT;
- devc->wport.byte_count = 0;
- devc->wport.frag_count = 0;
- }
- }
- mutex_unlock(&devc->io_mutex);
-
- file->private_data = devc;
- DBGRV();
- return 0;
-}
-
-/*
- * Release (close) the audio device.
- */
-
-static int vwsnd_audio_release(struct inode *inode, struct file *file)
-{
- vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data;
- vwsnd_port_t *wport = NULL, *rport = NULL;
- int err = 0;
-
- lock_kernel();
- mutex_lock(&devc->io_mutex);
- {
- DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
-
- if (file->f_mode & FMODE_READ)
- rport = &devc->rport;
- if (file->f_mode & FMODE_WRITE) {
- wport = &devc->wport;
- pcm_flush_frag(devc);
- pcm_write_sync(devc);
- }
- pcm_shutdown(devc, rport, wport);
- if (rport)
- rport->swstate = SW_OFF;
- if (wport)
- wport->swstate = SW_OFF;
- }
- mutex_unlock(&devc->io_mutex);
-
- mutex_lock(&devc->open_mutex);
- {
- devc->open_mode &= ~file->f_mode;
- }
- mutex_unlock(&devc->open_mutex);
- wake_up(&devc->open_wait);
- DEC_USE_COUNT;
- DBGR();
- unlock_kernel();
- return err;
-}
-
-static const struct file_operations vwsnd_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = vwsnd_audio_read,
- .write = vwsnd_audio_write,
- .poll = vwsnd_audio_poll,
- .ioctl = vwsnd_audio_ioctl,
- .mmap = vwsnd_audio_mmap,
- .open = vwsnd_audio_open,
- .release = vwsnd_audio_release,
-};
-
-/*****************************************************************************/
-/* mixer driver */
-
-/* open the mixer device. */
-
-static int vwsnd_mixer_open(struct inode *inode, struct file *file)
-{
- vwsnd_dev_t *devc;
-
- DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
-
- INC_USE_COUNT;
- for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
- if (devc->mixer_minor == iminor(inode))
- break;
-
- if (devc == NULL) {
- DEC_USE_COUNT;
- return -ENODEV;
- }
- file->private_data = devc;
- return 0;
-}
-
-/* release (close) the mixer device. */
-
-static int vwsnd_mixer_release(struct inode *inode, struct file *file)
-{
- DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
- DEC_USE_COUNT;
- return 0;
-}
-
-/* mixer_read_ioctl handles all read ioctls on the mixer device. */
-
-static int mixer_read_ioctl(vwsnd_dev_t *devc, unsigned int nr, void __user *arg)
-{
- int val = -1;
-
- DBGEV("(devc=0x%p, nr=0x%x, arg=0x%p)\n", devc, nr, arg);
-
- switch (nr) {
- case SOUND_MIXER_CAPS:
- val = SOUND_CAP_EXCL_INPUT;
- break;
-
- case SOUND_MIXER_DEVMASK:
- val = (SOUND_MASK_PCM | SOUND_MASK_LINE |
- SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_RECLEV);
- break;
-
- case SOUND_MIXER_STEREODEVS:
- val = (SOUND_MASK_PCM | SOUND_MASK_LINE |
- SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_RECLEV);
- break;
-
- case SOUND_MIXER_OUTMASK:
- val = (SOUND_MASK_PCM | SOUND_MASK_LINE |
- SOUND_MASK_MIC | SOUND_MASK_CD);
- break;
-
- case SOUND_MIXER_RECMASK:
- val = (SOUND_MASK_PCM | SOUND_MASK_LINE |
- SOUND_MASK_MIC | SOUND_MASK_CD);
- break;
-
- case SOUND_MIXER_PCM:
- val = ad1843_get_gain(&devc->lith, &ad1843_gain_PCM);
- break;
-
- case SOUND_MIXER_LINE:
- val = ad1843_get_gain(&devc->lith, &ad1843_gain_LINE);
- break;
-
- case SOUND_MIXER_MIC:
- val = ad1843_get_gain(&devc->lith, &ad1843_gain_MIC);
- break;
-
- case SOUND_MIXER_CD:
- val = ad1843_get_gain(&devc->lith, &ad1843_gain_CD);
- break;
-
- case SOUND_MIXER_RECLEV:
- val = ad1843_get_gain(&devc->lith, &ad1843_gain_RECLEV);
- break;
-
- case SOUND_MIXER_RECSRC:
- val = ad1843_get_recsrc(&devc->lith);
- break;
-
- case SOUND_MIXER_OUTSRC:
- val = ad1843_get_outsrc(&devc->lith);
- break;
-
- default:
- return -EINVAL;
- }
- return put_user(val, (int __user *) arg);
-}
-
-/* mixer_write_ioctl handles all write ioctls on the mixer device. */
-
-static int mixer_write_ioctl(vwsnd_dev_t *devc, unsigned int nr, void __user *arg)
-{
- int val;
- int err;
-
- DBGEV("(devc=0x%p, nr=0x%x, arg=0x%p)\n", devc, nr, arg);
-
- err = get_user(val, (int __user *) arg);
- if (err)
- return -EFAULT;
- switch (nr) {
- case SOUND_MIXER_PCM:
- val = ad1843_set_gain(&devc->lith, &ad1843_gain_PCM, val);
- break;
-
- case SOUND_MIXER_LINE:
- val = ad1843_set_gain(&devc->lith, &ad1843_gain_LINE, val);
- break;
-
- case SOUND_MIXER_MIC:
- val = ad1843_set_gain(&devc->lith, &ad1843_gain_MIC, val);
- break;
-
- case SOUND_MIXER_CD:
- val = ad1843_set_gain(&devc->lith, &ad1843_gain_CD, val);
- break;
-
- case SOUND_MIXER_RECLEV:
- val = ad1843_set_gain(&devc->lith, &ad1843_gain_RECLEV, val);
- break;
-
- case SOUND_MIXER_RECSRC:
- if (devc->rport.swbuf || devc->wport.swbuf)
- return -EBUSY; /* can't change recsrc while running */
- val = ad1843_set_recsrc(&devc->lith, val);
- break;
-
- case SOUND_MIXER_OUTSRC:
- val = ad1843_set_outsrc(&devc->lith, val);
- break;
-
- default:
- return -EINVAL;
- }
- if (val < 0)
- return val;
- return put_user(val, (int __user *) arg);
-}
-
-/* This is the ioctl entry to the mixer driver. */
-
-static int vwsnd_mixer_ioctl(struct inode *ioctl,
- struct file *file,
- unsigned int cmd,
- unsigned long arg)
-{
- vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data;
- const unsigned int nrmask = _IOC_NRMASK << _IOC_NRSHIFT;
- const unsigned int nr = (cmd & nrmask) >> _IOC_NRSHIFT;
- int retval;
-
- DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg);
-
- mutex_lock(&devc->mix_mutex);
- {
- if ((cmd & ~nrmask) == MIXER_READ(0))
- retval = mixer_read_ioctl(devc, nr, (void __user *) arg);
- else if ((cmd & ~nrmask) == MIXER_WRITE(0))
- retval = mixer_write_ioctl(devc, nr, (void __user *) arg);
- else
- retval = -EINVAL;
- }
- mutex_unlock(&devc->mix_mutex);
- return retval;
-}
-
-static const struct file_operations vwsnd_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = vwsnd_mixer_ioctl,
- .open = vwsnd_mixer_open,
- .release = vwsnd_mixer_release,
-};
-
-/*****************************************************************************/
-/* probe/attach/unload */
-
-/* driver probe routine. Return nonzero if hardware is found. */
-
-static int __init probe_vwsnd(struct address_info *hw_config)
-{
- lithium_t lith;
- int w;
- unsigned long later;
-
- DBGEV("(hw_config=0x%p)\n", hw_config);
-
- /* XXX verify lithium present (to prevent crash on non-vw) */
-
- if (li_create(&lith, hw_config->io_base) != 0) {
- printk(KERN_WARNING "probe_vwsnd: can't map lithium\n");
- return 0;
- }
- later = jiffies + 2;
- li_writel(&lith, LI_HOST_CONTROLLER, LI_HC_LINK_ENABLE);
- do {
- w = li_readl(&lith, LI_HOST_CONTROLLER);
- } while (w == LI_HC_LINK_ENABLE && time_before(jiffies, later));
-
- li_destroy(&lith);
-
- DBGPV("HC = 0x%04x\n", w);
-
- if ((w == LI_HC_LINK_ENABLE) || (w & LI_HC_LINK_CODEC)) {
-
- /* This may indicate a beta machine with no audio,
- * or a future machine with different audio.
- * On beta-release 320 w/ no audio, HC == 0x4000 */
-
- printk(KERN_WARNING "probe_vwsnd: audio codec not found\n");
- return 0;
- }
-
- if (w & LI_HC_LINK_FAILURE) {
- printk(KERN_WARNING "probe_vwsnd: can't init audio codec\n");
- return 0;
- }
-
- printk(KERN_INFO "vwsnd: lithium audio at mmio %#x irq %d\n",
- hw_config->io_base, hw_config->irq);
-
- return 1;
-}
-
-/*
- * driver attach routine. Initialize driver data structures and
- * initialize hardware. A new vwsnd_dev_t is allocated and put
- * onto the global list, vwsnd_dev_list.
- *
- * Return +minor_dev on success, -errno on failure.
- */
-
-static int __init attach_vwsnd(struct address_info *hw_config)
-{
- vwsnd_dev_t *devc = NULL;
- int err = -ENOMEM;
-
- DBGEV("(hw_config=0x%p)\n", hw_config);
-
- devc = kmalloc(sizeof (vwsnd_dev_t), GFP_KERNEL);
- if (devc == NULL)
- goto fail0;
-
- err = li_create(&devc->lith, hw_config->io_base);
- if (err)
- goto fail1;
-
- init_waitqueue_head(&devc->open_wait);
-
- devc->rport.hwbuf_size = HWBUF_SIZE;
- devc->rport.hwbuf_vaddr = __get_free_pages(GFP_KERNEL, HWBUF_ORDER);
- if (!devc->rport.hwbuf_vaddr)
- goto fail2;
- devc->rport.hwbuf = (void *) devc->rport.hwbuf_vaddr;
- devc->rport.hwbuf_paddr = virt_to_phys(devc->rport.hwbuf);
-
- /*
- * Quote from the NT driver:
- *
- * // WARNING!!! HACK to setup output dma!!!
- * // This is required because even on output there is some data
- * // trickling into the input DMA channel. This is a bug in the
- * // Lithium microcode.
- * // --sde
- *
- * We set the input side's DMA base address here. It will remain
- * valid until the driver is unloaded.
- */
-
- li_writel(&devc->lith, LI_COMM1_BASE,
- devc->rport.hwbuf_paddr >> 8 | 1 << (37 - 8));
-
- devc->wport.hwbuf_size = HWBUF_SIZE;
- devc->wport.hwbuf_vaddr = __get_free_pages(GFP_KERNEL, HWBUF_ORDER);
- if (!devc->wport.hwbuf_vaddr)
- goto fail3;
- devc->wport.hwbuf = (void *) devc->wport.hwbuf_vaddr;
- devc->wport.hwbuf_paddr = virt_to_phys(devc->wport.hwbuf);
- DBGP("wport hwbuf = 0x%p\n", devc->wport.hwbuf);
-
- DBGDO(shut_up++);
- err = ad1843_init(&devc->lith);
- DBGDO(shut_up--);
- if (err)
- goto fail4;
-
- /* install interrupt handler */
-
- err = request_irq(hw_config->irq, vwsnd_audio_intr, 0, "vwsnd", devc);
- if (err)
- goto fail5;
-
- /* register this device's drivers. */
-
- devc->audio_minor = register_sound_dsp(&vwsnd_audio_fops, -1);
- if ((err = devc->audio_minor) < 0) {
- DBGDO(printk(KERN_WARNING
- "attach_vwsnd: register_sound_dsp error %d\n",
- err));
- goto fail6;
- }
- devc->mixer_minor = register_sound_mixer(&vwsnd_mixer_fops,
- devc->audio_minor >> 4);
- if ((err = devc->mixer_minor) < 0) {
- DBGDO(printk(KERN_WARNING
- "attach_vwsnd: register_sound_mixer error %d\n",
- err));
- goto fail7;
- }
-
- /* Squirrel away device indices for unload routine. */
-
- hw_config->slots[0] = devc->audio_minor;
-
- /* Initialize as much of *devc as possible */
-
- mutex_init(&devc->open_mutex);
- mutex_init(&devc->io_mutex);
- mutex_init(&devc->mix_mutex);
- devc->open_mode = 0;
- spin_lock_init(&devc->rport.lock);
- init_waitqueue_head(&devc->rport.queue);
- devc->rport.swstate = SW_OFF;
- devc->rport.hwstate = HW_STOPPED;
- devc->rport.flags = 0;
- devc->rport.swbuf = NULL;
- spin_lock_init(&devc->wport.lock);
- init_waitqueue_head(&devc->wport.queue);
- devc->wport.swstate = SW_OFF;
- devc->wport.hwstate = HW_STOPPED;
- devc->wport.flags = 0;
- devc->wport.swbuf = NULL;
-
- /* Success. Link us onto the local device list. */
-
- devc->next_dev = vwsnd_dev_list;
- vwsnd_dev_list = devc;
- return devc->audio_minor;
-
- /* So many ways to fail. Undo what we did. */
-
- fail7:
- unregister_sound_dsp(devc->audio_minor);
- fail6:
- free_irq(hw_config->irq, devc);
- fail5:
- fail4:
- free_pages(devc->wport.hwbuf_vaddr, HWBUF_ORDER);
- fail3:
- free_pages(devc->rport.hwbuf_vaddr, HWBUF_ORDER);
- fail2:
- li_destroy(&devc->lith);
- fail1:
- kfree(devc);
- fail0:
- return err;
-}
-
-static int __exit unload_vwsnd(struct address_info *hw_config)
-{
- vwsnd_dev_t *devc, **devcp;
-
- DBGE("()\n");
-
- devcp = &vwsnd_dev_list;
- while ((devc = *devcp)) {
- if (devc->audio_minor == hw_config->slots[0]) {
- *devcp = devc->next_dev;
- break;
- }
- devcp = &devc->next_dev;
- }
-
- if (!devc)
- return -ENODEV;
-
- unregister_sound_mixer(devc->mixer_minor);
- unregister_sound_dsp(devc->audio_minor);
- free_irq(hw_config->irq, devc);
- free_pages(devc->wport.hwbuf_vaddr, HWBUF_ORDER);
- free_pages(devc->rport.hwbuf_vaddr, HWBUF_ORDER);
- li_destroy(&devc->lith);
- kfree(devc);
-
- return 0;
-}
-
-/*****************************************************************************/
-/* initialization and loadable kernel module interface */
-
-static struct address_info the_hw_config = {
- 0xFF001000, /* lithium phys addr */
- CO_IRQ(CO_APIC_LI_AUDIO) /* irq */
-};
-
-MODULE_DESCRIPTION("SGI Visual Workstation sound module");
-MODULE_AUTHOR("Bob Miller <kbob@sgi.com>");
-MODULE_LICENSE("GPL");
-
-static int __init init_vwsnd(void)
-{
- int err;
-
- DBGXV("\n");
- DBGXV("sound::vwsnd::init_module()\n");
-
- if (!probe_vwsnd(&the_hw_config))
- return -ENODEV;
-
- err = attach_vwsnd(&the_hw_config);
- if (err < 0)
- return err;
- return 0;
-}
-
-static void __exit cleanup_vwsnd(void)
-{
- DBGX("sound::vwsnd::cleanup_module()\n");
-
- unload_vwsnd(&the_hw_config);
-}
-
-module_init(init_vwsnd);
-module_exit(cleanup_vwsnd);
diff --git a/sound/oss/waveartist.c b/sound/oss/waveartist.c
index b48c72923a1..672af8b5654 100644
--- a/sound/oss/waveartist.c
+++ b/sound/oss/waveartist.c
@@ -35,19 +35,19 @@
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/bitops.h>
-#include <asm/system.h>
#include "sound_config.h"
#include "waveartist.h"
#ifdef CONFIG_ARM
-#include <asm/hardware.h>
+#include <mach/hardware.h>
#include <asm/mach-types.h>
#endif
@@ -183,14 +183,8 @@ waveartist_iack(wavnc_info *devc)
static inline int
waveartist_sleep(int timeout_ms)
{
- unsigned int timeout = timeout_ms * 10 * HZ / 100;
-
- do {
- set_current_state(TASK_INTERRUPTIBLE);
- timeout = schedule_timeout(timeout);
- } while (timeout);
-
- return 0;
+ unsigned int timeout = msecs_to_jiffies(timeout_ms*100);
+ return schedule_timeout_interruptible(timeout);
}
static int
@@ -835,7 +829,7 @@ static struct audio_driver waveartist_audio_driver = {
static irqreturn_t
waveartist_intr(int irq, void *dev_id)
{
- wavnc_info *devc = (wavnc_info *)dev_id;
+ wavnc_info *devc = dev_id;
int irqstatus, status;
spin_lock(&waveartist_lock);
@@ -1483,16 +1477,14 @@ static void __exit unload_waveartist(struct address_info *hw)
#define VNC_HANDSET_DETECT 0x40
#define VNC_DISABLE_AUTOSWITCH 0x80
-extern spinlock_t gpio_lock;
-
static inline void
vnc_mute_spkr(wavnc_info *devc)
{
unsigned long flags;
- spin_lock_irqsave(&gpio_lock, flags);
- cpld_modify(CPLD_UNMUTE, devc->spkr_mute_state ? 0 : CPLD_UNMUTE);
- spin_unlock_irqrestore(&gpio_lock, flags);
+ raw_spin_lock_irqsave(&nw_gpio_lock, flags);
+ nw_cpld_modify(CPLD_UNMUTE, devc->spkr_mute_state ? 0 : CPLD_UNMUTE);
+ raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
}
static void